diff --git a/src/common/communication.ts b/src/common/communication.ts index 57b8b9fe..68388c7d 100644 --- a/src/common/communication.ts +++ b/src/common/communication.ts @@ -97,3 +97,4 @@ export const RECEIVE_DROPDOWN_MENU_SIZE = 'receive-dropdown-menu-size'; export const SEND_DROPDOWN_MENU_SIZE = 'send-dropdown-menu-size'; export const BROWSER_HISTORY_PUSH = 'browser-history-push'; +export const APP_LOGGED_IN = 'app-logged-in'; diff --git a/src/common/tabs/TabView.ts b/src/common/tabs/TabView.ts index 97c047b9..58fc7ce2 100644 --- a/src/common/tabs/TabView.ts +++ b/src/common/tabs/TabView.ts @@ -30,17 +30,15 @@ export function getDefaultTeamWithTabsFromTeam(team: Team) { { name: TAB_MESSAGING, order: 0, - isClosed: false, + isOpen: true, }, { name: TAB_FOCALBOARD, order: 1, - isClosed: false, }, { name: TAB_PLAYBOOKS, order: 2, - isClosed: false, }, ], }; diff --git a/src/common/utils/util.ts b/src/common/utils/util.ts index fe5407dd..32c04fa6 100644 --- a/src/common/utils/util.ts +++ b/src/common/utils/util.ts @@ -37,7 +37,7 @@ function shorten(string: string, max?: number) { return string; } -export function isServerVersionGreaterThanOrEqualTo(currentVersion: string, compareVersion: string): boolean { +function isServerVersionGreaterThanOrEqualTo(currentVersion: string, compareVersion: string): boolean { if (currentVersion === compareVersion) { return true; } diff --git a/src/main/Validator.ts b/src/main/Validator.ts index bcd072a3..f641a31e 100644 --- a/src/main/Validator.ts +++ b/src/main/Validator.ts @@ -11,6 +11,7 @@ import {AppState} from 'types/appState'; import {ComparableCertificate} from 'types/certificate'; import {PermissionType, TrustedOrigin} from 'types/trustedOrigin'; +import {TAB_MESSAGING} from 'common/tabs/TabView'; import urlUtils from 'common/utils/url'; const defaultOptions = { @@ -103,7 +104,7 @@ const configDataSchemaV3 = Joi.object({ tabs: Joi.array().items(Joi.object({ name: Joi.string().required(), order: Joi.number().integer().min(0), - isClosed: Joi.boolean().default(false), + isOpen: Joi.boolean(), })).default([]), })).default([]), showTrayIcon: Joi.boolean().default(false), @@ -226,6 +227,14 @@ export function validateV3ConfigData(data: ConfigV3) { return { ...team, url: cleanURL(team.url), + + // Force messaging to stay open regardless of user config + tabs: team.tabs.map((tab) => { + return { + ...tab, + isOpen: tab.name === TAB_MESSAGING ? true : tab.isOpen, + }; + }), }; }); diff --git a/src/main/main.ts b/src/main/main.ts index b38d558b..e9da130e 100644 --- a/src/main/main.ts +++ b/src/main/main.ts @@ -47,7 +47,7 @@ import { import Config from 'common/config'; import {MattermostServer} from 'common/servers/MattermostServer'; import {getDefaultTeamWithTabsFromTeam, TAB_FOCALBOARD, TAB_MESSAGING, TAB_PLAYBOOKS} from 'common/tabs/TabView'; -import Utils, {isServerVersionGreaterThanOrEqualTo} from 'common/utils/util'; +import Utils from 'common/utils/util'; import urlUtils from 'common/utils/url'; @@ -515,12 +515,12 @@ function handleCloseTab(event: IpcMainEvent, serverName: string, tabName: string if (team.name === serverName) { team.tabs.forEach((tab) => { if (tab.name === tabName) { - tab.isClosed = true; + tab.isOpen = false; } }); } }); - const nextTab = teams.find((team) => team.name === serverName)!.tabs.filter((tab) => !tab.isClosed)[0].name; + const nextTab = teams.find((team) => team.name === serverName)!.tabs.filter((tab) => tab.isOpen)[0].name; WindowManager.switchTab(serverName, nextTab); config.set('teams', teams); } @@ -531,7 +531,7 @@ function handleOpenTab(event: IpcMainEvent, serverName: string, tabName: string) if (team.name === serverName) { team.tabs.forEach((tab) => { if (tab.name === tabName) { - tab.isClosed = false; + tab.isOpen = true; } }); } @@ -815,28 +815,26 @@ function updateServerInfos(teams: TeamWithTabs[]) { }); Promise.all(serverInfos).then((data: Array) => { const teams = config.teams; - teams.forEach((team) => closeUnneededTabs(data, team)); + teams.forEach((team) => openExtraTabs(data, team)); config.set('teams', teams); }).catch((reason: any) => { log.error('Error getting server infos', reason); }); } -function closeUnneededTabs(data: Array, team: TeamWithTabs) { +function openExtraTabs(data: Array, team: TeamWithTabs) { const remoteInfo = data.find((info) => info && typeof info !== 'string' && info.name === team.name) as RemoteInfo; if (remoteInfo) { team.tabs.forEach((tab) => { - if (tab.name === TAB_PLAYBOOKS && !remoteInfo.hasPlaybooks) { - log.info(`closing ${team.name}___${tab.name} on !hasPlaybooks`); - tab.isClosed = true; - } - if (tab.name === TAB_FOCALBOARD && !remoteInfo.hasFocalboard) { - log.info(`closing ${team.name}___${tab.name} on !hasFocalboard`); - tab.isClosed = true; - } - if (tab.name !== TAB_MESSAGING && remoteInfo.serverVersion && !isServerVersionGreaterThanOrEqualTo(remoteInfo.serverVersion, '6.0.0')) { - log.info(`closing ${team.name}___${tab.name} on !serverVersion`); - tab.isClosed = true; + if (tab.name !== TAB_MESSAGING && remoteInfo.serverVersion && Utils.isServerVersionGreaterThanOrEqualTo(remoteInfo.serverVersion, '6.0.0')) { + if (tab.name === TAB_PLAYBOOKS && remoteInfo.hasPlaybooks && tab.isOpen !== false) { + log.info(`opening ${team.name}___${tab.name} on hasPlaybooks`); + tab.isOpen = true; + } + if (tab.name === TAB_FOCALBOARD && remoteInfo.hasFocalboard && tab.isOpen !== false) { + log.info(`opening ${team.name}___${tab.name} on hasFocalboard`); + tab.isOpen = true; + } } }); } diff --git a/src/main/preload/mattermost.js b/src/main/preload/mattermost.js index 9e9c36ae..ec422f56 100644 --- a/src/main/preload/mattermost.js +++ b/src/main/preload/mattermost.js @@ -22,6 +22,7 @@ import { USER_ACTIVITY_UPDATE, CLOSE_TEAMS_DROPDOWN, BROWSER_HISTORY_PUSH, + APP_LOGGED_IN, } from 'common/communication'; const UNREAD_COUNT_INTERVAL = 1000; @@ -242,4 +243,10 @@ ipcRenderer.on(BROWSER_HISTORY_PUSH, (event, pathName) => { ); }); +window.addEventListener('storage', (e) => { + if (e.key === '__login__' && e.storageArea === localStorage && e.newValue) { + ipcRenderer.send(APP_LOGGED_IN, viewName); + } +}); + /* eslint-enable no-magic-numbers */ diff --git a/src/main/views/viewManager.ts b/src/main/views/viewManager.ts index b3d76528..dc5a18c3 100644 --- a/src/main/views/viewManager.ts +++ b/src/main/views/viewManager.ts @@ -20,7 +20,7 @@ import { UPDATE_LAST_ACTIVE, } from 'common/communication'; import urlUtils from 'common/utils/url'; -import {isServerVersionGreaterThanOrEqualTo} from 'common/utils/util'; +import Utils from 'common/utils/util'; import {getServerView, getTabViewName} from 'common/tabs/TabView'; @@ -72,12 +72,13 @@ export class ViewManager { loadView = (srv: MattermostServer, serverInfo: ServerInfo, tab: Tab, url?: string) => { const tabView = getServerView(srv, tab); - if (tab.isClosed) { + if (!tab.isOpen) { this.closedViews.set(tabView.name, {srv, tab}); return; } const view = new MattermostView(tabView, serverInfo, this.mainWindow, this.viewOptions); this.views.set(tabView.name, view); + this.showByName(tabView.name); if (!this.loadingScreen) { this.createLoadingScreen(); } @@ -88,6 +89,13 @@ export class ViewManager { view.once(LOAD_FAILED, this.failLoading); } + reloadViewIfNeeded = (viewName: string) => { + const view = this.views.get(viewName); + if (!view?.getWebContents()?.getURL().startsWith(view.tab.url.toString())) { + view?.load(view.tab.url); + } + } + load = () => { this.configServers.forEach((server) => this.loadServer(server)); } @@ -107,7 +115,7 @@ export class ViewManager { if (recycle && recycle.isVisible) { setFocus = recycle.name; } - if (tab.isClosed) { + if (!tab.isOpen) { this.closedViews.set(tabView.name, {srv, tab}); } else if (recycle && recycle.tab.name === tabView.name && recycle.tab.url.toString() === urlUtils.parseURL(tabView.url)!.toString()) { oldviews.delete(recycle.name); @@ -117,6 +125,14 @@ export class ViewManager { } }); }); + if (this.currentView && (oldviews.has(this.currentView) || this.closedViews.has(this.currentView))) { + if (configServers.length) { + delete this.currentView; + this.showInitial(); + } else { + this.mainWindow.webContents.send(SET_ACTIVE_VIEW); + } + } oldviews.forEach((unused) => { unused.destroy(); }); @@ -132,8 +148,8 @@ export class ViewManager { const element = this.configServers.find((e) => e.order === this.lastActiveServer || 0); if (element && element.tabs.length) { let tab = element.tabs.find((tab) => tab.order === element.lastActiveTab || 0); - if (tab?.isClosed) { - const openTabs = element.tabs.filter((tab) => !tab.isClosed); + if (!tab?.isOpen) { + const openTabs = element.tabs.filter((tab) => tab.isOpen); tab = openTabs.find((e) => e.order === 0) || openTabs[0]; } if (tab) { @@ -220,7 +236,7 @@ export class ViewManager { return; } const {srv, tab} = this.closedViews.get(name)!; - tab.isClosed = false; + tab.isOpen = true; this.closedViews.delete(name); this.loadView(srv, new ServerInfo(srv), tab, url); this.showByName(name); @@ -407,7 +423,7 @@ export class ViewManager { return; } - if (view.status === Status.READY && view.serverInfo.remoteInfo.serverVersion && isServerVersionGreaterThanOrEqualTo(view.serverInfo.remoteInfo.serverVersion, '6.0.0')) { + if (view.status === Status.READY && view.serverInfo.remoteInfo.serverVersion && Utils.isServerVersionGreaterThanOrEqualTo(view.serverInfo.remoteInfo.serverVersion, '6.0.0')) { const pathName = `/${urlWithSchema.replace(view.tab.server.url.toString(), '')}`; view.view.webContents.send(BROWSER_HISTORY_PUSH, pathName); this.deeplinkSuccess(view.name); diff --git a/src/main/windows/windowManager.ts b/src/main/windows/windowManager.ts index 519f5c4d..5502c3f1 100644 --- a/src/main/windows/windowManager.ts +++ b/src/main/windows/windowManager.ts @@ -17,6 +17,7 @@ import { GET_DARK_MODE, UPDATE_SHORTCUT_MENU, BROWSER_HISTORY_PUSH, + APP_LOGGED_IN, } from 'common/communication'; import urlUtils from 'common/utils/url'; @@ -52,6 +53,7 @@ ipcMain.handle(GET_DARK_MODE, handleGetDarkMode); ipcMain.on(REACT_APP_INITIALIZED, handleReactAppInitialized); ipcMain.on(LOADING_SCREEN_ANIMATION_FINISHED, handleLoadingScreenAnimationFinished); ipcMain.on(BROWSER_HISTORY_PUSH, handleBrowserHistoryPush); +ipcMain.on(APP_LOGGED_IN, handleAppLoggedIn); export function setConfig(data: CombinedConfig) { if (data) { @@ -363,8 +365,12 @@ export function switchServer(serverName: string) { return; } status.currentServerName = serverName; - const lastActiveTab = server.tabs.find((tab) => !tab.isClosed && tab.order === (server.lastActiveTab || 0)) || server.tabs[0]; - const tabViewName = getTabViewName(serverName, lastActiveTab.name); + let nextTab = server.tabs.find((tab) => tab.isOpen && tab.order === (server.lastActiveTab || 0)); + if (!nextTab) { + const openTabs = server.tabs.filter((tab) => tab.isOpen); + nextTab = openTabs.find((e) => e.order === 0) || openTabs[0]; + } + const tabViewName = getTabViewName(serverName, nextTab.name); status.viewManager?.showByName(tabViewName); ipcMain.emit(UPDATE_SHORTCUT_MENU); } @@ -489,7 +495,7 @@ export function selectNextTab() { } const currentTeamTabs = status.config?.teams.find((team) => team.name === currentView.tab.server.name)?.tabs; - const filteredTabs = currentTeamTabs?.filter((tab) => !tab.isClosed); + const filteredTabs = currentTeamTabs?.filter((tab) => tab.isOpen); const currentTab = currentTeamTabs?.find((tab) => tab.name === currentView.tab.type); if (!currentTeamTabs || !currentTab || !filteredTabs) { return; @@ -514,7 +520,7 @@ export function selectPreviousTab() { } const currentTeamTabs = status.config?.teams.find((team) => team.name === currentView.tab.server.name)?.tabs; - const filteredTabs = currentTeamTabs?.filter((tab) => !tab.isClosed); + const filteredTabs = currentTeamTabs?.filter((tab) => tab.isOpen); const currentTab = currentTeamTabs?.find((tab) => tab.name === currentView.tab.type); if (!currentTeamTabs || !currentTab || !filteredTabs) { return; @@ -554,3 +560,7 @@ function handleBrowserHistoryPush(e: IpcMainEvent, viewName: string, pathName: s export function getCurrentTeamName() { return status.currentServerName; } + +function handleAppLoggedIn(event: IpcMainEvent, viewName: string) { + status.viewManager?.reloadViewIfNeeded(viewName); +} diff --git a/src/renderer/components/MainPage.tsx b/src/renderer/components/MainPage.tsx index b4fe1e01..cbb25748 100644 --- a/src/renderer/components/MainPage.tsx +++ b/src/renderer/components/MainPage.tsx @@ -104,8 +104,8 @@ export default class MainPage extends React.PureComponent { const firstServer = this.props.teams.find((team) => team.order === this.props.lastActiveTeam || 0); let firstTab = firstServer?.tabs.find((tab) => tab.order === firstServer.lastActiveTab || 0); - if (firstTab?.isClosed) { - const openTabs = firstServer?.tabs.filter((tab) => !tab.isClosed) || []; + if (!firstTab?.isOpen) { + const openTabs = firstServer?.tabs.filter((tab) => tab.isOpen) || []; firstTab = openTabs?.find((e) => e.order === 0) || openTabs[0]; } diff --git a/src/renderer/components/SettingsPage.tsx b/src/renderer/components/SettingsPage.tsx index f0e11e5f..efabba46 100644 --- a/src/renderer/components/SettingsPage.tsx +++ b/src/renderer/components/SettingsPage.tsx @@ -15,7 +15,6 @@ 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, ADD_SERVER, RELOAD_CONFIGURATION} from 'common/communication'; -import {getDefaultTeamWithTabsFromTeam} from 'common/tabs/TabView'; import AutoSaveIndicator, {SavingState} from './AutoSaveIndicator'; @@ -349,23 +348,6 @@ export default class SettingsPage extends React.PureComponent { - const teams = this.state.teams || []; - teams[index] = newData; - window.timers.setImmediate(this.saveSetting, CONFIG_TYPE_SERVERS, {key: 'teams', data: teams}); - this.setState({ - teams, - }); - } - - addServer = (team: Team) => { - const teams = this.state.teams || []; - teams.push(getDefaultTeamWithTabsFromTeam(team)); - window.timers.setImmediate(this.saveSetting, CONFIG_TYPE_SERVERS, {key: 'teams', data: teams}); - this.setState({ - teams, - }); - } handleDoubleClick = () => { window.ipcRenderer.send(DOUBLE_CLICK_ON_WINDOW, 'settings'); diff --git a/src/renderer/components/TabBar.tsx b/src/renderer/components/TabBar.tsx index 3b9aedcc..f26b1c50 100644 --- a/src/renderer/components/TabBar.tsx +++ b/src/renderer/components/TabBar.tsx @@ -85,7 +85,7 @@ export default class TabBar extends React.PureComponent { index={orderedIndex} > {(provided, snapshot) => { - if (tab.isClosed) { + if (!tab.isOpen) { return (