[MM-36423][MM-36427] Edit/Delete modals for dropdown (#1682)

* [MM-36423] Edit/Delete modals for dropdown

* [MM-36427] Remove Server Management from Settings modal

* Style fixes

* Hover states for edit/delete buttons

* Update config.yml

* Oops I broke something
This commit is contained in:
Devin Binnie 2021-08-09 12:04:27 -04:00 committed by GitHub
parent 638e331c58
commit d77b6f81a9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 302 additions and 339 deletions

View file

@ -449,7 +449,7 @@ workflows:
branches:
only:
- /^release-\d+(\.\d+){1,2}(-rc.*)?/
- pull/1681
- pull/1682
- store_artifacts:
# for master/PR builds

View file

@ -39,6 +39,7 @@ if [[ -f "${SRC}/mattermost-desktop-${VERSION}-mac-x64.zip" ]]; then
cp "${SRC}/mattermost-desktop-${VERSION}-mac-x64.zip" "${DEST}/mattermost-desktop-${VERSION}-mac-x64.zip"
if [[ -f "${SRC}"/mattermost-desktop-${VERSION}-mac-x64.dmg ]]; then
cp "${SRC}/mattermost-desktop-${VERSION}-mac-x64.dmg.blockmap" "${DEST}/mattermost-desktop-${VERSION}-mac-x64.dmg.blockmap"
cp "${SRC}/mattermost-desktop-${VERSION}-mac-x64.dmg" "${DEST}/mattermost-desktop-${VERSION}-mac-x64.dmg"
fi
SOMETHING_COPIED=$((SOMETHING_COPIED + 8))
fi
@ -47,6 +48,7 @@ if [[ -f "${SRC}/mattermost-desktop-${VERSION}-mac-arm64.zip" ]]; then
cp "${SRC}/mattermost-desktop-${VERSION}-mac-arm64.zip" "${DEST}/mattermost-desktop-${VERSION}-mac-arm64.zip"
if [[ -f "${SRC}"/mattermost-desktop-${VERSION}-mac-arm64.dmg ]]; then
cp "${SRC}/mattermost-desktop-${VERSION}-mac-arm64.dmg.blockmap" "${DEST}/mattermost-desktop-${VERSION}-mac-arm64.dmg.blockmap"
cp "${SRC}/mattermost-desktop-${VERSION}-mac-arm64.dmg" "${DEST}/mattermost-desktop-${VERSION}-mac-arm64.dmg"
fi
SOMETHING_COPIED=$((SOMETHING_COPIED + 16))
fi

View file

@ -35,6 +35,8 @@ export const OPEN_EXTERNAL = 'open_external';
export const DOUBLE_CLICK_ON_WINDOW = 'double_click';
export const SHOW_NEW_SERVER_MODAL = 'show_new_server_modal';
export const SHOW_EDIT_SERVER_MODAL = 'show-edit-server-modal';
export const SHOW_REMOVE_SERVER_MODAL = 'show-remove-server-modal';
export const RETRIEVE_MODAL_INFO = 'retrieve-modal-info';
export const MODAL_INFO = 'modal-info';

View file

@ -37,6 +37,8 @@ import {
USER_ACTIVITY_UPDATE,
EMIT_CONFIGURATION,
SWITCH_TAB,
SHOW_EDIT_SERVER_MODAL,
SHOW_REMOVE_SERVER_MODAL,
} from 'common/communication';
import Config from 'common/config';
import {getDefaultTeamWithTabsFromTeam} from 'common/tabs/TabView';
@ -245,6 +247,8 @@ function initializeInterCommunicationEventListeners() {
ipcMain.on(DOUBLE_CLICK_ON_WINDOW, WindowManager.handleDoubleClick);
ipcMain.on(SHOW_NEW_SERVER_MODAL, handleNewServerModal);
ipcMain.on(SHOW_EDIT_SERVER_MODAL, handleEditServerModal);
ipcMain.on(SHOW_REMOVE_SERVER_MODAL, handleRemoveServerModal);
ipcMain.on(WINDOW_CLOSE, WindowManager.close);
ipcMain.on(WINDOW_MAXIMIZE, WindowManager.maximize);
ipcMain.on(WINDOW_MINIMIZE, WindowManager.minimize);
@ -504,6 +508,75 @@ function handleNewServerModal() {
}
}
function handleEditServerModal(e: IpcMainEvent, name: string) {
const html = getLocalURLString('editServer.html');
const modalPreload = getLocalPreload('modalPreload.js');
const mainWindow = WindowManager.getMainWindow();
if (!mainWindow) {
return;
}
const serverIndex = config.teams.findIndex((team) => team.name === name);
if (serverIndex < 0) {
return;
}
const modalPromise = addModal<Team, Team>('editServer', html, modalPreload, config.teams[serverIndex], mainWindow);
if (modalPromise) {
modalPromise.then((data) => {
const teams = config.teams;
teams[serverIndex].name = data.name;
teams[serverIndex].url = data.url;
config.set('teams', teams);
}).catch((e) => {
// e is undefined for user cancellation
if (e) {
log.error(`there was an error in the edit server modal: ${e}`);
}
});
} else {
log.warn('There is already an edit server modal');
}
}
function handleRemoveServerModal(e: IpcMainEvent, name: string) {
const html = getLocalURLString('removeServer.html');
const modalPreload = getLocalPreload('modalPreload.js');
const mainWindow = WindowManager.getMainWindow();
if (!mainWindow) {
return;
}
const modalPromise = addModal<string, boolean>('removeServer', html, modalPreload, name, mainWindow);
if (modalPromise) {
modalPromise.then((remove) => {
if (remove) {
const teams = config.teams;
const removedTeam = teams.findIndex((team) => team.name === name);
if (removedTeam < 0) {
return;
}
const removedOrder = teams[removedTeam].order;
teams.splice(removedTeam, 1);
teams.forEach((value) => {
if (value.order > removedOrder) {
value.order--;
}
});
config.set('teams', teams);
}
}).catch((e) => {
// e is undefined for user cancellation
if (e) {
log.error(`there was an error in the edit server modal: ${e}`);
}
});
} else {
log.warn('There is already an edit server modal');
}
}
function initializeAfterAppReady() {
app.setAppUserModelId('Mattermost.Desktop'); // Use explicit AppUserModelID
const defaultSession = session.defaultSession;

View file

@ -13,6 +13,8 @@ import {
SWITCH_SERVER,
CLOSE_TEAMS_DROPDOWN,
SHOW_NEW_SERVER_MODAL,
SHOW_EDIT_SERVER_MODAL,
SHOW_REMOVE_SERVER_MODAL,
UPDATE_TEAMS,
} from 'common/communication';
@ -32,6 +34,12 @@ window.addEventListener('message', async (event) => {
case SHOW_NEW_SERVER_MODAL:
ipcRenderer.send(SHOW_NEW_SERVER_MODAL);
break;
case SHOW_EDIT_SERVER_MODAL:
ipcRenderer.send(SHOW_EDIT_SERVER_MODAL, event.data.data.name);
break;
case SHOW_REMOVE_SERVER_MODAL:
ipcRenderer.send(SHOW_REMOVE_SERVER_MODAL, event.data.data.name);
break;
case CLOSE_TEAMS_DROPDOWN:
ipcRenderer.send(CLOSE_TEAMS_DROPDOWN);
break;

View file

@ -14,10 +14,9 @@ import {debounce} from 'underscore';
import {CombinedConfig, LocalConfiguration, Team} from 'types/config';
import {DeepPartial} from 'types/utils';
import {GET_LOCAL_CONFIGURATION, UPDATE_CONFIGURATION, DOUBLE_CLICK_ON_WINDOW, GET_DOWNLOAD_LOCATION, SWITCH_SERVER, ADD_SERVER, RELOAD_CONFIGURATION} from 'common/communication';
import {GET_LOCAL_CONFIGURATION, UPDATE_CONFIGURATION, DOUBLE_CLICK_ON_WINDOW, GET_DOWNLOAD_LOCATION, ADD_SERVER, RELOAD_CONFIGURATION} from 'common/communication';
import {getDefaultTeamWithTabsFromTeam} from 'common/tabs/TabView';
import TeamList from './TeamList';
import AutoSaveIndicator, {SavingState} from './AutoSaveIndicator';
const CONFIG_TYPE_SERVERS = 'servers';
@ -48,11 +47,6 @@ type SaveQueueItem = {
data: CombinedConfig[keyof CombinedConfig];
}
function backToIndex(serverName: string) {
window.ipcRenderer.send(SWITCH_SERVER, serverName);
window.close();
}
export default class SettingsPage extends React.PureComponent<Record<string, never>, State> {
trayIconThemeRef: React.RefObject<HTMLDivElement>;
downloadLocationRef: React.RefObject<HTMLInputElement>;
@ -428,64 +422,6 @@ export default class SettingsPage extends React.PureComponent<Record<string, nev
},
};
const teamsRow = (
<Row>
<Col md={12}>
<TeamList
teams={this.state.teams!}
showAddTeamForm={this.state.showAddTeamForm}
setAddTeamFormVisibility={this.setShowTeamFormVisibility}
onTeamsChange={this.handleTeamsChange}
updateTeam={this.updateTeam}
addServer={this.addServer}
onTeamClick={(name) => {
backToIndex(name);
}}
/>
</Col>
</Row>
);
const serversRow = (
<Row>
<Col
xs={8}
>
<h2 style={settingsPage.sectionHeading}>{'Server Management'}</h2>
<div className='IndicatorContainer'>
<AutoSaveIndicator
id='serversSaveIndicator'
savingState={this.state.savingState.servers}
errorMessage={'Can\'t save your changes. Please try again.'}
/>
</div>
</Col>
<Col
xs={4}
>
<p className='text-right'>
<a
style={settingsPage.sectionHeadingLink}
id='addNewServer'
href='#'
onClick={this.toggleShowTeamForm}
>{'+ Add New Server'}</a>
</p>
</Col>
</Row>
);
let srvMgmt;
if (this.state.enableServerManagement === true) {
srvMgmt = (
<div>
{serversRow}
{teamsRow}
<hr/>
</div>
);
}
const options = [];
// MacOS has an option in the Dock, to set the app to autostart, so we choose to not support this option for OSX
@ -800,12 +736,7 @@ export default class SettingsPage extends React.PureComponent<Record<string, nev
let waitForIpc;
if (this.state.ready) {
waitForIpc = (
<>
{srvMgmt}
{optionsRow}
</>
);
waitForIpc = optionsRow;
} else {
waitForIpc = (<p>{'Loading configuration...'}</p>);
}

View file

@ -1,193 +0,0 @@
// Copyright (c) 2015-2016 Yuya Ochiai
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
import {ListGroup} from 'react-bootstrap';
import {Team, TeamWithIndex} from 'types/config';
import TeamListItem from './TeamListItem';
import NewTeamModal from './NewTeamModal';
import RemoveServerModal from './RemoveServerModal';
type Props = {
onTeamClick: (teamName: string) => void;
onTeamsChange: (teams: Team[]) => void;
showAddTeamForm?: boolean;
teams: Team[];
addServer: (team: Team) => void;
updateTeam: (index: number, team: Team) => void;
setAddTeamFormVisibility: (visible: boolean) => void;
};
type State = {
team: TeamWithIndex;
showEditTeamForm: boolean;
indexToRemoveServer: number;
}
export default class TeamList extends React.PureComponent<Props, State> {
constructor(props: Props) {
super(props);
this.state = {
showEditTeamForm: false,
indexToRemoveServer: -1,
team: {
url: '',
name: '',
index: 0,
order: props.teams.length,
},
};
}
handleTeamRemove = (index: number) => {
console.log(index);
const teams = this.props.teams;
const removedOrder = this.props.teams[index].order;
teams.splice(index, 1);
teams.forEach((value) => {
if (value.order > removedOrder) {
value.order--;
}
});
this.props.onTeamsChange(teams);
}
handleTeamAdd = (team: TeamWithIndex) => {
const teams = this.props.teams;
// check if team already exists and then change existing team or add new one
if ((typeof team.index !== 'undefined') && teams[team.index]) {
teams[team.index].name = team.name;
teams[team.index].url = team.url;
teams[team.index].order = team.order;
} else {
teams.push(team);
}
this.setState({
showEditTeamForm: false,
team: {
url: '',
name: '',
index: 0,
order: teams.length,
},
});
this.props.onTeamsChange(teams);
}
openServerRemoveModal = (indexForServer: number) => {
this.setState({indexToRemoveServer: indexForServer});
}
closeServerRemoveModal = () => {
this.setState({indexToRemoveServer: -1});
}
handleTeamRemovePrompt = (index: number) => {
return () => {
(document.activeElement as HTMLElement).blur();
this.openServerRemoveModal(index);
};
}
handleTeamEditing = (team: Team, index: number) => {
return () => {
(document.activeElement as HTMLElement).blur();
this.setState({
showEditTeamForm: true,
team: {
url: team.url,
name: team.name,
index,
order: team.order,
},
});
};
}
render() {
const teamNodes = this.props.teams.map((team, i) => {
return (
<TeamListItem
key={`teamListItem_${team.name}`}
name={team.name}
url={team.url}
onTeamRemove={this.handleTeamRemovePrompt(i)}
onTeamEditing={this.handleTeamEditing(team, i)}
onTeamClick={() => this.props.onTeamClick(team.name)}
/>
);
});
const addServerForm = (
<NewTeamModal
currentOrder={this.props.teams.length}
show={this.props.showAddTeamForm || this.state.showEditTeamForm}
editMode={this.state.showEditTeamForm}
onClose={() => {
this.setState({
showEditTeamForm: false,
team: {
name: '',
url: '',
index: 0,
order: this.props.teams.length,
},
});
this.props.setAddTeamFormVisibility(false);
}}
onSave={(newTeam) => {
const teamData = {
name: newTeam.name,
url: newTeam.url,
order: newTeam.order,
};
if (this.props.showAddTeamForm) {
this.props.addServer(teamData);
} else {
this.props.updateTeam(newTeam.index, teamData);
}
this.setState({
showEditTeamForm: false,
team: {
name: '',
url: '',
index: 0,
order: newTeam.order + 1,
},
});
this.render();
this.props.setAddTeamFormVisibility(false);
}}
team={this.state.team}
/>);
const removeServer = this.props.teams[this.state.indexToRemoveServer];
const removeServerModal = (
<RemoveServerModal
show={this.state.indexToRemoveServer !== -1}
serverName={removeServer ? removeServer.name : ''}
onHide={this.closeServerRemoveModal}
onCancel={this.closeServerRemoveModal}
onAccept={() => {
this.handleTeamRemove(this.state.indexToRemoveServer);
this.closeServerRemoveModal();
}}
/>
);
return (
<ListGroup className='teamList'>
{ teamNodes }
{ addServerForm }
{ removeServerModal}
</ListGroup>
);
}
}

View file

@ -1,48 +0,0 @@
// Copyright (c) 2015-2016 Yuya Ochiai
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
type Props = {
name: string;
onTeamEditing: () => void;
onTeamRemove: () => void;
onTeamClick: React.MouseEventHandler<HTMLDivElement>;
url: string;
};
export default class TeamListItem extends React.PureComponent<Props> {
handleTeamRemove = () => {
this.props.onTeamRemove();
}
handleTeamEditing = () => {
this.props.onTeamEditing();
}
render() {
return (
<div className='TeamListItem list-group-item'>
<div
className='TeamListItem-left'
onClick={this.props.onTeamClick}
>
<h4 className='list-group-item-heading'>{ this.props.name }</h4>
<p className='list-group-item-text'>
{ this.props.url }
</p>
</div>
<div>
<a
href='#'
onClick={this.handleTeamEditing}
>{'Edit'}</a>
{' - '}
<a
href='#'
onClick={this.handleTeamRemove}
>{'Remove'}</a>
</div>
</div>
);
}
}

View file

@ -1,21 +0,0 @@
.TeamListItem {
display: flex;
}
.TeamListItem:hover {
background: #eee;
}
.TeamListItem-left {
flex-grow: 1;
}
.TeamListItem p {
overflow-wrap: break-word;
margin-bottom: 0;
}
.TeamListItem h4 {
overflow: hidden;
text-overflow: ellipsis;
};

View file

@ -5,7 +5,6 @@
@import url("NewTeamModal.css");
@import url("PermissionRequestDialog.css");
@import url("TabBar.css");
@import url("TeamListItem.css");
@import url("UpdaterPage.css");
@import url("CertificateModal.css");
@import url("ExtraBar.css");

View file

@ -183,8 +183,20 @@ body {
margin-left: 18px;
background-color: transparent;
border: none;
border-radius: 2px;
padding: 0;
&:hover, &:focus {
background: rgba(61, 60, 64, 0.08);
box-shadow: 0px 0px 0px 4px rgba(61, 60, 64, 0.08);
outline: none;
}
&.TeamDropdown__button-remove:hover, &.TeamDropdown__button-remove:focus {
background: rgba(247, 67, 67, 0.16);
box-shadow: 0px 0px 0px 4px rgba(247, 67, 67, 0.16);
}
> i::before {
margin: 0;
}
@ -194,6 +206,11 @@ body {
.TeamDropdown__button-edit, .TeamDropdown__button-remove {
opacity: 0;
pointer-events: none;
&:focus {
opacity: 1;
pointer-events: all;
}
}
.TeamDropdown__button-remove {
@ -204,7 +221,7 @@ body {
}
i {
color: #f74343;
color: #F74343;
}
}
@ -235,6 +252,15 @@ body {
> .TeamDropdown__draggable-handle > span, &.addServer > span {
color: #DDD;
}
.TeamDropdown__button-remove i {
color: #F74343;
}
.TeamDropdown__button-edit:hover, .TeamDropdown__button-edit:focus {
background: rgba(221, 223, 228, 0.08);
box-shadow: 0px 0px 0px 4px rgba(221, 223, 228, 0.08);
}
}
.TeamDropdown__badge-expired i {
@ -248,4 +274,12 @@ body {
.TeamDropdown__draggable-handle > i.icon-drag-vertical::before {
color:rgba(221, 221, 221, 0.32);
}
.TeamDropdown__badge-count i {
color: #e81023;
}
.TeamDropdown__badge-dot {
background: #196CAF;
}
}

View file

@ -8,7 +8,16 @@ import {DragDropContext, Draggable, DraggingStyle, Droppable, DropResult, NotDra
import {Team, TeamWithTabs} from 'types/config';
import {CLOSE_TEAMS_DROPDOWN, REQUEST_TEAMS_DROPDOWN_INFO, SEND_DROPDOWN_MENU_SIZE, SHOW_NEW_SERVER_MODAL, SWITCH_SERVER, UPDATE_TEAMS, UPDATE_TEAMS_DROPDOWN} from 'common/communication';
import {
CLOSE_TEAMS_DROPDOWN,
REQUEST_TEAMS_DROPDOWN_INFO,
SEND_DROPDOWN_MENU_SIZE,
SHOW_NEW_SERVER_MODAL,
SHOW_EDIT_SERVER_MODAL,
SHOW_REMOVE_SERVER_MODAL,
SWITCH_SERVER, UPDATE_TEAMS,
UPDATE_TEAMS_DROPDOWN,
} from 'common/communication';
import {getTabViewName} from 'common/tabs/TabView';
@ -144,6 +153,22 @@ class TeamDropdown extends React.PureComponent<Record<string, never>, State> {
}
}
editServer = (team: string) => {
return (event: React.MouseEvent<HTMLButtonElement>) => {
event.stopPropagation();
window.postMessage({type: SHOW_EDIT_SERVER_MODAL, data: {name: team}}, window.location.href);
this.closeMenu();
};
}
removeServer = (team: string) => {
return (event: React.MouseEvent<HTMLButtonElement>) => {
event.stopPropagation();
window.postMessage({type: SHOW_REMOVE_SERVER_MODAL, data: {name: team}}, window.location.href);
this.closeMenu();
};
}
render() {
return (
<div
@ -232,13 +257,13 @@ class TeamDropdown extends React.PureComponent<Record<string, never>, State> {
<div className='TeamDropdown__indicators'>
<button
className='TeamDropdown__button-edit'
disabled={true}
onClick={this.editServer(team.name)}
>
<i className='icon-pencil-outline'/>
</button>
<button
className='TeamDropdown__button-remove'
disabled={true}
onClick={this.removeServer(team.name)}
>
<i className='icon-trash-can-outline'/>
</button>

View file

@ -0,0 +1,66 @@
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import 'bootstrap/dist/css/bootstrap.min.css';
import 'renderer/css/modals.css';
import React, {useEffect, useState} from 'react';
import ReactDOM from 'react-dom';
import {TeamWithIndex} from 'types/config';
import {ModalMessage} from 'types/modals';
import {MODAL_CANCEL, MODAL_INFO, MODAL_RESULT, RETRIEVE_MODAL_INFO} from 'common/communication';
import NewTeamModal from '../../components/NewTeamModal'; //'./addServer.jsx';
import setupDarkMode from '../darkMode';
setupDarkMode();
const onClose = () => {
window.postMessage({type: MODAL_CANCEL}, window.location.href);
};
const onSave = (data: TeamWithIndex) => {
window.postMessage({type: MODAL_RESULT, data}, window.location.href);
};
const EditServerModalWrapper: React.FC = () => {
const [server, setServer] = useState<TeamWithIndex>();
const handleEditServerMessage = (event: {data: ModalMessage<TeamWithIndex>}) => {
switch (event.data.type) {
case MODAL_INFO: {
setServer(event.data.data);
break;
}
default:
break;
}
};
useEffect(() => {
window.addEventListener('message', handleEditServerMessage);
window.postMessage({type: RETRIEVE_MODAL_INFO}, window.location.href);
}, []);
return (
<NewTeamModal
onClose={onClose}
onSave={onSave}
editMode={true}
show={Boolean(server)}
team={server}
/>
);
};
const start = async () => {
ReactDOM.render(
<EditServerModalWrapper/>,
document.getElementById('app'),
);
};
start();

View file

@ -0,0 +1,71 @@
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import 'bootstrap/dist/css/bootstrap.min.css';
import 'renderer/css/modals.css';
import React, {useEffect, useState} from 'react';
import ReactDOM from 'react-dom';
import {ModalMessage} from 'types/modals';
import {MODAL_CANCEL, MODAL_INFO, MODAL_RESULT, RETRIEVE_MODAL_INFO} from 'common/communication';
import RemoveServerModal from '../../components/RemoveServerModal';
import setupDarkMode from '../darkMode';
setupDarkMode();
const onClose = () => {
window.postMessage({type: MODAL_CANCEL}, window.location.href);
};
const onSave = (data: boolean) => {
window.postMessage({type: MODAL_RESULT, data}, window.location.href);
};
const RemoveServerModalWrapper: React.FC = () => {
const [serverName, setServerName] = useState<string>('');
const handleRemoveServerMessage = (event: {data: ModalMessage<string>}) => {
switch (event.data.type) {
case MODAL_INFO: {
setServerName(event.data.data);
break;
}
default:
break;
}
};
useEffect(() => {
window.addEventListener('message', handleRemoveServerMessage);
window.postMessage({type: RETRIEVE_MODAL_INFO}, window.location.href);
}, []);
return (
<RemoveServerModal
show={true}
serverName={serverName}
onHide={() => {
onClose();
}}
onCancel={() => {
onSave(false);
}}
onAccept={() => {
onSave(true);
}}
/>
);
};
const start = async () => {
ReactDOM.render(
<RemoveServerModalWrapper/>,
document.getElementById('app'),
);
};
start();

View file

@ -22,6 +22,8 @@ module.exports = merge(base, {
dropdown: './src/renderer/dropdown.tsx',
urlView: './src/renderer/modals/urlView/urlView.tsx',
newServer: './src/renderer/modals/newServer/newServer.tsx',
editServer: './src/renderer/modals/editServer/editServer.tsx',
removeServer: './src/renderer/modals/removeServer/removeServer.tsx',
loginModal: './src/renderer/modals/login/login.tsx',
permissionModal: './src/renderer/modals/permission/permission.tsx',
certificateModal: './src/renderer/modals/certificate/certificate.tsx',
@ -62,6 +64,18 @@ module.exports = merge(base, {
chunks: ['newServer'],
filename: 'newServer.html',
}),
new HtmlWebpackPlugin({
title: 'Mattermost Desktop Settings',
template: 'src/renderer/index.html',
chunks: ['editServer'],
filename: 'editServer.html',
}),
new HtmlWebpackPlugin({
title: 'Mattermost Desktop Settings',
template: 'src/renderer/index.html',
chunks: ['removeServer'],
filename: 'removeServer.html',
}),
new HtmlWebpackPlugin({
title: 'Mattermost Desktop Settings',
template: 'src/renderer/index.html',