From 316beba9502284d334f88bb8a4570dd5a484428c Mon Sep 17 00:00:00 2001 From: Devin Binnie <52460000+devinbinnie@users.noreply.github.com> Date: Mon, 8 May 2023 09:17:01 -0400 Subject: [PATCH] [MM-14093] Rename 'team' to 'server' and 'tab' to 'view' in most cases, some additional cleanup (#2711) * Rename MattermostTeam -> UniqueServer, MattermostTab -> UniqueView * Rename 'team' to 'server' * Some further cleanup * Rename weirdly named function * Rename 'tab' to 'view' in most instances * Fix i18n * PR feedback --- .eslintrc.json | 5 +- README.md | 2 +- TESTING.md | 2 +- e2e/modules/environment.js | 12 +- e2e/specs/deep_linking/deeplink.test.js | 2 +- e2e/specs/focus.test.js | 16 +- e2e/specs/menu_bar/dropdown.test.js | 16 +- e2e/specs/menu_bar/window_menu.test.js | 8 +- .../add_server_modal.test.js | 48 ++-- .../configure_server_modal.test.js | 10 +- .../server_management/drag_and_drop.test.js | 32 +-- .../edit_server_modal.test.js | 46 +-- .../long_server_name.test.js | 8 +- .../remove_server_modal.test.js | 10 +- e2e/specs/startup/config.test.js | 6 +- i18n/de.json | 26 +- i18n/en.json | 26 +- i18n/en_AU.json | 26 +- i18n/es.json | 26 +- i18n/fa.json | 26 +- i18n/fr.json | 26 +- i18n/hu.json | 26 +- i18n/it.json | 8 +- i18n/ja.json | 26 +- i18n/ko.json | 26 +- i18n/nl.json | 26 +- i18n/pl.json | 26 +- i18n/pt-BR.json | 8 +- i18n/ru.json | 26 +- i18n/sv.json | 26 +- i18n/tr.json | 26 +- i18n/uk.json | 26 +- i18n/zh-CN.json | 26 +- resources/windows/gpo/README.md | 4 +- scripts/check_build_config.js | 4 +- src/assets/linux/README.md | 4 +- src/common/Validator.test.js | 2 +- src/common/Validator.ts | 36 +-- src/common/communication.ts | 12 +- src/common/config/RegistryConfig.test.js | 2 +- src/common/config/RegistryConfig.ts | 8 +- src/common/config/buildConfig.ts | 12 +- src/common/config/index.test.js | 84 +++--- src/common/config/index.ts | 35 +-- src/common/config/upgradePreferences.test.js | 34 +-- src/common/config/upgradePreferences.ts | 6 +- src/common/servers/MattermostServer.ts | 6 +- src/common/servers/serverManager.test.js | 72 ++--- src/common/servers/serverManager.ts | 262 +++++++++--------- src/common/utils/url.test.js | 8 +- src/common/utils/util.test.js | 4 +- .../BaseTabView.ts => views/BaseView.ts} | 10 +- .../FocalboardView.ts} | 8 +- .../MessagingView.ts} | 8 +- .../PlaybooksView.ts} | 8 +- src/common/{tabs/TabView.ts => views/View.ts} | 26 +- src/main/app/app.test.js | 6 +- src/main/app/app.ts | 4 +- src/main/app/config.test.js | 4 +- src/main/app/index.ts | 2 +- src/main/app/initialize.test.js | 2 +- src/main/app/initialize.ts | 20 +- src/main/app/intercom.test.js | 4 +- src/main/app/intercom.ts | 8 +- src/main/app/servers.test.js | 138 ++++----- src/main/app/servers.ts | 22 +- src/main/app/tabs.test.js | 39 --- src/main/app/tabs.ts | 73 ----- src/main/app/views.test.js | 39 +++ src/main/app/views.ts | 73 +++++ src/main/authManager.test.js | 58 +--- src/main/authManager.ts | 2 +- .../steps/step3.serverConnectivity.ts | 16 +- src/main/downloadsManager.ts | 2 +- src/main/menus/app.test.js | 40 +-- src/main/menus/app.ts | 32 +-- src/main/menus/tray.ts | 8 +- src/main/notifications/index.test.js | 4 +- src/main/notifications/index.ts | 2 +- src/main/preload/desktopAPI.js | 42 +-- src/main/preload/mattermost.js | 4 +- ....test.js => MattermostBrowserView.test.js} | 118 ++++---- ...ermostView.ts => MattermostBrowserView.ts} | 118 ++++---- ...iew.test.js => serverDropdownView.test.js} | 24 +- ...mDropdownView.ts => serverDropdownView.ts} | 54 ++-- src/main/views/viewManager.test.js | 177 ++++++------ src/main/views/viewManager.ts | 176 ++++++------ src/main/views/webContentEvents.ts | 4 +- src/main/windows/callsWidgetWindow.test.js | 110 ++++---- src/main/windows/callsWidgetWindow.ts | 12 +- src/main/windows/mainWindow.test.js | 2 +- src/renderer/components/ConfigureServer.tsx | 30 +- src/renderer/components/MainPage.tsx | 22 +- .../{NewTeamModal.tsx => NewServerModal.tsx} | 154 +++++----- ...ownButton.tsx => ServerDropdownButton.tsx} | 20 +- src/renderer/components/TabBar.tsx | 20 +- .../css/components/AddServerModal.css | 2 +- .../{NewTeamModal.css => NewServerModal.css} | 2 +- ...nButton.scss => ServerDropdownButton.scss} | 24 +- src/renderer/css/components/TabBar.css | 28 +- src/renderer/css/components/index.css | 2 +- src/renderer/css/dropdown.scss | 70 ++--- src/renderer/css/lazy/settings-dark.lazy.css | 2 +- src/renderer/dropdown.tsx | 144 +++++----- src/renderer/modals/editServer/editServer.tsx | 26 +- src/renderer/modals/loadingScreen/index.tsx | 2 +- src/renderer/modals/newServer/newServer.tsx | 16 +- .../modals/welcomeScreen/welcomeScreen.tsx | 12 +- src/types/config.ts | 100 +++---- src/types/window.ts | 30 +- 110 files changed, 1698 insertions(+), 1757 deletions(-) rename src/common/{tabs/BaseTabView.ts => views/BaseView.ts} (76%) rename src/common/{tabs/FocalboardTabView.ts => views/FocalboardView.ts} (65%) rename src/common/{tabs/MessagingTabView.ts => views/MessagingView.ts} (60%) rename src/common/{tabs/PlaybooksTabView.ts => views/PlaybooksView.ts} (66%) rename src/common/{tabs/TabView.ts => views/View.ts} (61%) delete mode 100644 src/main/app/tabs.test.js delete mode 100644 src/main/app/tabs.ts create mode 100644 src/main/app/views.test.js create mode 100644 src/main/app/views.ts rename src/main/views/{MattermostView.test.js => MattermostBrowserView.test.js} (77%) rename src/main/views/{MattermostView.ts => MattermostBrowserView.ts} (76%) rename src/main/views/{teamDropdownView.test.js => serverDropdownView.test.js} (61%) rename src/main/views/{teamDropdownView.ts => serverDropdownView.ts} (80%) rename src/renderer/components/{NewTeamModal.tsx => NewServerModal.tsx} (64%) rename src/renderer/components/{TeamDropdownButton.tsx => ServerDropdownButton.tsx} (76%) rename src/renderer/css/components/{NewTeamModal.css => NewServerModal.css} (59%) rename src/renderer/css/components/{TeamDropdownButton.scss => ServerDropdownButton.scss} (77%) diff --git a/.eslintrc.json b/.eslintrc.json index 7d875005..d5a4e2ab 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -26,7 +26,8 @@ "no-var": 2, "react/no-find-dom-node": 2, "multiline-ternary": 0, - "max-lines": ["warn", 650] + "max-lines": ["warn", 650], + "no-underscore-dangle": ["warn"] }, "overrides": [ { @@ -120,7 +121,7 @@ "src/renderer/components/Button/Button.stories.tsx", "src/renderer/components/TeamList.tsx", "src/renderer/components/LoginModal.tsx", - "src/renderer/components/NewTeamModal.tsx", + "src/renderer/components/NewServerModal.tsx", "src/renderer/settings.tsx", "src/renderer/index.tsx" ], diff --git a/README.md b/README.md index 6280a8fa..2f7e0165 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ Originally created as "electron-mattermost" by Yuya Ochiai. ## Features ### Desktop integration -* Server dropdown for access to multiple teams +* Server dropdown for access to multiple servers * Dedicated tabs for Channels, Boards and Playbooks * Desktop Notifications * Badges for unread channels and mentions diff --git a/TESTING.md b/TESTING.md index 5ee4ea3e..dcbb7db4 100644 --- a/TESTING.md +++ b/TESTING.md @@ -26,7 +26,7 @@ To contribute to the process of testing the Mattermost Desktop App: - Post a message with information on what you're testing, for example: `Testing Mattermost Desktop App 5.0.2 on Windows 10 64-bit`. - Reply to the post by clicking on "..." then "Reply" with This is a comment including files and upload five (5) files including at least one image, one sound file and one video clip from your Desktop App. - Search for the word "Desktop" and click "Jump" on the search result of your own post in Step 3.1. Click into the preview of the files you uploaded and try to download each one. - - Verify [Team Management works as documented](https://docs.mattermost.com/messaging/managing-desktop-app-servers.html). + - Verify [Server Management works as documented](https://docs.mattermost.com/messaging/managing-desktop-app-servers.html). - Verify [App Options work as documented](https://docs.mattermost.com/messaging/managing-desktop-app-options.html). - Verify Menu Bar options work as documented. - Use the desktop app for another 15 minutes, trying different features and functionality on the user interface. diff --git a/e2e/modules/environment.js b/e2e/modules/environment.js index f31e1d06..d9b54380 100644 --- a/e2e/modules/environment.js +++ b/e2e/modules/environment.js @@ -40,7 +40,7 @@ if (process.platform === 'win32') { robot.mouseClick(); } -const exampleTeam = { +const exampleServer = { name: 'example', url: exampleURL, order: 0, @@ -61,7 +61,7 @@ const exampleTeam = { ], lastActiveTab: 0, }; -const githubTeam = { +const githubServer = { name: 'github', url: 'https://github.com/', order: 1, @@ -87,7 +87,7 @@ const githubTeam = { const demoConfig = { version: 3, - teams: [exampleTeam, githubTeam], + teams: [exampleServer, githubServer], showTrayIcon: false, trayIconTheme: 'light', minimizeToTray: false, @@ -113,9 +113,9 @@ const demoConfig = { const demoMattermostConfig = { ...demoConfig, teams: [{ - ...exampleTeam, + ...exampleServer, url: mattermostURL, - }, githubTeam], + }, githubServer], }; const cmdOrCtrl = process.platform === 'darwin' ? 'command' : 'control'; @@ -235,7 +235,7 @@ module.exports = { return null; } const info = await window.testHelper.getViewInfoForTest(); - return {viewName: `${info.serverName}___${info.tabType}`, webContentsId: info.webContentsId}; + return {viewName: `${info.serverName}___${info.viewType}`, webContentsId: info.webContentsId}; }).then((result) => { if (result) { map[result.viewName] = {win, webContentsId: result.webContentsId}; diff --git a/e2e/specs/deep_linking/deeplink.test.js b/e2e/specs/deep_linking/deeplink.test.js index 7620756d..a1e1967c 100644 --- a/e2e/specs/deep_linking/deeplink.test.js +++ b/e2e/specs/deep_linking/deeplink.test.js @@ -46,7 +46,7 @@ describe('application', function desc() { return window.getBrowserViews().find((view) => view.webContents.id === id).webContents.getURL(); }, webContentsId); isActive.should.equal('https://github.com/test/url'); - const dropdownButtonText = await mainWindow.innerText('.TeamDropdownButton'); + const dropdownButtonText = await mainWindow.innerText('.ServerDropdownButton'); dropdownButtonText.should.equal('github'); await this.app.close(); }); diff --git a/e2e/specs/focus.test.js b/e2e/specs/focus.test.js index 329ec65f..91b5caf2 100644 --- a/e2e/specs/focus.test.js +++ b/e2e/specs/focus.test.js @@ -98,8 +98,8 @@ describe('focus', function desc() { it('MM-T1316 should return focus to the message box when closing the settings window', async () => { const mainView = this.app.windows().find((window) => window.url().includes('index')); const dropdownView = this.app.windows().find((window) => window.url().includes('dropdown')); - await mainView.click('.TeamDropdownButton'); - await dropdownView.click('.TeamDropdown .TeamDropdown__button.addServer'); + await mainView.click('.ServerDropdownButton'); + await dropdownView.click('.ServerDropdown .ServerDropdown__button.addServer'); const newServerView = await this.app.waitForEvent('window', { predicate: (window) => window.url().includes('newServer'), }); @@ -121,15 +121,15 @@ describe('focus', function desc() { it('MM-T1317 should return focus to the focused box when switching servers', async () => { const mainView = this.app.windows().find((window) => window.url().includes('index')); const dropdownView = this.app.windows().find((window) => window.url().includes('dropdown')); - await mainView.click('.TeamDropdownButton'); - await dropdownView.click('.TeamDropdown .TeamDropdown__button:has-text("community")'); + await mainView.click('.ServerDropdownButton'); + await dropdownView.click('.ServerDropdown .ServerDropdown__button:has-text("community")'); // eslint-disable-next-line dot-notation const secondServer = this.serverMap['community___TAB_MESSAGING'].win; await secondServer.waitForSelector('#input_loginId'); await secondServer.focus('#input_loginId'); - await mainView.click('.TeamDropdownButton'); - await dropdownView.click(`.TeamDropdown .TeamDropdown__button:has-text("${config.teams[0].name}")`); + await mainView.click('.ServerDropdownButton'); + await dropdownView.click(`.ServerDropdown .ServerDropdown__button:has-text("${config.teams[0].name}")`); const isTextboxFocused = await firstServer.$eval('#post_textbox', (el) => el === document.activeElement); isTextboxFocused.should.be.true; @@ -141,8 +141,8 @@ describe('focus', function desc() { const textboxString = await firstServer.inputValue('#post_textbox'); textboxString.should.equal('Mattermost'); - await mainView.click('.TeamDropdownButton'); - await dropdownView.click('.TeamDropdown .TeamDropdown__button:has-text("community")'); + await mainView.click('.ServerDropdownButton'); + await dropdownView.click('.ServerDropdown .ServerDropdown__button:has-text("community")'); const isLoginFocused = await secondServer.$eval('#input_loginId', (el) => el === document.activeElement); isLoginFocused.should.be.true; diff --git a/e2e/specs/menu_bar/dropdown.test.js b/e2e/specs/menu_bar/dropdown.test.js index 390fa2fe..57ac5672 100644 --- a/e2e/specs/menu_bar/dropdown.test.js +++ b/e2e/specs/menu_bar/dropdown.test.js @@ -32,9 +32,9 @@ describe('menu_bar/dropdown', function desc() { const mainWindow = this.app.windows().find((window) => window.url().includes('index')); const dropdownView = this.app.windows().find((window) => window.url().includes('dropdown')); - await mainWindow.click('.TeamDropdownButton'); - const firstMenuItem = await dropdownView.innerText('.TeamDropdown button.TeamDropdown__button:nth-child(1) span'); - const secondMenuItem = await dropdownView.innerText('.TeamDropdown button.TeamDropdown__button:nth-child(2) span'); + await mainWindow.click('.ServerDropdownButton'); + const firstMenuItem = await dropdownView.innerText('.ServerDropdown button.ServerDropdown__button:nth-child(1) span'); + const secondMenuItem = await dropdownView.innerText('.ServerDropdown button.ServerDropdown__button:nth-child(2) span'); firstMenuItem.should.equal(config.teams[0].name); secondMenuItem.should.equal(config.teams[1].name); @@ -57,7 +57,7 @@ describe('menu_bar/dropdown', function desc() { let dropdownHeight = await browserWindow.evaluate((window) => window.getBrowserViews().find((view) => view.webContents.getURL().includes('dropdown')).getBounds().height); dropdownHeight.should.equal(0); - await mainWindow.click('.TeamDropdownButton'); + await mainWindow.click('.ServerDropdownButton'); dropdownHeight = await browserWindow.evaluate((window) => window.getBrowserViews().find((view) => view.webContents.getURL().includes('dropdown')).getBounds().height); dropdownHeight.should.be.greaterThan(0); }); @@ -74,8 +74,8 @@ describe('menu_bar/dropdown', function desc() { const mainWindow = this.app.windows().find((window) => window.url().includes('index')); const dropdownView = this.app.windows().find((window) => window.url().includes('dropdown')); - await mainWindow.click('.TeamDropdownButton'); - await dropdownView.click('.TeamDropdown__button.addServer'); + await mainWindow.click('.ServerDropdownButton'); + await dropdownView.click('.ServerDropdown__button.addServer'); const newServerModal = await this.app.waitForEvent('window', { predicate: (window) => window.url().includes('newServer'), @@ -107,8 +107,8 @@ describe('menu_bar/dropdown', function desc() { }); it('MM-T4408_2 should show the second view after clicking the menu item', async () => { - await mainWindow.click('.TeamDropdownButton'); - await dropdownView.click('.TeamDropdown button.TeamDropdown__button:nth-child(2)'); + await mainWindow.click('.ServerDropdownButton'); + await dropdownView.click('.ServerDropdown button.ServerDropdown__button:nth-child(2)'); const firstViewIsAttached = await browserWindow.evaluate((window, url) => Boolean(window.getBrowserViews().find((view) => view.webContents.getURL() === url)), env.exampleURL); firstViewIsAttached.should.be.false; diff --git a/e2e/specs/menu_bar/window_menu.test.js b/e2e/specs/menu_bar/window_menu.test.js index 787802d5..b61ff439 100644 --- a/e2e/specs/menu_bar/window_menu.test.js +++ b/e2e/specs/menu_bar/window_menu.test.js @@ -72,23 +72,23 @@ describe('Menu/window_menu', function desc() { after(afterFunc); it('MM-T826_1 should show the second server', async () => { - let dropdownButtonText = await mainWindow.innerText('.TeamDropdownButton'); + let dropdownButtonText = await mainWindow.innerText('.ServerDropdownButton'); dropdownButtonText.should.equal('google'); robot.keyTap('2', ['control', process.platform === 'darwin' ? 'command' : 'shift']); - dropdownButtonText = await mainWindow.innerText('.TeamDropdownButton:has-text("github")'); + dropdownButtonText = await mainWindow.innerText('.ServerDropdownButton:has-text("github")'); dropdownButtonText.should.equal('github'); }); it('MM-T826_2 should show the third server', async () => { robot.keyTap('3', ['control', process.platform === 'darwin' ? 'command' : 'shift']); - const dropdownButtonText = await mainWindow.innerText('.TeamDropdownButton:has-text("google")'); + const dropdownButtonText = await mainWindow.innerText('.ServerDropdownButton:has-text("google")'); dropdownButtonText.should.equal('google'); }); it('MM-T826_3 should show the first server', async () => { robot.keyTap('1', ['control', process.platform === 'darwin' ? 'command' : 'shift']); - const dropdownButtonText = await mainWindow.innerText('.TeamDropdownButton:has-text("example")'); + const dropdownButtonText = await mainWindow.innerText('.ServerDropdownButton:has-text("example")'); dropdownButtonText.should.equal('example'); }); }); diff --git a/e2e/specs/server_management/add_server_modal.test.js b/e2e/specs/server_management/add_server_modal.test.js index 11b74fba..44f78a0b 100644 --- a/e2e/specs/server_management/add_server_modal.test.js +++ b/e2e/specs/server_management/add_server_modal.test.js @@ -21,8 +21,8 @@ describe('Add Server Modal', function desc() { const mainView = this.app.windows().find((window) => window.url().includes('index')); const dropdownView = this.app.windows().find((window) => window.url().includes('dropdown')); - await mainView.click('.TeamDropdownButton'); - await dropdownView.click('.TeamDropdown .TeamDropdown__button.addServer'); + await mainView.click('.ServerDropdownButton'); + await dropdownView.click('.ServerDropdown .ServerDropdown__button.addServer'); newServerView = await this.app.waitForEvent('window', { predicate: (window) => window.url().includes('newServer'), }); @@ -41,7 +41,7 @@ describe('Add Server Modal', function desc() { let newServerView; it('MM-T1312 should focus the first text input', async () => { - const isFocused = await newServerView.$eval('#teamUrlInput', (el) => el.isSameNode(document.activeElement)); + const isFocused = await newServerView.$eval('#serverUrlInput', (el) => el.isSameNode(document.activeElement)); isFocused.should.be.true; }); @@ -53,39 +53,39 @@ describe('Add Server Modal', function desc() { }); describe('MM-T4389 Invalid messages', () => { - it('MM-T4389_1 should not be valid if no team name or URL has been set', async () => { + it('MM-T4389_1 should not be valid if no server name or URL has been set', async () => { await newServerView.click('#saveNewServerModal'); - const existingName = await newServerView.isVisible('#teamNameInput.is-invalid'); - const existingUrl = await newServerView.isVisible('#teamUrlInput.is-invalid'); + const existingName = await newServerView.isVisible('#serverNameInput.is-invalid'); + const existingUrl = await newServerView.isVisible('#serverUrlInput.is-invalid'); existingName.should.be.true; existingUrl.should.be.true; }); it('should not be valid if a server with the same name exists', async () => { - await newServerView.type('#teamNameInput', config.teams[0].name); - await newServerView.type('#teamUrlInput', 'http://example.org'); + await newServerView.type('#serverNameInput', config.teams[0].name); + await newServerView.type('#serverUrlInput', 'http://example.org'); await newServerView.click('#saveNewServerModal'); - const existing = await newServerView.isVisible('#teamNameInput.is-invalid'); + const existing = await newServerView.isVisible('#serverNameInput.is-invalid'); existing.should.be.true; }); it('should not be valid if a server with the same URL exists', async () => { - await newServerView.type('#teamNameInput', 'some-new-server'); - await newServerView.type('#teamUrlInput', config.teams[0].url); + await newServerView.type('#serverNameInput', 'some-new-server'); + await newServerView.type('#serverUrlInput', config.teams[0].url); await newServerView.click('#saveNewServerModal'); - const existing = await newServerView.isVisible('#teamUrlInput.is-invalid'); + const existing = await newServerView.isVisible('#serverUrlInput.is-invalid'); existing.should.be.true; }); describe('Valid server name', async () => { beforeEach(async () => { - await newServerView.type('#teamNameInput', 'TestTeam'); + await newServerView.type('#serverNameInput', 'TestServer'); await newServerView.click('#saveNewServerModal'); }); it('MM-T4389_2 Name should not be marked invalid, URL should be marked invalid', async () => { - const existingName = await newServerView.isVisible('#teamNameInput.is-invalid'); - const existingUrl = await newServerView.isVisible('#teamUrlInput.is-invalid'); + const existingName = await newServerView.isVisible('#serverNameInput.is-invalid'); + const existingUrl = await newServerView.isVisible('#serverUrlInput.is-invalid'); const disabled = await newServerView.getAttribute('#saveNewServerModal', 'disabled'); existingName.should.be.false; existingUrl.should.be.true; @@ -95,13 +95,13 @@ describe('Add Server Modal', function desc() { describe('Valid server url', () => { beforeEach(async () => { - await newServerView.type('#teamUrlInput', 'http://example.org'); + await newServerView.type('#serverUrlInput', 'http://example.org'); await newServerView.click('#saveNewServerModal'); }); it('MM-T4389_3 URL should not be marked invalid, name should be marked invalid', async () => { - const existingName = await newServerView.isVisible('#teamNameInput.is-invalid'); - const existingUrl = await newServerView.isVisible('#teamUrlInput.is-invalid'); + const existingName = await newServerView.isVisible('#serverNameInput.is-invalid'); + const existingUrl = await newServerView.isVisible('#serverUrlInput.is-invalid'); const disabled = await newServerView.getAttribute('#saveNewServerModal', 'disabled'); existingName.should.be.true; existingUrl.should.be.false; @@ -111,16 +111,16 @@ describe('Add Server Modal', function desc() { }); it('MM-T2826_1 should not be valid if an invalid server address has been set', async () => { - await newServerView.type('#teamUrlInput', 'superInvalid url'); + await newServerView.type('#serverUrlInput', 'superInvalid url'); await newServerView.click('#saveNewServerModal'); - const existing = await newServerView.isVisible('#teamUrlInput.is-invalid'); + const existing = await newServerView.isVisible('#serverUrlInput.is-invalid'); existing.should.be.true; }); describe('Valid Team Settings', () => { beforeEach(async () => { - await newServerView.type('#teamUrlInput', 'http://example.org'); - await newServerView.type('#teamNameInput', 'TestTeam'); + await newServerView.type('#serverUrlInput', 'http://example.org'); + await newServerView.type('#serverNameInput', 'TestServer'); }); it('should be possible to click add', async () => { @@ -128,7 +128,7 @@ describe('Add Server Modal', function desc() { (disabled === null).should.be.true; }); - it('MM-T2826_2 should add the team to the config file', async () => { + it('MM-T2826_2 should add the server to the config file', async () => { await newServerView.click('#saveNewServerModal'); await asyncSleep(1000); const existing = Boolean(await this.app.windows().find((window) => window.url().includes('newServer'))); @@ -136,7 +136,7 @@ describe('Add Server Modal', function desc() { const savedConfig = JSON.parse(fs.readFileSync(env.configFilePath, 'utf8')); savedConfig.teams.should.deep.contain({ - name: 'TestTeam', + name: 'TestServer', url: 'http://example.org/', order: 2, lastActiveTab: 0, diff --git a/e2e/specs/server_management/configure_server_modal.test.js b/e2e/specs/server_management/configure_server_modal.test.js index d48f0cf2..47386e29 100644 --- a/e2e/specs/server_management/configure_server_modal.test.js +++ b/e2e/specs/server_management/configure_server_modal.test.js @@ -48,7 +48,7 @@ describe('Configure Server Modal', function desc() { }); it('MM-T5117 should be valid if display name and URL are set', async () => { - await configureServerModal.type('#input_name', 'TestTeam'); + await configureServerModal.type('#input_name', 'TestServer'); await configureServerModal.type('#input_url', 'http://example.org'); const connectButtonDisabled = await configureServerModal.getAttribute('#connectConfigureServer', 'disabled'); @@ -56,7 +56,7 @@ describe('Configure Server Modal', function desc() { }); it('MM-T5118 should not be valid if an invalid URL has been set', async () => { - await configureServerModal.type('#input_name', 'TestTeam'); + await configureServerModal.type('#input_name', 'TestServer'); await configureServerModal.type('#input_url', 'lorem.ipsum.dolor.sit.amet'); await configureServerModal.click('#connectConfigureServer'); @@ -70,8 +70,8 @@ describe('Configure Server Modal', function desc() { (connectButtonDisabled === '').should.be.true; }); - it('MM-T5119 should add the team to the config file', async () => { - await configureServerModal.type('#input_name', 'TestTeam'); + it('MM-T5119 should add the server to the config file', async () => { + await configureServerModal.type('#input_name', 'TestServer'); await configureServerModal.type('#input_url', 'http://example.org'); await configureServerModal.click('#connectConfigureServer'); @@ -84,7 +84,7 @@ describe('Configure Server Modal', function desc() { const savedConfig = JSON.parse(fs.readFileSync(env.configFilePath, 'utf8')); savedConfig.teams.should.deep.contain({ url: 'http://example.org/', - name: 'TestTeam', + name: 'TestServer', order: 0, lastActiveTab: 0, tabs: [ diff --git a/e2e/specs/server_management/drag_and_drop.test.js b/e2e/specs/server_management/drag_and_drop.test.js index f5b695cc..07da4d9d 100644 --- a/e2e/specs/server_management/drag_and_drop.test.js +++ b/e2e/specs/server_management/drag_and_drop.test.js @@ -64,41 +64,41 @@ describe('server_management/drag_and_drop', function desc() { await beforeFunc(); mainWindow = this.app.windows().find((window) => window.url().includes('index')); dropdownView = this.app.windows().find((window) => window.url().includes('dropdown')); - await mainWindow.click('.TeamDropdownButton'); + await mainWindow.click('.ServerDropdownButton'); }); after(afterFunc); it('MM-T2634_1 should appear the original order', async () => { - const firstMenuItem = await dropdownView.waitForSelector('.TeamDropdown button.TeamDropdown__button:nth-child(1) .TeamDropdown__draggable-handle'); + const firstMenuItem = await dropdownView.waitForSelector('.ServerDropdown button.ServerDropdown__button:nth-child(1) .ServerDropdown__draggable-handle'); const firstMenuItemText = await firstMenuItem.innerText(); firstMenuItemText.should.equal('example'); - const secondMenuItem = await dropdownView.waitForSelector('.TeamDropdown button.TeamDropdown__button:nth-child(2) .TeamDropdown__draggable-handle'); + const secondMenuItem = await dropdownView.waitForSelector('.ServerDropdown button.ServerDropdown__button:nth-child(2) .ServerDropdown__draggable-handle'); const secondMenuItemText = await secondMenuItem.innerText(); secondMenuItemText.should.equal('github'); - const thirdMenuItem = await dropdownView.waitForSelector('.TeamDropdown button.TeamDropdown__button:nth-child(3) .TeamDropdown__draggable-handle'); + const thirdMenuItem = await dropdownView.waitForSelector('.ServerDropdown button.ServerDropdown__button:nth-child(3) .ServerDropdown__draggable-handle'); const thirdMenuItemText = await thirdMenuItem.innerText(); thirdMenuItemText.should.equal('google'); }); it('MM-T2634_2 after dragging the server down, should appear in the new order', async () => { // Move the first server down, then re-open the dropdown - const initialMenuItem = await dropdownView.waitForSelector('.TeamDropdown button.TeamDropdown__button:nth-child(1) .TeamDropdown__draggable-handle'); + const initialMenuItem = await dropdownView.waitForSelector('.ServerDropdown button.ServerDropdown__button:nth-child(1) .ServerDropdown__draggable-handle'); await initialMenuItem.focus(); await dropdownView.keyboard.down(' '); await dropdownView.keyboard.down('ArrowDown'); await dropdownView.keyboard.down(' '); await asyncSleep(1000); await mainWindow.keyboard.press('Escape'); - await mainWindow.click('.TeamDropdownButton'); + await mainWindow.click('.ServerDropdownButton'); // Verify that the new order persists - const firstMenuItem = await dropdownView.waitForSelector('.TeamDropdown button.TeamDropdown__button:nth-child(1) .TeamDropdown__draggable-handle'); + const firstMenuItem = await dropdownView.waitForSelector('.ServerDropdown button.ServerDropdown__button:nth-child(1) .ServerDropdown__draggable-handle'); const firstMenuItemText = await firstMenuItem.innerText(); firstMenuItemText.should.equal('github'); - const secondMenuItem = await dropdownView.waitForSelector('.TeamDropdown button.TeamDropdown__button:nth-child(2) .TeamDropdown__draggable-handle'); + const secondMenuItem = await dropdownView.waitForSelector('.ServerDropdown button.ServerDropdown__button:nth-child(2) .ServerDropdown__draggable-handle'); const secondMenuItemText = await secondMenuItem.innerText(); secondMenuItemText.should.equal('example'); - const thirdMenuItem = await dropdownView.waitForSelector('.TeamDropdown button.TeamDropdown__button:nth-child(3) .TeamDropdown__draggable-handle'); + const thirdMenuItem = await dropdownView.waitForSelector('.ServerDropdown button.ServerDropdown__button:nth-child(3) .ServerDropdown__draggable-handle'); const thirdMenuItemText = await thirdMenuItem.innerText(); thirdMenuItemText.should.equal('google'); }); @@ -125,20 +125,20 @@ describe('server_management/drag_and_drop', function desc() { it('MM-T2635_1 should be in the original order', async () => { // Verify the original order - const firstTab = await mainWindow.waitForSelector('.TabBar li.teamTabItem:nth-child(1)'); + const firstTab = await mainWindow.waitForSelector('.TabBar li.serverTabItem:nth-child(1)'); const firstTabText = await firstTab.innerText(); firstTabText.should.equal('Channels'); - const secondTab = await mainWindow.waitForSelector('.TabBar li.teamTabItem:nth-child(2)'); + const secondTab = await mainWindow.waitForSelector('.TabBar li.serverTabItem:nth-child(2)'); const secondTabText = await secondTab.innerText(); secondTabText.should.equal('Boards'); - const thirdTab = await mainWindow.waitForSelector('.TabBar li.teamTabItem:nth-child(3)'); + const thirdTab = await mainWindow.waitForSelector('.TabBar li.serverTabItem:nth-child(3)'); const thirdTabText = await thirdTab.innerText(); thirdTabText.should.equal('Playbooks'); }); it('MM-T2635_2 after moving the tab to the right, the tab should be in the new order', async () => { // Move the first tab to the right - let firstTab = await mainWindow.waitForSelector('.TabBar li.teamTabItem:nth-child(1)'); + let firstTab = await mainWindow.waitForSelector('.TabBar li.serverTabItem:nth-child(1)'); await firstTab.focus(); await mainWindow.keyboard.down(' '); await mainWindow.keyboard.down('ArrowRight'); @@ -146,13 +146,13 @@ describe('server_management/drag_and_drop', function desc() { await asyncSleep(1000); // Verify that the new order is visible - firstTab = await mainWindow.waitForSelector('.TabBar li.teamTabItem:nth-child(1)'); + firstTab = await mainWindow.waitForSelector('.TabBar li.serverTabItem:nth-child(1)'); const firstTabText = await firstTab.innerText(); firstTabText.should.equal('Boards'); - const secondTab = await mainWindow.waitForSelector('.TabBar li.teamTabItem:nth-child(2)'); + const secondTab = await mainWindow.waitForSelector('.TabBar li.serverTabItem:nth-child(2)'); const secondTabText = await secondTab.innerText(); secondTabText.should.equal('Channels'); - const thirdTab = await mainWindow.waitForSelector('.TabBar li.teamTabItem:nth-child(3)'); + const thirdTab = await mainWindow.waitForSelector('.TabBar li.serverTabItem:nth-child(3)'); const thirdTabText = await thirdTab.innerText(); thirdTabText.should.equal('Playbooks'); }); diff --git a/e2e/specs/server_management/edit_server_modal.test.js b/e2e/specs/server_management/edit_server_modal.test.js index bd162902..cdb89e0a 100644 --- a/e2e/specs/server_management/edit_server_modal.test.js +++ b/e2e/specs/server_management/edit_server_modal.test.js @@ -21,9 +21,9 @@ describe('EditServerModal', function desc() { const mainView = this.app.windows().find((window) => window.url().includes('index')); const dropdownView = this.app.windows().find((window) => window.url().includes('dropdown')); - await mainView.click('.TeamDropdownButton'); - await dropdownView.hover('.TeamDropdown .TeamDropdown__button:nth-child(1)'); - await dropdownView.click('.TeamDropdown .TeamDropdown__button:nth-child(1) button.TeamDropdown__button-edit'); + await mainView.click('.ServerDropdownButton'); + await dropdownView.hover('.ServerDropdown .ServerDropdown__button:nth-child(1)'); + await dropdownView.click('.ServerDropdown .ServerDropdown__button:nth-child(1) button.ServerDropdown__button-edit'); editServerView = await this.app.waitForEvent('window', { predicate: (window) => window.url().includes('editServer'), @@ -39,7 +39,7 @@ describe('EditServerModal', function desc() { let editServerView; - it('should not edit team when Cancel is pressed', async () => { + it('should not edit server when Cancel is pressed', async () => { await editServerView.click('#cancelNewServerModal'); await asyncSleep(1000); const existing = Boolean(await this.app.windows().find((window) => window.url().includes('editServer'))); @@ -69,7 +69,7 @@ describe('EditServerModal', function desc() { }); }); - it('MM-T4391_1 should not edit team when Save is pressed but nothing edited', async () => { + it('MM-T4391_1 should not edit server when Save is pressed but nothing edited', async () => { await editServerView.click('#saveNewServerModal'); await asyncSleep(1000); const existing = Boolean(await this.app.windows().find((window) => window.url().includes('editServer'))); @@ -99,27 +99,27 @@ describe('EditServerModal', function desc() { }); }); - it('MM-T2826_3 should not edit team if an invalid server address has been set', async () => { - await editServerView.type('#teamUrlInput', 'superInvalid url'); + it('MM-T2826_3 should not edit server if an invalid server address has been set', async () => { + await editServerView.type('#serverUrlInput', 'superInvalid url'); await editServerView.click('#saveNewServerModal'); - const existing = await editServerView.isVisible('#teamUrlInput.is-invalid'); + const existing = await editServerView.isVisible('#serverUrlInput.is-invalid'); existing.should.be.true; }); - it('should not edit team if another server with the same name or URL exists', async () => { - await editServerView.fill('#teamNameInput', config.teams[1].name); + it('should not edit server if another server with the same name or URL exists', async () => { + await editServerView.fill('#serverNameInput', config.teams[1].name); await editServerView.click('#saveNewServerModal'); - let existing = await editServerView.isVisible('#teamNameInput.is-invalid'); + let existing = await editServerView.isVisible('#serverNameInput.is-invalid'); existing.should.be.true; - await editServerView.fill('#teamNameInput', 'NewTestTeam'); - await editServerView.fill('#teamUrlInput', config.teams[1].url); - existing = await editServerView.isVisible('#teamUrlInput.is-invalid'); + await editServerView.fill('#serverNameInput', 'NewTestServer'); + await editServerView.fill('#serverUrlInput', config.teams[1].url); + existing = await editServerView.isVisible('#serverUrlInput.is-invalid'); existing.should.be.true; }); - it('MM-T4391_2 should edit team when Save is pressed and name edited', async () => { - await editServerView.fill('#teamNameInput', 'NewTestTeam'); + it('MM-T4391_2 should edit server when Save is pressed and name edited', async () => { + await editServerView.fill('#serverNameInput', 'NewTestServer'); await editServerView.click('#saveNewServerModal'); await asyncSleep(1000); const existing = Boolean(await this.app.windows().find((window) => window.url().includes('editServer'))); @@ -148,7 +148,7 @@ describe('EditServerModal', function desc() { lastActiveTab: 0, }); savedConfig.teams.should.deep.contain({ - name: 'NewTestTeam', + name: 'NewTestServer', url: env.exampleURL, order: 0, tabs: [ @@ -170,8 +170,8 @@ describe('EditServerModal', function desc() { }); }); - it('MM-T4391_3 should edit team when Save is pressed and URL edited', async () => { - await editServerView.fill('#teamUrlInput', 'http://google.com'); + it('MM-T4391_3 should edit server when Save is pressed and URL edited', async () => { + await editServerView.fill('#serverUrlInput', 'http://google.com'); await editServerView.click('#saveNewServerModal'); await asyncSleep(1000); const existing = Boolean(await this.app.windows().find((window) => window.url().includes('editServer'))); @@ -222,9 +222,9 @@ describe('EditServerModal', function desc() { }); }); - it('MM-T4391_4 should edit team when Save is pressed and both edited', async () => { - await editServerView.fill('#teamNameInput', 'NewTestTeam'); - await editServerView.fill('#teamUrlInput', 'http://google.com'); + it('MM-T4391_4 should edit server when Save is pressed and both edited', async () => { + await editServerView.fill('#serverNameInput', 'NewTestServer'); + await editServerView.fill('#serverUrlInput', 'http://google.com'); await editServerView.click('#saveNewServerModal'); await asyncSleep(1000); const existing = Boolean(await this.app.windows().find((window) => window.url().includes('editServer'))); @@ -253,7 +253,7 @@ describe('EditServerModal', function desc() { lastActiveTab: 0, }); savedConfig.teams.should.deep.contain({ - name: 'NewTestTeam', + name: 'NewTestServer', url: 'http://google.com/', order: 0, tabs: [ diff --git a/e2e/specs/server_management/long_server_name.test.js b/e2e/specs/server_management/long_server_name.test.js index 43d6ca33..61417174 100644 --- a/e2e/specs/server_management/long_server_name.test.js +++ b/e2e/specs/server_management/long_server_name.test.js @@ -24,8 +24,8 @@ describe('LongServerName', function desc() { const mainView = this.app.windows().find((window) => window.url().includes('index')); const dropdownView = this.app.windows().find((window) => window.url().includes('dropdown')); - await mainView.click('.TeamDropdownButton'); - await dropdownView.click('.TeamDropdown .TeamDropdown__button.addServer'); + await mainView.click('.ServerDropdownButton'); + await dropdownView.click('.ServerDropdown .ServerDropdown__button.addServer'); newServerView = await this.app.waitForEvent('window', { predicate: (window) => window.url().includes('newServer'), }); @@ -44,8 +44,8 @@ describe('LongServerName', function desc() { let newServerView; it('MM-T4050 Long server name', async () => { - await newServerView.type('#teamNameInput', longServerName); - await newServerView.type('#teamUrlInput', longServerUrl); + await newServerView.type('#serverNameInput', longServerName); + await newServerView.type('#serverUrlInput', longServerUrl); await newServerView.click('#saveNewServerModal'); await asyncSleep(1000); diff --git a/e2e/specs/server_management/remove_server_modal.test.js b/e2e/specs/server_management/remove_server_modal.test.js index f2069e9c..c67adf1a 100644 --- a/e2e/specs/server_management/remove_server_modal.test.js +++ b/e2e/specs/server_management/remove_server_modal.test.js @@ -21,9 +21,9 @@ describe('RemoveServerModal', function desc() { const mainView = this.app.windows().find((window) => window.url().includes('index')); const dropdownView = this.app.windows().find((window) => window.url().includes('dropdown')); - await mainView.click('.TeamDropdownButton'); - await dropdownView.hover('.TeamDropdown .TeamDropdown__button:nth-child(1)'); - await dropdownView.click('.TeamDropdown .TeamDropdown__button:nth-child(1) button.TeamDropdown__button-remove'); + await mainView.click('.ServerDropdownButton'); + await dropdownView.hover('.ServerDropdown .ServerDropdown__button:nth-child(1)'); + await dropdownView.click('.ServerDropdown .ServerDropdown__button:nth-child(1) button.ServerDropdown__button-remove'); removeServerView = await this.app.waitForEvent('window', { predicate: (window) => window.url().includes('removeServer'), @@ -42,7 +42,7 @@ describe('RemoveServerModal', function desc() { let removeServerView; - it('MM-T4390_1 should remove existing team on click Remove', async () => { + it('MM-T4390_1 should remove existing server on click Remove', async () => { await removeServerView.click('button:has-text("Remove")'); await asyncSleep(1000); @@ -55,7 +55,7 @@ describe('RemoveServerModal', function desc() { savedConfig.teams.should.deep.equal(expectedConfig); }); - it('MM-T4390_2 should NOT remove existing team on click Cancel', async () => { + it('MM-T4390_2 should NOT remove existing server on click Cancel', async () => { await removeServerView.click('button:has-text("Cancel")'); await asyncSleep(1000); diff --git a/e2e/specs/startup/config.test.js b/e2e/specs/startup/config.test.js index bda9d113..29496750 100644 --- a/e2e/specs/startup/config.test.js +++ b/e2e/specs/startup/config.test.js @@ -44,7 +44,7 @@ describe('config', function desc() { it('MM-T4401_1 should show correct server in the dropdown button', async () => { const mainWindow = this.app.windows().find((window) => window.url().includes('index')); - const dropdownButtonText = await mainWindow.innerText('.TeamDropdownButton'); + const dropdownButtonText = await mainWindow.innerText('.ServerDropdownButton'); dropdownButtonText.should.equal('example'); }); @@ -66,8 +66,8 @@ describe('config', function desc() { fs.writeFileSync(env.configFilePath, JSON.stringify(oldConfig)); this.app = await env.getApp(); const mainWindow = this.app.windows().find((window) => window.url().includes('index')); - const dropdownButtonText = await mainWindow.innerText('.TeamDropdownButton:has-text("Primary team")'); - dropdownButtonText.should.equal('Primary team'); + const dropdownButtonText = await mainWindow.innerText('.ServerDropdownButton:has-text("Primary server")'); + dropdownButtonText.should.equal('Primary server'); const str = fs.readFileSync(env.configFilePath, 'utf8'); const upgradedConfig = JSON.parse(str); diff --git a/i18n/de.json b/i18n/de.json index 2376ee8f..da9467dd 100644 --- a/i18n/de.json +++ b/i18n/de.json @@ -133,7 +133,7 @@ "renderer.modals.certificate.certificateModal.certInfoButton": "Zertifikatsinformation", "renderer.dropdown.servers": "Server", "renderer.dropdown.addAServer": "Server hinzufügen", - "renderer.components.teamDropdownButton.noServersConfigured": "Keine Server konfiguriert", + "renderer.components.serverDropdownButton.noServersConfigured": "Keine Server konfiguriert", "renderer.components.showCertificateModal.subjectName": "Subject Name", "renderer.components.showCertificateModal.serialNumber": "Seriennummer", "renderer.components.showCertificateModal.publicKeyInfo": "Öffentlicher Schlüssel Info", @@ -201,18 +201,18 @@ "renderer.components.removeServerModal.title": "Server entfernen", "renderer.components.removeServerModal.confirm": "Bestätige, dass du den {serverName} Server entfernen möchtest?", "renderer.components.removeServerModal.body": "Dies wird den Server aus deiner Desktop-App entfernen aber keine seiner Daten löschen - Du kannst den Server jederzeit wieder zur App hinzufügen.", - "renderer.components.newTeamModal.title.edit": "Server bearbeiten", - "renderer.components.newTeamModal.title.add": "Server hinzufügen", - "renderer.components.newTeamModal.serverURL.description": "Die URL deines Mattermost Servers. Muss mit http:// oder https:// beginnen.", - "renderer.components.newTeamModal.serverURL": "Server URL", - "renderer.components.newTeamModal.serverDisplayName.description": "Der Name des Server, der auf der Desktop App Tab-Leiste angezeigt wird.", - "renderer.components.newTeamModal.serverDisplayName": "Server-Anzeigename", - "renderer.components.newTeamModal.error.urlRequired": "URL wird benötigt.", - "renderer.components.newTeamModal.error.urlNeedsHttp": "URL sollte mit http:// oder https:// beginnen.", - "renderer.components.newTeamModal.error.urlIncorrectFormatting": "Die URL ist nicht korrekt formatiert.", - "renderer.components.newTeamModal.error.serverUrlExists": "Ein Server mit der gleichen URL existiert schon.", - "renderer.components.newTeamModal.error.serverNameExists": "Ein Server mit diesem Namen existiert schon.", - "renderer.components.newTeamModal.error.nameRequired": "Name wird benötigt.", + "renderer.components.newServerModal.title.edit": "Server bearbeiten", + "renderer.components.newServerModal.title.add": "Server hinzufügen", + "renderer.components.newServerModal.serverURL.description": "Die URL deines Mattermost Servers. Muss mit http:// oder https:// beginnen.", + "renderer.components.newServerModal.serverURL": "Server URL", + "renderer.components.newServerModal.serverDisplayName.description": "Der Name des Server, der auf der Desktop App Tab-Leiste angezeigt wird.", + "renderer.components.newServerModal.serverDisplayName": "Server-Anzeigename", + "renderer.components.newServerModal.error.urlRequired": "URL wird benötigt.", + "renderer.components.newServerModal.error.urlNeedsHttp": "URL sollte mit http:// oder https:// beginnen.", + "renderer.components.newServerModal.error.urlIncorrectFormatting": "Die URL ist nicht korrekt formatiert.", + "renderer.components.newServerModal.error.serverUrlExists": "Ein Server mit der gleichen URL existiert schon.", + "renderer.components.newServerModal.error.serverNameExists": "Ein Server mit diesem Namen existiert schon.", + "renderer.components.newServerModal.error.nameRequired": "Name wird benötigt.", "renderer.components.mainPage.updateReady": "Update bereit zur Installation", "renderer.components.mainPage.updateAvailable": "Update verfügbar", "renderer.components.mainPage.downloadingUpdate": "Lade Update runter. {percentDone}% von {total} @ {speed}/s", diff --git a/i18n/en.json b/i18n/en.json index dc53f598..6150f56a 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -138,23 +138,24 @@ "renderer.components.input.required": "This field is required", "renderer.components.mainPage.contextMenu.ariaLabel": "Context menu", "renderer.components.mainPage.titleBar": "Mattermost", - "renderer.components.newTeamModal.error.nameRequired": "Name is required.", - "renderer.components.newTeamModal.error.serverNameExists": "A server with the same name already exists.", - "renderer.components.newTeamModal.error.serverUrlExists": "A server with the same URL already exists.", - "renderer.components.newTeamModal.error.urlIncorrectFormatting": "URL is not formatted correctly.", - "renderer.components.newTeamModal.error.urlNeedsHttp": "URL should start with http:// or https://.", - "renderer.components.newTeamModal.error.urlRequired": "URL is required.", - "renderer.components.newTeamModal.serverDisplayName": "Server Display Name", - "renderer.components.newTeamModal.serverDisplayName.description": "The name of the server displayed on your desktop app tab bar.", - "renderer.components.newTeamModal.serverURL": "Server URL", - "renderer.components.newTeamModal.serverURL.description": "The URL of your Mattermost server. Must start with http:// or https://.", - "renderer.components.newTeamModal.title.add": "Add Server", - "renderer.components.newTeamModal.title.edit": "Edit Server", + "renderer.components.newServerModal.error.nameRequired": "Name is required.", + "renderer.components.newServerModal.error.serverNameExists": "A server with the same name already exists.", + "renderer.components.newServerModal.error.serverUrlExists": "A server with the same URL already exists.", + "renderer.components.newServerModal.error.urlIncorrectFormatting": "URL is not formatted correctly.", + "renderer.components.newServerModal.error.urlNeedsHttp": "URL should start with http:// or https://.", + "renderer.components.newServerModal.error.urlRequired": "URL is required.", + "renderer.components.newServerModal.serverDisplayName": "Server Display Name", + "renderer.components.newServerModal.serverDisplayName.description": "The name of the server displayed on your desktop app tab bar.", + "renderer.components.newServerModal.serverURL": "Server URL", + "renderer.components.newServerModal.serverURL.description": "The URL of your Mattermost server. Must start with http:// or https://.", + "renderer.components.newServerModal.title.add": "Add Server", + "renderer.components.newServerModal.title.edit": "Edit Server", "renderer.components.removeServerModal.body": "This will remove the server from your Desktop App but will not delete any of its data - you can add the server back to the app at any time.", "renderer.components.removeServerModal.confirm": "Confirm you wish to remove the {serverName} server?", "renderer.components.removeServerModal.title": "Remove Server", "renderer.components.saveButton.save": "Save", "renderer.components.saveButton.saving": "Saving", + "renderer.components.serverDropdownButton.noServersConfigured": "No servers configured", "renderer.components.settingsPage.afterRestart": "Setting takes effect after restarting the app.", "renderer.components.settingsPage.appLanguage": "Set app language (beta)", "renderer.components.settingsPage.appLanguage.description": "Chooses the language that the Desktop App will use for menu items and popups. Still in beta, some languages will be missing translation strings.", @@ -219,7 +220,6 @@ "renderer.components.showCertificateModal.publicKeyInfo": "Public Key Info", "renderer.components.showCertificateModal.serialNumber": "Serial Number", "renderer.components.showCertificateModal.subjectName": "Subject Name", - "renderer.components.teamDropdownButton.noServersConfigured": "No servers configured", "renderer.components.welcomeScreen.button.getStarted": "Get Started", "renderer.components.welcomeScreen.slides.boards.subtitle": "Ship on time, every time, with a project and task management solution built for digital operations.", "renderer.components.welcomeScreen.slides.boards.title": "Boards", diff --git a/i18n/en_AU.json b/i18n/en_AU.json index 1c9f8245..9832e688 100644 --- a/i18n/en_AU.json +++ b/i18n/en_AU.json @@ -56,7 +56,7 @@ "renderer.modals.certificate.certificateModal.certInfoButton": "Certificate Information", "renderer.dropdown.servers": "Servers", "renderer.dropdown.addAServer": "Add a server", - "renderer.components.teamDropdownButton.noServersConfigured": "No servers configured", + "renderer.components.serverDropdownButton.noServersConfigured": "No servers configured", "renderer.components.showCertificateModal.subjectName": "Subject Name", "renderer.components.showCertificateModal.serialNumber": "Serial Number", "renderer.components.showCertificateModal.publicKeyInfo": "Public Key Info", @@ -124,18 +124,18 @@ "renderer.components.removeServerModal.confirm": "Confirm you wish to remove the {serverName} server?", "renderer.components.removeServerModal.title": "Remove Server", "renderer.components.removeServerModal.body": "This will remove the server from your Desktop App but will not delete any of its data - you can add the server back to the app at any time.", - "renderer.components.newTeamModal.title.edit": "Edit Server", - "renderer.components.newTeamModal.title.add": "Add Server", - "renderer.components.newTeamModal.serverURL.description": "The URL of your Mattermost server. Must start with http:// or https://.", - "renderer.components.newTeamModal.serverURL": "Server URL", - "renderer.components.newTeamModal.serverDisplayName.description": "The name of the server displayed on your desktop app tab bar.", - "renderer.components.newTeamModal.serverDisplayName": "Server Display Name", - "renderer.components.newTeamModal.error.urlRequired": "URL is required.", - "renderer.components.newTeamModal.error.urlNeedsHttp": "URL should start with http:// or https://.", - "renderer.components.newTeamModal.error.urlIncorrectFormatting": "URL is not formatted correctly.", - "renderer.components.newTeamModal.error.serverUrlExists": "A server with the same URL already exists.", - "renderer.components.newTeamModal.error.serverNameExists": "A server with the same name already exists.", - "renderer.components.newTeamModal.error.nameRequired": "Name is required.", + "renderer.components.newServerModal.title.edit": "Edit Server", + "renderer.components.newServerModal.title.add": "Add Server", + "renderer.components.newServerModal.serverURL.description": "The URL of your Mattermost server. Must start with http:// or https://.", + "renderer.components.newServerModal.serverURL": "Server URL", + "renderer.components.newServerModal.serverDisplayName.description": "The name of the server displayed on your desktop app tab bar.", + "renderer.components.newServerModal.serverDisplayName": "Server Display Name", + "renderer.components.newServerModal.error.urlRequired": "URL is required.", + "renderer.components.newServerModal.error.urlNeedsHttp": "URL should start with http:// or https://.", + "renderer.components.newServerModal.error.urlIncorrectFormatting": "URL is not formatted correctly.", + "renderer.components.newServerModal.error.serverUrlExists": "A server with the same URL already exists.", + "renderer.components.newServerModal.error.serverNameExists": "A server with the same name already exists.", + "renderer.components.newServerModal.error.nameRequired": "Name is required.", "renderer.components.mainPage.updateReady": "Update ready to install", "renderer.components.mainPage.updateAvailable": "Update available", "renderer.components.mainPage.downloadingUpdate": "Downloading update. {percentDone}% of {total} @ {speed}/s", diff --git a/i18n/es.json b/i18n/es.json index 7f5dbfde..e85acfa8 100644 --- a/i18n/es.json +++ b/i18n/es.json @@ -36,15 +36,15 @@ "common.tabs.TAB_MESSAGING": "Canales", "common.tabs.TAB_FOCALBOARD": "Tableros", "common.permissions.canBasicAuth": "Autenticación Web", - "renderer.components.newTeamModal.serverURL": "URL del servidor", - "renderer.components.newTeamModal.serverDisplayName.description": "El nombre del servidor tal y como aparecerá en la barra de pestañas.", - "renderer.components.newTeamModal.serverDisplayName": "Nombre del servidor", - "renderer.components.newTeamModal.error.urlRequired": "El campo de URL es obligatorio.", - "renderer.components.newTeamModal.error.urlNeedsHttp": "La URL debería comenzar con http:// o https://.", - "renderer.components.newTeamModal.error.urlIncorrectFormatting": "La URL no está tiene un formato correcto.", - "renderer.components.newTeamModal.error.serverUrlExists": "Ya existe un servidor con la misma URL.", - "renderer.components.newTeamModal.error.serverNameExists": "Ya existe un servidor con ese mismo nombre.", - "renderer.components.newTeamModal.error.nameRequired": "El campo nombre es obligatorio.", + "renderer.components.newServerModal.serverURL": "URL del servidor", + "renderer.components.newServerModal.serverDisplayName.description": "El nombre del servidor tal y como aparecerá en la barra de pestañas.", + "renderer.components.newServerModal.serverDisplayName": "Nombre del servidor", + "renderer.components.newServerModal.error.urlRequired": "El campo de URL es obligatorio.", + "renderer.components.newServerModal.error.urlNeedsHttp": "La URL debería comenzar con http:// o https://.", + "renderer.components.newServerModal.error.urlIncorrectFormatting": "La URL no está tiene un formato correcto.", + "renderer.components.newServerModal.error.serverUrlExists": "Ya existe un servidor con la misma URL.", + "renderer.components.newServerModal.error.serverNameExists": "Ya existe un servidor con ese mismo nombre.", + "renderer.components.newServerModal.error.nameRequired": "El campo nombre es obligatorio.", "renderer.components.mainPage.updateReady": "Actualización lista para instalar", "renderer.components.mainPage.updateAvailable": "Actualización disponible", "renderer.components.mainPage.downloadingUpdate": "Descargando actualización. {percentDone}% de {total} @ {speed}/s", @@ -169,7 +169,7 @@ "renderer.components.welcomeScreen.slides.channels.subtitle": "Todas las comunicaciones de tu equipo en un solo sitio.

Colaboración segura a la medida de los desarrolladores.", "renderer.components.welcomeScreen.slides.boards.title": "Boards", "renderer.components.welcomeScreen.button.getStarted": "Comenzar", - "renderer.components.teamDropdownButton.noServersConfigured": "No hay servidores configurados", + "renderer.components.serverDropdownButton.noServersConfigured": "No hay servidores configurados", "renderer.components.showCertificateModal.subjectName": "Nombre del firmante", "renderer.components.showCertificateModal.serialNumber": "Número de serie", "renderer.components.showCertificateModal.publicKeyInfo": "Información de clave pública", @@ -237,9 +237,9 @@ "renderer.components.removeServerModal.title": "Eliminar servidor", "renderer.components.removeServerModal.confirm": "¿Deseas eliminar el servidor {serverName}?", "renderer.components.removeServerModal.body": "Se eliminará el servidor de tu aplicación, pero no borrara sus datos - puedes volver a añadirlo en cualquier momento.", - "renderer.components.newTeamModal.title.edit": "Editar servidor", - "renderer.components.newTeamModal.title.add": "Añadir servidor", - "renderer.components.newTeamModal.serverURL.description": "La URL de tu servidor Mattermost debe comenzar con http:// o https://.", + "renderer.components.newServerModal.title.edit": "Editar servidor", + "renderer.components.newServerModal.title.add": "Añadir servidor", + "renderer.components.newServerModal.serverURL.description": "La URL de tu servidor Mattermost debe comenzar con http:// o https://.", "renderer.components.mainPage.titleBar": "Mattermost", "renderer.components.configureServer.subtitle": "Configura tu primer servidor para conectar tu

hub de comunicación del equipo", "renderer.downloadsDropdown.remaining": "restante", diff --git a/i18n/fa.json b/i18n/fa.json index 60958a11..e6fdc220 100644 --- a/i18n/fa.json +++ b/i18n/fa.json @@ -39,7 +39,7 @@ "label.accept": "قبول", "common.tabs.TAB_MESSAGING": "کانال‌ها", "common.permissions.canBasicAuth": "احراز هویت تحت وب", - "renderer.components.newTeamModal.error.urlNeedsHttp": "آدرس باید با ‭http://‬ یا ‭https://‬ شروع شود.", + "renderer.components.newServerModal.error.urlNeedsHttp": "آدرس باید با ‭http://‬ یا ‭https://‬ شروع شود.", "renderer.components.settingsPage.loggingLevel.level.warn": "اخطارها و هشدارها (warn)", "renderer.components.settingsPage.loggingLevel.level.verbose": "تمام‌جزئیات (verbose)", "renderer.components.settingsPage.loggingLevel.level.silly": "مختصرترین (silly)", @@ -84,7 +84,7 @@ "renderer.components.welcomeScreen.slides.channels.title": "کانال‌ها", "renderer.components.welcomeScreen.slides.boards.title": "تابلوها", "renderer.components.welcomeScreen.button.getStarted": "آغاز کردن", - "renderer.components.teamDropdownButton.noServersConfigured": "هیچ سروری پیکربندی نشده", + "renderer.components.serverDropdownButton.noServersConfigured": "هیچ سروری پیکربندی نشده", "renderer.components.showCertificateModal.subjectName": "نام نهاد", "renderer.components.showCertificateModal.serialNumber": "شماره سریال", "renderer.components.showCertificateModal.publicKeyInfo": "اطلاعات کلید عمومی", @@ -139,16 +139,16 @@ "renderer.components.removeServerModal.title": "حذف سرور", "renderer.components.removeServerModal.confirm": "تایید کنید که می‌خواهید سرور {serverName} را حذف کنید؟", "renderer.components.removeServerModal.body": "این کار سرور را از برنامه میزکار شما حذف می‌کند ولی هیچ اطلاعاتی از سرور پاک نمی‌شود - هر وقتی که تصمیم گرفتید، دوباره می‌توانید همین سرور را اضافه کنید.", - "renderer.components.newTeamModal.title.edit": "ویرایش سرور", - "renderer.components.newTeamModal.title.add": "افزودن سرور", - "renderer.components.newTeamModal.serverURL.description": "آدرس سرور مترموست. حتما باید با ‭http://‬ یا ‭https://‬ شروع شود.", - "renderer.components.newTeamModal.serverURL": "آدرس سرور", - "renderer.components.newTeamModal.serverDisplayName.description": "نام سرور در برنامه میزکار در قسمت نوار بالایی نمایش داده می‌شود.", - "renderer.components.newTeamModal.serverDisplayName": "نام نمایشی سرور", - "renderer.components.newTeamModal.error.urlRequired": "آدرس اجباری است.", - "renderer.components.newTeamModal.error.serverUrlExists": "سروری با همین آدرس موجود است.", - "renderer.components.newTeamModal.error.serverNameExists": "سروری با همین نام موجود است.", - "renderer.components.newTeamModal.error.nameRequired": "نام اجباری است.", + "renderer.components.newServerModal.title.edit": "ویرایش سرور", + "renderer.components.newServerModal.title.add": "افزودن سرور", + "renderer.components.newServerModal.serverURL.description": "آدرس سرور مترموست. حتما باید با ‭http://‬ یا ‭https://‬ شروع شود.", + "renderer.components.newServerModal.serverURL": "آدرس سرور", + "renderer.components.newServerModal.serverDisplayName.description": "نام سرور در برنامه میزکار در قسمت نوار بالایی نمایش داده می‌شود.", + "renderer.components.newServerModal.serverDisplayName": "نام نمایشی سرور", + "renderer.components.newServerModal.error.urlRequired": "آدرس اجباری است.", + "renderer.components.newServerModal.error.serverUrlExists": "سروری با همین آدرس موجود است.", + "renderer.components.newServerModal.error.serverNameExists": "سروری با همین نام موجود است.", + "renderer.components.newServerModal.error.nameRequired": "نام اجباری است.", "renderer.components.mainPage.titleBar": "مترموست", "renderer.components.mainPage.contextMenu.ariaLabel": "فهرست دسترسی", "renderer.components.input.required": "این قسمت اجباری است", @@ -165,7 +165,7 @@ "renderer.components.configureServer.connect.saving": "در حال اتصال…", "renderer.components.configureServer.connect.default": "اتصال", "main.tray.tray.mention": "در گفت‌وگویی به شما اشاره شده است", - "renderer.components.newTeamModal.error.urlIncorrectFormatting": "آدرس به درستی وارد نشده است.", + "renderer.components.newServerModal.error.urlIncorrectFormatting": "آدرس به درستی وارد نشده است.", "renderer.components.configureServer.cardtitle": "اطلاعات سرور خود را وارد کنید", "renderer.components.autoSaveIndicator.saving": "در حال ذخیره...", "renderer.components.autoSaveIndicator.saved": "ذخیره شد", diff --git a/i18n/fr.json b/i18n/fr.json index a149216c..4309d57f 100644 --- a/i18n/fr.json +++ b/i18n/fr.json @@ -17,7 +17,7 @@ "renderer.modals.certificate.certificateModal.certInfoButton": "Informations sur le certificat", "renderer.dropdown.servers": "Serveurs", "renderer.dropdown.addAServer": "Ajouter un serveur", - "renderer.components.teamDropdownButton.noServersConfigured": "Aucun serveur configuré", + "renderer.components.serverDropdownButton.noServersConfigured": "Aucun serveur configuré", "renderer.components.showCertificateModal.subjectName": "Nom du sujet", "renderer.components.showCertificateModal.serialNumber": "Numéro de série", "renderer.components.showCertificateModal.publicKeyInfo": "Informations sur les clés publiques", @@ -85,18 +85,18 @@ "renderer.components.removeServerModal.title": "Retirer le serveur", "renderer.components.removeServerModal.confirm": "Confirmez que vous souhaitez supprimer le serveur {serverName} ?", "renderer.components.removeServerModal.body": "Cette opération supprime le serveur de votre application de bureau mais ne supprime aucune de ses données. Vous pouvez réintégrer le serveur dans l'application à tout moment.", - "renderer.components.newTeamModal.title.edit": "Éditer le serveur", - "renderer.components.newTeamModal.title.add": "Ajouter un serveur", - "renderer.components.newTeamModal.serverURL.description": "L'URL de votre serveur Mattermost. Doit commencer par http:// ou https://.", - "renderer.components.newTeamModal.serverURL": "URL du serveur", - "renderer.components.newTeamModal.serverDisplayName.description": "Le nom du serveur affiché dans la barre d'onglets de votre application de bureau.", - "renderer.components.newTeamModal.serverDisplayName": "Nom d'affichage du serveur", - "renderer.components.newTeamModal.error.urlRequired": "URL requise.", - "renderer.components.newTeamModal.error.urlNeedsHttp": "L'URL doit commencer par http:// ou https://.", - "renderer.components.newTeamModal.error.urlIncorrectFormatting": "L'URL n'est pas formatée correctement.", - "renderer.components.newTeamModal.error.serverUrlExists": "Un serveur avec la même URL existe déjà.", - "renderer.components.newTeamModal.error.serverNameExists": "Un serveur portant le même nom existe déjà.", - "renderer.components.newTeamModal.error.nameRequired": "Le nom est obligatoire.", + "renderer.components.newServerModal.title.edit": "Éditer le serveur", + "renderer.components.newServerModal.title.add": "Ajouter un serveur", + "renderer.components.newServerModal.serverURL.description": "L'URL de votre serveur Mattermost. Doit commencer par http:// ou https://.", + "renderer.components.newServerModal.serverURL": "URL du serveur", + "renderer.components.newServerModal.serverDisplayName.description": "Le nom du serveur affiché dans la barre d'onglets de votre application de bureau.", + "renderer.components.newServerModal.serverDisplayName": "Nom d'affichage du serveur", + "renderer.components.newServerModal.error.urlRequired": "URL requise.", + "renderer.components.newServerModal.error.urlNeedsHttp": "L'URL doit commencer par http:// ou https://.", + "renderer.components.newServerModal.error.urlIncorrectFormatting": "L'URL n'est pas formatée correctement.", + "renderer.components.newServerModal.error.serverUrlExists": "Un serveur avec la même URL existe déjà.", + "renderer.components.newServerModal.error.serverNameExists": "Un serveur portant le même nom existe déjà.", + "renderer.components.newServerModal.error.nameRequired": "Le nom est obligatoire.", "renderer.components.mainPage.updateReady": "Mise à jour prête à être installée", "renderer.components.mainPage.updateAvailable": "Mise à jour disponible", "renderer.components.mainPage.downloadingUpdate": "Téléchargement de la mise à jour. {percentDone}% de {total} @ {speed}/s", diff --git a/i18n/hu.json b/i18n/hu.json index 72703c9f..a1e693e9 100644 --- a/i18n/hu.json +++ b/i18n/hu.json @@ -17,7 +17,7 @@ "renderer.modals.certificate.certificateModal.certInfoButton": "Tanúsítvány információk", "renderer.dropdown.servers": "Kiszolgálók", "renderer.dropdown.addAServer": "Kiszogáló hozzáadása", - "renderer.components.teamDropdownButton.noServersConfigured": "Nincs kiszolgáló beállítva", + "renderer.components.serverDropdownButton.noServersConfigured": "Nincs kiszolgáló beállítva", "renderer.components.showCertificateModal.subjectName": "Tárgy neve", "renderer.components.showCertificateModal.serialNumber": "Sorozatszám", "renderer.components.showCertificateModal.publicKeyInfo": "Nyilvános kulcs információk", @@ -85,18 +85,18 @@ "renderer.components.removeServerModal.title": "Kiszolgáló eltávolítása", "renderer.components.removeServerModal.confirm": "Megerősíti, hogy el kívánja távolítani a {serverName} kiszolgálót?", "renderer.components.removeServerModal.body": "Ez eltávolítja a kiszolgálót az asztali alkalmazásból, de nem törli annak adatait - a kiszolgálót bármikor visszaadhatja az alkalmazáshoz.", - "renderer.components.newTeamModal.serverURL.description": "A Mattermost kiszolgáló URL-címe. Az URL-nek http:// vagy https:// -el kell kezdődnie.", - "renderer.components.newTeamModal.title.edit": "Kiszolgáló szerkesztése", - "renderer.components.newTeamModal.title.add": "Kiszolgáló hozzáadása", - "renderer.components.newTeamModal.serverDisplayName.description": "A kiszolgáló neve, amely az asztali alkalmazás fülsávján lesz látható.", - "renderer.components.newTeamModal.serverURL": "Kiszolgáló URL", - "renderer.components.newTeamModal.serverDisplayName": "Kiszolgáló megjelenítési neve", - "renderer.components.newTeamModal.error.urlRequired": "URL kötelező.", - "renderer.components.newTeamModal.error.urlNeedsHttp": "Az URL-nek http:// vagy https:// -el kell kezdődnie.", - "renderer.components.newTeamModal.error.urlIncorrectFormatting": "Az URL nincs jól formázva.", - "renderer.components.newTeamModal.error.serverUrlExists": "Egy ilyen URL-ű kiszolgáló már létezik.", - "renderer.components.newTeamModal.error.serverNameExists": "Egy ilyen nevű kiszolgáló már létezik.", - "renderer.components.newTeamModal.error.nameRequired": "Név kötelező.", + "renderer.components.newServerModal.serverURL.description": "A Mattermost kiszolgáló URL-címe. Az URL-nek http:// vagy https:// -el kell kezdődnie.", + "renderer.components.newServerModal.title.edit": "Kiszolgáló szerkesztése", + "renderer.components.newServerModal.title.add": "Kiszolgáló hozzáadása", + "renderer.components.newServerModal.serverDisplayName.description": "A kiszolgáló neve, amely az asztali alkalmazás fülsávján lesz látható.", + "renderer.components.newServerModal.serverURL": "Kiszolgáló URL", + "renderer.components.newServerModal.serverDisplayName": "Kiszolgáló megjelenítési neve", + "renderer.components.newServerModal.error.urlRequired": "URL kötelező.", + "renderer.components.newServerModal.error.urlNeedsHttp": "Az URL-nek http:// vagy https:// -el kell kezdődnie.", + "renderer.components.newServerModal.error.urlIncorrectFormatting": "Az URL nincs jól formázva.", + "renderer.components.newServerModal.error.serverUrlExists": "Egy ilyen URL-ű kiszolgáló már létezik.", + "renderer.components.newServerModal.error.serverNameExists": "Egy ilyen nevű kiszolgáló már létezik.", + "renderer.components.newServerModal.error.nameRequired": "Név kötelező.", "renderer.components.mainPage.updateReady": "Frissítés készen áll a telepítésre", "renderer.components.mainPage.updateAvailable": "Frissítés érhető el", "renderer.components.errorView.troubleshooting.urlIsCorrect.appNameIsCorrect": "A {appName} alkalmazás URL {url} helyes", diff --git a/i18n/it.json b/i18n/it.json index c056126c..4a2ca6ad 100644 --- a/i18n/it.json +++ b/i18n/it.json @@ -33,14 +33,14 @@ "renderer.components.settingsPage.flashWindow.description.note": "NOTA: ", "renderer.components.settingsPage.enableHardwareAcceleration": "Usa l'accelerazione hardware della GPU", "renderer.components.settingsPage.appLanguage.useSystemDefault": "Usa il default di sistema", - "renderer.components.newTeamModal.error.urlNeedsHttp": "URL deve iniziare con http:// o https://.", + "renderer.components.newServerModal.error.urlNeedsHttp": "URL deve iniziare con http:// o https://.", "renderer.components.removeServerModal.title": "Rimuovi server", "renderer.components.settingsPage.appOptions": "Opzioni dell'app", "renderer.components.saveButton.save": "Salva", - "renderer.components.newTeamModal.title.edit": "Modifica server", - "renderer.components.newTeamModal.title.add": "Aggiungi server", + "renderer.components.newServerModal.title.edit": "Modifica server", + "renderer.components.newServerModal.title.add": "Aggiungi server", "renderer.components.input.required": "Questo campo è richiesto", - "renderer.components.newTeamModal.serverURL": "URL del server", + "renderer.components.newServerModal.serverURL": "URL del server", "renderer.components.mainPage.titleBar": "Mattermost", "renderer.components.extraBar.back": "Indietro", "renderer.components.configureServer.url.placeholder": "URL del server", diff --git a/i18n/ja.json b/i18n/ja.json index df451d99..e5c35eab 100644 --- a/i18n/ja.json +++ b/i18n/ja.json @@ -20,7 +20,7 @@ "renderer.modals.certificate.certificateModal.certInfoButton": "証明書情報", "renderer.dropdown.servers": "サーバー", "renderer.dropdown.addAServer": "サーバーを追加", - "renderer.components.teamDropdownButton.noServersConfigured": "サーバーが設定されていません", + "renderer.components.serverDropdownButton.noServersConfigured": "サーバーが設定されていません", "renderer.components.showCertificateModal.subjectName": "Subject Name", "renderer.components.showCertificateModal.serialNumber": "Serial Number", "renderer.components.showCertificateModal.publicKeyInfo": "公開鍵情報", @@ -88,18 +88,18 @@ "renderer.components.removeServerModal.title": "サーバーを削除", "renderer.components.removeServerModal.confirm": "本当に {serverName} サーバーを削除しますか?", "renderer.components.removeServerModal.body": "この操作によりデスクトップアプリからサーバーが削除されますが、データは削除されません - いつでもアプリにサーバーを追加し直すことができます。", - "renderer.components.newTeamModal.title.edit": "サーバーを編集", - "renderer.components.newTeamModal.title.add": "サーバーを追加", - "renderer.components.newTeamModal.serverURL.description": "あなたのMattermostサーバーのURLです。http:// または https:// で始まる必要があります。", - "renderer.components.newTeamModal.serverURL": "サーバーURL", - "renderer.components.newTeamModal.serverDisplayName.description": "デスクトップアプリのタブバーに表示されるサーバーの名前です。", - "renderer.components.newTeamModal.serverDisplayName": "サーバー表示名", - "renderer.components.newTeamModal.error.urlRequired": "URLは必須です。", - "renderer.components.newTeamModal.error.urlNeedsHttp": "URLは http:// または https:// で始まる必要があります。", - "renderer.components.newTeamModal.error.urlIncorrectFormatting": "URLの形式が正しくありません。", - "renderer.components.newTeamModal.error.serverUrlExists": "同じURLのサーバーが既に存在しています。", - "renderer.components.newTeamModal.error.serverNameExists": "同名のサーバーが既に存在しています。", - "renderer.components.newTeamModal.error.nameRequired": "名前は必須です。", + "renderer.components.newServerModal.title.edit": "サーバーを編集", + "renderer.components.newServerModal.title.add": "サーバーを追加", + "renderer.components.newServerModal.serverURL.description": "あなたのMattermostサーバーのURLです。http:// または https:// で始まる必要があります。", + "renderer.components.newServerModal.serverURL": "サーバーURL", + "renderer.components.newServerModal.serverDisplayName.description": "デスクトップアプリのタブバーに表示されるサーバーの名前です。", + "renderer.components.newServerModal.serverDisplayName": "サーバー表示名", + "renderer.components.newServerModal.error.urlRequired": "URLは必須です。", + "renderer.components.newServerModal.error.urlNeedsHttp": "URLは http:// または https:// で始まる必要があります。", + "renderer.components.newServerModal.error.urlIncorrectFormatting": "URLの形式が正しくありません。", + "renderer.components.newServerModal.error.serverUrlExists": "同じURLのサーバーが既に存在しています。", + "renderer.components.newServerModal.error.serverNameExists": "同名のサーバーが既に存在しています。", + "renderer.components.newServerModal.error.nameRequired": "名前は必須です。", "renderer.components.mainPage.updateReady": "更新をインストールする準備ができました", "renderer.components.mainPage.updateAvailable": "更新が利用可能です", "renderer.components.mainPage.downloadingUpdate": "更新をダウンロード中です。{total} 中 {percentDone}% 完了@ {speed}/s", diff --git a/i18n/ko.json b/i18n/ko.json index 822782e9..04d89cc2 100644 --- a/i18n/ko.json +++ b/i18n/ko.json @@ -156,7 +156,7 @@ "renderer.components.welcomeScreen.slides.boards.title": "보드", "renderer.components.welcomeScreen.slides.boards.subtitle": "디지털 오퍼레이션에 최적화된 프로젝트 및 작업 관리 솔루션을 사용해 항상 기한 내에 제품을 출시하세요.", "renderer.components.welcomeScreen.button.getStarted": "시작하기", - "renderer.components.teamDropdownButton.noServersConfigured": "구성된 서버 없음", + "renderer.components.serverDropdownButton.noServersConfigured": "구성된 서버 없음", "renderer.components.showCertificateModal.subjectName": "주체 이름(Subject Name)", "renderer.components.showCertificateModal.serialNumber": "일련번호", "renderer.components.showCertificateModal.publicKeyInfo": "공개 키 정보", @@ -225,18 +225,18 @@ "renderer.components.removeServerModal.title": "서버 제거", "renderer.components.removeServerModal.confirm": "{serverName} 서버를 제거하시겠습니까?", "renderer.components.removeServerModal.body": "이렇게 하면 데스크톱 앱에서 서버가 제거되지만 해당 데이터는 삭제되지 않습니다. 언제든지 앱에 서버를 다시 추가할 수 있습니다.", - "renderer.components.newTeamModal.title.edit": "서버 수정", - "renderer.components.newTeamModal.title.add": "서버 추가", - "renderer.components.newTeamModal.serverURL.description": "Mattermost 서버 URL입니다. http:// 또는 https://로 시작해야 합니다.", - "renderer.components.newTeamModal.serverURL": "서버 URL", - "renderer.components.newTeamModal.serverDisplayName.description": "데스크톱 앱 탭 표시줄에 표시되는 서버 이름입니다.", - "renderer.components.newTeamModal.serverDisplayName": "서버 표시 이름", - "renderer.components.newTeamModal.error.urlRequired": "URL이 필요합니다.", - "renderer.components.newTeamModal.error.urlNeedsHttp": "URL은 http:// 또는 https://로 시작해야 합니다.", - "renderer.components.newTeamModal.error.urlIncorrectFormatting": "URL 형식이 올바르지 않습니다.", - "renderer.components.newTeamModal.error.serverUrlExists": "동일한 URL을 가진 서버가 이미 존재합니다.", - "renderer.components.newTeamModal.error.serverNameExists": "같은 이름의 서버가 이미 존재합니다.", - "renderer.components.newTeamModal.error.nameRequired": "이름이 필요합니다.", + "renderer.components.newServerModal.title.edit": "서버 수정", + "renderer.components.newServerModal.title.add": "서버 추가", + "renderer.components.newServerModal.serverURL.description": "Mattermost 서버 URL입니다. http:// 또는 https://로 시작해야 합니다.", + "renderer.components.newServerModal.serverURL": "서버 URL", + "renderer.components.newServerModal.serverDisplayName.description": "데스크톱 앱 탭 표시줄에 표시되는 서버 이름입니다.", + "renderer.components.newServerModal.serverDisplayName": "서버 표시 이름", + "renderer.components.newServerModal.error.urlRequired": "URL이 필요합니다.", + "renderer.components.newServerModal.error.urlNeedsHttp": "URL은 http:// 또는 https://로 시작해야 합니다.", + "renderer.components.newServerModal.error.urlIncorrectFormatting": "URL 형식이 올바르지 않습니다.", + "renderer.components.newServerModal.error.serverUrlExists": "동일한 URL을 가진 서버가 이미 존재합니다.", + "renderer.components.newServerModal.error.serverNameExists": "같은 이름의 서버가 이미 존재합니다.", + "renderer.components.newServerModal.error.nameRequired": "이름이 필요합니다.", "renderer.components.mainPage.titleBar": "Mattermost", "renderer.components.mainPage.contextMenu.ariaLabel": "컨텍스트 메뉴", "renderer.components.input.required": "이 필드는 필수입니다", diff --git a/i18n/nl.json b/i18n/nl.json index b2fb95d7..f867d2b3 100644 --- a/i18n/nl.json +++ b/i18n/nl.json @@ -48,7 +48,7 @@ "renderer.modals.certificate.certificateModal.certInfoButton": "Informatie over het certificaat", "renderer.dropdown.servers": "Servers", "renderer.dropdown.addAServer": "Voeg een server toe", - "renderer.components.teamDropdownButton.noServersConfigured": "Geen geconfigureerde servers", + "renderer.components.serverDropdownButton.noServersConfigured": "Geen geconfigureerde servers", "renderer.components.showCertificateModal.subjectName": "Subject Name", "renderer.components.showCertificateModal.serialNumber": "Serienummer", "renderer.components.showCertificateModal.publicKeyInfo": "Info publieke sleutel", @@ -116,18 +116,18 @@ "renderer.components.removeServerModal.title": "Server verwijderen", "renderer.components.removeServerModal.confirm": "Bevestig dat je de {serverNaam} server wil verwijderen?", "renderer.components.removeServerModal.body": "Dit verwijdert de server van je desktop-applicatie maar verwijdert geen gegevens - je kan de server op elk moment opnieuw toevoegen aan de applicatie.", - "renderer.components.newTeamModal.title.edit": "Server bewerken", - "renderer.components.newTeamModal.title.add": "Server toevoegen", - "renderer.components.newTeamModal.serverURL.description": "De URL van je Mattermost server. Moet beginnen met http:// of https://.", - "renderer.components.newTeamModal.serverURL": "Server-URL", - "renderer.components.newTeamModal.serverDisplayName.description": "De naam van de server die op de tabbalk van jouw desktop app wordt weergegeven.", - "renderer.components.newTeamModal.serverDisplayName": "Weergave naam server", - "renderer.components.newTeamModal.error.urlRequired": "URL is verplicht.", - "renderer.components.newTeamModal.error.urlNeedsHttp": "URL moet beginnen met http:// of https://.", - "renderer.components.newTeamModal.error.urlIncorrectFormatting": "URL heeft een ongeldig formaat.", - "renderer.components.newTeamModal.error.serverUrlExists": "Een server met dezelfde URL bestaat reeds.", - "renderer.components.newTeamModal.error.serverNameExists": "Een server met dezelfde naam bestaat reeds.", - "renderer.components.newTeamModal.error.nameRequired": "Naam is verplicht.", + "renderer.components.newServerModal.title.edit": "Server bewerken", + "renderer.components.newServerModal.title.add": "Server toevoegen", + "renderer.components.newServerModal.serverURL.description": "De URL van je Mattermost server. Moet beginnen met http:// of https://.", + "renderer.components.newServerModal.serverURL": "Server-URL", + "renderer.components.newServerModal.serverDisplayName.description": "De naam van de server die op de tabbalk van jouw desktop app wordt weergegeven.", + "renderer.components.newServerModal.serverDisplayName": "Weergave naam server", + "renderer.components.newServerModal.error.urlRequired": "URL is verplicht.", + "renderer.components.newServerModal.error.urlNeedsHttp": "URL moet beginnen met http:// of https://.", + "renderer.components.newServerModal.error.urlIncorrectFormatting": "URL heeft een ongeldig formaat.", + "renderer.components.newServerModal.error.serverUrlExists": "Een server met dezelfde URL bestaat reeds.", + "renderer.components.newServerModal.error.serverNameExists": "Een server met dezelfde naam bestaat reeds.", + "renderer.components.newServerModal.error.nameRequired": "Naam is verplicht.", "renderer.components.mainPage.updateReady": "Update klaar om geïnstalleerd te worden", "renderer.components.mainPage.updateAvailable": "Update beschikbaar", "renderer.components.mainPage.downloadingUpdate": "Update wordt gedownload. {percentDone}% van {total} @ {speed}/s", diff --git a/i18n/pl.json b/i18n/pl.json index 8d210f6b..2a4e725a 100644 --- a/i18n/pl.json +++ b/i18n/pl.json @@ -76,18 +76,18 @@ "renderer.components.removeServerModal.title": "Usuń Serwer", "renderer.components.removeServerModal.confirm": "Potwierdzasz, że chcesz usunąć serwer {serverName}?", "renderer.components.removeServerModal.body": "To usunie serwer z Twojej aplikacji Desktop App, ale nie usunie żadnych jego danych - możesz dodać serwer z powrotem do aplikacji w dowolnym momencie.", - "renderer.components.newTeamModal.title.edit": "Edytuj Serwer", - "renderer.components.newTeamModal.title.add": "Dodaj Serwer", - "renderer.components.newTeamModal.serverURL.description": "Adres URL Twojego serwera Mattermost. Musi zaczynać się od http:// lub https://.", - "renderer.components.newTeamModal.serverURL": "URL Serwera", - "renderer.components.newTeamModal.serverDisplayName.description": "Nazwa serwera wyświetlana na pasku zakładek aplikacji desktopowej.", - "renderer.components.newTeamModal.serverDisplayName": "Wyświetlana Nazwa Serwera", - "renderer.components.newTeamModal.error.urlRequired": "Wymagany jest adres URL.", - "renderer.components.newTeamModal.error.urlNeedsHttp": "Adres URL powinien zaczynać się od http:// lub https://.", - "renderer.components.newTeamModal.error.urlIncorrectFormatting": "Adres URL nie jest poprawnie sformatowany.", - "renderer.components.newTeamModal.error.serverUrlExists": "Serwer o tym samym adresie URL już istnieje.", - "renderer.components.newTeamModal.error.serverNameExists": "Serwer o tej samej nazwie już istnieje.", - "renderer.components.newTeamModal.error.nameRequired": "Nazwa jest wymagana.", + "renderer.components.newServerModal.title.edit": "Edytuj Serwer", + "renderer.components.newServerModal.title.add": "Dodaj Serwer", + "renderer.components.newServerModal.serverURL.description": "Adres URL Twojego serwera Mattermost. Musi zaczynać się od http:// lub https://.", + "renderer.components.newServerModal.serverURL": "URL Serwera", + "renderer.components.newServerModal.serverDisplayName.description": "Nazwa serwera wyświetlana na pasku zakładek aplikacji desktopowej.", + "renderer.components.newServerModal.serverDisplayName": "Wyświetlana Nazwa Serwera", + "renderer.components.newServerModal.error.urlRequired": "Wymagany jest adres URL.", + "renderer.components.newServerModal.error.urlNeedsHttp": "Adres URL powinien zaczynać się od http:// lub https://.", + "renderer.components.newServerModal.error.urlIncorrectFormatting": "Adres URL nie jest poprawnie sformatowany.", + "renderer.components.newServerModal.error.serverUrlExists": "Serwer o tym samym adresie URL już istnieje.", + "renderer.components.newServerModal.error.serverNameExists": "Serwer o tej samej nazwie już istnieje.", + "renderer.components.newServerModal.error.nameRequired": "Nazwa jest wymagana.", "renderer.components.mainPage.updateReady": "Aktualizacja gotowa do zainstalowania", "renderer.components.mainPage.updateAvailable": "Dostępna aktualizacja", "renderer.components.mainPage.downloadingUpdate": "Pobieranie aktualizacji. {percentDone}% z {total} @ {speed}/s", @@ -192,7 +192,7 @@ "renderer.components.settingsPage.loggingLevel.level.debug": "Debuguj (debug)", "renderer.components.settingsPage.loggingLevel.description.subtitle": "Zwiększenie poziomu dziennika zwiększa zużycie miejsca na dysku i może wpłynąć na wydajność. Zalecamy zwiększenie poziomu dziennika tylko w przypadku wystąpienia problemów.", "renderer.components.welcomeScreen.button.getStarted": "Rozpocznij", - "renderer.components.teamDropdownButton.noServersConfigured": "Brak skonfigurowanych serwerów", + "renderer.components.serverDropdownButton.noServersConfigured": "Brak skonfigurowanych serwerów", "renderer.components.showCertificateModal.subjectName": "Nazwa tematu", "renderer.components.showCertificateModal.serialNumber": "Numer seryjny", "renderer.components.showCertificateModal.publicKeyInfo": "Informacje o kluczach publicznych", diff --git a/i18n/pt-BR.json b/i18n/pt-BR.json index 437a1cca..07988360 100644 --- a/i18n/pt-BR.json +++ b/i18n/pt-BR.json @@ -128,10 +128,10 @@ "main.menus.app.view.downloads": "Downloads", "renderer.components.saveButton.save": "Salvar", "renderer.components.removeServerModal.title": "Remover Servidor", - "renderer.components.newTeamModal.title.edit": "Editar Servidor", - "renderer.components.newTeamModal.title.add": "Adicionar Servidor", - "renderer.components.newTeamModal.serverURL": "URL do Servidor", - "renderer.components.newTeamModal.error.urlRequired": "URL é necessária.", + "renderer.components.newServerModal.title.edit": "Editar Servidor", + "renderer.components.newServerModal.title.add": "Adicionar Servidor", + "renderer.components.newServerModal.serverURL": "URL do Servidor", + "renderer.components.newServerModal.error.urlRequired": "URL é necessária.", "renderer.components.mainPage.contextMenu.ariaLabel": "Menu de contexto", "renderer.components.extraBar.back": "Voltar", "renderer.components.errorView.troubleshooting.computerIsConnected": "Seu computador está conectado à internet.", diff --git a/i18n/ru.json b/i18n/ru.json index 98f588d3..c594a27e 100644 --- a/i18n/ru.json +++ b/i18n/ru.json @@ -48,7 +48,7 @@ "renderer.components.welcomeScreen.slides.boards.title": "Boards", "renderer.components.welcomeScreen.slides.boards.subtitle": "Успевайте каждый раз вовремя выполнить задачи, с решением для управления проектами и задачами, созданным для цифровых операций.", "renderer.components.welcomeScreen.button.getStarted": "Начать", - "renderer.components.teamDropdownButton.noServersConfigured": "Серверы не настроены", + "renderer.components.serverDropdownButton.noServersConfigured": "Серверы не настроены", "renderer.components.showCertificateModal.subjectName": "Имя субъекта (SN)", "renderer.components.showCertificateModal.serialNumber": "Серийный номер", "renderer.components.showCertificateModal.publicKeyInfo": "Информация о публичном ключе", @@ -118,19 +118,19 @@ "renderer.components.removeServerModal.title": "Удалить сервер", "renderer.components.removeServerModal.confirm": "Подтвердите, что вы хотите удалить сервер {serverName}?", "renderer.components.removeServerModal.body": "Это действие удалит сервер из вашего приложения, но не удалит его данные - вы можете добавить сервер обратно в приложение в любое время.", - "renderer.components.newTeamModal.title.edit": "Изменение настроек сервера", - "renderer.components.newTeamModal.title.add": "Добавить сервер", - "renderer.components.newTeamModal.serverURL.description": "URL вашего сервера Mattermost. Должен начинаться с http:// или https://.", - "renderer.components.newTeamModal.serverURL": "URL сервера", - "renderer.components.newTeamModal.serverDisplayName.description": "Имя сервера, отображаемое на панели вкладок вашего приложения.", - "renderer.components.newTeamModal.serverDisplayName": "Отображаемое имя сервера", + "renderer.components.newServerModal.title.edit": "Изменение настроек сервера", + "renderer.components.newServerModal.title.add": "Добавить сервер", + "renderer.components.newServerModal.serverURL.description": "URL вашего сервера Mattermost. Должен начинаться с http:// или https://.", + "renderer.components.newServerModal.serverURL": "URL сервера", + "renderer.components.newServerModal.serverDisplayName.description": "Имя сервера, отображаемое на панели вкладок вашего приложения.", + "renderer.components.newServerModal.serverDisplayName": "Отображаемое имя сервера", "common.tabs.TAB_MESSAGING": "Channels", - "renderer.components.newTeamModal.error.nameRequired": "Укажите имя сервера.", - "renderer.components.newTeamModal.error.urlRequired": "Укажите URL-адрес.", - "renderer.components.newTeamModal.error.urlNeedsHttp": "URL-адрес должен начинаться с http:// или https://.", - "renderer.components.newTeamModal.error.urlIncorrectFormatting": "URL-адрес неверно отформатирован.", - "renderer.components.newTeamModal.error.serverUrlExists": "Сервер с таким URL уже существует.", - "renderer.components.newTeamModal.error.serverNameExists": "Сервер с таким же именем уже существует.", + "renderer.components.newServerModal.error.nameRequired": "Укажите имя сервера.", + "renderer.components.newServerModal.error.urlRequired": "Укажите URL-адрес.", + "renderer.components.newServerModal.error.urlNeedsHttp": "URL-адрес должен начинаться с http:// или https://.", + "renderer.components.newServerModal.error.urlIncorrectFormatting": "URL-адрес неверно отформатирован.", + "renderer.components.newServerModal.error.serverUrlExists": "Сервер с таким URL уже существует.", + "renderer.components.newServerModal.error.serverNameExists": "Сервер с таким же именем уже существует.", "renderer.components.mainPage.titleBar": "Mattermost", "renderer.components.mainPage.contextMenu.ariaLabel": "Контекстное меню", "renderer.components.input.required": "Обязательное поле", diff --git a/i18n/sv.json b/i18n/sv.json index 4abc09bf..aa6d441b 100644 --- a/i18n/sv.json +++ b/i18n/sv.json @@ -24,18 +24,18 @@ "renderer.components.removeServerModal.title": "Ta bort servern", "renderer.components.removeServerModal.confirm": "Bekräftar du att du vill ta bort anslutningen till servern {serverName}?", "renderer.components.removeServerModal.body": "Detta tar bort servern från din skrivbordsapplikation, men raderar inte dess data - du kan när som helst lägga till servern i appen igen.", - "renderer.components.newTeamModal.title.edit": "Redigera server", - "renderer.components.newTeamModal.title.add": "Lägg till server", - "renderer.components.newTeamModal.serverURL.description": "URL för din Mattermost-server. Måste börja med http:// eller https://.", - "renderer.components.newTeamModal.serverURL": "Server-URL", - "renderer.components.newTeamModal.serverDisplayName.description": "Namnet på servern som visas på fliken i skrivbordsappen.", - "renderer.components.newTeamModal.serverDisplayName": "Serverns visningsnamn", - "renderer.components.newTeamModal.error.urlRequired": "Du måste ange en URL.", - "renderer.components.newTeamModal.error.urlNeedsHttp": "Måste börja med http:// eller https://.", - "renderer.components.newTeamModal.error.urlIncorrectFormatting": "URL-adressen är inte korrekt formaterad.", - "renderer.components.newTeamModal.error.serverUrlExists": "Det finns redan en server med samma URL.", - "renderer.components.newTeamModal.error.serverNameExists": "Det finns redan en server med samma namn.", - "renderer.components.newTeamModal.error.nameRequired": "Du måste ange Namn.", + "renderer.components.newServerModal.title.edit": "Redigera server", + "renderer.components.newServerModal.title.add": "Lägg till server", + "renderer.components.newServerModal.serverURL.description": "URL för din Mattermost-server. Måste börja med http:// eller https://.", + "renderer.components.newServerModal.serverURL": "Server-URL", + "renderer.components.newServerModal.serverDisplayName.description": "Namnet på servern som visas på fliken i skrivbordsappen.", + "renderer.components.newServerModal.serverDisplayName": "Serverns visningsnamn", + "renderer.components.newServerModal.error.urlRequired": "Du måste ange en URL.", + "renderer.components.newServerModal.error.urlNeedsHttp": "Måste börja med http:// eller https://.", + "renderer.components.newServerModal.error.urlIncorrectFormatting": "URL-adressen är inte korrekt formaterad.", + "renderer.components.newServerModal.error.serverUrlExists": "Det finns redan en server med samma URL.", + "renderer.components.newServerModal.error.serverNameExists": "Det finns redan en server med samma namn.", + "renderer.components.newServerModal.error.nameRequired": "Du måste ange Namn.", "renderer.components.mainPage.updateReady": "Uppdatering klar att installera", "renderer.components.mainPage.updateAvailable": "Uppdatering tillgänglig", "renderer.components.mainPage.downloadingUpdate": "Hämtar uppdatering. {percentDone}% av {total} @ {speed}/s", @@ -189,7 +189,7 @@ "renderer.modals.certificate.certificateModal.certInfoButton": "Information om certifikat", "renderer.dropdown.servers": "Servrar", "renderer.dropdown.addAServer": "Lägg till en server", - "renderer.components.teamDropdownButton.noServersConfigured": "Inga servrar konfigurerade", + "renderer.components.serverDropdownButton.noServersConfigured": "Inga servrar konfigurerade", "renderer.components.showCertificateModal.subjectName": "Ämnesnamn", "renderer.components.showCertificateModal.serialNumber": "Serienummer", "renderer.components.showCertificateModal.publicKeyInfo": "Offentlig nyckel", diff --git a/i18n/tr.json b/i18n/tr.json index e88f5b3d..d486fa0f 100644 --- a/i18n/tr.json +++ b/i18n/tr.json @@ -17,7 +17,7 @@ "renderer.modals.certificate.certificateModal.certInfoButton": "Sertifika bilgileri", "renderer.dropdown.servers": "Sunucular", "renderer.dropdown.addAServer": "Bir sunucu ekle", - "renderer.components.teamDropdownButton.noServersConfigured": "Herhangi bir sunucu yapılandırılmamış", + "renderer.components.serverDropdownButton.noServersConfigured": "Herhangi bir sunucu yapılandırılmamış", "renderer.components.showCertificateModal.subjectName": "Özne adı", "renderer.components.showCertificateModal.serialNumber": "Seri numarası", "renderer.components.showCertificateModal.publicKeyInfo": "Herkese açık anahtar bilgileri", @@ -85,18 +85,18 @@ "renderer.components.removeServerModal.title": "Sunucuyu kaldır", "renderer.components.removeServerModal.confirm": "{serverName} sunucunu kaldırmak istediğinizi onaylıyor musunuz?", "renderer.components.removeServerModal.body": "Bu işlem sunucuyu masaüstü uygulamanızdan kaldırır ancak hiçbir verisini silmez. İstediğiniz zaman sunucuyu uygulamaya yeniden ekleyebilirsiniz.", - "renderer.components.newTeamModal.title.edit": "Sunucuyu düzenle", - "renderer.components.newTeamModal.title.add": "Sunucu ekle", - "renderer.components.newTeamModal.serverURL.description": "Mattermost sunucunuzun adresi. http:// ya da https:// ile başlamalıdır.", - "renderer.components.newTeamModal.serverURL": "Sunucu adresi", - "renderer.components.newTeamModal.serverDisplayName.description": "Sunucunun masaüstü uygulama sekmesi çubuğunda görüntülenecek adı.", - "renderer.components.newTeamModal.serverDisplayName": "Sunucunun görüntülenecek adı", - "renderer.components.newTeamModal.error.urlRequired": "Adresin yazılması zorunludur.", - "renderer.components.newTeamModal.error.urlNeedsHttp": "Adres http:// ya da https:// ile başlamalıdır.", - "renderer.components.newTeamModal.error.urlIncorrectFormatting": "Adresin biçimi doğru değil.", - "renderer.components.newTeamModal.error.serverUrlExists": "Aynı adresi kullanan bir sunucu zaten var.", - "renderer.components.newTeamModal.error.serverNameExists": "Aynı adlı bir sunucu zaten var.", - "renderer.components.newTeamModal.error.nameRequired": "Ad yazılması zorunludur.", + "renderer.components.newServerModal.title.edit": "Sunucuyu düzenle", + "renderer.components.newServerModal.title.add": "Sunucu ekle", + "renderer.components.newServerModal.serverURL.description": "Mattermost sunucunuzun adresi. http:// ya da https:// ile başlamalıdır.", + "renderer.components.newServerModal.serverURL": "Sunucu adresi", + "renderer.components.newServerModal.serverDisplayName.description": "Sunucunun masaüstü uygulama sekmesi çubuğunda görüntülenecek adı.", + "renderer.components.newServerModal.serverDisplayName": "Sunucunun görüntülenecek adı", + "renderer.components.newServerModal.error.urlRequired": "Adresin yazılması zorunludur.", + "renderer.components.newServerModal.error.urlNeedsHttp": "Adres http:// ya da https:// ile başlamalıdır.", + "renderer.components.newServerModal.error.urlIncorrectFormatting": "Adresin biçimi doğru değil.", + "renderer.components.newServerModal.error.serverUrlExists": "Aynı adresi kullanan bir sunucu zaten var.", + "renderer.components.newServerModal.error.serverNameExists": "Aynı adlı bir sunucu zaten var.", + "renderer.components.newServerModal.error.nameRequired": "Ad yazılması zorunludur.", "renderer.components.mainPage.updateReady": "Güncelleme kurulmaya hazır", "renderer.components.mainPage.updateAvailable": "Güncelleme yayınlanmış", "renderer.components.mainPage.downloadingUpdate": "Güncelleme indiriliyor. %{percentDone}/{total} indirildi. Hız: {speed}/s", diff --git a/i18n/uk.json b/i18n/uk.json index 69af4ce5..b00daec4 100644 --- a/i18n/uk.json +++ b/i18n/uk.json @@ -10,18 +10,18 @@ "renderer.components.removeServerModal.title": "Видалити сервер", "renderer.components.removeServerModal.confirm": "Ви дійсно хочете прибрати цей {serverName} сервер?", "renderer.components.removeServerModal.body": "Це прибере сервер із вашого десктопного додатку, але не видалить його даних – ви можете повернути сервер до застосунку у будь–який час.", - "renderer.components.newTeamModal.title.edit": "Редагувати сервер", - "renderer.components.newTeamModal.title.add": "Додати сервер", - "renderer.components.newTeamModal.serverURL.description": "Посилання URL на сервер Mattermost повинно починатись із with http:// or https://.", - "renderer.components.newTeamModal.serverURL": "Посилання URL", - "renderer.components.newTeamModal.serverDisplayName.description": "Ім'я серверу відображатиметься на панелі вкладок у десктопному додатку.", - "renderer.components.newTeamModal.serverDisplayName": "Ім'я серверу, що відображатиметься", - "renderer.components.newTeamModal.error.urlRequired": "Необхідне посилання URL.", - "renderer.components.newTeamModal.error.urlNeedsHttp": "Посилання URL має починатись із http:// or https://.", - "renderer.components.newTeamModal.error.urlIncorrectFormatting": "Посилання URL має неправильний формат.", - "renderer.components.newTeamModal.error.serverUrlExists": "Сервер з таким посиланням URL вже існує.", - "renderer.components.newTeamModal.error.serverNameExists": "Сервер з таким ім'ям вже існує.", - "renderer.components.newTeamModal.error.nameRequired": "Необхідне ім'я.", + "renderer.components.newServerModal.title.edit": "Редагувати сервер", + "renderer.components.newServerModal.title.add": "Додати сервер", + "renderer.components.newServerModal.serverURL.description": "Посилання URL на сервер Mattermost повинно починатись із with http:// or https://.", + "renderer.components.newServerModal.serverURL": "Посилання URL", + "renderer.components.newServerModal.serverDisplayName.description": "Ім'я серверу відображатиметься на панелі вкладок у десктопному додатку.", + "renderer.components.newServerModal.serverDisplayName": "Ім'я серверу, що відображатиметься", + "renderer.components.newServerModal.error.urlRequired": "Необхідне посилання URL.", + "renderer.components.newServerModal.error.urlNeedsHttp": "Посилання URL має починатись із http:// or https://.", + "renderer.components.newServerModal.error.urlIncorrectFormatting": "Посилання URL має неправильний формат.", + "renderer.components.newServerModal.error.serverUrlExists": "Сервер з таким посиланням URL вже існує.", + "renderer.components.newServerModal.error.serverNameExists": "Сервер з таким ім'ям вже існує.", + "renderer.components.newServerModal.error.nameRequired": "Необхідне ім'я.", "renderer.components.mainPage.titleBar": "Mattermost", "renderer.components.mainPage.contextMenu.ariaLabel": "Контекстне меню", "renderer.components.input.required": "Це поле є обов'язковим", @@ -180,7 +180,7 @@ "common.tabs.TAB_FOCALBOARD": "Дошки", "renderer.components.welcomeScreen.slides.boards.title": "Дошки", "renderer.components.welcomeScreen.button.getStarted": "Розпочнемо", - "renderer.components.teamDropdownButton.noServersConfigured": "Немає налаштованих серверів", + "renderer.components.serverDropdownButton.noServersConfigured": "Немає налаштованих серверів", "renderer.components.showCertificateModal.serialNumber": "Серійний номер", "renderer.components.showCertificateModal.notValidBefore": "Недійсний до", "renderer.components.showCertificateModal.notValidAfter": "Недійсний після", diff --git a/i18n/zh-CN.json b/i18n/zh-CN.json index 11b97eaa..7386d7a8 100644 --- a/i18n/zh-CN.json +++ b/i18n/zh-CN.json @@ -170,7 +170,7 @@ "renderer.components.welcomeScreen.slides.boards.title": "公告板", "renderer.components.welcomeScreen.slides.boards.subtitle": "通过一个为数字运营而建立的项目和任务管理解决方案,每次都要按时交付。", "renderer.components.welcomeScreen.button.getStarted": "开始吧", - "renderer.components.teamDropdownButton.noServersConfigured": "没有配置服务器", + "renderer.components.serverDropdownButton.noServersConfigured": "没有配置服务器", "renderer.components.showCertificateModal.subjectName": "主题", "renderer.components.showCertificateModal.serialNumber": "序列号", "renderer.components.showCertificateModal.publicKeyInfo": "公钥信息", @@ -236,18 +236,18 @@ "renderer.components.removeServerModal.title": "移除服务器", "renderer.components.removeServerModal.confirm": "确认要删除{serverName}服务器?", "renderer.components.removeServerModal.body": "这将从您的桌面应用程序中删除服务器,但不会删除其任何数据-您可以随时将服务器添加回应用程序。", - "renderer.components.newTeamModal.title.edit": "编辑服务器", - "renderer.components.newTeamModal.title.add": "添加服务器", - "renderer.components.newTeamModal.serverURL.description": "您Mattermost服务器的URL。必须以http://或https://开头。", - "renderer.components.newTeamModal.serverURL": "服务器URL", - "renderer.components.newTeamModal.serverDisplayName.description": "显示在桌面应用程序选项卡上的服务器名称。", - "renderer.components.newTeamModal.serverDisplayName": "服务器显示的名称", - "renderer.components.newTeamModal.error.urlRequired": "URL是必填项。", - "renderer.components.newTeamModal.error.urlNeedsHttp": "URL应以http://或https://开头。", - "renderer.components.newTeamModal.error.urlIncorrectFormatting": "URL格式不正确。", - "renderer.components.newTeamModal.error.serverUrlExists": "已经存在具有相同URL的服务器。", - "renderer.components.newTeamModal.error.serverNameExists": "已经存在同名服务器。", - "renderer.components.newTeamModal.error.nameRequired": "需要填写姓名。", + "renderer.components.newServerModal.title.edit": "编辑服务器", + "renderer.components.newServerModal.title.add": "添加服务器", + "renderer.components.newServerModal.serverURL.description": "您Mattermost服务器的URL。必须以http://或https://开头。", + "renderer.components.newServerModal.serverURL": "服务器URL", + "renderer.components.newServerModal.serverDisplayName.description": "显示在桌面应用程序选项卡上的服务器名称。", + "renderer.components.newServerModal.serverDisplayName": "服务器显示的名称", + "renderer.components.newServerModal.error.urlRequired": "URL是必填项。", + "renderer.components.newServerModal.error.urlNeedsHttp": "URL应以http://或https://开头。", + "renderer.components.newServerModal.error.urlIncorrectFormatting": "URL格式不正确。", + "renderer.components.newServerModal.error.serverUrlExists": "已经存在具有相同URL的服务器。", + "renderer.components.newServerModal.error.serverNameExists": "已经存在同名服务器。", + "renderer.components.newServerModal.error.nameRequired": "需要填写姓名。", "renderer.components.mainPage.contextMenu.ariaLabel": "快捷菜单", "renderer.components.input.required": "此栏为必填项", "renderer.components.extraBar.back": "返回", diff --git a/resources/windows/gpo/README.md b/resources/windows/gpo/README.md index 6be7d6c0..39daf59d 100644 --- a/resources/windows/gpo/README.md +++ b/resources/windows/gpo/README.md @@ -1,6 +1,6 @@ # Developer guide for using Group Policy Objects (GPO) (Windows 10 Pro) -GPOs are used to pre-configure servers/teams, autoUpdater and server management +GPOs are used to pre-configure servers, autoUpdater and server management You can read more about GPOs [here](https://learn.microsoft.com/en-us/previous-versions/windows/desktop/policy/group-policy-objects) @@ -18,7 +18,7 @@ Example: | Value Name | Value | |------------|----------------------------------| | Community | | -8. Now if you open your Mattermost desktop application you should be able to see the server in the server dropdown (team dropdown) +8. Now if you open your Mattermost desktop application you should be able to see the server in the server dropdown --- diff --git a/scripts/check_build_config.js b/scripts/check_build_config.js index 1aff77ef..f5838eaa 100644 --- a/scripts/check_build_config.js +++ b/scripts/check_build_config.js @@ -4,10 +4,10 @@ const buildConfig = require('../dist/buildConfig'); function validateBuildConfig(config) { - if (config.enableServerManagement === false && config.defaultTeams && config.defaultTeams.length === 0) { + if (config.enableServerManagement === false && config.defaultServers && config.defaultServers.length === 0) { return { result: false, - message: `Specify at least one server for "defaultTeams" in buildConfig.js when "enableServerManagement is set to false.\n${JSON.stringify(config, null, 2)}`, + message: `Specify at least one server for "defaultServers" in buildConfig.js when "enableServerManagement is set to false.\n${JSON.stringify(config, null, 2)}`, }; } return {result: true}; diff --git a/src/assets/linux/README.md b/src/assets/linux/README.md index 2b5aed76..f4e65788 100644 --- a/src/assets/linux/README.md +++ b/src/assets/linux/README.md @@ -48,10 +48,10 @@ You're now all set! See the [User Guide](#user-guide) below for instructions. ## User Guide -After launching, you need to configure the application to interact with your team. +After launching, you need to configure the application to interact with your server. 1. If you don't see a page titled "Settings", select **File** > **Settings...** from the menu bar. -2. Click **Add new team** next to the right of Team Management section. +2. Click **Add new server** next to the right of Server Management section. 3. Enter **Name** and a valid **URL**, which begins with either `http://` or `https://`. 4. Click **Add**. 5. Click **Save**. diff --git a/src/common/Validator.test.js b/src/common/Validator.test.js index 40c06934..26a368a9 100644 --- a/src/common/Validator.test.js +++ b/src/common/Validator.test.js @@ -153,7 +153,7 @@ describe('common/Validator', () => { version: 3, }; - it('should ensure messaging tab is open', () => { + it('should ensure messaging view is open', () => { const modifiedConfig = { ...config, teams: [ diff --git a/src/common/Validator.ts b/src/common/Validator.ts index 649aa60f..385cfd7e 100644 --- a/src/common/Validator.ts +++ b/src/common/Validator.ts @@ -12,7 +12,7 @@ import {ComparableCertificate} from 'types/certificate'; import {PermissionType, TrustedOrigin} from 'types/trustedOrigin'; import {Logger} from 'common/log'; -import {TAB_MESSAGING} from 'common/tabs/TabView'; +import {TAB_MESSAGING} from 'common/views/View'; import {isValidURL} from 'common/utils/url'; const log = new Logger('Validator'); @@ -206,45 +206,45 @@ function cleanURL(url: string): string { return updatedURL; } -function cleanTeam(team: T) { +function cleanServer(server: T) { return { - ...team, - url: cleanURL(team.url), + ...server, + url: cleanURL(server.url), }; } -function cleanTeamWithTabs(team: ConfigServer) { +function cleanServerWithViews(server: ConfigServer) { return { - ...cleanTeam(team), - tabs: team.tabs.map((tab) => { + ...cleanServer(server), + tabs: server.tabs.map((view) => { return { - ...tab, - isOpen: tab.name === TAB_MESSAGING ? true : tab.isOpen, + ...view, + isOpen: view.name === TAB_MESSAGING ? true : view.isOpen, }; }), }; } -function cleanTeams(teams: T[], func: (team: T) => T) { - let newTeams = teams; - if (Array.isArray(newTeams) && newTeams.length) { +function cleanServers(servers: T[], func: (server: T) => T) { + let newServers = servers; + if (Array.isArray(newServers) && newServers.length) { // first replace possible backslashes with forward slashes - newTeams = newTeams.map((team) => func(team)); + newServers = newServers.map((server) => func(server)); // next filter out urls that are still invalid so all is not lost - newTeams = newTeams.filter(({url}) => isValidURL(url)); + newServers = newServers.filter(({url}) => isValidURL(url)); } - return newTeams; + return newServers; } // validate v.1 config.json export function validateV1ConfigData(data: ConfigV1) { - data.teams = cleanTeams(data.teams, cleanTeam); + data.teams = cleanServers(data.teams, cleanServer); return validateAgainstSchema(data, configDataSchemaV1); } export function validateV2ConfigData(data: ConfigV2) { - data.teams = cleanTeams(data.teams, cleanTeam); + data.teams = cleanServers(data.teams, cleanServer); if (data.spellCheckerURL && !isValidURL(data.spellCheckerURL)) { log.error('Invalid download location for spellchecker dictionary, removing from config'); delete data.spellCheckerURL; @@ -253,7 +253,7 @@ export function validateV2ConfigData(data: ConfigV2) { } export function validateV3ConfigData(data: ConfigV3) { - data.teams = cleanTeams(data.teams, cleanTeamWithTabs); + data.teams = cleanServers(data.teams, cleanServerWithViews); if (data.spellCheckerURL && !isValidURL(data.spellCheckerURL)) { log.error('Invalid download location for spellchecker dictionary, removing from config'); delete data.spellCheckerURL; diff --git a/src/common/communication.ts b/src/common/communication.ts index aeeff20c..abdcf81a 100644 --- a/src/common/communication.ts +++ b/src/common/communication.ts @@ -3,8 +3,8 @@ export const SWITCH_SERVER = 'switch-server'; export const SWITCH_TAB = 'switch-tab'; -export const CLOSE_TAB = 'close-tab'; -export const OPEN_TAB = 'open-tab'; +export const CLOSE_VIEW = 'close-view'; +export const OPEN_VIEW = 'open-view'; export const SET_ACTIVE_VIEW = 'set-active-view'; export const FOCUS_BROWSERVIEW = 'focus-browserview'; export const HISTORY = 'history'; @@ -76,10 +76,10 @@ export const FOCUS_THREE_DOT_MENU = 'focus-three-dot-menu'; export const LOADSCREEN_END = 'loadscreen-end'; -export const OPEN_TEAMS_DROPDOWN = 'open-teams-dropdown'; -export const CLOSE_TEAMS_DROPDOWN = 'close-teams-dropdown'; -export const UPDATE_TEAMS_DROPDOWN = 'update-teams-dropdown'; -export const REQUEST_TEAMS_DROPDOWN_INFO = 'request-teams-dropdown-info'; +export const OPEN_SERVERS_DROPDOWN = 'open-servers-dropdown'; +export const CLOSE_SERVERS_DROPDOWN = 'close-servers-dropdown'; +export const UPDATE_SERVERS_DROPDOWN = 'update-servers-dropdown'; +export const REQUEST_SERVERS_DROPDOWN_INFO = 'request-servers-dropdown-info'; export const RECEIVE_DROPDOWN_MENU_SIZE = 'receive-dropdown-menu-size'; export const UPDATE_AVAILABLE = 'update-available'; diff --git a/src/common/config/RegistryConfig.test.js b/src/common/config/RegistryConfig.test.js index 382cb753..89f8cfca 100644 --- a/src/common/config/RegistryConfig.test.js +++ b/src/common/config/RegistryConfig.test.js @@ -64,7 +64,7 @@ describe('common/config/RegistryConfig', () => { Object.defineProperty(process, 'platform', { value: originalPlatform, }); - expect(registryConfig.data.teams).toContainEqual({ + expect(registryConfig.data.servers).toContainEqual({ name: 'server-1', url: 'http://server-1.com', }); diff --git a/src/common/config/RegistryConfig.ts b/src/common/config/RegistryConfig.ts index 65ce5436..248cc895 100644 --- a/src/common/config/RegistryConfig.ts +++ b/src/common/config/RegistryConfig.ts @@ -6,7 +6,7 @@ import {EventEmitter} from 'events'; import WindowsRegistry from 'winreg'; import WindowsRegistryUTF8 from 'winreg-utf8'; -import {RegistryConfig as RegistryConfigType, Team} from 'types/config'; +import {RegistryConfig as RegistryConfigType, Server} from 'types/config'; import {Logger} from 'common/log'; @@ -26,7 +26,7 @@ export default class RegistryConfig extends EventEmitter { super(); this.initialized = false; this.data = { - teams: [], + servers: [], }; } @@ -41,7 +41,7 @@ export default class RegistryConfig extends EventEmitter { try { const servers = await this.getServersListFromRegistry(); if (servers.length) { - this.data.teams!.push(...servers); + this.data.servers!.push(...servers); } } catch (error) { log.warn('Nothing retrieved for \'DefaultServerList\'', error); @@ -78,7 +78,7 @@ export default class RegistryConfig extends EventEmitter { */ async getServersListFromRegistry() { const defaultServers = await this.getRegistryEntry(`${BASE_REGISTRY_KEY_PATH}\\DefaultServerList`); - return defaultServers.flat(2).reduce((servers: Team[], server) => { + return defaultServers.flat(2).reduce((servers: Server[], server) => { if (server) { servers.push({ name: (server as WindowsRegistry.RegistryItem).name, diff --git a/src/common/config/buildConfig.ts b/src/common/config/buildConfig.ts index e6fc3204..d0a34e91 100644 --- a/src/common/config/buildConfig.ts +++ b/src/common/config/buildConfig.ts @@ -8,20 +8,20 @@ import {BuildConfig} from 'types/config'; /** * Build-time configuration. End-users can't change these parameters. - * @prop {Object[]} defaultTeams - * @prop {string} defaultTeams[].name - The tab name for default team. - * @prop {string} defaultTeams[].url - The URL for default team. - * @prop {string} defaultTeams[].order - Sort order for team tabs (0, 1, 2) + * @prop {Object[]} defaultServers + * @prop {string} defaultServers[].name - The view name for default server. + * @prop {string} defaultServers[].url - The URL for default server. + * @prop {string} defaultServers[].order - Sort order for server views (0, 1, 2) * @prop {string} helpLink - The URL for "Help->Learn More..." menu item. * If null is specified, the menu disappears. * @prop {boolean} enableServerManagement - Whether users can edit servers configuration. - * Specify at least one server for "defaultTeams" + * Specify at least one server for "defaultServers" * when "enableServerManagement is set to false * @prop {[]} managedResources - Defines which paths are managed * @prop {[]} allowedProtocols - Defines which protocols should be automatically allowed */ const buildConfig: BuildConfig = { - defaultTeams: [/* + defaultServers: [/* { name: 'example', url: 'https://example.com' diff --git a/src/common/config/index.test.js b/src/common/config/index.test.js index 15a583d6..7f106682 100644 --- a/src/common/config/index.test.js +++ b/src/common/config/index.test.js @@ -24,54 +24,54 @@ jest.mock('common/Validator', () => ({ validateConfigData: (configData) => (configData.version === 3 ? configData : null), })); -jest.mock('common/tabs/TabView', () => ({ - getDefaultConfigTeamFromTeam: (value) => ({ +jest.mock('common/views/View', () => ({ + getDefaultViewsForConfigServer: (value) => ({ ...value, tabs: [ { - name: 'tab1', + name: 'view1', }, { - name: 'tab2', + name: 'view2', }, ], }), })); -const buildTeam = { - name: 'build-team-1', +const buildServer = { + name: 'build-server-1', order: 0, - url: 'http://build-team-1.com', + url: 'http://build-server-1.com', }; -const buildTeamWithTabs = { - ...buildTeam, +const buildServerWithViews = { + ...buildServer, tabs: [ { - name: 'tab1', + name: 'view1', }, { - name: 'tab2', + name: 'view2', }, ], }; -const registryTeam = { - name: 'registry-team-1', +const registryServer = { + name: 'registry-server-1', order: 0, - url: 'http://registry-team-1.com', + url: 'http://registry-server-1.com', }; -const team = { - name: 'team-1', +const server = { + name: 'server-1', order: 0, - url: 'http://team-1.com', + url: 'http://server-1.com', tabs: [ { - name: 'tab1', + name: 'view1', }, { - name: 'tab2', + name: 'view2', }, ], }; @@ -86,7 +86,7 @@ jest.mock('common/config/migrationPreferences', () => jest.fn()); jest.mock('common/config/buildConfig', () => { return { - defaultTeams: [buildTeam], + defaultServers: [buildServer], }; }); @@ -99,7 +99,7 @@ describe('common/config', () => { const config = new Config(); config.reload = jest.fn(); config.init(configPath, appName, appPath); - expect(config.predefinedTeams).toContainEqual(buildTeamWithTabs); + expect(config.predefinedServers).toContainEqual(buildServerWithViews); }); describe('loadRegistry', () => { @@ -107,16 +107,16 @@ describe('common/config', () => { const config = new Config(); config.reload = jest.fn(); config.init(configPath, appName, appPath); - config.onLoadRegistry({teams: [registryTeam]}); + config.onLoadRegistry({servers: [registryServer]}); expect(config.reload).toHaveBeenCalled(); - expect(config.predefinedTeams).toContainEqual({ - ...registryTeam, + expect(config.predefinedServers).toContainEqual({ + ...registryServer, tabs: [ { - name: 'tab1', + name: 'view1', }, { - name: 'tab2', + name: 'view2', }, ], }); @@ -159,19 +159,19 @@ describe('common/config', () => { expect(config.saveLocalConfigData).toHaveBeenCalled(); }); - it('should not allow teams to be set using this method', () => { + it('should not allow servers to be set using this method', () => { const config = new Config(); config.reload = jest.fn(); config.init(configPath, appName, appPath); - config.localConfigData = {teams: [team]}; + config.localConfigData = {teams: [server]}; config.regenerateCombinedConfigData = jest.fn().mockImplementation(() => { config.combinedData = {...config.localConfigData}; }); config.saveLocalConfigData = jest.fn(); - config.set('teams', [{...buildTeamWithTabs, name: 'build-team-2'}]); - expect(config.localConfigData.teams).not.toContainEqual({...buildTeamWithTabs, name: 'build-team-2'}); - expect(config.localConfigData.teams).toContainEqual(team); + config.set('teams', [{...buildServerWithViews, name: 'build-team-2'}]); + expect(config.localConfigData.teams).not.toContainEqual({...buildServerWithViews, name: 'build-team-2'}); + expect(config.localConfigData.teams).toContainEqual(server); }); }); @@ -186,8 +186,8 @@ describe('common/config', () => { }); config.saveLocalConfigData = jest.fn(); - config.setServers([{...buildTeamWithTabs, name: 'build-team-2'}, team], 0); - expect(config.localConfigData.teams).toContainEqual({...buildTeamWithTabs, name: 'build-team-2'}); + config.setServers([{...buildServerWithViews, name: 'build-server-2'}, server], 0); + expect(config.localConfigData.teams).toContainEqual({...buildServerWithViews, name: 'build-server-2'}); expect(config.localConfigData.lastActiveTeam).toBe(0); expect(config.regenerateCombinedConfigData).toHaveBeenCalled(); expect(config.saveLocalConfigData).toHaveBeenCalled(); @@ -341,7 +341,7 @@ describe('common/config', () => { }); }); - it('should not include any teams in the combined config', () => { + it('should not include any servers in the combined config', () => { const config = new Config(); config.reload = jest.fn(); config.init(configPath, appName, appPath); @@ -349,20 +349,20 @@ describe('common/config', () => { config.localConfigData = {}; config.buildConfigData = {enableServerManagement: true}; config.registryConfigData = {}; - config.predefinedTeams.push(team, team); + config.predefinedServers.push(server, server); config.useNativeWindow = false; config.localConfigData = {teams: [ - team, + server, { - ...team, - name: 'local-team-2', - url: 'http://local-team-2.com', + ...server, + name: 'local-server-2', + url: 'http://local-server-2.com', }, { - ...team, - name: 'local-team-1', + ...server, + name: 'local-server-1', order: 1, - url: 'http://local-team-1.com', + url: 'http://local-server-1.com', }, ]}; diff --git a/src/common/config/index.ts b/src/common/config/index.ts index a0ff1f67..b2208495 100644 --- a/src/common/config/index.ts +++ b/src/common/config/index.ts @@ -18,7 +18,7 @@ import { } from 'types/config'; import {Logger} from 'common/log'; -import {getDefaultConfigTeamFromTeam} from 'common/tabs/TabView'; +import {getDefaultViewsForConfigServer} from 'common/views/View'; import Utils, {copy} from 'common/utils/util'; import * as Validator from 'common/Validator'; @@ -36,7 +36,7 @@ export class Config extends EventEmitter { private appPath?: string; private registryConfig: RegistryConfig; - private predefinedServers: ConfigServer[]; + private _predefinedServers: ConfigServer[]; private useNativeWindow: boolean; private combinedData?: CombinedConfig; @@ -49,9 +49,9 @@ export class Config extends EventEmitter { constructor() { super(); this.registryConfig = new RegistryConfig(); - this.predefinedServers = []; - if (buildConfig.defaultTeams) { - this.predefinedServers.push(...buildConfig.defaultTeams.map((team, index) => getDefaultConfigTeamFromTeam({...team, order: index}))); + this._predefinedServers = []; + if (buildConfig.defaultServers) { + this._predefinedServers.push(...buildConfig.defaultServers.map((server, index) => getDefaultViewsForConfigServer({...server, order: index}))); } try { this.useNativeWindow = os.platform() === 'win32' && !Utils.isVersionGreaterThanOrEqualTo(os.release(), '6.2'); @@ -138,10 +138,10 @@ export class Config extends EventEmitter { this.saveLocalConfigData(); } - setServers = (servers: ConfigServer[], lastActiveTeam?: number) => { - log.debug('setServers', servers, lastActiveTeam); + setServers = (servers: ConfigServer[], lastActiveServer?: number) => { + log.debug('setServers', servers, lastActiveServer); - this.localConfigData = Object.assign({}, this.localConfigData, {teams: servers, lastActiveTeam: lastActiveTeam ?? this.localConfigData?.lastActiveTeam}); + this.localConfigData = Object.assign({}, this.localConfigData, {teams: servers, lastActiveTeam: lastActiveServer ?? this.localConfigData?.lastActiveTeam}); this.regenerateCombinedConfigData(); this.saveLocalConfigData(); } @@ -172,11 +172,11 @@ export class Config extends EventEmitter { get darkMode() { return this.combinedData?.darkMode ?? defaultPreferences.darkMode; } - get localTeams() { + get localServers() { return this.localConfigData?.teams ?? defaultPreferences.teams; } - get predefinedTeams() { - return this.predefinedServers; + get predefinedServers() { + return this._predefinedServers; } get enableHardwareAcceleration() { return this.combinedData?.enableHardwareAcceleration ?? defaultPreferences.enableHardwareAcceleration; @@ -229,7 +229,7 @@ export class Config extends EventEmitter { get minimizeToTray() { return this.combinedData?.minimizeToTray; } - get lastActiveTeam() { + get lastActiveServer() { return this.combinedData?.lastActiveTeam; } get alwaysClose() { @@ -252,17 +252,17 @@ export class Config extends EventEmitter { } /** - * Gets the teams from registry into the config object and reload + * Gets the servers from registry into the config object and reload * - * @param {object} registryData Team configuration from the registry and if teams can be managed by user + * @param {object} registryData Server configuration from the registry and if servers can be managed by user */ private onLoadRegistry = (registryData: Partial): void => { log.debug('loadRegistry', {registryData}); this.registryConfigData = registryData; - if (this.registryConfigData.teams) { - this.predefinedTeams.push(...this.registryConfigData.teams.map((team, index) => getDefaultConfigTeamFromTeam({...team, order: index}))); + if (this.registryConfigData.servers) { + this._predefinedServers.push(...this.registryConfigData.servers.map((server, index) => getDefaultViewsForConfigServer({...server, order: index}))); } this.reload(); } @@ -378,7 +378,8 @@ export class Config extends EventEmitter { // We don't want to include the servers in the combined config, they should only be accesible via the ServerManager delete (this.combinedData as any).teams; - delete (this.combinedData as any).defaultTeams; + delete (this.combinedData as any).servers; + delete (this.combinedData as any).defaultServers; if (this.combinedData) { this.combinedData.appName = this.appName; diff --git a/src/common/config/upgradePreferences.test.js b/src/common/config/upgradePreferences.test.js index e1cdc786..1dd3998b 100644 --- a/src/common/config/upgradePreferences.test.js +++ b/src/common/config/upgradePreferences.test.js @@ -4,15 +4,15 @@ import {upgradeV0toV1, upgradeV1toV2, upgradeV2toV3} from 'common/config/upgradePreferences'; import pastDefaultPreferences from 'common/config/pastDefaultPreferences'; -jest.mock('common/tabs/TabView', () => ({ - getDefaultConfigTeamFromTeam: (value) => ({ +jest.mock('common/views/View', () => ({ + getDefaultViewsForConfigServer: (value) => ({ ...value, tabs: [ { - name: 'tab1', + name: 'view1', }, { - name: 'tab2', + name: 'view2', }, ], }), @@ -27,7 +27,7 @@ describe('common/config/upgradePreferences', () => { version: 1, teams: [ { - name: 'Primary team', + name: 'Primary server', url: config.url, }, ], @@ -39,10 +39,10 @@ describe('common/config/upgradePreferences', () => { const config = { version: 1, teams: [{ - name: 'Primary team', + name: 'Primary server', url: 'http://server-1.com', }, { - name: 'Secondary team', + name: 'Secondary server', url: 'http://server-2.com', }], showTrayIcon: true, @@ -64,11 +64,11 @@ describe('common/config/upgradePreferences', () => { ...config, version: 2, teams: [{ - name: 'Primary team', + name: 'Primary server', url: 'http://server-1.com', order: 0, }, { - name: 'Secondary team', + name: 'Secondary server', url: 'http://server-2.com', order: 1, }], @@ -80,11 +80,11 @@ describe('common/config/upgradePreferences', () => { const config = { version: 2, teams: [{ - name: 'Primary team', + name: 'Primary server', url: 'http://server-1.com', order: 0, }, { - name: 'Secondary team', + name: 'Secondary server', url: 'http://server-2.com', order: 1, }], @@ -111,27 +111,27 @@ describe('common/config/upgradePreferences', () => { ...config, version: 3, teams: [{ - name: 'Primary team', + name: 'Primary server', url: 'http://server-1.com', order: 0, tabs: [ { - name: 'tab1', + name: 'view1', }, { - name: 'tab2', + name: 'view2', }, ], }, { - name: 'Secondary team', + name: 'Secondary server', url: 'http://server-2.com', order: 1, tabs: [ { - name: 'tab1', + name: 'view1', }, { - name: 'tab2', + name: 'view2', }, ], }], diff --git a/src/common/config/upgradePreferences.ts b/src/common/config/upgradePreferences.ts index 860f8a27..14bc2d08 100644 --- a/src/common/config/upgradePreferences.ts +++ b/src/common/config/upgradePreferences.ts @@ -4,7 +4,7 @@ import {ConfigV3, ConfigV2, ConfigV1, ConfigV0, AnyConfig} from 'types/config'; -import {getDefaultConfigTeamFromTeam} from 'common/tabs/TabView'; +import {getDefaultViewsForConfigServer} from 'common/views/View'; import pastDefaultPreferences from './pastDefaultPreferences'; @@ -15,7 +15,7 @@ function deepCopy(object: T): T { export function upgradeV0toV1(configV0: ConfigV0) { const config = deepCopy(pastDefaultPreferences[1]); config.teams.push({ - name: 'Primary team', + name: 'Primary server', url: configV0.url, }); return config; @@ -37,7 +37,7 @@ export function upgradeV2toV3(configV2: ConfigV2) { const config: ConfigV3 = Object.assign({}, deepCopy(pastDefaultPreferences[3]), configV2); config.version = 3; config.teams = configV2.teams.map((value) => { - return getDefaultConfigTeamFromTeam(value); + return getDefaultViewsForConfigServer(value); }); config.lastActiveTeam = 0; config.spellCheckerLocales = []; diff --git a/src/common/servers/MattermostServer.ts b/src/common/servers/MattermostServer.ts index 1ed72d19..63a15379 100644 --- a/src/common/servers/MattermostServer.ts +++ b/src/common/servers/MattermostServer.ts @@ -3,7 +3,7 @@ import {v4 as uuid} from 'uuid'; -import {MattermostTeam, Team} from 'types/config'; +import {UniqueServer, Server} from 'types/config'; import {parseURL} from 'common/utils/url'; @@ -13,7 +13,7 @@ export class MattermostServer { url!: URL; isPredefined: boolean; - constructor(server: Team, isPredefined: boolean) { + constructor(server: Server, isPredefined: boolean) { this.id = uuid(); this.name = server.name; @@ -29,7 +29,7 @@ export class MattermostServer { } } - toMattermostTeam = (): MattermostTeam => { + toUniqueServer = (): UniqueServer => { return { name: this.name, url: this.url.toString(), diff --git a/src/common/servers/serverManager.test.js b/src/common/servers/serverManager.test.js index f980243b..5d5d6e79 100644 --- a/src/common/servers/serverManager.test.js +++ b/src/common/servers/serverManager.test.js @@ -1,7 +1,7 @@ // Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {TAB_MESSAGING, TAB_FOCALBOARD, TAB_PLAYBOOKS} from 'common/tabs/TabView'; +import {TAB_MESSAGING, TAB_FOCALBOARD, TAB_PLAYBOOKS} from 'common/views/View'; import {parseURL, isInternalURL} from 'common/utils/url'; import Utils from 'common/utils/util'; @@ -31,12 +31,12 @@ describe('common/servers/serverManager', () => { server.url = new URL(url); }; serverManager.servers = new Map([['server-1', server]]); - serverManager.tabs = new Map([ - ['tab-1', {id: 'tab-1', type: TAB_MESSAGING, isOpen: true, server}], - ['tab-2', {id: 'tab-2', type: TAB_PLAYBOOKS, server}], - ['tab-3', {id: 'tab-3', type: TAB_FOCALBOARD, server}], + serverManager.views = new Map([ + ['view-1', {id: 'view-1', type: TAB_MESSAGING, isOpen: true, server}], + ['view-2', {id: 'view-2', type: TAB_PLAYBOOKS, server}], + ['view-3', {id: 'view-3', type: TAB_FOCALBOARD, server}], ]); - serverManager.tabOrder = new Map([['server-1', ['tab-1', 'tab-2', 'tab-3']]]); + serverManager.viewOrder = new Map([['server-1', ['view-1', 'view-2', 'view-3']]]); serverManager.persistServers = jest.fn(); Utils.isVersionGreaterThanOrEqualTo.mockImplementation((version) => version === '6.0.0'); }); @@ -52,7 +52,7 @@ describe('common/servers/serverManager', () => { expect(serverManager.persistServers).not.toHaveBeenCalled(); }); - it('should open all tabs', async () => { + it('should open all views', async () => { serverManager.updateRemoteInfos(new Map([['server-1', { siteURL: 'http://server-1.com', serverVersion: '6.0.0', @@ -60,8 +60,8 @@ describe('common/servers/serverManager', () => { hasFocalboard: true, }]])); - expect(serverManager.tabs.get('tab-2').isOpen).toBe(true); - expect(serverManager.tabs.get('tab-3').isOpen).toBe(true); + expect(serverManager.views.get('view-2').isOpen).toBe(true); + expect(serverManager.views.get('view-3').isOpen).toBe(true); }); it('should open only playbooks', async () => { @@ -72,8 +72,8 @@ describe('common/servers/serverManager', () => { hasFocalboard: false, }]])); - expect(serverManager.tabs.get('tab-2').isOpen).toBe(true); - expect(serverManager.tabs.get('tab-3').isOpen).toBeUndefined(); + expect(serverManager.views.get('view-2').isOpen).toBe(true); + expect(serverManager.views.get('view-3').isOpen).toBeUndefined(); }); it('should open none when server version is too old', async () => { @@ -84,8 +84,8 @@ describe('common/servers/serverManager', () => { hasFocalboard: true, }]])); - expect(serverManager.tabs.get('tab-2').isOpen).toBeUndefined(); - expect(serverManager.tabs.get('tab-3').isOpen).toBeUndefined(); + expect(serverManager.views.get('view-2').isOpen).toBeUndefined(); + expect(serverManager.views.get('view-3').isOpen).toBeUndefined(); }); it('should update server URL using site URL', async () => { @@ -100,7 +100,7 @@ describe('common/servers/serverManager', () => { }); }); - describe('lookupTabByURL', () => { + describe('lookupViewByURL', () => { const serverManager = new ServerManager(); serverManager.getAllServers = () => [ {id: 'server-1', url: new URL('http://server-1.com')}, @@ -109,16 +109,16 @@ describe('common/servers/serverManager', () => { serverManager.getOrderedTabsForServer = (serverId) => { if (serverId === 'server-1') { return [ - {id: 'tab-1', url: new URL('http://server-1.com')}, - {id: 'tab-1-type-1', url: new URL('http://server-1.com/type1')}, - {id: 'tab-1-type-2', url: new URL('http://server-1.com/type2')}, + {id: 'view-1', url: new URL('http://server-1.com')}, + {id: 'view-1-type-1', url: new URL('http://server-1.com/type1')}, + {id: 'view-1-type-2', url: new URL('http://server-1.com/type2')}, ]; } if (serverId === 'server-2') { return [ - {id: 'tab-2', url: new URL('http://server-2.com/subpath')}, - {id: 'tab-2-type-1', url: new URL('http://server-2.com/subpath/type1')}, - {id: 'tab-2-type-2', url: new URL('http://server-2.com/subpath/type2')}, + {id: 'view-2', url: new URL('http://server-2.com/subpath')}, + {id: 'view-2-type-1', url: new URL('http://server-2.com/subpath/type1')}, + {id: 'view-2-type-2', url: new URL('http://server-2.com/subpath/type2')}, ]; } return []; @@ -135,47 +135,47 @@ describe('common/servers/serverManager', () => { it('should match the correct server - base URL', () => { const inputURL = new URL('http://server-1.com'); - expect(serverManager.lookupTabByURL(inputURL)).toStrictEqual({id: 'tab-1', url: new URL('http://server-1.com')}); + expect(serverManager.lookupViewByURL(inputURL)).toStrictEqual({id: 'view-1', url: new URL('http://server-1.com')}); }); - it('should match the correct server - base tab', () => { - const inputURL = new URL('http://server-1.com/team'); - expect(serverManager.lookupTabByURL(inputURL)).toStrictEqual({id: 'tab-1', url: new URL('http://server-1.com')}); + it('should match the correct server - base view', () => { + const inputURL = new URL('http://server-1.com/server'); + expect(serverManager.lookupViewByURL(inputURL)).toStrictEqual({id: 'view-1', url: new URL('http://server-1.com')}); }); - it('should match the correct server - different tab', () => { + it('should match the correct server - different view', () => { const inputURL = new URL('http://server-1.com/type1/app'); - expect(serverManager.lookupTabByURL(inputURL)).toStrictEqual({id: 'tab-1-type-1', url: new URL('http://server-1.com/type1')}); + expect(serverManager.lookupViewByURL(inputURL)).toStrictEqual({id: 'view-1-type-1', url: new URL('http://server-1.com/type1')}); }); it('should return undefined for server with subpath and URL without', () => { const inputURL = new URL('http://server-2.com'); - expect(serverManager.lookupTabByURL(inputURL)).toBe(undefined); + expect(serverManager.lookupViewByURL(inputURL)).toBe(undefined); }); it('should return undefined for server with subpath and URL with wrong subpath', () => { const inputURL = new URL('http://server-2.com/different/subpath'); - expect(serverManager.lookupTabByURL(inputURL)).toBe(undefined); + expect(serverManager.lookupViewByURL(inputURL)).toBe(undefined); }); it('should match the correct server with a subpath - base URL', () => { const inputURL = new URL('http://server-2.com/subpath'); - expect(serverManager.lookupTabByURL(inputURL)).toStrictEqual({id: 'tab-2', url: new URL('http://server-2.com/subpath')}); + expect(serverManager.lookupViewByURL(inputURL)).toStrictEqual({id: 'view-2', url: new URL('http://server-2.com/subpath')}); }); - it('should match the correct server with a subpath - base tab', () => { - const inputURL = new URL('http://server-2.com/subpath/team'); - expect(serverManager.lookupTabByURL(inputURL)).toStrictEqual({id: 'tab-2', url: new URL('http://server-2.com/subpath')}); + it('should match the correct server with a subpath - base view', () => { + const inputURL = new URL('http://server-2.com/subpath/server'); + expect(serverManager.lookupViewByURL(inputURL)).toStrictEqual({id: 'view-2', url: new URL('http://server-2.com/subpath')}); }); - it('should match the correct server with a subpath - different tab', () => { - const inputURL = new URL('http://server-2.com/subpath/type2/team'); - expect(serverManager.lookupTabByURL(inputURL)).toStrictEqual({id: 'tab-2-type-2', url: new URL('http://server-2.com/subpath/type2')}); + it('should match the correct server with a subpath - different view', () => { + const inputURL = new URL('http://server-2.com/subpath/type2/server'); + expect(serverManager.lookupViewByURL(inputURL)).toStrictEqual({id: 'view-2-type-2', url: new URL('http://server-2.com/subpath/type2')}); }); it('should return undefined for wrong server', () => { const inputURL = new URL('http://server-3.com'); - expect(serverManager.lookupTabByURL(inputURL)).toBe(undefined); + expect(serverManager.lookupViewByURL(inputURL)).toBe(undefined); }); }); }); diff --git a/src/common/servers/serverManager.ts b/src/common/servers/serverManager.ts index 146550a1..ae323372 100644 --- a/src/common/servers/serverManager.ts +++ b/src/common/servers/serverManager.ts @@ -3,7 +3,7 @@ import EventEmitter from 'events'; -import {Team, ConfigServer, ConfigTab} from 'types/config'; +import {Server, ConfigServer, ConfigView} from 'types/config'; import {RemoteInfo} from 'types/server'; import Config from 'common/config'; @@ -13,10 +13,10 @@ import { } from 'common/communication'; import {Logger, getLevel} from 'common/log'; import {MattermostServer} from 'common/servers/MattermostServer'; -import {TAB_FOCALBOARD, TAB_MESSAGING, TAB_PLAYBOOKS, TabView, getDefaultTabs} from 'common/tabs/TabView'; -import MessagingTabView from 'common/tabs/MessagingTabView'; -import FocalboardTabView from 'common/tabs/FocalboardTabView'; -import PlaybooksTabView from 'common/tabs/PlaybooksTabView'; +import {TAB_FOCALBOARD, TAB_MESSAGING, TAB_PLAYBOOKS, MattermostView, getDefaultViews} from 'common/views/View'; +import MessagingView from 'common/views/MessagingView'; +import FocalboardView from 'common/views/FocalboardView'; +import PlaybooksView from 'common/views/PlaybooksView'; import {isInternalURL, parseURL} from 'common/utils/url'; import Utils from 'common/utils/util'; @@ -28,9 +28,9 @@ export class ServerManager extends EventEmitter { private serverOrder: string[]; private currentServerId?: string; - private tabs: Map; - private tabOrder: Map; - private lastActiveTab: Map; + private views: Map; + private viewOrder: Map; + private lastActiveView: Map; constructor() { super(); @@ -38,25 +38,25 @@ export class ServerManager extends EventEmitter { this.servers = new Map(); this.remoteInfo = new Map(); this.serverOrder = []; - this.tabs = new Map(); - this.tabOrder = new Map(); - this.lastActiveTab = new Map(); + this.views = new Map(); + this.viewOrder = new Map(); + this.lastActiveView = new Map(); } getOrderedTabsForServer = (serverId: string) => { log.withPrefix(serverId).debug('getOrderedTabsForServer'); - const tabOrder = this.tabOrder.get(serverId); - if (!tabOrder) { + const viewOrder = this.viewOrder.get(serverId); + if (!viewOrder) { return []; } - return tabOrder.reduce((tabs, tabId) => { - const tab = this.tabs.get(tabId); - if (tab) { - tabs.push(tab); + return viewOrder.reduce((views, viewId) => { + const view = this.views.get(viewId); + if (view) { + views.push(view); } - return tabs; - }, [] as TabView[]); + return views; + }, [] as MattermostView[]); } getOrderedServers = () => { @@ -87,22 +87,22 @@ export class ServerManager extends EventEmitter { getLastActiveTabForServer = (serverId: string) => { log.withPrefix(serverId).debug('getLastActiveTabForServer'); - const lastActiveTab = this.lastActiveTab.get(serverId); - if (lastActiveTab) { - const tab = this.tabs.get(lastActiveTab); - if (tab && tab?.isOpen) { - return tab; + const lastActiveView = this.lastActiveView.get(serverId); + if (lastActiveView) { + const view = this.views.get(lastActiveView); + if (view && view?.isOpen) { + return view; } } - return this.getFirstOpenTabForServer(serverId); + return this.getFirstOpenViewForServer(serverId); } getServer = (id: string) => { return this.servers.get(id); } - getTab = (id: string) => { - return this.tabs.get(id); + getView = (id: string) => { + return this.views.get(id); } getAllServers = () => { @@ -122,7 +122,7 @@ export class ServerManager extends EventEmitter { remoteInfos.forEach((remoteInfo, serverId) => { this.remoteInfo.set(serverId, remoteInfo); hasUpdates = this.updateServerURL(serverId) || hasUpdates; - hasUpdates = this.openExtraTabs(serverId) || hasUpdates; + hasUpdates = this.openExtraViews(serverId) || hasUpdates; }); if (hasUpdates) { @@ -130,8 +130,8 @@ export class ServerManager extends EventEmitter { } } - lookupTabByURL = (inputURL: URL | string, ignoreScheme = false) => { - log.silly('lookupTabByURL', `${inputURL}`, ignoreScheme); + lookupViewByURL = (inputURL: URL | string, ignoreScheme = false) => { + log.silly('lookupViewByURL', `${inputURL}`, ignoreScheme); const parsedURL = parseURL(inputURL); if (!parsedURL) { @@ -143,17 +143,17 @@ export class ServerManager extends EventEmitter { if (!server) { return undefined; } - const tabs = this.getOrderedTabsForServer(server.id); + const views = this.getOrderedTabsForServer(server.id); - let selectedTab = tabs.find((tab) => tab && tab.type === TAB_MESSAGING); - tabs. - filter((tab) => tab && tab.type !== TAB_MESSAGING). - forEach((tab) => { - if (parsedURL.pathname.match(new RegExp(`^${tab.url.pathname}(/(.+))?`))) { - selectedTab = tab; + let selectedView = views.find((view) => view && view.type === TAB_MESSAGING); + views. + filter((view) => view && view.type !== TAB_MESSAGING). + forEach((view) => { + if (parsedURL.pathname.match(new RegExp(`^${view.url.pathname}(/(.+))?`))) { + selectedView = view; } }); - return selectedTab; + return selectedView; } updateServerOrder = (serverOrder: string[]) => { @@ -163,14 +163,14 @@ export class ServerManager extends EventEmitter { this.persistServers(); } - updateTabOrder = (serverId: string, tabOrder: string[]) => { - log.withPrefix(serverId).debug('updateTabOrder', tabOrder); + updateTabOrder = (serverId: string, viewOrder: string[]) => { + log.withPrefix(serverId).debug('updateTabOrder', viewOrder); - this.tabOrder.set(serverId, tabOrder); + this.viewOrder.set(serverId, viewOrder); this.persistServers(); } - addServer = (server: Team) => { + addServer = (server: Server) => { const newServer = new MattermostServer(server, false); if (this.servers.has(newServer.id)) { @@ -179,13 +179,13 @@ export class ServerManager extends EventEmitter { this.servers.set(newServer.id, newServer); this.serverOrder.push(newServer.id); - const tabOrder: string[] = []; - getDefaultTabs().forEach((tab) => { - const newTab = this.getTabView(newServer, tab.name, tab.isOpen); - this.tabs.set(newTab.id, newTab); - tabOrder.push(newTab.id); + const viewOrder: string[] = []; + getDefaultViews().forEach((view) => { + const newView = this.getNewView(newServer, view.name, view.isOpen); + this.views.set(newView.id, newView); + viewOrder.push(newView.id); }); - this.tabOrder.set(newServer.id, tabOrder); + this.viewOrder.set(newServer.id, viewOrder); if (!this.currentServerId) { this.currentServerId = newServer.id; @@ -197,7 +197,7 @@ export class ServerManager extends EventEmitter { return newServer; } - editServer = (serverId: string, server: Team) => { + editServer = (serverId: string, server: Server) => { const existingServer = this.servers.get(serverId); if (!existingServer) { return; @@ -212,11 +212,11 @@ export class ServerManager extends EventEmitter { existingServer.updateURL(server.url); this.servers.set(serverId, existingServer); - this.tabOrder.get(serverId)?.forEach((tabId) => { - const tab = this.tabs.get(tabId); - if (tab) { - tab.server = existingServer; - this.tabs.set(tabId, tab); + this.viewOrder.get(serverId)?.forEach((viewId) => { + const view = this.views.get(viewId); + if (view) { + view.server = existingServer; + this.views.set(viewId, view); } }); @@ -225,9 +225,9 @@ export class ServerManager extends EventEmitter { } removeServer = (serverId: string) => { - this.tabOrder.get(serverId)?.forEach((tabId) => this.tabs.delete(tabId)); - this.tabOrder.delete(serverId); - this.lastActiveTab.delete(serverId); + this.viewOrder.get(serverId)?.forEach((viewId) => this.views.delete(viewId)); + this.viewOrder.delete(serverId); + this.lastActiveView.delete(serverId); const index = this.serverOrder.findIndex((id) => id === serverId); this.serverOrder.splice(index, 1); @@ -241,26 +241,26 @@ export class ServerManager extends EventEmitter { this.persistServers(); } - setTabIsOpen = (tabId: string, isOpen: boolean) => { - const tab = this.tabs.get(tabId); - if (!tab) { + setViewIsOpen = (viewId: string, isOpen: boolean) => { + const view = this.views.get(viewId); + if (!view) { return; } - tab.isOpen = isOpen; + view.isOpen = isOpen; this.persistServers(); } - updateLastActive = (tabId: string) => { - const tab = this.tabs.get(tabId); - if (!tab) { + updateLastActive = (viewId: string) => { + const view = this.views.get(viewId); + if (!view) { return; } - this.lastActiveTab.set(tab.server.id, tabId); + this.lastActiveView.set(view.server.id, viewId); - this.currentServerId = tab.server.id; + this.currentServerId = view.server.id; - const serverOrder = this.serverOrder.findIndex((srv) => srv === tab.server.id); + const serverOrder = this.serverOrder.findIndex((srv) => srv === view.server.id); if (serverOrder < 0) { throw new Error('Server order corrupt, ID not found.'); } @@ -270,26 +270,26 @@ export class ServerManager extends EventEmitter { reloadFromConfig = () => { const serverOrder: string[] = []; - Config.predefinedTeams.forEach((team) => { - const id = this.initServer(team, true); + Config.predefinedServers.forEach((server) => { + const id = this.initServer(server, true); serverOrder.push(id); }); if (Config.enableServerManagement) { - Config.localTeams.sort((a, b) => a.order - b.order).forEach((team) => { - const id = this.initServer(team, false); + Config.localServers.sort((a, b) => a.order - b.order).forEach((server) => { + const id = this.initServer(server, false); serverOrder.push(id); }); } - this.filterOutDuplicateTeams(); + this.filterOutDuplicateServers(); this.serverOrder = serverOrder; - if (Config.lastActiveTeam && this.serverOrder[Config.lastActiveTeam]) { - this.currentServerId = this.serverOrder[Config.lastActiveTeam]; + if (Config.lastActiveServer && this.serverOrder[Config.lastActiveServer]) { + this.currentServerId = this.serverOrder[Config.lastActiveServer]; } else { this.currentServerId = this.serverOrder[0]; } } - private filterOutDuplicateTeams = () => { + private filterOutDuplicateServers = () => { const servers = [...this.servers.keys()].map((key) => ({key, value: this.servers.get(key)!})); const uniqueServers = new Set(); servers.forEach((server) => { @@ -301,38 +301,38 @@ export class ServerManager extends EventEmitter { }); } - private initServer = (team: ConfigServer, isPredefined: boolean) => { - const server = new MattermostServer(team, isPredefined); + private initServer = (configServer: ConfigServer, isPredefined: boolean) => { + const server = new MattermostServer(configServer, isPredefined); this.servers.set(server.id, server); log.withPrefix(server.id).debug('initialized server'); - const tabOrder: string[] = []; - team.tabs.sort((a, b) => a.order - b.order).forEach((tab) => { - const tabView = this.getTabView(server, tab.name, tab.isOpen); - log.withPrefix(tabView.id).debug('initialized tab'); + const viewOrder: string[] = []; + configServer.tabs.sort((a, b) => a.order - b.order).forEach((view) => { + const mattermostView = this.getNewView(server, view.name, view.isOpen); + log.withPrefix(mattermostView.id).debug('initialized view'); - this.tabs.set(tabView.id, tabView); - tabOrder.push(tabView.id); + this.views.set(mattermostView.id, mattermostView); + viewOrder.push(mattermostView.id); }); - this.tabOrder.set(server.id, tabOrder); - if (typeof team.lastActiveTab !== 'undefined') { - this.lastActiveTab.set(server.id, tabOrder[team.lastActiveTab]); + this.viewOrder.set(server.id, viewOrder); + if (typeof configServer.lastActiveTab !== 'undefined') { + this.lastActiveView.set(server.id, viewOrder[configServer.lastActiveTab]); } return server.id; } - private getFirstOpenTabForServer = (serverId: string) => { - const tabOrder = this.getOrderedTabsForServer(serverId); - const openTabs = tabOrder.filter((tab) => tab.isOpen); - const firstTab = openTabs[0]; - if (!firstTab) { - throw new Error(`No tabs open for server id ${serverId}`); + private getFirstOpenViewForServer = (serverId: string) => { + const viewOrder = this.getOrderedTabsForServer(serverId); + const openViews = viewOrder.filter((view) => view.isOpen); + const firstView = openViews[0]; + if (!firstView) { + throw new Error(`No views open for server id ${serverId}`); } - return firstTab; + return firstView; } - private persistServers = async (lastActiveTeam?: number) => { + private persistServers = async (lastActiveServer?: number) => { this.emit(SERVERS_UPDATE); const localServers = [...this.servers.values()]. @@ -343,18 +343,18 @@ export class ServerManager extends EventEmitter { servers.push(this.toConfigServer(srv)); return servers; }, [] as ConfigServer[]); - await Config.setServers(localServers, lastActiveTeam); + await Config.setServers(localServers, lastActiveServer); } - private getLastActiveTab = (serverId: string) => { - let lastActiveTab: number | undefined; - if (this.lastActiveTab.has(serverId)) { - const index = this.tabOrder.get(serverId)?.indexOf(this.lastActiveTab.get(serverId)!); + private getLastActiveView = (serverId: string) => { + let lastActiveView: number | undefined; + if (this.lastActiveView.has(serverId)) { + const index = this.viewOrder.get(serverId)?.indexOf(this.lastActiveView.get(serverId)!); if (typeof index !== 'undefined' && index >= 0) { - lastActiveTab = index; + lastActiveView = index; } } - return lastActiveTab; + return lastActiveView; } private toConfigServer = (server: MattermostServer): ConfigServer => { @@ -362,30 +362,30 @@ export class ServerManager extends EventEmitter { name: server.name, url: `${server.url}`, order: this.serverOrder.indexOf(server.id), - lastActiveTab: this.getLastActiveTab(server.id), - tabs: this.tabOrder.get(server.id)?.reduce((tabs, tabId, index) => { - const tab = this.tabs.get(tabId); - if (!tab) { - return tabs; + lastActiveTab: this.getLastActiveView(server.id), + tabs: this.viewOrder.get(server.id)?.reduce((views, viewId, index) => { + const view = this.views.get(viewId); + if (!view) { + return views; } - tabs.push({ - name: tab?.type, + views.push({ + name: view?.type, order: index, - isOpen: tab.isOpen, + isOpen: view.isOpen, }); - return tabs; - }, [] as ConfigTab[]) ?? [], + return views; + }, [] as ConfigView[]) ?? [], }; } - private getTabView = (srv: MattermostServer, tabName: string, isOpen?: boolean) => { - switch (tabName) { + private getNewView = (srv: MattermostServer, viewName: string, isOpen?: boolean) => { + switch (viewName) { case TAB_MESSAGING: - return new MessagingTabView(srv, isOpen); + return new MessagingView(srv, isOpen); case TAB_FOCALBOARD: - return new FocalboardTabView(srv, isOpen); + return new FocalboardView(srv, isOpen); case TAB_PLAYBOOKS: - return new PlaybooksTabView(srv, isOpen); + return new PlaybooksView(srv, isOpen); default: throw new Error('Not implemeneted'); } @@ -407,7 +407,7 @@ export class ServerManager extends EventEmitter { return false; } - private openExtraTabs = (serverId: string) => { + private openExtraViews = (serverId: string) => { const server = this.servers.get(serverId); const remoteInfo = this.remoteInfo.get(serverId); @@ -420,21 +420,21 @@ export class ServerManager extends EventEmitter { } let hasUpdates = false; - const tabOrder = this.tabOrder.get(serverId); - if (tabOrder) { - tabOrder.forEach((tabId) => { - const tab = this.tabs.get(tabId); - if (tab) { - if (tab.type === TAB_PLAYBOOKS && remoteInfo.hasPlaybooks && typeof tab.isOpen === 'undefined') { - log.withPrefix(tab.id).verbose('opening Playbooks'); - tab.isOpen = true; - this.tabs.set(tabId, tab); + const viewOrder = this.viewOrder.get(serverId); + if (viewOrder) { + viewOrder.forEach((viewId) => { + const view = this.views.get(viewId); + if (view) { + if (view.type === TAB_PLAYBOOKS && remoteInfo.hasPlaybooks && typeof view.isOpen === 'undefined') { + log.withPrefix(view.id).verbose('opening Playbooks'); + view.isOpen = true; + this.views.set(viewId, view); hasUpdates = true; } - if (tab.type === TAB_FOCALBOARD && remoteInfo.hasFocalboard && typeof tab.isOpen === 'undefined') { - log.withPrefix(tab.id).verbose('opening Boards'); - tab.isOpen = true; - this.tabs.set(tabId, tab); + if (view.type === TAB_FOCALBOARD && remoteInfo.hasFocalboard && typeof view.isOpen === 'undefined') { + log.withPrefix(view.id).verbose('opening Boards'); + view.isOpen = true; + this.views.set(viewId, view); hasUpdates = true; } } @@ -457,7 +457,7 @@ export class ServerManager extends EventEmitter { }; getViewLog = (viewId: string, ...additionalPrefixes: string[]) => { - const view = this.getTab(viewId); + const view = this.getView(viewId); if (!view) { return new Logger(viewId); } diff --git a/src/common/utils/url.test.js b/src/common/utils/url.test.js index 40930461..e926a230 100644 --- a/src/common/utils/url.test.js +++ b/src/common/utils/url.test.js @@ -14,11 +14,11 @@ import { isTrustedURL, } from 'common/utils/url'; -jest.mock('common/tabs/TabView', () => ({ - getServerView: (srv, tab) => { +jest.mock('common/views/View', () => ({ + getServerView: (srv, view) => { return { - name: `${srv.name}_${tab.name}`, - url: `${srv.url}${srv.url.toString().endsWith('/') ? '' : '/'}${tab.name.split('-')[1] || ''}`, + name: `${srv.name}_${view.name}`, + url: `${srv.url}${srv.url.toString().endsWith('/') ? '' : '/'}${view.name.split('-')[1] || ''}`, }; }, })); diff --git a/src/common/utils/util.test.js b/src/common/utils/util.test.js index e641d20d..e64bb673 100644 --- a/src/common/utils/util.test.js +++ b/src/common/utils/util.test.js @@ -119,8 +119,8 @@ describe('common/utils/util', () => { describe('escapeRegex', () => { it('should escape special chars in string when used inside regex', () => { const str = 'Language C++'; - const regex = `${escapeRegex(str)}___TAB_[A-Z]+`; - expect(new RegExp(regex).test('Language C++___TAB_ABCDEF')).toBe(true); + const regex = `${escapeRegex(str)}___VIEW_[A-Z]+`; + expect(new RegExp(regex).test('Language C++___VIEW_ABCDEF')).toBe(true); }); }); }); diff --git a/src/common/tabs/BaseTabView.ts b/src/common/views/BaseView.ts similarity index 76% rename from src/common/tabs/BaseTabView.ts rename to src/common/views/BaseView.ts index f05737d2..109d9bbd 100644 --- a/src/common/tabs/BaseTabView.ts +++ b/src/common/views/BaseView.ts @@ -3,13 +3,13 @@ import {v4 as uuid} from 'uuid'; -import {MattermostTab} from 'types/config'; +import {UniqueView} from 'types/config'; import {MattermostServer} from 'common/servers/MattermostServer'; -import {TabType, TabView} from './TabView'; +import {ViewType, MattermostView} from './View'; -export default abstract class BaseTabView implements TabView { +export default abstract class BaseView implements MattermostView { id: string; server: MattermostServer; isOpen?: boolean; @@ -22,14 +22,14 @@ export default abstract class BaseTabView implements TabView { get url(): URL { throw new Error('Not implemented'); } - get type(): TabType { + get type(): ViewType { throw new Error('Not implemented'); } get shouldNotify(): boolean { return false; } - toMattermostTab = (): MattermostTab => { + toUniqueView = (): UniqueView => { return { id: this.id, name: this.type, diff --git a/src/common/tabs/FocalboardTabView.ts b/src/common/views/FocalboardView.ts similarity index 65% rename from src/common/tabs/FocalboardTabView.ts rename to src/common/views/FocalboardView.ts index 12e4660e..45a85502 100644 --- a/src/common/tabs/FocalboardTabView.ts +++ b/src/common/views/FocalboardView.ts @@ -3,15 +3,15 @@ import {getFormattedPathName} from 'common/utils/url'; -import BaseTabView from './BaseTabView'; -import {TabType, TAB_FOCALBOARD} from './TabView'; +import BaseView from './BaseView'; +import {ViewType, TAB_FOCALBOARD} from './View'; -export default class FocalboardTabView extends BaseTabView { +export default class FocalboardView extends BaseView { get url(): URL { return new URL(`${this.server.url.origin}${getFormattedPathName(this.server.url.pathname)}boards`); } - get type(): TabType { + get type(): ViewType { return TAB_FOCALBOARD; } } diff --git a/src/common/tabs/MessagingTabView.ts b/src/common/views/MessagingView.ts similarity index 60% rename from src/common/tabs/MessagingTabView.ts rename to src/common/views/MessagingView.ts index 15b4920f..09b4b144 100644 --- a/src/common/tabs/MessagingTabView.ts +++ b/src/common/views/MessagingView.ts @@ -1,15 +1,15 @@ // Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import BaseTabView from './BaseTabView'; -import {TabType, TAB_MESSAGING} from './TabView'; +import BaseView from './BaseView'; +import {ViewType, TAB_MESSAGING} from './View'; -export default class MessagingTabView extends BaseTabView { +export default class MessagingView extends BaseView { get url(): URL { return this.server.url; } - get type(): TabType { + get type(): ViewType { return TAB_MESSAGING; } diff --git a/src/common/tabs/PlaybooksTabView.ts b/src/common/views/PlaybooksView.ts similarity index 66% rename from src/common/tabs/PlaybooksTabView.ts rename to src/common/views/PlaybooksView.ts index bb9a439d..e9520026 100644 --- a/src/common/tabs/PlaybooksTabView.ts +++ b/src/common/views/PlaybooksView.ts @@ -3,15 +3,15 @@ import {getFormattedPathName} from 'common/utils/url'; -import BaseTabView from './BaseTabView'; -import {TabType, TAB_PLAYBOOKS} from './TabView'; +import BaseView from './BaseView'; +import {ViewType, TAB_PLAYBOOKS} from './View'; -export default class PlaybooksTabView extends BaseTabView { +export default class PlaybooksView extends BaseView { get url(): URL { return new URL(`${this.server.url.origin}${getFormattedPathName(this.server.url.pathname)}playbooks`); } - get type(): TabType { + get type(): ViewType { return TAB_PLAYBOOKS; } } diff --git a/src/common/tabs/TabView.ts b/src/common/views/View.ts similarity index 61% rename from src/common/tabs/TabView.ts rename to src/common/views/View.ts index a4c8f57a..6a72829c 100644 --- a/src/common/tabs/TabView.ts +++ b/src/common/views/View.ts @@ -1,35 +1,35 @@ // Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {MattermostTab, Team} from 'types/config'; +import {UniqueView, Server} from 'types/config'; import {MattermostServer} from 'common/servers/MattermostServer'; export const TAB_MESSAGING = 'TAB_MESSAGING'; export const TAB_FOCALBOARD = 'TAB_FOCALBOARD'; export const TAB_PLAYBOOKS = 'TAB_PLAYBOOKS'; -export type TabType = typeof TAB_MESSAGING | typeof TAB_FOCALBOARD | typeof TAB_PLAYBOOKS; +export type ViewType = typeof TAB_MESSAGING | typeof TAB_FOCALBOARD | typeof TAB_PLAYBOOKS; -export interface TabView { +export interface MattermostView { id: string; server: MattermostServer; isOpen?: boolean; - get type(): TabType; + get type(): ViewType; get url(): URL; get shouldNotify(): boolean; - toMattermostTab(): MattermostTab; + toUniqueView(): UniqueView; } -export function getDefaultConfigTeamFromTeam(team: Team & {order: number; lastActiveTab?: number}) { +export function getDefaultViewsForConfigServer(server: Server & {order: number; lastActiveView?: number}) { return { - ...team, - tabs: getDefaultTabs(), + ...server, + tabs: getDefaultViews(), }; } -export function getDefaultTabs() { +export function getDefaultViews() { return [ { name: TAB_MESSAGING, @@ -47,8 +47,8 @@ export function getDefaultTabs() { ]; } -export function getTabDisplayName(tabType: TabType) { - switch (tabType) { +export function getViewDisplayName(viewType: ViewType) { + switch (viewType) { case TAB_MESSAGING: return 'Channels'; case TAB_FOCALBOARD: @@ -60,6 +60,6 @@ export function getTabDisplayName(tabType: TabType) { } } -export function canCloseTab(tabType: TabType) { - return tabType !== TAB_MESSAGING; +export function canCloseView(viewType: ViewType) { + return viewType !== TAB_MESSAGING; } diff --git a/src/main/app/app.test.js b/src/main/app/app.test.js index 80a11694..3100f0af 100644 --- a/src/main/app/app.test.js +++ b/src/main/app/app.test.js @@ -95,9 +95,9 @@ describe('main/app/app', () => { const promise = Promise.resolve({}); const certificate = {}; const view = { - tab: { + view: { server: { - name: 'test-team', + name: 'test-server', url: new URL(testURL), }, }, @@ -163,7 +163,7 @@ describe('main/app/app', () => { expect(CertificateStore.save).toHaveBeenCalled(); }); - it('should load URL using MattermostView when trusting certificate', async () => { + it('should load URL using MattermostBrowserView when trusting certificate', async () => { dialog.showMessageBox.mockResolvedValue({response: 0}); await handleAppCertificateError(event, webContents, testURL, 'error-1', certificate, callback); expect(callback).toHaveBeenCalledWith(true); diff --git a/src/main/app/app.ts b/src/main/app/app.ts index eb304b8e..974381d9 100644 --- a/src/main/app/app.ts +++ b/src/main/app/app.ts @@ -96,8 +96,8 @@ export async function handleAppCertificateError(event: Event, webContents: WebCo const errorID = `${parsedURL.origin}:${error}`; const view = ViewManager.getViewByWebContentsId(webContents.id); - if (view?.tab.server) { - const serverURL = parseURL(view.tab.server.url); + if (view?.view.server) { + const serverURL = parseURL(view.view.server.url); if (serverURL && serverURL.origin !== parsedURL.origin) { log.warn(`Ignoring certificate for unmatched origin ${parsedURL.origin}, will not trust`); callback(false); diff --git a/src/main/app/config.test.js b/src/main/app/config.test.js index 17d7cc72..f19399c5 100644 --- a/src/main/app/config.test.js +++ b/src/main/app/config.test.js @@ -93,14 +93,14 @@ describe('main/app/config', () => { }); }); - it('should recheck teams after config update if registry data is pulled in', () => { + it('should recheck servers after config update if registry data is pulled in', () => { const originalPlatform = process.platform; Object.defineProperty(process, 'platform', { value: 'win32', }); Config.registryConfigData = {}; - handleConfigUpdate({teams: []}); + handleConfigUpdate({servers: []}); expect(handleMainWindowIsShown).toHaveBeenCalled(); Object.defineProperty(process, 'platform', { diff --git a/src/main/app/index.ts b/src/main/app/index.ts index a83b1593..fc8368ca 100644 --- a/src/main/app/index.ts +++ b/src/main/app/index.ts @@ -6,7 +6,7 @@ import {initialize} from './initialize'; // TODO: Singletons, we need DI :D -import('main/views/teamDropdownView'); +import('main/views/serverDropdownView'); import('main/views/downloadsDropdownMenuView'); import('main/views/downloadsDropdownView'); diff --git a/src/main/app/initialize.test.js b/src/main/app/initialize.test.js index 4943a9db..cd764cca 100644 --- a/src/main/app/initialize.test.js +++ b/src/main/app/initialize.test.js @@ -278,7 +278,7 @@ describe('main/app/initialize', () => { it('should allow permission requests for supported types from trusted URLs', async () => { ViewManager.getViewByWebContentsId.mockReturnValue({ - tab: { + view: { server: { url: new URL('http://server-1.com'), }, diff --git a/src/main/app/initialize.ts b/src/main/app/initialize.ts index 40a00450..a6a4055a 100644 --- a/src/main/app/initialize.ts +++ b/src/main/app/initialize.ts @@ -14,8 +14,8 @@ import { SHOW_NEW_SERVER_MODAL, NOTIFY_MENTION, SWITCH_TAB, - CLOSE_TAB, - OPEN_TAB, + CLOSE_VIEW, + OPEN_VIEW, SHOW_EDIT_SERVER_MODAL, SHOW_REMOVE_SERVER_MODAL, UPDATE_SHORTCUT_MENU, @@ -100,8 +100,8 @@ import { switchServer, } from './servers'; import { - handleCloseTab, handleGetLastActive, handleGetOrderedTabsForServer, handleOpenTab, -} from './tabs'; + handleCloseView, handleGetLastActive, handleGetOrderedViewsForServer, handleOpenView, +} from './views'; import { clearAppCache, getDeeplinkingURL, @@ -279,8 +279,8 @@ function initializeInterCommunicationEventListeners() { ipcMain.on(SWITCH_SERVER, (event, serverId) => switchServer(serverId)); ipcMain.on(SWITCH_TAB, (event, viewId) => ViewManager.showById(viewId)); - ipcMain.on(CLOSE_TAB, handleCloseTab); - ipcMain.on(OPEN_TAB, handleOpenTab); + ipcMain.on(CLOSE_VIEW, handleCloseView); + ipcMain.on(OPEN_VIEW, handleOpenView); ipcMain.on(QUIT, handleQuit); @@ -296,10 +296,10 @@ function initializeInterCommunicationEventListeners() { ipcMain.on(UPDATE_CONFIGURATION, updateConfiguration); ipcMain.on(UPDATE_SERVER_ORDER, (event, serverOrder) => ServerManager.updateServerOrder(serverOrder)); - ipcMain.on(UPDATE_TAB_ORDER, (event, serverId, tabOrder) => ServerManager.updateTabOrder(serverId, tabOrder)); + ipcMain.on(UPDATE_TAB_ORDER, (event, serverId, viewOrder) => ServerManager.updateTabOrder(serverId, viewOrder)); ipcMain.handle(GET_LAST_ACTIVE, handleGetLastActive); - ipcMain.handle(GET_ORDERED_SERVERS, () => ServerManager.getOrderedServers().map((srv) => srv.toMattermostTeam())); - ipcMain.handle(GET_ORDERED_TABS_FOR_SERVER, handleGetOrderedTabsForServer); + ipcMain.handle(GET_ORDERED_SERVERS, () => ServerManager.getOrderedServers().map((srv) => srv.toUniqueServer())); + ipcMain.handle(GET_ORDERED_TABS_FOR_SERVER, handleGetOrderedViewsForServer); ipcMain.handle(GET_DARK_MODE, handleGetDarkMode); ipcMain.on(WINDOW_CLOSE, handleClose); @@ -453,7 +453,7 @@ async function initializeAfterAppReady() { } const requestingURL = webContents.getURL(); - const serverURL = ViewManager.getViewByWebContentsId(webContents.id)?.tab.server.url; + const serverURL = ViewManager.getViewByWebContentsId(webContents.id)?.view.server.url; if (!serverURL) { callback(false); diff --git a/src/main/app/intercom.test.js b/src/main/app/intercom.test.js index 5d27f131..28bb162b 100644 --- a/src/main/app/intercom.test.js +++ b/src/main/app/intercom.test.js @@ -16,14 +16,14 @@ jest.mock('common/config', () => ({ })); jest.mock('main/notifications', () => ({})); jest.mock('common/servers/serverManager', () => ({ - setTabIsOpen: jest.fn(), + setViewIsOpen: jest.fn(), getAllServers: jest.fn(), hasServers: jest.fn(), addServer: jest.fn(), editServer: jest.fn(), removeServer: jest.fn(), getServer: jest.fn(), - getTab: jest.fn(), + getView: jest.fn(), getLastActiveTabForServer: jest.fn(), })); jest.mock('main/utils', () => ({ diff --git a/src/main/app/intercom.ts b/src/main/app/intercom.ts index 9bfcfc69..5b947759 100644 --- a/src/main/app/intercom.ts +++ b/src/main/app/intercom.ts @@ -3,7 +3,7 @@ import {app, IpcMainEvent, IpcMainInvokeEvent, Menu} from 'electron'; -import {MattermostTeam} from 'types/config'; +import {UniqueServer} from 'types/config'; import {MentionData} from 'types/notification'; import {Logger} from 'common/log'; @@ -93,11 +93,11 @@ export function handleWelcomeScreenModal() { if (!mainWindow) { return; } - const modalPromise = ModalManager.addModal('welcomeScreen', html, preload, ServerManager.getAllServers().map((team) => team.toMattermostTeam()), mainWindow, !ServerManager.hasServers()); + const modalPromise = ModalManager.addModal('welcomeScreen', html, preload, ServerManager.getAllServers().map((server) => server.toUniqueServer()), mainWindow, !ServerManager.hasServers()); if (modalPromise) { modalPromise.then((data) => { - const newTeam = ServerManager.addServer(data); - switchServer(newTeam.id, true); + const newServer = ServerManager.addServer(data); + switchServer(newServer.id, true); }).catch((e) => { // e is undefined for user cancellation if (e) { diff --git a/src/main/app/servers.test.js b/src/main/app/servers.test.js index 01f8cf64..5476c2cd 100644 --- a/src/main/app/servers.test.js +++ b/src/main/app/servers.test.js @@ -2,7 +2,7 @@ // See LICENSE.txt for license information. import ServerManager from 'common/servers/serverManager'; -import {getDefaultConfigTeamFromTeam} from 'common/tabs/TabView'; +import {getDefaultViewsForConfigServer} from 'common/views/View'; import ModalManager from 'main/views/modalManager'; import {getLocalURLString, getLocalPreload} from 'main/utils'; @@ -18,19 +18,19 @@ jest.mock('electron', () => ({ })); jest.mock('common/servers/serverManager', () => ({ - setTabIsOpen: jest.fn(), + setViewIsOpen: jest.fn(), getAllServers: jest.fn(), hasServers: jest.fn(), addServer: jest.fn(), editServer: jest.fn(), removeServer: jest.fn(), getServer: jest.fn(), - getTab: jest.fn(), + getView: jest.fn(), getLastActiveTabForServer: jest.fn(), getServerLog: jest.fn(), })); -jest.mock('common/tabs/TabView', () => ({ - getDefaultConfigTeamFromTeam: jest.fn(), +jest.mock('common/views/View', () => ({ + getDefaultViewsForConfigServer: jest.fn(), })); jest.mock('main/views/modalManager', () => ({ addModal: jest.fn(), @@ -50,22 +50,22 @@ jest.mock('main/views/viewManager', () => ({ const tabs = [ { - name: 'tab-1', + name: 'view-1', order: 0, isOpen: false, }, { - name: 'tab-2', + name: 'view-2', order: 2, isOpen: true, }, { - name: 'tab-3', + name: 'view-3', order: 1, isOpen: true, }, ]; -const teams = [ +const servers = [ { id: 'server-1', name: 'server-1', @@ -77,9 +77,9 @@ const teams = [ describe('main/app/servers', () => { describe('switchServer', () => { const views = new Map([ - ['tab-1', {id: 'tab-1'}], - ['tab-2', {id: 'tab-2'}], - ['tab-3', {id: 'tab-3'}], + ['view-1', {id: 'view-1'}], + ['view-2', {id: 'view-2'}], + ['view-3', {id: 'view-3'}], ]); beforeEach(() => { @@ -119,69 +119,69 @@ describe('main/app/servers', () => { expect(ViewManager.showById).not.toBeCalled(); }); - it('should show first open tab in order when last active not defined', () => { - ServerManager.getLastActiveTabForServer.mockReturnValue({id: 'tab-3'}); + it('should show first open view in order when last active not defined', () => { + ServerManager.getLastActiveTabForServer.mockReturnValue({id: 'view-3'}); Servers.switchServer('server-1'); - expect(ViewManager.showById).toHaveBeenCalledWith('tab-3'); + expect(ViewManager.showById).toHaveBeenCalledWith('view-3'); }); - it('should show last active tab of chosen server', () => { - ServerManager.getLastActiveTabForServer.mockReturnValue({id: 'tab-2'}); + it('should show last active view of chosen server', () => { + ServerManager.getLastActiveTabForServer.mockReturnValue({id: 'view-2'}); Servers.switchServer('server-2'); - expect(ViewManager.showById).toHaveBeenCalledWith('tab-2'); + expect(ViewManager.showById).toHaveBeenCalledWith('view-2'); }); it('should wait for view to exist if specified', () => { - ServerManager.getLastActiveTabForServer.mockReturnValue({id: 'tab-3'}); - views.delete('tab-3'); + ServerManager.getLastActiveTabForServer.mockReturnValue({id: 'view-3'}); + views.delete('view-3'); Servers.switchServer('server-1', true); expect(ViewManager.showById).not.toBeCalled(); jest.advanceTimersByTime(200); expect(ViewManager.showById).not.toBeCalled(); - views.set('tab-3', {}); + views.set('view-3', {}); jest.advanceTimersByTime(200); - expect(ViewManager.showById).toBeCalledWith('tab-3'); + expect(ViewManager.showById).toBeCalledWith('view-3'); }); }); describe('handleNewServerModal', () => { - let teamsCopy; + let serversCopy; beforeEach(() => { getLocalURLString.mockReturnValue('/some/index.html'); getLocalPreload.mockReturnValue('/some/preload.js'); MainWindow.get.mockReturnValue({}); - teamsCopy = JSON.parse(JSON.stringify(teams)); + serversCopy = JSON.parse(JSON.stringify(servers)); ServerManager.getAllServers.mockReturnValue([]); ServerManager.addServer.mockImplementation(() => { - const newTeam = { + const newServer = { id: 'server-1', - name: 'new-team', - url: 'http://new-team.com', + name: 'new-server', + url: 'http://new-server.com', tabs, }; - teamsCopy = [ - ...teamsCopy, - newTeam, + serversCopy = [ + ...serversCopy, + newServer, ]; - return newTeam; + return newServer; }); - ServerManager.hasServers.mockReturnValue(Boolean(teamsCopy.length)); + ServerManager.hasServers.mockReturnValue(Boolean(serversCopy.length)); ServerManager.getServerLog.mockReturnValue({debug: jest.fn(), error: jest.fn()}); - getDefaultConfigTeamFromTeam.mockImplementation((team) => ({ - ...team, + getDefaultViewsForConfigServer.mockImplementation((server) => ({ + ...server, tabs, })); }); - it('should add new team to the config', async () => { + it('should add new server to the config', async () => { const data = { - name: 'new-team', - url: 'http://new-team.com', + name: 'new-server', + url: 'http://new-server.com', }; const promise = Promise.resolve(data); ModalManager.addModal.mockReturnValue(promise); @@ -190,10 +190,10 @@ describe('main/app/servers', () => { await promise; expect(ServerManager.addServer).toHaveBeenCalledWith(data); - expect(teamsCopy).toContainEqual(expect.objectContaining({ + expect(serversCopy).toContainEqual(expect.objectContaining({ id: 'server-1', - name: 'new-team', - url: 'http://new-team.com', + name: 'new-server', + url: 'http://new-server.com', tabs, })); @@ -203,31 +203,31 @@ describe('main/app/servers', () => { }); describe('handleEditServerModal', () => { - let teamsCopy; + let serversCopy; beforeEach(() => { getLocalURLString.mockReturnValue('/some/index.html'); getLocalPreload.mockReturnValue('/some/preload.js'); MainWindow.get.mockReturnValue({}); - teamsCopy = JSON.parse(JSON.stringify(teams)); + serversCopy = JSON.parse(JSON.stringify(servers)); ServerManager.getServer.mockImplementation((id) => { - if (id !== teamsCopy[0].id) { + if (id !== serversCopy[0].id) { return undefined; } - return {...teamsCopy[0], toMattermostTeam: jest.fn()}; + return {...serversCopy[0], toUniqueServer: jest.fn()}; }); - ServerManager.editServer.mockImplementation((id, team) => { - if (id !== teamsCopy[0].id) { + ServerManager.editServer.mockImplementation((id, server) => { + if (id !== serversCopy[0].id) { return; } - const newTeam = { - ...teamsCopy[0], - ...team, + const newServer = { + ...serversCopy[0], + ...server, }; - teamsCopy = [newTeam]; + serversCopy = [newServer]; }); - ServerManager.getAllServers.mockReturnValue(teamsCopy.map((team) => ({...team, toMattermostTeam: jest.fn()}))); + ServerManager.getAllServers.mockReturnValue(serversCopy.map((server) => ({...server, toUniqueServer: jest.fn()}))); }); it('should do nothing when the server cannot be found', () => { @@ -235,58 +235,58 @@ describe('main/app/servers', () => { expect(ModalManager.addModal).not.toBeCalled(); }); - it('should edit the existing team', async () => { + it('should edit the existing server', async () => { const promise = Promise.resolve({ - name: 'new-team', - url: 'http://new-team.com', + name: 'new-server', + url: 'http://new-server.com', }); ModalManager.addModal.mockReturnValue(promise); Servers.handleEditServerModal(null, 'server-1'); await promise; - expect(teamsCopy).not.toContainEqual(expect.objectContaining({ + expect(serversCopy).not.toContainEqual(expect.objectContaining({ id: 'server-1', name: 'server-1', url: 'http://server-1.com', tabs, })); - expect(teamsCopy).toContainEqual(expect.objectContaining({ + expect(serversCopy).toContainEqual(expect.objectContaining({ id: 'server-1', - name: 'new-team', - url: 'http://new-team.com', + name: 'new-server', + url: 'http://new-server.com', tabs, })); }); }); describe('handleRemoveServerModal', () => { - let teamsCopy; + let serversCopy; beforeEach(() => { getLocalURLString.mockReturnValue('/some/index.html'); getLocalPreload.mockReturnValue('/some/preload.js'); MainWindow.get.mockReturnValue({}); - teamsCopy = JSON.parse(JSON.stringify(teams)); + serversCopy = JSON.parse(JSON.stringify(servers)); ServerManager.getServer.mockImplementation((id) => { - if (id !== teamsCopy[0].id) { + if (id !== serversCopy[0].id) { return undefined; } - return teamsCopy[0]; + return serversCopy[0]; }); ServerManager.removeServer.mockImplementation(() => { - teamsCopy = []; + serversCopy = []; }); - ServerManager.getAllServers.mockReturnValue(teamsCopy); + ServerManager.getAllServers.mockReturnValue(serversCopy); }); - it('should remove the existing team', async () => { + it('should remove the existing server', async () => { const promise = Promise.resolve(true); ModalManager.addModal.mockReturnValue(promise); Servers.handleRemoveServerModal(null, 'server-1'); await promise; - expect(teamsCopy).not.toContainEqual(expect.objectContaining({ + expect(serversCopy).not.toContainEqual(expect.objectContaining({ id: 'server-1', name: 'server-1', url: 'http://server-1.com', @@ -294,11 +294,11 @@ describe('main/app/servers', () => { })); }); - it('should not remove the existing team when clicking Cancel', async () => { + it('should not remove the existing server when clicking Cancel', async () => { const promise = Promise.resolve(false); ModalManager.addModal.mockReturnValue(promise); - expect(teamsCopy).toContainEqual(expect.objectContaining({ + expect(serversCopy).toContainEqual(expect.objectContaining({ id: 'server-1', name: 'server-1', url: 'http://server-1.com', @@ -307,7 +307,7 @@ describe('main/app/servers', () => { Servers.handleRemoveServerModal(null, 'server-1'); await promise; - expect(teamsCopy).toContainEqual(expect.objectContaining({ + expect(serversCopy).toContainEqual(expect.objectContaining({ id: 'server-1', name: 'server-1', url: 'http://server-1.com', diff --git a/src/main/app/servers.ts b/src/main/app/servers.ts index 9cbfb2b8..053c09aa 100644 --- a/src/main/app/servers.ts +++ b/src/main/app/servers.ts @@ -3,7 +3,7 @@ import {IpcMainEvent, ipcMain} from 'electron'; -import {MattermostTeam, Team} from 'types/config'; +import {UniqueServer, Server} from 'types/config'; import {UPDATE_SHORTCUT_MENU} from 'common/communication'; import {Logger} from 'common/log'; @@ -24,16 +24,16 @@ export const switchServer = (serverId: string, waitForViewToExist = false) => { ServerManager.getServerLog(serverId, 'WindowManager').error('Cannot find server in config'); return; } - const nextTab = ServerManager.getLastActiveTabForServer(serverId); + const nextView = ServerManager.getLastActiveTabForServer(serverId); if (waitForViewToExist) { const timeout = setInterval(() => { - if (ViewManager.getView(nextTab.id)) { - ViewManager.showById(nextTab.id); + if (ViewManager.getView(nextView.id)) { + ViewManager.showById(nextView.id); clearInterval(timeout); } }, 100); } else { - ViewManager.showById(nextTab.id); + ViewManager.showById(nextView.id); } ipcMain.emit(UPDATE_SHORTCUT_MENU); }; @@ -49,11 +49,11 @@ export const handleNewServerModal = () => { if (!mainWindow) { return; } - const modalPromise = ModalManager.addModal('newServer', html, preload, ServerManager.getAllServers().map((team) => team.toMattermostTeam()), mainWindow, !ServerManager.hasServers()); + const modalPromise = ModalManager.addModal('newServer', html, preload, ServerManager.getAllServers().map((server) => server.toUniqueServer()), mainWindow, !ServerManager.hasServers()); if (modalPromise) { modalPromise.then((data) => { - const newTeam = ServerManager.addServer(data); - switchServer(newTeam.id, true); + const newServer = ServerManager.addServer(data); + switchServer(newServer.id, true); }).catch((e) => { // e is undefined for user cancellation if (e) { @@ -80,13 +80,13 @@ export const handleEditServerModal = (e: IpcMainEvent, id: string) => { if (!server) { return; } - const modalPromise = ModalManager.addModal<{currentTeams: MattermostTeam[]; team: MattermostTeam}, Team>( + const modalPromise = ModalManager.addModal<{currentServers: UniqueServer[]; server: UniqueServer}, Server>( 'editServer', html, preload, { - currentTeams: ServerManager.getAllServers().map((team) => team.toMattermostTeam()), - team: server.toMattermostTeam(), + currentServers: ServerManager.getAllServers().map((server) => server.toUniqueServer()), + server: server.toUniqueServer(), }, mainWindow); if (modalPromise) { diff --git a/src/main/app/tabs.test.js b/src/main/app/tabs.test.js deleted file mode 100644 index 4a2a6daa..00000000 --- a/src/main/app/tabs.test.js +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -import ServerManager from 'common/servers/serverManager'; -import ViewManager from 'main/views/viewManager'; - -import { - handleCloseTab, - handleOpenTab, -} from './tabs'; - -jest.mock('common/servers/serverManager', () => ({ - setTabIsOpen: jest.fn(), - getTab: jest.fn(), - getLastActiveTabForServer: jest.fn(), -})); - -jest.mock('main/views/viewManager', () => ({ - showById: jest.fn(), -})); - -describe('main/app/tabs', () => { - describe('handleCloseTab', () => { - it('should close the specified tab and switch to the next open tab', () => { - ServerManager.getTab.mockReturnValue({server: {id: 'server-1'}}); - ServerManager.getLastActiveTabForServer.mockReturnValue({id: 'tab-2'}); - handleCloseTab(null, 'tab-3'); - expect(ServerManager.setTabIsOpen).toBeCalledWith('tab-3', false); - expect(ViewManager.showById).toBeCalledWith('tab-2'); - }); - }); - - describe('handleOpenTab', () => { - it('should open the specified tab', () => { - handleOpenTab(null, 'tab-1'); - expect(ViewManager.showById).toBeCalledWith('tab-1'); - }); - }); -}); diff --git a/src/main/app/tabs.ts b/src/main/app/tabs.ts deleted file mode 100644 index 2260be6e..00000000 --- a/src/main/app/tabs.ts +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -import {IpcMainEvent, IpcMainInvokeEvent} from 'electron'; - -import ServerManager from 'common/servers/serverManager'; -import {Logger} from 'common/log'; - -import ViewManager from 'main/views/viewManager'; - -const log = new Logger('App.Tabs'); - -export const handleCloseTab = (event: IpcMainEvent, tabId: string) => { - log.debug('handleCloseTab', {tabId}); - - const tab = ServerManager.getTab(tabId); - if (!tab) { - return; - } - ServerManager.setTabIsOpen(tabId, false); - const nextTab = ServerManager.getLastActiveTabForServer(tab.server.id); - ViewManager.showById(nextTab.id); -}; - -export const handleOpenTab = (event: IpcMainEvent, tabId: string) => { - log.debug('handleOpenTab', {tabId}); - - ServerManager.setTabIsOpen(tabId, true); - ViewManager.showById(tabId); -}; - -export const selectNextTab = () => { - selectTab((order) => order + 1); -}; - -export const selectPreviousTab = () => { - selectTab((order, length) => (length + (order - 1))); -}; - -export const handleGetOrderedTabsForServer = (event: IpcMainInvokeEvent, serverId: string) => { - return ServerManager.getOrderedTabsForServer(serverId).map((tab) => tab.toMattermostTab()); -}; - -export const handleGetLastActive = () => { - const server = ServerManager.getCurrentServer(); - const tab = ServerManager.getLastActiveTabForServer(server.id); - return {server: server.id, tab: tab.id}; -}; - -const selectTab = (fn: (order: number, length: number) => number) => { - const currentView = ViewManager.getCurrentView(); - if (!currentView) { - return; - } - - const currentTeamTabs = ServerManager.getOrderedTabsForServer(currentView.tab.server.id).map((tab, index) => ({tab, index})); - const filteredTabs = currentTeamTabs?.filter((tab) => tab.tab.isOpen); - const currentTab = currentTeamTabs?.find((tab) => tab.tab.type === currentView.tab.type); - if (!currentTeamTabs || !currentTab || !filteredTabs) { - return; - } - - let currentOrder = currentTab.index; - let nextIndex = -1; - while (nextIndex === -1) { - const nextOrder = (fn(currentOrder, currentTeamTabs.length) % currentTeamTabs.length); - nextIndex = filteredTabs.findIndex((tab) => tab.index === nextOrder); - currentOrder = nextOrder; - } - - const newTab = filteredTabs[nextIndex].tab; - ViewManager.showById(newTab.id); -}; diff --git a/src/main/app/views.test.js b/src/main/app/views.test.js new file mode 100644 index 00000000..bccd3420 --- /dev/null +++ b/src/main/app/views.test.js @@ -0,0 +1,39 @@ +// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import ServerManager from 'common/servers/serverManager'; +import ViewManager from 'main/views/viewManager'; + +import { + handleCloseView, + handleOpenView, +} from './views'; + +jest.mock('common/servers/serverManager', () => ({ + setViewIsOpen: jest.fn(), + getView: jest.fn(), + getLastActiveTabForServer: jest.fn(), +})); + +jest.mock('main/views/viewManager', () => ({ + showById: jest.fn(), +})); + +describe('main/app/views', () => { + describe('handleCloseView', () => { + it('should close the specified view and switch to the next open view', () => { + ServerManager.getView.mockReturnValue({server: {id: 'server-1'}}); + ServerManager.getLastActiveTabForServer.mockReturnValue({id: 'view-2'}); + handleCloseView(null, 'view-3'); + expect(ServerManager.setViewIsOpen).toBeCalledWith('view-3', false); + expect(ViewManager.showById).toBeCalledWith('view-2'); + }); + }); + + describe('handleOpenView', () => { + it('should open the specified view', () => { + handleOpenView(null, 'view-1'); + expect(ViewManager.showById).toBeCalledWith('view-1'); + }); + }); +}); diff --git a/src/main/app/views.ts b/src/main/app/views.ts new file mode 100644 index 00000000..477d0bf7 --- /dev/null +++ b/src/main/app/views.ts @@ -0,0 +1,73 @@ +// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import {IpcMainEvent, IpcMainInvokeEvent} from 'electron'; + +import ServerManager from 'common/servers/serverManager'; +import {Logger} from 'common/log'; + +import ViewManager from 'main/views/viewManager'; + +const log = new Logger('App.Views'); + +export const handleCloseView = (event: IpcMainEvent, viewId: string) => { + log.debug('handleCloseView', {viewId}); + + const view = ServerManager.getView(viewId); + if (!view) { + return; + } + ServerManager.setViewIsOpen(viewId, false); + const nextView = ServerManager.getLastActiveTabForServer(view.server.id); + ViewManager.showById(nextView.id); +}; + +export const handleOpenView = (event: IpcMainEvent, viewId: string) => { + log.debug('handleOpenView', {viewId}); + + ServerManager.setViewIsOpen(viewId, true); + ViewManager.showById(viewId); +}; + +export const selectNextView = () => { + selectView((order) => order + 1); +}; + +export const selectPreviousView = () => { + selectView((order, length) => (length + (order - 1))); +}; + +export const handleGetOrderedViewsForServer = (event: IpcMainInvokeEvent, serverId: string) => { + return ServerManager.getOrderedTabsForServer(serverId).map((view) => view.toUniqueView()); +}; + +export const handleGetLastActive = () => { + const server = ServerManager.getCurrentServer(); + const view = ServerManager.getLastActiveTabForServer(server.id); + return {server: server.id, view: view.id}; +}; + +const selectView = (fn: (order: number, length: number) => number) => { + const currentView = ViewManager.getCurrentView(); + if (!currentView) { + return; + } + + const currentServerViews = ServerManager.getOrderedTabsForServer(currentView.view.server.id).map((view, index) => ({view, index})); + const filteredViews = currentServerViews?.filter((view) => view.view.isOpen); + const currentServerView = currentServerViews?.find((view) => view.view.type === currentView.view.type); + if (!currentServerViews || !currentServerView || !filteredViews) { + return; + } + + let currentOrder = currentServerView.index; + let nextIndex = -1; + while (nextIndex === -1) { + const nextOrder = (fn(currentOrder, currentServerViews.length) % currentServerViews.length); + nextIndex = filteredViews.findIndex((view) => view.index === nextOrder); + currentOrder = nextOrder; + } + + const newView = filteredViews[nextIndex].view; + ViewManager.showById(newView.id); +}; diff --git a/src/main/authManager.test.js b/src/main/authManager.test.js index 4f508450..bcf9fc73 100644 --- a/src/main/authManager.test.js +++ b/src/main/authManager.test.js @@ -7,54 +7,6 @@ import MainWindow from 'main/windows/mainWindow'; import ModalManager from 'main/views/modalManager'; import ViewManager from 'main/views/viewManager'; -jest.mock('common/config', () => ({ - teams: [{ - name: 'example', - url: 'http://example.com', - order: 0, - tabs: [ - { - name: 'TAB_MESSAGING', - order: 0, - isOpen: true, - }, - { - name: 'TAB_FOCALBOARD', - order: 1, - isOpen: true, - }, - { - name: 'TAB_PLAYBOOKS', - order: 2, - isOpen: true, - }, - ], - lastActiveTab: 0, - }, { - name: 'github', - url: 'https://github.com/', - order: 1, - tabs: [ - { - name: 'TAB_MESSAGING', - order: 0, - isOpen: true, - }, - { - name: 'TAB_FOCALBOARD', - order: 1, - isOpen: true, - }, - { - name: 'TAB_PLAYBOOKS', - order: 2, - isOpen: true, - }, - ], - lastActiveTab: 0, - }], -})); - jest.mock('common/utils/url', () => { const actualUrl = jest.requireActual('common/utils/url'); return { @@ -116,35 +68,35 @@ describe('main/authManager', () => { }); it('should popLoginModal when isTrustedURL', () => { - ViewManager.getViewByWebContentsId.mockReturnValue({tab: {server: {url: new URL('http://trustedurl.com/')}}}); + ViewManager.getViewByWebContentsId.mockReturnValue({view: {server: {url: new URL('http://trustedurl.com/')}}}); authManager.handleAppLogin({preventDefault: jest.fn()}, {id: 1}, {url: 'http://trustedurl.com/'}, null, jest.fn()); expect(authManager.popLoginModal).toBeCalled(); expect(authManager.popPermissionModal).not.toBeCalled(); }); it('should popLoginModal when isCustomLoginURL', () => { - ViewManager.getViewByWebContentsId.mockReturnValue({tab: {server: {url: new URL('http://customloginurl.com/')}}}); + ViewManager.getViewByWebContentsId.mockReturnValue({view: {server: {url: new URL('http://customloginurl.com/')}}}); authManager.handleAppLogin({preventDefault: jest.fn()}, {id: 1}, {url: 'http://customloginurl.com/'}, null, jest.fn()); expect(authManager.popLoginModal).toBeCalled(); expect(authManager.popPermissionModal).not.toBeCalled(); }); it('should popLoginModal when has permission', () => { - ViewManager.getViewByWebContentsId.mockReturnValue({tab: {server: {url: new URL('http://haspermissionurl.com/')}}}); + ViewManager.getViewByWebContentsId.mockReturnValue({view: {server: {url: new URL('http://haspermissionurl.com/')}}}); authManager.handleAppLogin({preventDefault: jest.fn()}, {id: 1}, {url: 'http://haspermissionurl.com/'}, null, jest.fn()); expect(authManager.popLoginModal).toBeCalled(); expect(authManager.popPermissionModal).not.toBeCalled(); }); it('should popPermissionModal when anything else is true', () => { - ViewManager.getViewByWebContentsId.mockReturnValue({tab: {server: {url: new URL('http://someotherurl.com/')}}}); + ViewManager.getViewByWebContentsId.mockReturnValue({view: {server: {url: new URL('http://someotherurl.com/')}}}); authManager.handleAppLogin({preventDefault: jest.fn()}, {id: 1}, {url: 'http://someotherurl.com/'}, null, jest.fn()); expect(authManager.popLoginModal).not.toBeCalled(); expect(authManager.popPermissionModal).toBeCalled(); }); it('should set login callback when logging in', () => { - ViewManager.getViewByWebContentsId.mockReturnValue({tab: {server: {url: new URL('http://someotherurl.com/')}}}); + ViewManager.getViewByWebContentsId.mockReturnValue({view: {server: {url: new URL('http://someotherurl.com/')}}}); const callback = jest.fn(); authManager.handleAppLogin({preventDefault: jest.fn()}, {id: 1}, {url: 'http://someotherurl.com/'}, null, callback); expect(authManager.loginCallbackMap.get('http://someotherurl.com/')).toEqual(callback); diff --git a/src/main/authManager.ts b/src/main/authManager.ts index 126da3f7..b78e090a 100644 --- a/src/main/authManager.ts +++ b/src/main/authManager.ts @@ -40,7 +40,7 @@ export class AuthManager { if (!parsedURL) { return; } - const serverURL = ViewManager.getViewByWebContentsId(webContents.id)?.tab.server.url; + const serverURL = ViewManager.getViewByWebContentsId(webContents.id)?.view.server.url; if (!serverURL) { return; } diff --git a/src/main/diagnostics/steps/step3.serverConnectivity.ts b/src/main/diagnostics/steps/step3.serverConnectivity.ts index 006e46d8..1b6e8209 100644 --- a/src/main/diagnostics/steps/step3.serverConnectivity.ts +++ b/src/main/diagnostics/steps/step3.serverConnectivity.ts @@ -15,26 +15,26 @@ const stepDescriptiveName = 'serverConnectivity'; const run = async (logger: ElectronLog): Promise => { try { - const teams = ServerManager.getAllServers(); + const servers = ServerManager.getAllServers(); - await Promise.all(teams.map(async (team) => { - logger.debug('Pinging server: ', team.url); + await Promise.all(servers.map(async (server) => { + logger.debug('Pinging server: ', server.url); - if (!team.name || !team.url) { - throw new Error(`Invalid server configuration. Team Url: ${team.url}, team name: ${team.name}`); + if (!server.name || !server.url) { + throw new Error(`Invalid server configuration. Server Url: ${server.url}, server name: ${server.name}`); } - const serverOnline = await isOnline(logger, `${team.url}/api/v4/system/ping`); + const serverOnline = await isOnline(logger, `${server.url}/api/v4/system/ping`); if (!serverOnline) { - throw new Error(`Server appears to be offline. Team url: ${team.url}`); + throw new Error(`Server appears to be offline. Server url: ${server.url}`); } })); return { message: `${stepName} finished successfully`, succeeded: true, - payload: teams, + payload: servers, }; } catch (error) { logger.warn(`Diagnostics ${stepName} Failure`, {error}); diff --git a/src/main/downloadsManager.ts b/src/main/downloadsManager.ts index 43924fee..0fcaba4d 100644 --- a/src/main/downloadsManager.ts +++ b/src/main/downloadsManager.ts @@ -554,7 +554,7 @@ export class DownloadsManager extends JsonFileManager { log.debug('doneEventController', {state}); if (state === 'completed' && !this.open) { - displayDownloadCompleted(path.basename(item.savePath), item.savePath, ViewManager.getViewByWebContentsId(webContents.id)?.tab.server.name ?? ''); + displayDownloadCompleted(path.basename(item.savePath), item.savePath, ViewManager.getViewByWebContentsId(webContents.id)?.view.server.name ?? ''); } const bookmark = this.bookmarks.get(this.getFileId(item)); diff --git a/src/main/menus/app.test.js b/src/main/menus/app.test.js index bc73dcf1..067ae0f6 100644 --- a/src/main/menus/app.test.js +++ b/src/main/menus/app.test.js @@ -67,8 +67,8 @@ jest.mock('main/windows/mainWindow', () => ({ sendToRenderer: jest.fn(), })); jest.mock('main/windows/settingsWindow', () => ({})); -jest.mock('common/tabs/TabView', () => ({ - getTabDisplayName: (name) => name, +jest.mock('common/views/View', () => ({ + getViewDisplayName: (name) => name, })); describe('main/menus/app', () => { @@ -88,19 +88,19 @@ describe('main/menus/app', () => { url: 'https:/ /github.com/', }, ]; - const tabs = [ + const views = [ { - id: 'tab-1', + id: 'view-1', name: 'TAB_MESSAGING', isOpen: true, }, { - id: 'tab-2', + id: 'view-2', name: 'TAB_FOCALBOARD', isOpen: true, }, { - id: 'tab-3', + id: 'view-3', name: 'TAB_PLAYBOOKS', isOpen: true, }, @@ -109,7 +109,7 @@ describe('main/menus/app', () => { beforeEach(() => { ServerManager.getCurrentServer.mockReturnValue(servers[0]); ServerManager.getOrderedServers.mockReturnValue(servers); - ServerManager.getOrderedTabsForServer.mockReturnValue(tabs); + ServerManager.getOrderedTabsForServer.mockReturnValue(views); getDarwinDoNotDisturb.mockReturnValue(false); }); @@ -217,7 +217,7 @@ describe('main/menus/app', () => { expect(signInOption).toBe(undefined); }); - it('should not show `Sign in to Another Server` if no teams are configured', () => { + it('should not show `Sign in to Another Server` if no servers are configured', () => { localizeMessage.mockImplementation((id) => { switch (id) { case 'main.menus.app.file': @@ -247,15 +247,15 @@ describe('main/menus/app', () => { name: `server-${key}`, url: `http://server-${key}.com`, })); - const modifiedTabs = [ + const modifiedViews = [ { - id: 'tab-1', + id: 'view-1', type: 'TAB_MESSAGING', isOpen: true, }, ]; ServerManager.getOrderedServers.mockReturnValue(modifiedServers); - ServerManager.getOrderedTabsForServer.mockReturnValue(modifiedTabs); + ServerManager.getOrderedTabsForServer.mockReturnValue(modifiedViews); const menu = createTemplate(config); const windowMenu = menu.find((item) => item.label === '&Window'); for (let i = 0; i < 9; i++) { @@ -268,32 +268,32 @@ describe('main/menus/app', () => { } }); - it('should show the first 9 tabs (using order) in the Window menu', () => { + it('should show the first 9 views (using order) in the Window menu', () => { localizeMessage.mockImplementation((id) => { if (id === 'main.menus.app.window') { return '&Window'; } - if (id.startsWith('common.tabs')) { - return id.replace('common.tabs.', ''); + if (id.startsWith('common.views')) { + return id.replace('common.views.', ''); } return id; }); ServerManager.getCurrentServer.mockImplementation(() => ({id: servers[0].id})); - const modifiedTabs = [...Array(15).keys()].map((key) => ({ - id: `tab-${key}`, - type: `tab-${key}`, + const modifiedViews = [...Array(15).keys()].map((key) => ({ + id: `view-${key}`, + type: `view-${key}`, isOpen: true, })); - ServerManager.getOrderedTabsForServer.mockReturnValue(modifiedTabs); + ServerManager.getOrderedTabsForServer.mockReturnValue(modifiedViews); const menu = createTemplate(config); const windowMenu = menu.find((item) => item.label === '&Window'); for (let i = 0; i < 9; i++) { - const menuItem = windowMenu.submenu.find((item) => item.label === ` tab-${i}`); + const menuItem = windowMenu.submenu.find((item) => item.label === ` view-${i}`); expect(menuItem).not.toBe(undefined); } for (let i = 9; i < 15; i++) { - const menuItem = windowMenu.submenu.find((item) => item.label === ` tab-${i}`); + const menuItem = windowMenu.submenu.find((item) => item.label === ` view-${i}`); expect(menuItem).toBe(undefined); } }); diff --git a/src/main/menus/app.ts b/src/main/menus/app.ts index fbd66709..92daa825 100644 --- a/src/main/menus/app.ts +++ b/src/main/menus/app.ts @@ -6,9 +6,9 @@ import {app, ipcMain, Menu, MenuItemConstructorOptions, MenuItem, session, shell, WebContents, clipboard} from 'electron'; import log from 'electron-log'; -import {OPEN_TEAMS_DROPDOWN, SHOW_NEW_SERVER_MODAL} from 'common/communication'; +import {OPEN_SERVERS_DROPDOWN, SHOW_NEW_SERVER_MODAL} from 'common/communication'; import {t} from 'common/utils/util'; -import {getTabDisplayName, TabType} from 'common/tabs/TabView'; +import {getViewDisplayName, ViewType} from 'common/views/View'; import {Config} from 'common/config'; import {localizeMessage} from 'main/i18nManager'; @@ -18,7 +18,7 @@ import downloadsManager from 'main/downloadsManager'; import Diagnostics from 'main/diagnostics'; import ViewManager from 'main/views/viewManager'; import SettingsWindow from 'main/windows/settingsWindow'; -import {selectNextTab, selectPreviousTab} from 'main/app/tabs'; +import {selectNextView, selectPreviousView} from 'main/app/views'; import {switchServer} from 'main/app/servers'; export function createTemplate(config: Config, updateManager: UpdateManager) { @@ -233,7 +233,7 @@ export function createTemplate(config: Config, updateManager: UpdateManager) { }], }); - const teams = ServerManager.getOrderedServers(); + const servers = ServerManager.getOrderedServers(); const windowMenu = { id: 'window', label: localizeMessage('main.menus.app.window', '&Window'), @@ -257,25 +257,25 @@ export function createTemplate(config: Config, updateManager: UpdateManager) { label: localizeMessage('main.menus.app.window.showServers', 'Show Servers'), accelerator: `${process.platform === 'darwin' ? 'Cmd+Ctrl' : 'Ctrl+Shift'}+S`, click() { - ipcMain.emit(OPEN_TEAMS_DROPDOWN); + ipcMain.emit(OPEN_SERVERS_DROPDOWN); }, }] : []), - ...teams.slice(0, 9).map((team, i) => { + ...servers.slice(0, 9).map((server, i) => { const items = []; items.push({ - label: team.name, + label: server.name, accelerator: `${process.platform === 'darwin' ? 'Cmd+Ctrl' : 'Ctrl+Shift'}+${i + 1}`, click() { - switchServer(team.id); + switchServer(server.id); }, }); - if (ServerManager.getCurrentServer().id === team.id) { - ServerManager.getOrderedTabsForServer(team.id).slice(0, 9).forEach((tab, i) => { + if (ServerManager.getCurrentServer().id === server.id) { + ServerManager.getOrderedTabsForServer(server.id).slice(0, 9).forEach((view, i) => { items.push({ - label: ` ${localizeMessage(`common.tabs.${tab.type}`, getTabDisplayName(tab.type as TabType))}`, + label: ` ${localizeMessage(`common.views.${view.type}`, getViewDisplayName(view.type as ViewType))}`, accelerator: `CmdOrCtrl+${i + 1}`, click() { - ViewManager.showById(tab.id); + ViewManager.showById(view.id); }, }); }); @@ -285,16 +285,16 @@ export function createTemplate(config: Config, updateManager: UpdateManager) { label: localizeMessage('main.menus.app.window.selectNextTab', 'Select Next Tab'), accelerator: 'Ctrl+Tab', click() { - selectNextTab(); + selectNextView(); }, - enabled: (teams.length > 1), + enabled: (servers.length > 1), }, { label: localizeMessage('main.menus.app.window.selectPreviousTab', 'Select Previous Tab'), accelerator: 'Ctrl+Shift+Tab', click() { - selectPreviousTab(); + selectPreviousView(); }, - enabled: (teams.length > 1), + enabled: (servers.length > 1), }, ...(isMac ? [separatorItem, { role: 'front', label: localizeMessage('main.menus.app.window.bringAllToFront', 'Bring All to Front'), diff --git a/src/main/menus/tray.ts b/src/main/menus/tray.ts index 275299af..748cadcf 100644 --- a/src/main/menus/tray.ts +++ b/src/main/menus/tray.ts @@ -12,13 +12,13 @@ import SettingsWindow from 'main/windows/settingsWindow'; import {switchServer} from 'main/app/servers'; export function createTemplate() { - const teams = ServerManager.getOrderedServers(); + const servers = ServerManager.getOrderedServers(); const template = [ - ...teams.slice(0, 9).map((team) => { + ...servers.slice(0, 9).map((server) => { return { - label: team.name.length > 50 ? `${team.name.slice(0, 50)}...` : team.name, + label: server.name.length > 50 ? `${server.name.slice(0, 50)}...` : server.name, click: () => { - switchServer(team.id); + switchServer(server.id); }, }; }), { diff --git a/src/main/notifications/index.test.js b/src/main/notifications/index.test.js index 8784aa75..d6a0c9a5 100644 --- a/src/main/notifications/index.test.js +++ b/src/main/notifications/index.test.js @@ -76,7 +76,7 @@ jest.mock('macos-notification-state', () => ({ jest.mock('../views/viewManager', () => ({ getViewByWebContentsId: () => ({ id: 'server_id', - tab: { + view: { server: { name: 'server_name', }, @@ -231,7 +231,7 @@ describe('main/notifications', () => { }); }); - it('should switch tab when clicking on notification', () => { + it('should switch view when clicking on notification', () => { displayMention( 'click_test', 'mention_click_body', diff --git a/src/main/notifications/index.ts b/src/main/notifications/index.ts index 315e8bb4..34134f4f 100644 --- a/src/main/notifications/index.ts +++ b/src/main/notifications/index.ts @@ -40,7 +40,7 @@ export function displayMention(title: string, body: string, channel: {id: string if (!view) { return; } - const serverName = view.tab.server.name; + const serverName = view.view.server.name; const options = { title: `${serverName}: ${title}`, diff --git a/src/main/preload/desktopAPI.js b/src/main/preload/desktopAPI.js index 4b128fc6..9a7b2f54 100644 --- a/src/main/preload/desktopAPI.js +++ b/src/main/preload/desktopAPI.js @@ -10,10 +10,10 @@ import { GET_LANGUAGE_INFORMATION, QUIT, OPEN_APP_MENU, - CLOSE_TEAMS_DROPDOWN, - OPEN_TEAMS_DROPDOWN, + CLOSE_SERVERS_DROPDOWN, + OPEN_SERVERS_DROPDOWN, SWITCH_TAB, - CLOSE_TAB, + CLOSE_VIEW, WINDOW_CLOSE, WINDOW_MINIMIZE, WINDOW_MAXIMIZE, @@ -59,8 +59,8 @@ import { DOWNLOADS_DROPDOWN_MENU_OPEN_FILE, UPDATE_DOWNLOADS_DROPDOWN_MENU, REQUEST_DOWNLOADS_DROPDOWN_MENU_INFO, - UPDATE_TEAMS_DROPDOWN, - REQUEST_TEAMS_DROPDOWN_INFO, + UPDATE_SERVERS_DROPDOWN, + REQUEST_SERVERS_DROPDOWN_INFO, RECEIVE_DROPDOWN_MENU_SIZE, SWITCH_SERVER, SHOW_NEW_SERVER_MODAL, @@ -111,10 +111,10 @@ contextBridge.exposeInMainWorld('mas', { contextBridge.exposeInMainWorld('desktop', { quit: (reason, stack) => ipcRenderer.send(QUIT, reason, stack), openAppMenu: () => ipcRenderer.send(OPEN_APP_MENU), - closeTeamsDropdown: () => ipcRenderer.send(CLOSE_TEAMS_DROPDOWN), - openTeamsDropdown: () => ipcRenderer.send(OPEN_TEAMS_DROPDOWN), - switchTab: (tabId) => ipcRenderer.send(SWITCH_TAB, tabId), - closeTab: (tabId) => ipcRenderer.send(CLOSE_TAB, tabId), + closeServersDropdown: () => ipcRenderer.send(CLOSE_SERVERS_DROPDOWN), + openServersDropdown: () => ipcRenderer.send(OPEN_SERVERS_DROPDOWN), + switchTab: (viewId) => ipcRenderer.send(SWITCH_TAB, viewId), + closeView: (viewId) => ipcRenderer.send(CLOSE_VIEW, viewId), closeWindow: () => ipcRenderer.send(WINDOW_CLOSE), minimizeWindow: () => ipcRenderer.send(WINDOW_MINIMIZE), maximizeWindow: () => ipcRenderer.send(WINDOW_MAXIMIZE), @@ -130,7 +130,7 @@ contextBridge.exposeInMainWorld('desktop', { updateConfiguration: (saveQueueItems) => ipcRenderer.send(UPDATE_CONFIGURATION, saveQueueItems), updateServerOrder: (serverOrder) => ipcRenderer.send(UPDATE_SERVER_ORDER, serverOrder), - updateTabOrder: (serverId, tabOrder) => ipcRenderer.send(UPDATE_TAB_ORDER, serverId, tabOrder), + updateTabOrder: (serverId, viewOrder) => ipcRenderer.send(UPDATE_TAB_ORDER, serverId, viewOrder), getLastActive: () => ipcRenderer.invoke(GET_LAST_ACTIVE), getOrderedServers: () => ipcRenderer.invoke(GET_ORDERED_SERVERS), getOrderedTabsForServer: (serverId) => ipcRenderer.invoke(GET_ORDERED_TABS_FOR_SERVER, serverId), @@ -153,7 +153,7 @@ contextBridge.exposeInMainWorld('desktop', { onLoadRetry: (listener) => ipcRenderer.on(LOAD_RETRY, (_, viewId, retry, err, loadUrl) => listener(viewId, retry, err, loadUrl)), onLoadSuccess: (listener) => ipcRenderer.on(LOAD_SUCCESS, (_, viewId) => listener(viewId)), onLoadFailed: (listener) => ipcRenderer.on(LOAD_FAILED, (_, viewId, err, loadUrl) => listener(viewId, err, loadUrl)), - onSetActiveView: (listener) => ipcRenderer.on(SET_ACTIVE_VIEW, (_, serverId, tabId) => listener(serverId, tabId)), + onSetActiveView: (listener) => ipcRenderer.on(SET_ACTIVE_VIEW, (_, serverId, viewId) => listener(serverId, viewId)), onMaximizeChange: (listener) => ipcRenderer.on(MAXIMIZE_CHANGE, (_, maximize) => listener(maximize)), onEnterFullScreen: (listener) => ipcRenderer.on('enter-full-screen', () => listener()), onLeaveFullScreen: (listener) => ipcRenderer.on('leave-full-screen', () => listener()), @@ -162,8 +162,8 @@ contextBridge.exposeInMainWorld('desktop', { onModalClose: (listener) => ipcRenderer.on(MODAL_CLOSE, () => listener()), onToggleBackButton: (listener) => ipcRenderer.on(TOGGLE_BACK_BUTTON, (_, showExtraBar) => listener(showExtraBar)), onUpdateMentions: (listener) => ipcRenderer.on(UPDATE_MENTIONS, (_event, view, mentions, unreads, isExpired) => listener(view, mentions, unreads, isExpired)), - onCloseTeamsDropdown: (listener) => ipcRenderer.on(CLOSE_TEAMS_DROPDOWN, () => listener()), - onOpenTeamsDropdown: (listener) => ipcRenderer.on(OPEN_TEAMS_DROPDOWN, () => listener()), + onCloseServersDropdown: (listener) => ipcRenderer.on(CLOSE_SERVERS_DROPDOWN, () => listener()), + onOpenServersDropdown: (listener) => ipcRenderer.on(OPEN_SERVERS_DROPDOWN, () => listener()), onCloseDownloadsDropdown: (listener) => ipcRenderer.on(CLOSE_DOWNLOADS_DROPDOWN, () => listener()), onOpenDownloadsDropdown: (listener) => ipcRenderer.on(OPEN_DOWNLOADS_DROPDOWN, () => listener()), onShowDownloadsDropdownButtonBadge: (listener) => ipcRenderer.on(SHOW_DOWNLOADS_DROPDOWN_BUTTON_BADGE, () => listener()), @@ -195,29 +195,29 @@ contextBridge.exposeInMainWorld('desktop', { }, serverDropdown: { - requestInfo: () => ipcRenderer.send(REQUEST_TEAMS_DROPDOWN_INFO), + requestInfo: () => ipcRenderer.send(REQUEST_SERVERS_DROPDOWN_INFO), sendSize: (width, height) => ipcRenderer.send(RECEIVE_DROPDOWN_MENU_SIZE, width, height), switchServer: (serverId) => ipcRenderer.send(SWITCH_SERVER, serverId), showNewServerModal: () => ipcRenderer.send(SHOW_NEW_SERVER_MODAL), showEditServerModal: (serverId) => ipcRenderer.send(SHOW_EDIT_SERVER_MODAL, serverId), showRemoveServerModal: (serverId) => ipcRenderer.send(SHOW_REMOVE_SERVER_MODAL, serverId), - onUpdateServerDropdown: (listener) => ipcRenderer.on(UPDATE_TEAMS_DROPDOWN, (_, - teams, - activeTeam, + onUpdateServerDropdown: (listener) => ipcRenderer.on(UPDATE_SERVERS_DROPDOWN, (_, + servers, + activeServer, darkMode, enableServerManagement, - hasGPOTeams, + hasGPOServers, expired, mentions, unreads, windowBounds, ) => listener( - teams, - activeTeam, + servers, + activeServer, darkMode, enableServerManagement, - hasGPOTeams, + hasGPOServers, expired, mentions, unreads, diff --git a/src/main/preload/mattermost.js b/src/main/preload/mattermost.js index 7f65b38e..b389fba3 100644 --- a/src/main/preload/mattermost.js +++ b/src/main/preload/mattermost.js @@ -20,7 +20,7 @@ import { SET_VIEW_OPTIONS, REACT_APP_INITIALIZED, USER_ACTIVITY_UPDATE, - CLOSE_TEAMS_DROPDOWN, + CLOSE_SERVERS_DROPDOWN, BROWSER_HISTORY_BUTTON, BROWSER_HISTORY_PUSH, APP_LOGGED_IN, @@ -272,7 +272,7 @@ function isDownloadLink(el) { } window.addEventListener('click', (e) => { - ipcRenderer.send(CLOSE_TEAMS_DROPDOWN); + ipcRenderer.send(CLOSE_SERVERS_DROPDOWN); const el = e.target; if (!isDownloadLink(el)) { ipcRenderer.send(CLOSE_DOWNLOADS_DROPDOWN); diff --git a/src/main/views/MattermostView.test.js b/src/main/views/MattermostBrowserView.test.js similarity index 77% rename from src/main/views/MattermostView.test.js rename to src/main/views/MattermostBrowserView.test.js index cb577945..e44d77c7 100644 --- a/src/main/views/MattermostView.test.js +++ b/src/main/views/MattermostBrowserView.test.js @@ -6,13 +6,13 @@ import AppState from 'common/appState'; import {LOAD_FAILED, TOGGLE_BACK_BUTTON, UPDATE_TARGET_URL} from 'common/communication'; import {MattermostServer} from 'common/servers/MattermostServer'; -import MessagingTabView from 'common/tabs/MessagingTabView'; +import MessagingView from 'common/views/MessagingView'; import MainWindow from '../windows/mainWindow'; import ContextMenu from '../contextMenu'; import Utils from '../utils'; -import {MattermostView} from './MattermostView'; +import {MattermostBrowserView} from './MattermostBrowserView'; jest.mock('electron', () => ({ app: { @@ -59,12 +59,12 @@ jest.mock('../utils', () => ({ })); const server = new MattermostServer({name: 'server_name', url: 'http://server-1.com'}); -const tabView = new MessagingTabView(server, true); +const view = new MessagingView(server, true); -describe('main/views/MattermostView', () => { +describe('main/views/MattermostBrowserView', () => { describe('load', () => { const window = {on: jest.fn()}; - const mattermostView = new MattermostView(tabView, {}, {}); + const mattermostView = new MattermostBrowserView(view, {}, {}); beforeEach(() => { MainWindow.get.mockReturnValue(window); @@ -74,38 +74,38 @@ describe('main/views/MattermostView', () => { it('should load provided URL when provided', async () => { const promise = Promise.resolve(); - mattermostView.view.webContents.loadURL.mockImplementation(() => promise); + mattermostView.browserView.webContents.loadURL.mockImplementation(() => promise); mattermostView.load('http://server-2.com'); await promise; - expect(mattermostView.view.webContents.loadURL).toBeCalledWith('http://server-2.com/', expect.any(Object)); + expect(mattermostView.browserView.webContents.loadURL).toBeCalledWith('http://server-2.com/', expect.any(Object)); expect(mattermostView.loadSuccess).toBeCalledWith('http://server-2.com/'); }); it('should load server URL when not provided', async () => { const promise = Promise.resolve(); - mattermostView.view.webContents.loadURL.mockImplementation(() => promise); + mattermostView.browserView.webContents.loadURL.mockImplementation(() => promise); mattermostView.load(); await promise; - expect(mattermostView.view.webContents.loadURL).toBeCalledWith('http://server-1.com/', expect.any(Object)); + expect(mattermostView.browserView.webContents.loadURL).toBeCalledWith('http://server-1.com/', expect.any(Object)); expect(mattermostView.loadSuccess).toBeCalledWith('http://server-1.com/'); }); it('should load server URL when bad url provided', async () => { const promise = Promise.resolve(); - mattermostView.view.webContents.loadURL.mockImplementation(() => promise); + mattermostView.browserView.webContents.loadURL.mockImplementation(() => promise); mattermostView.load('a-bad { const error = new Error('test'); const promise = Promise.reject(error); - mattermostView.view.webContents.loadURL.mockImplementation(() => promise); + mattermostView.browserView.webContents.loadURL.mockImplementation(() => promise); mattermostView.load('a-bad { const error = new Error('test'); error.code = 'ERR_CERT_ERROR'; const promise = Promise.reject(error); - mattermostView.view.webContents.loadURL.mockImplementation(() => promise); + mattermostView.browserView.webContents.loadURL.mockImplementation(() => promise); mattermostView.load('a-bad { const window = {on: jest.fn()}; - const mattermostView = new MattermostView(tabView, {}, {}); + const mattermostView = new MattermostBrowserView(view, {}, {}); const retryInBackgroundFn = jest.fn(); beforeEach(() => { jest.useFakeTimers(); MainWindow.get.mockReturnValue(window); - mattermostView.view.webContents.loadURL.mockImplementation(() => Promise.resolve()); + mattermostView.browserView.webContents.loadURL.mockImplementation(() => Promise.resolve()); mattermostView.loadSuccess = jest.fn(); mattermostView.loadRetry = jest.fn(); mattermostView.emit = jest.fn(); @@ -143,16 +143,16 @@ describe('main/views/MattermostView', () => { }); it('should do nothing when webcontents are destroyed', () => { - const webContents = mattermostView.view.webContents; - mattermostView.view.webContents = null; + const webContents = mattermostView.browserView.webContents; + mattermostView.browserView.webContents = null; mattermostView.retry('http://server-1.com')(); expect(mattermostView.loadSuccess).not.toBeCalled(); - mattermostView.view.webContents = webContents; + mattermostView.browserView.webContents = webContents; }); it('should call loadSuccess on successful load', async () => { const promise = Promise.resolve(); - mattermostView.view.webContents.loadURL.mockImplementation(() => promise); + mattermostView.browserView.webContents.loadURL.mockImplementation(() => promise); mattermostView.retry('http://server-1.com')(); await promise; expect(mattermostView.loadSuccess).toBeCalledWith('http://server-1.com'); @@ -162,10 +162,10 @@ describe('main/views/MattermostView', () => { mattermostView.maxRetries = 10; const error = new Error('test'); const promise = Promise.reject(error); - mattermostView.view.webContents.loadURL.mockImplementation(() => promise); + mattermostView.browserView.webContents.loadURL.mockImplementation(() => promise); mattermostView.retry('http://server-1.com')(); await expect(promise).rejects.toThrow(error); - expect(mattermostView.view.webContents.loadURL).toBeCalledWith('http://server-1.com', expect.any(Object)); + expect(mattermostView.browserView.webContents.loadURL).toBeCalledWith('http://server-1.com', expect.any(Object)); expect(mattermostView.loadRetry).toBeCalledWith('http://server-1.com', error); }); @@ -173,12 +173,12 @@ describe('main/views/MattermostView', () => { mattermostView.maxRetries = 0; const error = new Error('test'); const promise = Promise.reject(error); - mattermostView.view.webContents.loadURL.mockImplementation(() => promise); + mattermostView.browserView.webContents.loadURL.mockImplementation(() => promise); mattermostView.retry('http://server-1.com')(); await expect(promise).rejects.toThrow(error); - expect(mattermostView.view.webContents.loadURL).toBeCalledWith('http://server-1.com', expect.any(Object)); + expect(mattermostView.browserView.webContents.loadURL).toBeCalledWith('http://server-1.com', expect.any(Object)); expect(mattermostView.loadRetry).not.toBeCalled(); - expect(MainWindow.sendToRenderer).toBeCalledWith(LOAD_FAILED, mattermostView.tab.id, expect.any(String), expect.any(String)); + expect(MainWindow.sendToRenderer).toBeCalledWith(LOAD_FAILED, mattermostView.view.id, expect.any(String), expect.any(String)); expect(mattermostView.status).toBe(-1); jest.runAllTimers(); expect(retryInBackgroundFn).toBeCalled(); @@ -187,7 +187,7 @@ describe('main/views/MattermostView', () => { describe('goToOffset', () => { const window = {on: jest.fn()}; - const mattermostView = new MattermostView(tabView, {}, {}); + const mattermostView = new MattermostBrowserView(view, {}, {}); mattermostView.reload = jest.fn(); afterEach(() => { @@ -196,18 +196,18 @@ describe('main/views/MattermostView', () => { }); it('should only go to offset if it can', () => { - mattermostView.view.webContents.canGoToOffset.mockReturnValue(false); + mattermostView.browserView.webContents.canGoToOffset.mockReturnValue(false); mattermostView.goToOffset(1); - expect(mattermostView.view.webContents.goToOffset).not.toBeCalled(); + expect(mattermostView.browserView.webContents.goToOffset).not.toBeCalled(); - mattermostView.view.webContents.canGoToOffset.mockReturnValue(true); + mattermostView.browserView.webContents.canGoToOffset.mockReturnValue(true); mattermostView.goToOffset(1); - expect(mattermostView.view.webContents.goToOffset).toBeCalled(); + expect(mattermostView.browserView.webContents.goToOffset).toBeCalled(); }); it('should call reload if an error occurs', () => { - mattermostView.view.webContents.canGoToOffset.mockReturnValue(true); - mattermostView.view.webContents.goToOffset.mockImplementation(() => { + mattermostView.browserView.webContents.canGoToOffset.mockReturnValue(true); + mattermostView.browserView.webContents.goToOffset.mockImplementation(() => { throw new Error('hi'); }); mattermostView.goToOffset(1); @@ -217,8 +217,8 @@ describe('main/views/MattermostView', () => { describe('onLogin', () => { const window = {on: jest.fn()}; - const mattermostView = new MattermostView(tabView, {}, {}); - mattermostView.view.webContents.getURL = jest.fn(); + const mattermostView = new MattermostBrowserView(view, {}, {}); + mattermostView.browserView.webContents.getURL = jest.fn(); mattermostView.reload = jest.fn(); afterEach(() => { @@ -227,19 +227,19 @@ describe('main/views/MattermostView', () => { }); it('should reload view when URL is not on subpath of original server URL', () => { - mattermostView.view.webContents.getURL.mockReturnValue('http://server-2.com/subpath'); + mattermostView.browserView.webContents.getURL.mockReturnValue('http://server-2.com/subpath'); mattermostView.onLogin(true); expect(mattermostView.reload).toHaveBeenCalled(); }); it('should not reload if URLs are matching', () => { - mattermostView.view.webContents.getURL.mockReturnValue('http://server-1.com'); + mattermostView.browserView.webContents.getURL.mockReturnValue('http://server-1.com'); mattermostView.onLogin(true); expect(mattermostView.reload).not.toHaveBeenCalled(); }); it('should not reload if URL is subpath of server URL', () => { - mattermostView.view.webContents.getURL.mockReturnValue('http://server-1.com/subpath'); + mattermostView.browserView.webContents.getURL.mockReturnValue('http://server-1.com/subpath'); mattermostView.onLogin(true); expect(mattermostView.reload).not.toHaveBeenCalled(); }); @@ -247,7 +247,7 @@ describe('main/views/MattermostView', () => { describe('loadSuccess', () => { const window = {on: jest.fn()}; - const mattermostView = new MattermostView(tabView, {}, {}); + const mattermostView = new MattermostBrowserView(view, {}, {}); beforeEach(() => { jest.useFakeTimers(); @@ -275,7 +275,7 @@ describe('main/views/MattermostView', () => { describe('show', () => { const window = {addBrowserView: jest.fn(), removeBrowserView: jest.fn(), on: jest.fn(), setTopBrowserView: jest.fn()}; - const mattermostView = new MattermostView(tabView, {}, {}); + const mattermostView = new MattermostBrowserView(view, {}, {}); beforeEach(() => { jest.useFakeTimers(); @@ -293,7 +293,7 @@ describe('main/views/MattermostView', () => { it('should add browser view to window and set bounds when request is true and view not currently visible', () => { mattermostView.isVisible = false; mattermostView.show(); - expect(window.addBrowserView).toBeCalledWith(mattermostView.view); + expect(window.addBrowserView).toBeCalledWith(mattermostView.browserView); expect(mattermostView.setBounds).toBeCalled(); expect(mattermostView.isVisible).toBe(true); }); @@ -314,7 +314,7 @@ describe('main/views/MattermostView', () => { describe('hide', () => { const window = {addBrowserView: jest.fn(), removeBrowserView: jest.fn(), on: jest.fn(), setTopBrowserView: jest.fn()}; - const mattermostView = new MattermostView(tabView, {}, {}); + const mattermostView = new MattermostBrowserView(view, {}, {}); beforeEach(() => { MainWindow.get.mockReturnValue(window); @@ -323,7 +323,7 @@ describe('main/views/MattermostView', () => { it('should remove browser view', () => { mattermostView.isVisible = true; mattermostView.hide(); - expect(window.removeBrowserView).toBeCalledWith(mattermostView.view); + expect(window.removeBrowserView).toBeCalledWith(mattermostView.browserView); expect(mattermostView.isVisible).toBe(false); }); @@ -336,7 +336,7 @@ describe('main/views/MattermostView', () => { describe('updateHistoryButton', () => { const window = {on: jest.fn()}; - const mattermostView = new MattermostView(tabView, {}, {}); + const mattermostView = new MattermostBrowserView(view, {}, {}); beforeEach(() => { MainWindow.get.mockReturnValue(window); @@ -345,7 +345,7 @@ describe('main/views/MattermostView', () => { it('should erase history and set isAtRoot when navigating to root URL', () => { mattermostView.atRoot = false; mattermostView.updateHistoryButton(); - expect(mattermostView.view.webContents.clearHistory).toHaveBeenCalled(); + expect(mattermostView.browserView.webContents.clearHistory).toHaveBeenCalled(); expect(mattermostView.isAtRoot).toBe(true); }); }); @@ -362,22 +362,22 @@ describe('main/views/MattermostView', () => { }); it('should remove browser view from window', () => { - const mattermostView = new MattermostView(tabView, {}, {}); - mattermostView.view.webContents.destroy = jest.fn(); + const mattermostView = new MattermostBrowserView(view, {}, {}); + mattermostView.browserView.webContents.destroy = jest.fn(); mattermostView.destroy(); - expect(window.removeBrowserView).toBeCalledWith(mattermostView.view); + expect(window.removeBrowserView).toBeCalledWith(mattermostView.browserView); }); it('should clear mentions', () => { - const mattermostView = new MattermostView(tabView, {}, {}); - mattermostView.view.webContents.destroy = jest.fn(); + const mattermostView = new MattermostBrowserView(view, {}, {}); + mattermostView.browserView.webContents.destroy = jest.fn(); mattermostView.destroy(); - expect(AppState.clear).toBeCalledWith(mattermostView.tab.id); + expect(AppState.clear).toBeCalledWith(mattermostView.view.id); }); it('should clear outstanding timeouts', () => { - const mattermostView = new MattermostView(tabView, {}, {}); - mattermostView.view.webContents.destroy = jest.fn(); + const mattermostView = new MattermostBrowserView(view, {}, {}); + mattermostView.browserView.webContents.destroy = jest.fn(); const spy = jest.spyOn(global, 'clearTimeout'); mattermostView.retryLoad = 999; mattermostView.removeLoading = 1000; @@ -388,7 +388,7 @@ describe('main/views/MattermostView', () => { describe('handleInputEvents', () => { const window = {on: jest.fn()}; - const mattermostView = new MattermostView(tabView, {}, {}); + const mattermostView = new MattermostBrowserView(view, {}, {}); it('should open three dot menu on pressing Alt', () => { MainWindow.get.mockReturnValue(window); @@ -413,7 +413,7 @@ describe('main/views/MattermostView', () => { describe('handleDidNavigate', () => { const window = {on: jest.fn()}; - const mattermostView = new MattermostView(tabView, {}, {}); + const mattermostView = new MattermostBrowserView(view, {}, {}); beforeEach(() => { MainWindow.get.mockReturnValue(window); @@ -435,7 +435,7 @@ describe('main/views/MattermostView', () => { describe('handleUpdateTarget', () => { const window = {on: jest.fn()}; - const mattermostView = new MattermostView(tabView, {}, {}); + const mattermostView = new MattermostBrowserView(view, {}, {}); beforeEach(() => { MainWindow.get.mockReturnValue(window); @@ -466,16 +466,16 @@ describe('main/views/MattermostView', () => { }); describe('updateMentionsFromTitle', () => { - const mattermostView = new MattermostView(tabView, {}, {}); + const mattermostView = new MattermostBrowserView(view, {}, {}); it('should parse mentions from title', () => { mattermostView.updateMentionsFromTitle('(7) Mattermost'); - expect(AppState.updateMentions).toHaveBeenCalledWith(mattermostView.tab.id, 7); + expect(AppState.updateMentions).toHaveBeenCalledWith(mattermostView.view.id, 7); }); it('should parse unreads from title', () => { mattermostView.updateMentionsFromTitle('* Mattermost'); - expect(AppState.updateMentions).toHaveBeenCalledWith(mattermostView.tab.id, 0); + expect(AppState.updateMentions).toHaveBeenCalledWith(mattermostView.view.id, 0); }); }); }); diff --git a/src/main/views/MattermostView.ts b/src/main/views/MattermostBrowserView.ts similarity index 76% rename from src/main/views/MattermostView.ts rename to src/main/views/MattermostBrowserView.ts index 0b336cc1..5506fb77 100644 --- a/src/main/views/MattermostView.ts +++ b/src/main/views/MattermostBrowserView.ts @@ -23,7 +23,7 @@ import { import ServerManager from 'common/servers/serverManager'; import {Logger} from 'common/log'; import {isInternalURL, parseURL} from 'common/utils/url'; -import {TabView} from 'common/tabs/TabView'; +import {MattermostView} from 'common/views/View'; import MainWindow from 'main/windows/mainWindow'; @@ -42,12 +42,12 @@ enum Status { const MENTIONS_GROUP = 2; const titleParser = /(\((\d+)\) )?(\* )?/g; -export class MattermostView extends EventEmitter { - tab: TabView; +export class MattermostBrowserView extends EventEmitter { + view: MattermostView; isVisible: boolean; private log: Logger; - private view: BrowserView; + private browserView: BrowserView; private loggedIn: boolean; private atRoot: boolean; private options: BrowserViewConstructorOptions; @@ -58,9 +58,9 @@ export class MattermostView extends EventEmitter { private maxRetries: number; private altPressStatus: boolean; - constructor(tab: TabView, options: BrowserViewConstructorOptions) { + constructor(view: MattermostView, options: BrowserViewConstructorOptions) { super(); - this.tab = tab; + this.view = view; const preload = getLocalPreload('preload.js'); this.options = Object.assign({}, options); @@ -75,24 +75,24 @@ export class MattermostView extends EventEmitter { this.isVisible = false; this.loggedIn = false; this.atRoot = true; - this.view = new BrowserView(this.options); + this.browserView = new BrowserView(this.options); this.resetLoadingStatus(); - this.log = ServerManager.getViewLog(this.id, 'MattermostView'); + this.log = ServerManager.getViewLog(this.id, 'MattermostBrowserView'); this.log.verbose('View created'); - this.view.webContents.on('did-finish-load', this.handleDidFinishLoad); - this.view.webContents.on('page-title-updated', this.handleTitleUpdate); - this.view.webContents.on('page-favicon-updated', this.handleFaviconUpdate); - this.view.webContents.on('update-target-url', this.handleUpdateTarget); - this.view.webContents.on('did-navigate', this.handleDidNavigate); + this.browserView.webContents.on('did-finish-load', this.handleDidFinishLoad); + this.browserView.webContents.on('page-title-updated', this.handleTitleUpdate); + this.browserView.webContents.on('page-favicon-updated', this.handleFaviconUpdate); + this.browserView.webContents.on('update-target-url', this.handleUpdateTarget); + this.browserView.webContents.on('did-navigate', this.handleDidNavigate); if (process.platform !== 'darwin') { - this.view.webContents.on('before-input-event', this.handleInputEvents); + this.browserView.webContents.on('before-input-event', this.handleInputEvents); } - WebContentsEventManager.addWebContentsEventListeners(this.view.webContents); + WebContentsEventManager.addWebContentsEventListeners(this.browserView.webContents); - this.contextMenu = new ContextMenu({}, this.view); + this.contextMenu = new ContextMenu({}, this.browserView); this.maxRetries = MAX_SERVER_RETRIES; this.altPressStatus = false; @@ -105,7 +105,7 @@ export class MattermostView extends EventEmitter { } get id() { - return this.tab.id; + return this.view.id; } get isAtRoot() { return this.atRoot; @@ -114,10 +114,10 @@ export class MattermostView extends EventEmitter { return this.loggedIn; } get currentURL() { - return parseURL(this.view.webContents.getURL()); + return parseURL(this.browserView.webContents.getURL()); } get webContentsId() { - return this.view.webContents.id; + return this.browserView.webContents.id; } onLogin = (loggedIn: boolean) => { @@ -127,19 +127,19 @@ export class MattermostView extends EventEmitter { this.loggedIn = loggedIn; - // If we're logging in from a different tab, force a reload + // If we're logging in from a different view, force a reload if (loggedIn && - this.currentURL?.toString() !== this.tab.url.toString() && - !this.currentURL?.toString().startsWith(this.tab.url.toString()) + this.currentURL?.toString() !== this.view.url.toString() && + !this.currentURL?.toString().startsWith(this.view.url.toString()) ) { this.reload(); } } goToOffset = (offset: number) => { - if (this.view.webContents.canGoToOffset(offset)) { + if (this.browserView.webContents.canGoToOffset(offset)) { try { - this.view.webContents.goToOffset(offset); + this.browserView.webContents.goToOffset(offset); this.updateHistoryButton(); } catch (error) { this.log.error(error); @@ -149,17 +149,17 @@ export class MattermostView extends EventEmitter { } updateHistoryButton = () => { - if (this.currentURL?.toString() === this.tab.url.toString()) { - this.view.webContents.clearHistory(); + if (this.currentURL?.toString() === this.view.url.toString()) { + this.browserView.webContents.clearHistory(); this.atRoot = true; } else { this.atRoot = false; } - this.view.webContents.send(BROWSER_HISTORY_BUTTON, this.view.webContents.canGoBack(), this.view.webContents.canGoForward()); + this.browserView.webContents.send(BROWSER_HISTORY_BUTTON, this.browserView.webContents.canGoBack(), this.browserView.webContents.canGoForward()); } load = (someURL?: URL | string) => { - if (!this.tab) { + if (!this.browserView) { return; } @@ -170,13 +170,13 @@ export class MattermostView extends EventEmitter { loadURL = parsedURL.toString(); } else { this.log.error('Cannot parse provided url, using current server url', someURL); - loadURL = this.tab.url.toString(); + loadURL = this.view.url.toString(); } } else { - loadURL = this.tab.url.toString(); + loadURL = this.view.url.toString(); } this.log.verbose(`Loading ${loadURL}`); - const loading = this.view.webContents.loadURL(loadURL, {userAgent: composeUserAgent()}); + const loading = this.browserView.webContents.loadURL(loadURL, {userAgent: composeUserAgent()}); loading.then(this.loadSuccess(loadURL)).catch((err) => { if (err.code && err.code.startsWith('ERR_CERT')) { MainWindow.sendToRenderer(LOAD_FAILED, this.id, err.toString(), loadURL.toString()); @@ -205,9 +205,9 @@ export class MattermostView extends EventEmitter { return; } this.isVisible = true; - mainWindow.addBrowserView(this.view); - mainWindow.setTopBrowserView(this.view); - this.setBounds(getWindowBoundaries(mainWindow, shouldHaveBackBar(this.tab.url || '', this.currentURL))); + mainWindow.addBrowserView(this.browserView); + mainWindow.setTopBrowserView(this.browserView); + this.setBounds(getWindowBoundaries(mainWindow, shouldHaveBackBar(this.view.url || '', this.currentURL))); if (this.status === Status.READY) { this.focus(); } @@ -216,7 +216,7 @@ export class MattermostView extends EventEmitter { hide = () => { if (this.isVisible) { this.isVisible = false; - MainWindow.get()?.removeBrowserView(this.view); + MainWindow.get()?.removeBrowserView(this.browserView); } } @@ -226,27 +226,27 @@ export class MattermostView extends EventEmitter { } getBounds = () => { - return this.view.getBounds(); + return this.browserView.getBounds(); } openFind = () => { - this.view.webContents.sendInputEvent({type: 'keyDown', keyCode: 'F', modifiers: [process.platform === 'darwin' ? 'cmd' : 'ctrl', 'shift']}); + this.browserView.webContents.sendInputEvent({type: 'keyDown', keyCode: 'F', modifiers: [process.platform === 'darwin' ? 'cmd' : 'ctrl', 'shift']}); } setBounds = (boundaries: Electron.Rectangle) => { - this.view.setBounds(boundaries); + this.browserView.setBounds(boundaries); } destroy = () => { WebContentsEventManager.removeWebContentsListeners(this.webContentsId); AppState.clear(this.id); - MainWindow.get()?.removeBrowserView(this.view); + MainWindow.get()?.removeBrowserView(this.browserView); // workaround to eliminate zombie processes // https://github.com/mattermost/desktop/pull/1519 // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore - this.view.webContents.destroy(); + this.browserView.webContents.destroy(); this.isVisible = false; if (this.retryLoad) { @@ -293,7 +293,7 @@ export class MattermostView extends EventEmitter { } openDevTools = () => { - this.view.webContents.openDevTools({mode: 'detach'}); + this.browserView.webContents.openDevTools({mode: 'detach'}); } /** @@ -301,16 +301,16 @@ export class MattermostView extends EventEmitter { */ sendToRenderer = (channel: string, ...args: any[]) => { - this.view.webContents.send(channel, ...args); + this.browserView.webContents.send(channel, ...args); } isDestroyed = () => { - return this.view.webContents.isDestroyed(); + return this.browserView.webContents.isDestroyed(); } focus = () => { - if (this.view.webContents) { - this.view.webContents.focus(); + if (this.browserView.webContents) { + this.browserView.webContents.focus(); } else { this.log.warn('trying to focus the browserview, but it doesn\'t yet have webcontents.'); } @@ -361,7 +361,7 @@ export class MattermostView extends EventEmitter { // if favicon is null, it will affect appState, but won't be memoized private findUnreadState = (favicon: string | null) => { try { - this.view.webContents.send(IS_UNREAD, favicon, this.id); + this.browserView.webContents.send(IS_UNREAD, favicon, this.id); } catch (err: any) { this.log.error('There was an error trying to request the unread state', err); } @@ -388,17 +388,17 @@ export class MattermostView extends EventEmitter { private retry = (loadURL: string) => { return () => { // window was closed while retrying - if (!this.view || !this.view.webContents) { + if (!this.browserView || !this.browserView.webContents) { return; } - const loading = this.view.webContents.loadURL(loadURL, {userAgent: composeUserAgent()}); + const loading = this.browserView.webContents.loadURL(loadURL, {userAgent: composeUserAgent()}); loading.then(this.loadSuccess(loadURL)).catch((err) => { if (this.maxRetries-- > 0) { this.loadRetry(loadURL, err); } else { MainWindow.sendToRenderer(LOAD_FAILED, this.id, err.toString(), loadURL.toString()); this.emit(LOAD_FAILED, this.id, err.toString(), loadURL.toString()); - this.log.info(`Couldn't establish a connection with ${loadURL}, will continue to retry in the background`, err); + this.log.info(`Couldn't esviewlish a connection with ${loadURL}, will continue to retry in the background`, err); this.status = Status.ERROR; this.retryLoad = setTimeout(this.retryInBackground(loadURL), RELOAD_INTERVAL); } @@ -409,10 +409,10 @@ export class MattermostView extends EventEmitter { private retryInBackground = (loadURL: string) => { return () => { // window was closed while retrying - if (!this.view || !this.view.webContents) { + if (!this.browserView || !this.browserView.webContents) { return; } - const loading = this.view.webContents.loadURL(loadURL, {userAgent: composeUserAgent()}); + const loading = this.browserView.webContents.loadURL(loadURL, {userAgent: composeUserAgent()}); loading.then(this.loadSuccess(loadURL)).catch(() => { this.retryLoad = setTimeout(this.retryInBackground(loadURL), RELOAD_INTERVAL); }); @@ -431,7 +431,7 @@ export class MattermostView extends EventEmitter { MainWindow.sendToRenderer(LOAD_SUCCESS, this.id); this.maxRetries = MAX_SERVER_RETRIES; if (this.status === Status.LOADING) { - this.updateMentionsFromTitle(this.view.webContents.getTitle()); + this.updateMentionsFromTitle(this.browserView.webContents.getTitle()); this.findUnreadState(null); } this.status = Status.WAITING_MM; @@ -439,7 +439,7 @@ export class MattermostView extends EventEmitter { this.emit(LOAD_SUCCESS, this.id, loadURL); const mainWindow = MainWindow.get(); if (mainWindow && this.currentURL) { - this.setBounds(getWindowBoundaries(mainWindow, shouldHaveBackBar(this.tab.url || '', this.currentURL))); + this.setBounds(getWindowBoundaries(mainWindow, shouldHaveBackBar(this.view.url || '', this.currentURL))); } }; } @@ -453,13 +453,13 @@ export class MattermostView extends EventEmitter { // wait for screen to truly finish loading before sending the message down const timeout = setInterval(() => { - if (!this.view.webContents) { + if (!this.browserView.webContents) { return; } - if (!this.view.webContents.isLoading()) { + if (!this.browserView.webContents.isLoading()) { try { - this.view.webContents.send(SET_VIEW_OPTIONS, this.id, this.tab.shouldNotify); + this.browserView.webContents.send(SET_VIEW_OPTIONS, this.id, this.view.shouldNotify); clearTimeout(timeout); } catch (e) { this.log.error('failed to send view options to view'); @@ -480,7 +480,7 @@ export class MattermostView extends EventEmitter { return; } - if (shouldHaveBackBar(this.tab.url || '', parsedURL)) { + if (shouldHaveBackBar(this.view.url || '', parsedURL)) { this.setBounds(getWindowBoundaries(mainWindow, true)); MainWindow.sendToRenderer(TOGGLE_BACK_BUTTON, true); this.log.debug('show back button'); @@ -494,7 +494,7 @@ export class MattermostView extends EventEmitter { private handleUpdateTarget = (e: Event, url: string) => { this.log.silly('handleUpdateTarget', url); const parsedURL = parseURL(url); - if (parsedURL && isInternalURL(parsedURL, this.tab.server.url)) { + if (parsedURL && isInternalURL(parsedURL, this.view.server.url)) { this.emit(UPDATE_TARGET_URL); } else { this.emit(UPDATE_TARGET_URL, url); @@ -502,7 +502,7 @@ export class MattermostView extends EventEmitter { } private handleServerWasModified = (serverIds: string) => { - if (serverIds.includes(this.tab.server.id)) { + if (serverIds.includes(this.view.server.id)) { this.reload(); } } diff --git a/src/main/views/teamDropdownView.test.js b/src/main/views/serverDropdownView.test.js similarity index 61% rename from src/main/views/teamDropdownView.test.js rename to src/main/views/serverDropdownView.test.js index ac3888fd..1ee96eb7 100644 --- a/src/main/views/teamDropdownView.test.js +++ b/src/main/views/serverDropdownView.test.js @@ -7,7 +7,7 @@ import {TAB_BAR_HEIGHT, THREE_DOT_MENU_WIDTH, THREE_DOT_MENU_WIDTH_MAC, MENU_SHA import MainWindow from 'main/windows/mainWindow'; -import {TeamDropdownView} from './teamDropdownView'; +import {ServerDropdownView} from './serverDropdownView'; jest.mock('main/utils', () => ({ getLocalPreload: (file) => file, @@ -38,36 +38,36 @@ jest.mock('common/servers/serverManager', () => ({ getOrderedServers: jest.fn().mockReturnValue([]), })); -describe('main/views/teamDropdownView', () => { +describe('main/views/serverDropdownView', () => { describe('getBounds', () => { beforeEach(() => { MainWindow.getBounds.mockReturnValue({width: 500, height: 400, x: 0, y: 0}); }); - const teamDropdownView = new TeamDropdownView(); + const serverDropdownView = new ServerDropdownView(); if (process.platform === 'darwin') { it('should account for three dot menu, tab bar and shadow', () => { - expect(teamDropdownView.getBounds(400, 300)).toStrictEqual({x: THREE_DOT_MENU_WIDTH_MAC - MENU_SHADOW_WIDTH, y: TAB_BAR_HEIGHT - MENU_SHADOW_WIDTH, width: 400, height: 300}); + expect(serverDropdownView.getBounds(400, 300)).toStrictEqual({x: THREE_DOT_MENU_WIDTH_MAC - MENU_SHADOW_WIDTH, y: TAB_BAR_HEIGHT - MENU_SHADOW_WIDTH, width: 400, height: 300}); }); } else { it('should account for three dot menu, tab bar and shadow', () => { - expect(teamDropdownView.getBounds(400, 300)).toStrictEqual({x: THREE_DOT_MENU_WIDTH - MENU_SHADOW_WIDTH, y: TAB_BAR_HEIGHT - MENU_SHADOW_WIDTH, width: 400, height: 300}); + expect(serverDropdownView.getBounds(400, 300)).toStrictEqual({x: THREE_DOT_MENU_WIDTH - MENU_SHADOW_WIDTH, y: TAB_BAR_HEIGHT - MENU_SHADOW_WIDTH, width: 400, height: 300}); }); } }); it('should change the view bounds based on open/closed state', () => { - const teamDropdownView = new TeamDropdownView(); - teamDropdownView.view = { + const serverDropdownView = new ServerDropdownView(); + serverDropdownView.view = { setBounds: jest.fn(), webContents: { focus: jest.fn(), }, }; - teamDropdownView.bounds = {width: 400, height: 300}; - teamDropdownView.handleOpen(); - expect(teamDropdownView.view.setBounds).toBeCalledWith(teamDropdownView.bounds); - teamDropdownView.handleClose(); - expect(teamDropdownView.view.setBounds).toBeCalledWith({width: 0, height: 0, x: expect.any(Number), y: expect.any(Number)}); + serverDropdownView.bounds = {width: 400, height: 300}; + serverDropdownView.handleOpen(); + expect(serverDropdownView.view.setBounds).toBeCalledWith(serverDropdownView.bounds); + serverDropdownView.handleClose(); + expect(serverDropdownView.view.setBounds).toBeCalledWith({width: 0, height: 0, x: expect.any(Number), y: expect.any(Number)}); }); }); diff --git a/src/main/views/teamDropdownView.ts b/src/main/views/serverDropdownView.ts similarity index 80% rename from src/main/views/teamDropdownView.ts rename to src/main/views/serverDropdownView.ts index 8b1626c4..92d5bf02 100644 --- a/src/main/views/teamDropdownView.ts +++ b/src/main/views/serverDropdownView.ts @@ -3,16 +3,16 @@ import {BrowserView, ipcMain, IpcMainEvent} from 'electron'; -import {MattermostTeam} from 'types/config'; +import {UniqueServer} from 'types/config'; import AppState from 'common/appState'; import { - CLOSE_TEAMS_DROPDOWN, + CLOSE_SERVERS_DROPDOWN, EMIT_CONFIGURATION, - OPEN_TEAMS_DROPDOWN, - UPDATE_TEAMS_DROPDOWN, + OPEN_SERVERS_DROPDOWN, + UPDATE_SERVERS_DROPDOWN, UPDATE_APPSTATE, - REQUEST_TEAMS_DROPDOWN_INFO, + REQUEST_SERVERS_DROPDOWN_INFO, RECEIVE_DROPDOWN_MENU_SIZE, SERVERS_UPDATE, MAIN_WINDOW_CREATED, @@ -27,12 +27,12 @@ import {getLocalPreload, getLocalURLString} from 'main/utils'; import MainWindow from '../windows/mainWindow'; -const log = new Logger('TeamDropdownView'); +const log = new Logger('ServerDropdownView'); -export class TeamDropdownView { +export class ServerDropdownView { private view?: BrowserView; - private teams: MattermostTeam[]; - private hasGPOTeams: boolean; + private servers: UniqueServer[]; + private hasGPOServers: boolean; private isOpen: boolean; private bounds: Electron.Rectangle; @@ -43,8 +43,8 @@ export class TeamDropdownView { private windowBounds?: Electron.Rectangle; constructor() { - this.teams = []; - this.hasGPOTeams = false; + this.servers = []; + this.hasGPOServers = false; this.isOpen = false; this.bounds = this.getBounds(0, 0); @@ -55,12 +55,12 @@ export class TeamDropdownView { MainWindow.on(MAIN_WINDOW_CREATED, this.init); MainWindow.on(MAIN_WINDOW_RESIZED, this.updateWindowBounds); - ipcMain.on(OPEN_TEAMS_DROPDOWN, this.handleOpen); - ipcMain.on(CLOSE_TEAMS_DROPDOWN, this.handleClose); + ipcMain.on(OPEN_SERVERS_DROPDOWN, this.handleOpen); + ipcMain.on(CLOSE_SERVERS_DROPDOWN, this.handleClose); ipcMain.on(RECEIVE_DROPDOWN_MENU_SIZE, this.handleReceivedMenuSize); ipcMain.on(EMIT_CONFIGURATION, this.updateDropdown); - ipcMain.on(REQUEST_TEAMS_DROPDOWN_INFO, this.updateDropdown); + ipcMain.on(REQUEST_SERVERS_DROPDOWN_INFO, this.updateDropdown); AppState.on(UPDATE_APPSTATE, this.updateMentions); ServerManager.on(SERVERS_UPDATE, this.updateServers); @@ -84,7 +84,7 @@ export class TeamDropdownView { }}); this.view.webContents.loadURL(getLocalURLString('dropdown.html')); - this.setOrderedTeams(); + this.setOrderedServers(); this.windowBounds = MainWindow.getBounds(); this.updateDropdown(); MainWindow.get()?.addBrowserView(this.view); @@ -94,13 +94,13 @@ export class TeamDropdownView { log.silly('updateDropdown'); this.view?.webContents.send( - UPDATE_TEAMS_DROPDOWN, - this.teams, + UPDATE_SERVERS_DROPDOWN, + this.servers, Config.darkMode, this.windowBounds, ServerManager.hasServers() ? ServerManager.getCurrentServer().id : undefined, Config.enableServerManagement, - this.hasGPOTeams, + this.hasGPOServers, this.expired, this.mentions, this.unreads, @@ -108,7 +108,7 @@ export class TeamDropdownView { } private updateServers = () => { - this.setOrderedTeams(); + this.setOrderedServers(); this.updateDropdown(); } @@ -137,7 +137,7 @@ export class TeamDropdownView { this.view.setBounds(this.bounds); MainWindow.get()?.setTopBrowserView(this.view); this.view.webContents.focus(); - MainWindow.sendToRenderer(OPEN_TEAMS_DROPDOWN); + MainWindow.sendToRenderer(OPEN_SERVERS_DROPDOWN); this.isOpen = true; } @@ -145,7 +145,7 @@ export class TeamDropdownView { log.debug('handleClose'); this.view?.setBounds(this.getBounds(0, 0)); - MainWindow.sendToRenderer(CLOSE_TEAMS_DROPDOWN); + MainWindow.sendToRenderer(CLOSE_SERVERS_DROPDOWN); this.isOpen = false; } @@ -174,7 +174,7 @@ export class TeamDropdownView { private reduceNotifications = (inputMap: Map, items: Map, modifier: (base?: T, value?: T) => T) => { inputMap.clear(); return [...items.keys()].reduce((map, key) => { - const view = ServerManager.getTab(key); + const view = ServerManager.getView(key); if (!view) { return map; } @@ -183,11 +183,11 @@ export class TeamDropdownView { }, inputMap); } - private setOrderedTeams = () => { - this.teams = ServerManager.getOrderedServers().map((team) => team.toMattermostTeam()); - this.hasGPOTeams = this.teams.some((srv) => srv.isPredefined); + private setOrderedServers = () => { + this.servers = ServerManager.getOrderedServers().map((server) => server.toUniqueServer()); + this.hasGPOServers = this.servers.some((srv) => srv.isPredefined); } } -const teamDropdownView = new TeamDropdownView(); -export default teamDropdownView; +const serverDropdownView = new ServerDropdownView(); +export default serverDropdownView; diff --git a/src/main/views/viewManager.test.js b/src/main/views/viewManager.test.js index a1d57b48..e164f73e 100644 --- a/src/main/views/viewManager.test.js +++ b/src/main/views/viewManager.test.js @@ -7,13 +7,13 @@ import {dialog} from 'electron'; import {BROWSER_HISTORY_PUSH, LOAD_SUCCESS, SET_ACTIVE_VIEW} from 'common/communication'; -import {TAB_MESSAGING} from 'common/tabs/TabView'; +import {TAB_MESSAGING} from 'common/views/View'; import ServerManager from 'common/servers/serverManager'; import urlUtils from 'common/utils/url'; import MainWindow from 'main/windows/mainWindow'; -import {MattermostView} from './MattermostView'; +import {MattermostBrowserView} from './MattermostBrowserView'; import {ViewManager} from './viewManager'; import LoadingScreen from './loadingScreen'; @@ -30,12 +30,9 @@ jest.mock('electron', () => ({ handle: jest.fn(), }, })); -jest.mock('common/config', () => ({ - teams: [], -})); -jest.mock('common/tabs/TabView', () => ({ - getTabViewName: jest.fn((a, b) => `${a}-${b}`), - TAB_MESSAGING: 'tab', +jest.mock('common/views/View', () => ({ + getViewName: jest.fn((a, b) => `${a}-${b}`), + TAB_MESSAGING: 'view', })); jest.mock('common/servers/MattermostServer', () => ({ @@ -79,7 +76,7 @@ jest.mock('common/servers/serverManager', () => ({ getLastActiveServer: jest.fn(), getLastActiveTabForServer: jest.fn(), updateLastActive: jest.fn(), - lookupTabByURL: jest.fn(), + lookupViewByURL: jest.fn(), getRemoteInfo: jest.fn(), on: jest.fn(), getServerLog: () => ({ @@ -100,8 +97,8 @@ jest.mock('common/servers/serverManager', () => ({ }), })); -jest.mock('./MattermostView', () => ({ - MattermostView: jest.fn(), +jest.mock('./MattermostBrowserView', () => ({ + MattermostBrowserView: jest.fn(), })); jest.mock('./modalManager', () => ({ @@ -121,12 +118,12 @@ describe('main/views/viewManager', () => { beforeEach(() => { viewManager.showById = jest.fn(); MainWindow.get.mockReturnValue({}); - MattermostView.mockImplementation((tab) => ({ + MattermostBrowserView.mockImplementation((view) => ({ on: jest.fn(), load: loadFn, once: onceFn, destroy: destroyFn, - id: tab.id, + id: view.id, })); }); @@ -136,21 +133,21 @@ describe('main/views/viewManager', () => { viewManager.views = new Map(); }); - it('should add closed tabs to closedViews', () => { - viewManager.loadView({id: 'server1'}, {id: 'tab1', isOpen: false}); - expect(viewManager.closedViews.has('tab1')).toBe(true); + it('should add closed views to closedViews', () => { + viewManager.loadView({id: 'server1'}, {id: 'view1', isOpen: false}); + expect(viewManager.closedViews.has('view1')).toBe(true); }); - it('should remove from remove from closedViews when the tab is open', () => { - viewManager.closedViews.set('tab1', {}); - expect(viewManager.closedViews.has('tab1')).toBe(true); - viewManager.loadView({id: 'server1'}, {id: 'tab1', isOpen: true}); - expect(viewManager.closedViews.has('tab1')).toBe(false); + it('should remove from remove from closedViews when the view is open', () => { + viewManager.closedViews.set('view1', {}); + expect(viewManager.closedViews.has('view1')).toBe(true); + viewManager.loadView({id: 'server1'}, {id: 'view1', isOpen: true}); + expect(viewManager.closedViews.has('view1')).toBe(false); }); it('should add view to views map and add listeners', () => { - viewManager.loadView({id: 'server1'}, {id: 'tab1', isOpen: true}, 'http://server-1.com/subpath'); - expect(viewManager.views.has('tab1')).toBe(true); + viewManager.loadView({id: 'server1'}, {id: 'view1', isOpen: true}, 'http://server-1.com/subpath'); + expect(viewManager.views.has('view1')).toBe(true); expect(onceFn).toHaveBeenCalledWith(LOAD_SUCCESS, viewManager.activateView); expect(loadFn).toHaveBeenCalledWith('http://server-1.com/subpath'); }); @@ -173,14 +170,14 @@ describe('main/views/viewManager', () => { const onceFn = jest.fn(); const loadFn = jest.fn(); const destroyFn = jest.fn(); - MattermostView.mockImplementation((tab) => ({ + MattermostBrowserView.mockImplementation((view) => ({ on: jest.fn(), load: loadFn, once: onceFn, destroy: destroyFn, - id: tab.id, + id: view.id, updateServerInfo: jest.fn(), - tab, + view, })); }); @@ -193,45 +190,45 @@ describe('main/views/viewManager', () => { it('should recycle existing views', () => { const makeSpy = jest.spyOn(viewManager, 'makeView'); - const view = new MattermostView({ - id: 'tab1', + const view = new MattermostBrowserView({ + id: 'view1', server: { id: 'server1', }, }); - viewManager.views.set('tab1', view); + viewManager.views.set('view1', view); ServerManager.getAllServers.mockReturnValue([{ id: 'server1', url: new URL('http://server1.com'), }]); ServerManager.getOrderedTabsForServer.mockReturnValue([ { - id: 'tab1', + id: 'view1', isOpen: true, }, ]); viewManager.handleReloadConfiguration(); - expect(viewManager.views.get('tab1')).toBe(view); + expect(viewManager.views.get('view1')).toBe(view); expect(makeSpy).not.toHaveBeenCalled(); makeSpy.mockRestore(); }); - it('should close tabs that arent open', () => { + it('should close views that arent open', () => { ServerManager.getAllServers.mockReturnValue([{ id: 'server1', url: new URL('http://server1.com'), }]); ServerManager.getOrderedTabsForServer.mockReturnValue([ { - id: 'tab1', + id: 'view1', isOpen: false, }, ]); viewManager.handleReloadConfiguration(); - expect(viewManager.closedViews.has('tab1')).toBe(true); + expect(viewManager.closedViews.has('view1')).toBe(true); }); - it('should create new views for new tabs', () => { + it('should create new views for new views', () => { const makeSpy = jest.spyOn(viewManager, 'makeView'); ServerManager.getAllServers.mockReturnValue([{ id: 'server1', @@ -240,10 +237,10 @@ describe('main/views/viewManager', () => { }]); ServerManager.getOrderedTabsForServer.mockReturnValue([ { - id: 'tab1', - name: 'tab1', + id: 'view1', + name: 'view1', isOpen: true, - url: new URL('http://server1.com/tab'), + url: new URL('http://server1.com/view'), }, ]); viewManager.handleReloadConfiguration(); @@ -254,10 +251,10 @@ describe('main/views/viewManager', () => { url: new URL('http://server1.com'), }, { - id: 'tab1', - name: 'tab1', + id: 'view1', + name: 'view1', isOpen: true, - url: new URL('http://server1.com/tab'), + url: new URL('http://server1.com/view'), }, ); makeSpy.mockRestore(); @@ -265,27 +262,27 @@ describe('main/views/viewManager', () => { it('should set focus to current view on reload', () => { const view = { - id: 'tab1', - tab: { + id: 'view1', + view: { server: { id: 'server-1', }, - id: 'tab1', + id: 'view1', url: new URL('http://server1.com'), }, destroy: jest.fn(), updateServerInfo: jest.fn(), focus: jest.fn(), }; - viewManager.currentView = 'tab1'; - viewManager.views.set('tab1', view); + viewManager.currentView = 'view1'; + viewManager.views.set('view1', view); ServerManager.getAllServers.mockReturnValue([{ id: 'server1', url: new URL('http://server1.com'), }]); ServerManager.getOrderedTabsForServer.mockReturnValue([ { - id: 'tab1', + id: 'view1', isOpen: true, }, ]); @@ -295,23 +292,23 @@ describe('main/views/viewManager', () => { it('should show initial if currentView has been removed', () => { const view = { - id: 'tab1', - tab: { - id: 'tab1', + id: 'view1', + view: { + id: 'view1', url: new URL('http://server1.com'), }, destroy: jest.fn(), updateServerInfo: jest.fn(), }; - viewManager.currentView = 'tab1'; - viewManager.views.set('tab1', view); + viewManager.currentView = 'view1'; + viewManager.views.set('view1', view); ServerManager.getAllServers.mockReturnValue([{ id: 'server2', url: new URL('http://server2.com'), }]); ServerManager.getOrderedTabsForServer.mockReturnValue([ { - id: 'tab1', + id: 'view1', isOpen: false, }, ]); @@ -321,21 +318,21 @@ describe('main/views/viewManager', () => { it('should remove unused views', () => { const view = { - name: 'tab1', - tab: { - name: 'tab1', + name: 'view1', + view: { + name: 'view1', url: new URL('http://server1.com'), }, destroy: jest.fn(), }; - viewManager.views.set('tab1', view); + viewManager.views.set('view1', view); ServerManager.getAllServers.mockReturnValue([{ id: 'server2', url: new URL('http://server2.com'), }]); ServerManager.getOrderedTabsForServer.mockReturnValue([ { - id: 'tab1', + id: 'view1', isOpen: false, }, ]); @@ -360,11 +357,11 @@ describe('main/views/viewManager', () => { jest.resetAllMocks(); }); - it('should show last active tab and server', () => { + it('should show last active view and server', () => { ServerManager.getLastActiveServer.mockReturnValue({id: 'server-1'}); - ServerManager.getLastActiveTabForServer.mockReturnValue({id: 'tab-1'}); + ServerManager.getLastActiveTabForServer.mockReturnValue({id: 'view-1'}); viewManager.showInitial(); - expect(viewManager.showById).toHaveBeenCalledWith('tab-1'); + expect(viewManager.showById).toHaveBeenCalledWith('view-1'); }); it('should open new server modal when no servers exist', () => { @@ -385,7 +382,7 @@ describe('main/views/viewManager', () => { order: 0, tabs: [ { - name: 'tab-messaging', + name: 'view-messaging', order: 0, isOpen: true, }, @@ -403,9 +400,9 @@ describe('main/views/viewManager', () => { }, ]; const view1 = { - id: 'server-1_tab-messaging', + id: 'server-1_view-messaging', isLoggedIn: true, - tab: { + view: { type: TAB_MESSAGING, server: { url: 'http://server-1.com', @@ -416,21 +413,21 @@ describe('main/views/viewManager', () => { const view2 = { ...view1, id: 'server-1_other_type_1', - tab: { - ...view1.tab, + view: { + ...view1.view, type: 'other_type_1', }, }; const view3 = { ...view1, id: 'server-1_other_type_2', - tab: { - ...view1.tab, + view: { + ...view1.view, type: 'other_type_2', }, }; const views = new Map([ - ['server-1_tab-messaging', view1], + ['server-1_view-messaging', view1], ['server-1_other_type_1', view2], ]); const closedViews = new Map([ @@ -438,7 +435,7 @@ describe('main/views/viewManager', () => { ]); viewManager.getView = (viewId) => views.get(viewId); viewManager.isViewClosed = (viewId) => closedViews.has(viewId); - viewManager.openClosedTab = jest.fn(); + viewManager.openClosedView = jest.fn(); beforeEach(() => { ServerManager.getAllServers.mockReturnValue(servers); @@ -451,24 +448,24 @@ describe('main/views/viewManager', () => { }); it('should open closed view if pushing to it', () => { - viewManager.openClosedTab.mockImplementation((name) => { + viewManager.openClosedView.mockImplementation((name) => { const view = closedViews.get(name); closedViews.delete(name); views.set(name, view); }); - ServerManager.lookupTabByURL.mockReturnValue({id: 'server-1_other_type_2'}); - viewManager.handleBrowserHistoryPush(null, 'server-1_tab-messaging', '/other_type_2/subpath'); - expect(viewManager.openClosedTab).toBeCalledWith('server-1_other_type_2', 'http://server-1.com/other_type_2/subpath'); + ServerManager.lookupViewByURL.mockReturnValue({id: 'server-1_other_type_2'}); + viewManager.handleBrowserHistoryPush(null, 'server-1_view-messaging', '/other_type_2/subpath'); + expect(viewManager.openClosedView).toBeCalledWith('server-1_other_type_2', 'http://server-1.com/other_type_2/subpath'); }); it('should open redirect view if different from current view', () => { - ServerManager.lookupTabByURL.mockReturnValue({id: 'server-1_other_type_1'}); - viewManager.handleBrowserHistoryPush(null, 'server-1_tab-messaging', '/other_type_1/subpath'); + ServerManager.lookupViewByURL.mockReturnValue({id: 'server-1_other_type_1'}); + viewManager.handleBrowserHistoryPush(null, 'server-1_view-messaging', '/other_type_1/subpath'); expect(viewManager.showById).toBeCalledWith('server-1_other_type_1'); }); - it('should ignore redirects to "/" to Messages from other tabs', () => { - ServerManager.lookupTabByURL.mockReturnValue({id: 'server-1_tab-messaging'}); + it('should ignore redirects to "/" to Messages from other views', () => { + ServerManager.lookupViewByURL.mockReturnValue({id: 'server-1_view-messaging'}); viewManager.handleBrowserHistoryPush(null, 'server-1_other_type_1', '/'); expect(view1.sendToRenderer).not.toBeCalled(); }); @@ -487,11 +484,11 @@ describe('main/views/viewManager', () => { send: jest.fn(), }, }, - tab: { + view: { server: { name: 'server-1', }, - type: 'tab-1', + type: 'view-1', }, }; @@ -510,9 +507,9 @@ describe('main/views/viewManager', () => { ...baseView, isVisible: true, }; - viewManager.views.set('server1-tab1', view); + viewManager.views.set('server1-view1', view); - viewManager.showById('server1-tab1'); + viewManager.showById('server1-view1'); expect(viewManager.currentView).toBeUndefined(); expect(view.isReady).not.toBeCalled(); expect(view.show).not.toBeCalled(); @@ -584,7 +581,7 @@ describe('main/views/viewManager', () => { }; beforeEach(() => { - viewManager.openClosedTab = jest.fn(); + viewManager.openClosedView = jest.fn(); }); afterEach(() => { @@ -594,7 +591,7 @@ describe('main/views/viewManager', () => { }); it('should load URL into matching view', () => { - ServerManager.lookupTabByURL.mockImplementation(() => ({id: 'view1', url: new URL('http://server-1.com/')})); + ServerManager.lookupViewByURL.mockImplementation(() => ({id: 'view1', url: new URL('http://server-1.com/')})); const view = {...baseView}; viewManager.views.set('view1', view); viewManager.handleDeepLink('mattermost://server-1.com/deep/link?thing=yes'); @@ -602,11 +599,11 @@ describe('main/views/viewManager', () => { }); it('should send the URL to the view if its already loaded on a 6.0 server', () => { - ServerManager.lookupTabByURL.mockImplementation(() => ({id: 'view1', url: new URL('http://server-1.com/')})); + ServerManager.lookupViewByURL.mockImplementation(() => ({id: 'view1', url: new URL('http://server-1.com/')})); ServerManager.getRemoteInfo.mockReturnValue({serverVersion: '6.0.0'}); const view = { ...baseView, - tab: { + view: { server: { url: new URL('http://server-1.com'), }, @@ -619,7 +616,7 @@ describe('main/views/viewManager', () => { }); it('should throw error if view is missing', () => { - ServerManager.lookupTabByURL.mockImplementation(() => ({id: 'view1', url: new URL('http://server-1.com/')})); + ServerManager.lookupViewByURL.mockImplementation(() => ({id: 'view1', url: new URL('http://server-1.com/')})); const view = {...baseView}; viewManager.handleDeepLink('mattermost://server-1.com/deep/link?thing=yes'); expect(view.load).not.toHaveBeenCalled(); @@ -632,11 +629,11 @@ describe('main/views/viewManager', () => { expect(dialog.showErrorBox).toHaveBeenCalled(); }); - it('should reopen closed tab if called upon', () => { - ServerManager.lookupTabByURL.mockImplementation(() => ({id: 'view1', url: new URL('http://server-1.com/')})); + it('should reopen closed view if called upon', () => { + ServerManager.lookupViewByURL.mockImplementation(() => ({id: 'view1', url: new URL('http://server-1.com/')})); viewManager.closedViews.set('view1', {}); viewManager.handleDeepLink('mattermost://server-1.com/deep/link?thing=yes'); - expect(viewManager.openClosedTab).toHaveBeenCalledWith('view1', 'http://server-1.com/deep/link?thing=yes'); + expect(viewManager.openClosedView).toHaveBeenCalledWith('view1', 'http://server-1.com/deep/link?thing=yes'); }); }); }); diff --git a/src/main/views/viewManager.ts b/src/main/views/viewManager.ts index 1f45e6ab..05f9067d 100644 --- a/src/main/views/viewManager.ts +++ b/src/main/views/viewManager.ts @@ -11,7 +11,7 @@ import { LOAD_FAILED, LOADSCREEN_END, SET_ACTIVE_VIEW, - OPEN_TAB, + OPEN_VIEW, BROWSER_HISTORY_PUSH, UPDATE_URL_VIEW_WIDTH, SERVERS_UPDATE, @@ -33,7 +33,7 @@ import {Logger} from 'common/log'; import Utils from 'common/utils/util'; import {MattermostServer} from 'common/servers/MattermostServer'; import ServerManager from 'common/servers/serverManager'; -import {TabView, TAB_MESSAGING} from 'common/tabs/TabView'; +import {MattermostView, TAB_MESSAGING} from 'common/views/View'; import {parseURL} from 'common/utils/url'; import {localizeMessage} from 'main/i18nManager'; @@ -41,7 +41,7 @@ import MainWindow from 'main/windows/mainWindow'; import {getLocalURLString, getLocalPreload, getAdjustedWindowBoundaries, shouldHaveBackBar} from '../utils'; -import {MattermostView} from './MattermostView'; +import {MattermostBrowserView} from './MattermostBrowserView'; import modalManager from './modalManager'; import LoadingScreen from './loadingScreen'; @@ -50,14 +50,14 @@ const URL_VIEW_DURATION = 10 * SECOND; const URL_VIEW_HEIGHT = 20; export class ViewManager { - private closedViews: Map; - private views: Map; + private closedViews: Map; + private views: Map; private currentView?: string; private urlViewCancel?: () => void; constructor() { - this.views = new Map(); // keep in mind that this doesn't need to hold server order, only tabs on the renderer need that. + this.views = new Map(); // keep in mind that this doesn't need to hold server order, only views on the renderer need that. this.closedViews = new Map(); MainWindow.on(MAIN_WINDOW_CREATED, this.init); @@ -102,23 +102,23 @@ export class ViewManager { return this.closedViews.has(viewId); } - showById = (tabId: string) => { - this.getViewLogger(tabId).debug('showById', tabId); + showById = (viewId: string) => { + this.getViewLogger(viewId).debug('showById', viewId); - const newView = this.views.get(tabId); + const newView = this.views.get(viewId); if (newView) { if (newView.isVisible) { return; } let hidePrevious; - if (this.currentView && this.currentView !== tabId) { + if (this.currentView && this.currentView !== viewId) { const previous = this.getCurrentView(); if (previous) { hidePrevious = () => previous.hide(); } } - this.currentView = tabId; + this.currentView = viewId; if (!newView.isErrored()) { newView.show(); if (newView.needsLoadingScreen()) { @@ -126,10 +126,10 @@ export class ViewManager { } } hidePrevious?.(); - MainWindow.get()?.webContents.send(SET_ACTIVE_VIEW, newView.tab.server.id, newView.tab.id); - ServerManager.updateLastActive(newView.tab.id); + MainWindow.get()?.webContents.send(SET_ACTIVE_VIEW, newView.view.server.id, newView.view.id); + ServerManager.updateLastActive(newView.view.id); } else { - this.getViewLogger(tabId).warn(`Couldn't find a view with name: ${tabId}`); + this.getViewLogger(viewId).warn(`Couldn't find a view with name: ${viewId}`); } modalManager.showModal(); } @@ -175,28 +175,28 @@ export class ViewManager { handleDeepLink = (url: string | URL) => { if (url) { const parsedURL = parseURL(url)!; - const tabView = ServerManager.lookupTabByURL(parsedURL, true); - if (tabView) { - const urlWithSchema = `${tabView.url.origin}${parsedURL.pathname}${parsedURL.search}`; - if (this.closedViews.has(tabView.id)) { - this.openClosedTab(tabView.id, urlWithSchema); + const view = ServerManager.lookupViewByURL(parsedURL, true); + if (view) { + const urlWithSchema = `${view.url.origin}${parsedURL.pathname}${parsedURL.search}`; + if (this.closedViews.has(view.id)) { + this.openClosedView(view.id, urlWithSchema); } else { - const view = this.views.get(tabView.id); - if (!view) { - log.error(`Couldn't find a view matching the id ${tabView.id}`); + const browserView = this.views.get(view.id); + if (!browserView) { + log.error(`Couldn't find a view matching the id ${view.id}`); return; } - if (view.isReady() && ServerManager.getRemoteInfo(view.tab.server.id)?.serverVersion && Utils.isVersionGreaterThanOrEqualTo(ServerManager.getRemoteInfo(view.tab.server.id)?.serverVersion ?? '', '6.0.0')) { - const pathName = `/${urlWithSchema.replace(view.tab.server.url.toString(), '')}`; - view.sendToRenderer(BROWSER_HISTORY_PUSH, pathName); - this.deeplinkSuccess(view.id); + if (browserView.isReady() && ServerManager.getRemoteInfo(browserView.view.server.id)?.serverVersion && Utils.isVersionGreaterThanOrEqualTo(ServerManager.getRemoteInfo(browserView.view.server.id)?.serverVersion ?? '', '6.0.0')) { + const pathName = `/${urlWithSchema.replace(browserView.view.server.url.toString(), '')}`; + browserView.sendToRenderer(BROWSER_HISTORY_PUSH, pathName); + this.deeplinkSuccess(browserView.id); } else { // attempting to change parsedURL protocol results in it not being modified. - view.resetLoadingStatus(); - view.load(urlWithSchema); - view.once(LOAD_SUCCESS, this.deeplinkSuccess); - view.once(LOAD_FAILED, this.deeplinkFailed); + browserView.resetLoadingStatus(); + browserView.load(urlWithSchema); + browserView.once(LOAD_SUCCESS, this.deeplinkSuccess); + browserView.once(LOAD_FAILED, this.deeplinkFailed); } } } else { @@ -225,35 +225,35 @@ export class ViewManager { */ private loadServer = (server: MattermostServer) => { - const tabs = ServerManager.getOrderedTabsForServer(server.id); - tabs.forEach((tab) => this.loadView(server, tab)); + const views = ServerManager.getOrderedTabsForServer(server.id); + views.forEach((view) => this.loadView(server, view)); } - private loadView = (srv: MattermostServer, tab: TabView, url?: string) => { - if (!tab.isOpen) { - this.closedViews.set(tab.id, {srv, tab}); + private loadView = (srv: MattermostServer, view: MattermostView, url?: string) => { + if (!view.isOpen) { + this.closedViews.set(view.id, {srv, view}); return; } - const view = this.makeView(srv, tab, url); - this.addView(view); + const browserView = this.makeView(srv, view, url); + this.addView(browserView); } - private makeView = (srv: MattermostServer, tab: TabView, url?: string): MattermostView => { + private makeView = (srv: MattermostServer, view: MattermostView, url?: string): MattermostBrowserView => { const mainWindow = MainWindow.get(); if (!mainWindow) { throw new Error('Cannot create view, no main window present'); } - const view = new MattermostView(tab, {webPreferences: {spellcheck: Config.useSpellChecker}}); - view.once(LOAD_SUCCESS, this.activateView); - view.on(LOADSCREEN_END, this.finishLoading); - view.on(LOAD_FAILED, this.failLoading); - view.on(UPDATE_TARGET_URL, this.showURLView); - view.load(url); - return view; + const browserView = new MattermostBrowserView(view, {webPreferences: {spellcheck: Config.useSpellChecker}}); + browserView.once(LOAD_SUCCESS, this.activateView); + browserView.on(LOADSCREEN_END, this.finishLoading); + browserView.on(LOAD_FAILED, this.failLoading); + browserView.on(UPDATE_TARGET_URL, this.showURLView); + browserView.load(url); + return browserView; } - private addView = (view: MattermostView): void => { + private addView = (view: MattermostBrowserView): void => { this.views.set(view.id, view); if (this.closedViews.has(view.id)) { this.closedViews.delete(view.id); @@ -265,8 +265,8 @@ export class ViewManager { if (ServerManager.hasServers()) { const lastActiveServer = ServerManager.getCurrentServer(); - const lastActiveTab = ServerManager.getLastActiveTabForServer(lastActiveServer.id); - this.showById(lastActiveTab.id); + const lastActiveView = ServerManager.getLastActiveTabForServer(lastActiveServer.id); + this.showById(lastActiveView.id); } else { MainWindow.get()?.webContents.send(SET_ACTIVE_VIEW); } @@ -382,33 +382,33 @@ export class ViewManager { */ /** Called when a new configuration is received - * Servers or tabs have been added or edited. We need to - * close, open, or reload tabs, taking care to reuse tabs and - * preserve focus on the currently selected tab. */ + * Servers or views have been added or edited. We need to + * close, open, or reload views, taking care to reuse views and + * preserve focus on the currently selected view. */ private handleReloadConfiguration = () => { log.debug('handleReloadConfiguration'); - const currentTabId: string | undefined = this.views.get(this.currentView as string)?.tab.id; + const currentViewId: string | undefined = this.views.get(this.currentView as string)?.view.id; - const current: Map = new Map(); + const current: Map = new Map(); for (const view of this.views.values()) { - current.set(view.tab.id, view); + current.set(view.view.id, view); } - const views: Map = new Map(); - const closed: Map = new Map(); + const views: Map = new Map(); + const closed: Map = new Map(); - const sortedTabs = ServerManager.getAllServers().flatMap((x) => ServerManager.getOrderedTabsForServer(x.id). - map((t): [MattermostServer, TabView] => [x, t])); + const sortedViews = ServerManager.getAllServers().flatMap((x) => ServerManager.getOrderedTabsForServer(x.id). + map((t): [MattermostServer, MattermostView] => [x, t])); - for (const [srv, tab] of sortedTabs) { - const recycle = current.get(tab.id); - if (!tab.isOpen) { - closed.set(tab.id, {srv, tab}); + for (const [srv, view] of sortedViews) { + const recycle = current.get(view.id); + if (!view.isOpen) { + closed.set(view.id, {srv, view}); } else if (recycle) { - views.set(tab.id, recycle); + views.set(view.id, recycle); } else { - views.set(tab.id, this.makeView(srv, tab)); + views.set(view.id, this.makeView(srv, view)); } } @@ -428,10 +428,10 @@ export class ViewManager { // commit closed for (const x of closed.values()) { - this.closedViews.set(x.tab.id, {srv: x.srv, tab: x.tab}); + this.closedViews.set(x.view.id, {srv: x.srv, view: x.view}); } - if ((currentTabId && closed.has(currentTabId)) || (this.currentView && this.closedViews.has(this.currentView))) { + if ((currentViewId && closed.has(currentViewId)) || (this.currentView && this.closedViews.has(this.currentView))) { if (ServerManager.hasServers()) { this.currentView = undefined; this.showInitial(); @@ -440,13 +440,13 @@ export class ViewManager { } } - // show the focused tab (or initial) - if (currentTabId && views.has(currentTabId)) { - const view = views.get(currentTabId); + // show the focused view (or initial) + if (currentViewId && views.has(currentViewId)) { + const view = views.get(currentViewId); if (view && view.id !== this.currentView) { this.currentView = view.id; this.showById(view.id); - MainWindow.get()?.webContents.send(SET_ACTIVE_VIEW, view.tab.server.id, view.tab.id); + MainWindow.get()?.webContents.send(SET_ACTIVE_VIEW, view.view.server.id, view.view.id); } else { this.focusCurrentView(); } @@ -475,17 +475,17 @@ export class ViewManager { return; } let cleanedPathName = pathName; - if (currentView.tab.server.url.pathname !== '/' && pathName.startsWith(currentView.tab.server.url.pathname)) { - cleanedPathName = pathName.replace(currentView.tab.server.url.pathname, ''); + if (currentView.view.server.url.pathname !== '/' && pathName.startsWith(currentView.view.server.url.pathname)) { + cleanedPathName = pathName.replace(currentView.view.server.url.pathname, ''); } - const redirectedviewId = ServerManager.lookupTabByURL(`${currentView.tab.server.url.toString().replace(/\/$/, '')}${cleanedPathName}`)?.id || viewId; + const redirectedviewId = ServerManager.lookupViewByURL(`${currentView.view.server.url.toString().replace(/\/$/, '')}${cleanedPathName}`)?.id || viewId; if (this.isViewClosed(redirectedviewId)) { // If it's a closed view, just open it and stop - this.openClosedTab(redirectedviewId, `${currentView.tab.server.url}${cleanedPathName}`); + this.openClosedView(redirectedviewId, `${currentView.view.server.url}${cleanedPathName}`); return; } let redirectedView = this.getView(redirectedviewId) || currentView; - if (redirectedView !== currentView && redirectedView?.tab.server.id === ServerManager.getCurrentServer().id && redirectedView?.isLoggedIn) { + if (redirectedView !== currentView && redirectedView?.view.server.id === ServerManager.getCurrentServer().id && redirectedView?.isLoggedIn) { log.info('redirecting to a new view', redirectedView?.id || viewId); this.showById(redirectedView?.id || viewId); } else { @@ -493,7 +493,7 @@ export class ViewManager { } // Special case check for Channels to not force a redirect to "/", causing a refresh - if (!(redirectedView !== currentView && redirectedView?.tab.type === TAB_MESSAGING && cleanedPathName === '/')) { + if (!(redirectedView !== currentView && redirectedView?.view.type === TAB_MESSAGING && cleanedPathName === '/')) { redirectedView?.sendToRenderer(BROWSER_HISTORY_PUSH, cleanedPathName); if (redirectedView) { this.handleBrowserHistoryButton(e, redirectedView.id); @@ -547,7 +547,7 @@ export class ViewManager { const currentView = this.getCurrentView(); if (currentView && currentView.currentURL) { - const adjustedBounds = getAdjustedWindowBoundaries(newBounds.width, newBounds.height, shouldHaveBackBar(currentView.tab.url, currentView.currentURL)); + const adjustedBounds = getAdjustedWindowBoundaries(newBounds.width, newBounds.height, shouldHaveBackBar(currentView.view.url, currentView.currentURL)); currentView.setBounds(adjustedBounds); } } @@ -556,21 +556,21 @@ export class ViewManager { * Helper functions */ - private openClosedTab = (id: string, url?: string) => { + private openClosedView = (id: string, url?: string) => { if (!this.closedViews.has(id)) { return; } - const {srv, tab} = this.closedViews.get(id)!; - tab.isOpen = true; - this.loadView(srv, tab, url); + const {srv, view} = this.closedViews.get(id)!; + view.isOpen = true; + this.loadView(srv, view, url); this.showById(id); - const view = this.views.get(id)!; - view.isVisible = true; - view.on(LOAD_SUCCESS, () => { - view.isVisible = false; + const browserView = this.views.get(id)!; + browserView.isVisible = true; + browserView.on(LOAD_SUCCESS, () => { + browserView.isVisible = false; this.showById(id); }); - ipcMain.emit(OPEN_TAB, null, tab.id); + ipcMain.emit(OPEN_VIEW, null, view.id); } private getViewLogger = (viewId: string) => { @@ -585,8 +585,8 @@ export class ViewManager { return { id: view.id, webContentsId: view.webContentsId, - serverName: view.tab.server.name, - tabType: view.tab.type, + serverName: view.view.server.name, + viewType: view.view.type, }; } } diff --git a/src/main/views/webContentEvents.ts b/src/main/views/webContentEvents.ts index 97f0861e..51a8de1e 100644 --- a/src/main/views/webContentEvents.ts +++ b/src/main/views/webContentEvents.ts @@ -81,7 +81,7 @@ export class WebContentsEventManager { return CallsWidgetWindow.getURL(); } - return ViewManager.getViewByWebContentsId(webContentsId)?.tab.server.url; + return ViewManager.getViewByWebContentsId(webContentsId)?.view.server.url; } private generateWillNavigate = (webContentsId: number) => { @@ -274,7 +274,7 @@ export class WebContentsEventManager { return {action: 'deny'}; } - const otherServerURL = ServerManager.lookupTabByURL(parsedURL); + const otherServerURL = ServerManager.lookupViewByURL(parsedURL); if (otherServerURL && isTeamUrl(otherServerURL.server.url, parsedURL, true)) { ViewManager.handleDeepLink(parsedURL); return {action: 'deny'}; diff --git a/src/main/windows/callsWidgetWindow.test.js b/src/main/windows/callsWidgetWindow.test.js index 187676b9..e5a410e7 100644 --- a/src/main/windows/callsWidgetWindow.test.js +++ b/src/main/windows/callsWidgetWindow.test.js @@ -247,7 +247,7 @@ describe('main/windows/callsWidgetWindow', () => { title: 'call test title #/&', }; callsWidgetWindow.mainView = { - tab: { + view: { server: { url: new URL('http://localhost:8065'), }, @@ -262,7 +262,7 @@ describe('main/windows/callsWidgetWindow', () => { it('getWidgetURL - under subpath', () => { callsWidgetWindow.mainView = { - tab: { + view: { server: { url: new URL('http://localhost:8065/subpath'), }, @@ -339,7 +339,7 @@ describe('main/windows/callsWidgetWindow', () => { beforeEach(() => { callsWidgetWindow.options = {callID: 'id'}; callsWidgetWindow.mainView = { - tab: { + view: { server: { url: new URL('http://localhost:8065'), }, @@ -491,7 +491,7 @@ describe('main/windows/callsWidgetWindow', () => { callsWidgetWindow.close = jest.fn(); callsWidgetWindow.getWidgetURL = jest.fn(); const view = { - name: 'server-1_tab-messaging', + name: 'server-1_view-messaging', serverInfo: { server: { url: new URL('http://server-1.com'), @@ -526,12 +526,12 @@ describe('main/windows/callsWidgetWindow', () => { it('should create calls widget window', async () => { expect(callsWidgetWindow.win).toBeUndefined(); - await callsWidgetWindow.handleCreateCallsWidgetWindow('server-1_tab-messaging', {callID: 'test'}); + await callsWidgetWindow.handleCreateCallsWidgetWindow('server-1_view-messaging', {callID: 'test'}); expect(callsWidgetWindow.win).toBeDefined(); }); it('should create with correct initial configuration', async () => { - await callsWidgetWindow.handleCreateCallsWidgetWindow('server-1_tab-messaging', {callID: 'test'}); + await callsWidgetWindow.handleCreateCallsWidgetWindow('server-1_view-messaging', {callID: 'test'}); expect(BrowserWindow).toHaveBeenCalledWith(expect.objectContaining({ width: MINIMUM_CALLS_WIDGET_WIDTH, height: MINIMUM_CALLS_WIDGET_HEIGHT, @@ -560,7 +560,7 @@ describe('main/windows/callsWidgetWindow', () => { const window = {webContents: {id: 2}}; callsWidgetWindow.win = window; callsWidgetWindow.options = {callID: 'test'}; - await callsWidgetWindow.handleCreateCallsWidgetWindow('server-1_tab-messaging', {callID: 'test'}); + await callsWidgetWindow.handleCreateCallsWidgetWindow('server-1_view-messaging', {callID: 'test'}); expect(callsWidgetWindow.win).toEqual(window); }); @@ -568,7 +568,7 @@ describe('main/windows/callsWidgetWindow', () => { const window = {webContents: {id: 2}}; callsWidgetWindow.win = window; callsWidgetWindow.getCallID = jest.fn(() => 'test'); - await callsWidgetWindow.handleCreateCallsWidgetWindow('server-1_tab-messaging', {callID: 'test2'}); + await callsWidgetWindow.handleCreateCallsWidgetWindow('server-1_view-messaging', {callID: 'test2'}); expect(callsWidgetWindow.win).not.toEqual(window); }); }); @@ -580,18 +580,18 @@ describe('main/windows/callsWidgetWindow', () => { send: jest.fn(), }, }; - const teams = [ + const servers = [ { name: 'server-1', order: 1, - tabs: [ + views: [ { - name: 'tab-1', + name: 'view-1', order: 0, isOpen: false, }, { - name: 'tab-2', + name: 'view-2', order: 2, isOpen: true, }, @@ -599,24 +599,24 @@ describe('main/windows/callsWidgetWindow', () => { }, { name: 'server-2', order: 0, - tabs: [ + views: [ { - name: 'tab-1', + name: 'view-1', order: 0, isOpen: false, }, { - name: 'tab-2', + name: 'view-2', order: 2, isOpen: true, }, ], - lastActiveTab: 2, + lastActiveView: 2, }, ]; - const map = teams.reduce((arr, item) => { - item.tabs.forEach((tab) => { - arr.push([`${item.name}_${tab.name}`, { + const map = servers.reduce((arr, item) => { + item.views.forEach((view) => { + arr.push([`${item.name}_${view.name}`, { sendToRenderer: jest.fn(), }]); }); @@ -649,9 +649,9 @@ describe('main/windows/callsWidgetWindow', () => { }, ]); - await callsWidgetWindow.handleGetDesktopSources('server-1_tab-1', null); + await callsWidgetWindow.handleGetDesktopSources('server-1_view-1', null); - expect(views.get('server-1_tab-1').sendToRenderer).toHaveBeenCalledWith('desktop-sources-result', [ + expect(views.get('server-1_view-1').sendToRenderer).toHaveBeenCalledWith('desktop-sources-result', [ { id: 'screen0', }, @@ -663,11 +663,11 @@ describe('main/windows/callsWidgetWindow', () => { it('should send error with no sources', async () => { jest.spyOn(desktopCapturer, 'getSources').mockResolvedValue([]); - await callsWidgetWindow.handleGetDesktopSources('server-2_tab-1', null); + await callsWidgetWindow.handleGetDesktopSources('server-2_view-1', null); expect(callsWidgetWindow.win.webContents.send).toHaveBeenCalledWith('calls-error', { err: 'screen-permissions', }); - expect(views.get('server-2_tab-1').sendToRenderer).toHaveBeenCalledWith('calls-error', { + expect(views.get('server-2_view-1').sendToRenderer).toHaveBeenCalledWith('calls-error', { err: 'screen-permissions', }); expect(callsWidgetWindow.win.webContents.send).toHaveBeenCalledTimes(1); @@ -684,16 +684,16 @@ describe('main/windows/callsWidgetWindow', () => { ]); jest.spyOn(systemPreferences, 'getMediaAccessStatus').mockReturnValue('denied'); - await callsWidgetWindow.handleGetDesktopSources('server-1_tab-1', null); + await callsWidgetWindow.handleGetDesktopSources('server-1_view-1', null); expect(systemPreferences.getMediaAccessStatus).toHaveBeenCalledWith('screen'); expect(callsWidgetWindow.win.webContents.send).toHaveBeenCalledWith('calls-error', { err: 'screen-permissions', }); - expect(views.get('server-1_tab-1').sendToRenderer).toHaveBeenCalledWith('calls-error', { + expect(views.get('server-1_view-1').sendToRenderer).toHaveBeenCalledWith('calls-error', { err: 'screen-permissions', }); - expect(views.get('server-1_tab-1').sendToRenderer).toHaveBeenCalledTimes(1); + expect(views.get('server-1_view-1').sendToRenderer).toHaveBeenCalledTimes(1); expect(callsWidgetWindow.win.webContents.send).toHaveBeenCalledTimes(1); }); @@ -713,7 +713,7 @@ describe('main/windows/callsWidgetWindow', () => { ]); jest.spyOn(systemPreferences, 'getMediaAccessStatus').mockReturnValue('denied'); - await callsWidgetWindow.handleGetDesktopSources('server-1_tab-1', null); + await callsWidgetWindow.handleGetDesktopSources('server-1_view-1', null); expect(callsWidgetWindow.missingScreensharePermissions).toBe(true); expect(resetScreensharePermissionsMacOS).toHaveBeenCalledTimes(1); @@ -721,11 +721,11 @@ describe('main/windows/callsWidgetWindow', () => { expect(callsWidgetWindow.win.webContents.send).toHaveBeenCalledWith('calls-error', { err: 'screen-permissions', }); - expect(views.get('server-1_tab-1').sendToRenderer).toHaveBeenCalledWith('calls-error', { + expect(views.get('server-1_view-1').sendToRenderer).toHaveBeenCalledWith('calls-error', { err: 'screen-permissions', }); - await callsWidgetWindow.handleGetDesktopSources('server-1_tab-1', null); + await callsWidgetWindow.handleGetDesktopSources('server-1_view-1', null); expect(resetScreensharePermissionsMacOS).toHaveBeenCalledTimes(2); expect(openScreensharePermissionsSettingsMacOS).toHaveBeenCalledTimes(1); @@ -739,25 +739,25 @@ describe('main/windows/callsWidgetWindow', () => { describe('handleDesktopSourcesModalRequest', () => { const callsWidgetWindow = new CallsWidgetWindow(); callsWidgetWindow.mainView = { - tab: { + view: { server: { id: 'server-1', }, }, sendToRenderer: jest.fn(), }; - const teams = [ + const servers = [ { name: 'server-1', order: 1, - tabs: [ + views: [ { - name: 'tab-1', + name: 'view-1', order: 0, isOpen: false, }, { - name: 'tab-2', + name: 'view-2', order: 2, isOpen: true, }, @@ -765,24 +765,24 @@ describe('main/windows/callsWidgetWindow', () => { }, { name: 'server-2', order: 0, - tabs: [ + views: [ { - name: 'tab-1', + name: 'view-1', order: 0, isOpen: false, }, { - name: 'tab-2', + name: 'view-2', order: 2, isOpen: true, }, ], - lastActiveTab: 2, + lastActiveView: 2, }, ]; - const map = teams.reduce((arr, item) => { - item.tabs.forEach((tab) => { - arr.push([`${item.name}_${tab.name}`, {}]); + const map = servers.reduce((arr, item) => { + item.views.forEach((view) => { + arr.push([`${item.name}_${view.name}`, {}]); }); return arr; }, []); @@ -805,7 +805,7 @@ describe('main/windows/callsWidgetWindow', () => { describe('handleCallsWidgetChannelLinkClick', () => { const callsWidgetWindow = new CallsWidgetWindow(); callsWidgetWindow.mainView = { - tab: { + view: { server: { id: 'server-2', }, @@ -813,18 +813,18 @@ describe('main/windows/callsWidgetWindow', () => { sendToRenderer: jest.fn(), }; callsWidgetWindow.getChannelURL = jest.fn(); - const teams = [ + const servers = [ { name: 'server-1', order: 1, - tabs: [ + views: [ { - name: 'tab-1', + name: 'view-1', order: 0, isOpen: false, }, { - name: 'tab-2', + name: 'view-2', order: 2, isOpen: true, }, @@ -832,24 +832,24 @@ describe('main/windows/callsWidgetWindow', () => { }, { name: 'server-2', order: 0, - tabs: [ + views: [ { - name: 'tab-1', + name: 'view-1', order: 0, isOpen: false, }, { - name: 'tab-2', + name: 'view-2', order: 2, isOpen: true, }, ], - lastActiveTab: 2, + lastActiveView: 2, }, ]; - const map = teams.reduce((arr, item) => { - item.tabs.forEach((tab) => { - arr.push([`${item.name}_${tab.name}`, {}]); + const map = servers.reduce((arr, item) => { + item.views.forEach((view) => { + arr.push([`${item.name}_${view.name}`, {}]); }); return arr; }, []); @@ -872,7 +872,7 @@ describe('main/windows/callsWidgetWindow', () => { describe('handleCallsError', () => { const callsWidgetWindow = new CallsWidgetWindow(); callsWidgetWindow.mainView = { - tab: { + view: { server: { id: 'server-2', }, @@ -899,7 +899,7 @@ describe('main/windows/callsWidgetWindow', () => { describe('handleCallsLinkClick', () => { const view = { - tab: { + view: { server: { id: 'server-1', }, diff --git a/src/main/windows/callsWidgetWindow.ts b/src/main/windows/callsWidgetWindow.ts index 194170d4..74a86b7f 100644 --- a/src/main/windows/callsWidgetWindow.ts +++ b/src/main/windows/callsWidgetWindow.ts @@ -14,7 +14,7 @@ import { CallsWidgetWindowConfig, } from 'types/calls'; -import {MattermostView} from 'main/views/MattermostView'; +import {MattermostBrowserView} from 'main/views/MattermostBrowserView'; import {getLocalPreload, openScreensharePermissionsSettingsMacOS, resetScreensharePermissionsMacOS} from 'main/utils'; @@ -47,7 +47,7 @@ const log = new Logger('CallsWidgetWindow'); export class CallsWidgetWindow { private win?: BrowserWindow; - private mainView?: MattermostView; + private mainView?: MattermostBrowserView; private options?: CallsWidgetWindowConfig; private missingScreensharePermissions?: boolean; @@ -82,7 +82,7 @@ export class CallsWidgetWindow { } private get serverID() { - return this.mainView?.tab.server.id; + return this.mainView?.view.server.id; } /** @@ -101,7 +101,7 @@ export class CallsWidgetWindow { if (!this.mainView) { return undefined; } - const u = parseURL(this.mainView.tab.server.url.toString()) as URL; + const u = parseURL(this.mainView.view.server.url.toString()) as URL; u.pathname = getFormattedPathName(u.pathname); u.pathname += `plugins/${CALLS_PLUGIN_ID}/standalone/widget.html`; @@ -119,7 +119,7 @@ export class CallsWidgetWindow { return u.toString(); } - private init = (view: MattermostView, options: CallsWidgetWindowConfig) => { + private init = (view: MattermostBrowserView, options: CallsWidgetWindowConfig) => { this.win = new BrowserWindow({ width: MINIMUM_CALLS_WIDGET_WIDTH, height: MINIMUM_CALLS_WIDGET_HEIGHT, @@ -271,7 +271,7 @@ export class CallsWidgetWindow { if (!parsedURL) { return {action: 'deny' as const}; } - if (isCallsPopOutURL(this.mainView?.tab.server.url, parsedURL, this.options?.callID)) { + if (isCallsPopOutURL(this.mainView?.view.server.url, parsedURL, this.options?.callID)) { return { action: 'allow' as const, overrideBrowserWindowOptions: { diff --git a/src/main/windows/mainWindow.test.js b/src/main/windows/mainWindow.test.js index 41782224..58d31107 100644 --- a/src/main/windows/mainWindow.test.js +++ b/src/main/windows/mainWindow.test.js @@ -421,7 +421,7 @@ describe('main/windows/mainWindow', () => { expect(window.setFullScreen).toHaveBeenCalledWith(false); }); - it('should select tabs using alt+cmd+arrow keys on Mac', () => { + it('should select views using alt+cmd+arrow keys on Mac', () => { const originalPlatform = process.platform; Object.defineProperty(process, 'platform', { value: 'darwin', diff --git a/src/renderer/components/ConfigureServer.tsx b/src/renderer/components/ConfigureServer.tsx index 8738b542..cc44bd08 100644 --- a/src/renderer/components/ConfigureServer.tsx +++ b/src/renderer/components/ConfigureServer.tsx @@ -5,7 +5,7 @@ import React, {useState, useCallback, useEffect} from 'react'; import {useIntl, FormattedMessage} from 'react-intl'; import classNames from 'classnames'; -import {MattermostTeam} from 'types/config'; +import {UniqueServer} from 'types/config'; import {isValidURL, parseURL} from 'common/utils/url'; import {MODAL_TRANSITION_TIMEOUT} from 'common/utils/constants'; @@ -22,8 +22,8 @@ import 'renderer/css/components/ConfigureServer.scss'; import 'renderer/css/components/LoadingScreen.css'; type ConfigureServerProps = { - currentTeams: MattermostTeam[]; - team?: MattermostTeam; + currentServers: UniqueServer[]; + server?: UniqueServer; mobileView?: boolean; darkMode?: boolean; messageTitle?: string; @@ -32,12 +32,12 @@ type ConfigureServerProps = { alternateLinkMessage?: string; alternateLinkText?: string; alternateLinkURL?: string; - onConnect: (data: MattermostTeam) => void; + onConnect: (data: UniqueServer) => void; }; function ConfigureServer({ - currentTeams, - team, + currentServers, + server, mobileView, darkMode, messageTitle, @@ -54,7 +54,7 @@ function ConfigureServer({ name: prevName, url: prevURL, id, - } = team || {}; + } = server || {}; const [transition, setTransition] = useState<'inFromRight' | 'outToLeft'>(); const [name, setName] = useState(prevName || ''); @@ -92,14 +92,14 @@ function ConfigureServer({ if (!newName) { return formatMessage({ - id: 'renderer.components.newTeamModal.error.nameRequired', + id: 'renderer.components.newServerModal.error.nameRequired', defaultMessage: 'Name is required.', }); } - if (currentTeams.find(({name: existingName}) => existingName === newName)) { + if (currentServers.find(({name: existingName}) => existingName === newName)) { return formatMessage({ - id: 'renderer.components.newTeamModal.error.serverNameExists', + id: 'renderer.components.newServerModal.error.serverNameExists', defaultMessage: 'A server with the same name already exists.', }); } @@ -110,28 +110,28 @@ function ConfigureServer({ const validateURL = async (fullURL: string) => { if (!fullURL) { return formatMessage({ - id: 'renderer.components.newTeamModal.error.urlRequired', + id: 'renderer.components.newServerModal.error.urlRequired', defaultMessage: 'URL is required.', }); } if (!parseURL(fullURL)) { return formatMessage({ - id: 'renderer.components.newTeamModal.error.urlIncorrectFormatting', + id: 'renderer.components.newServerModal.error.urlIncorrectFormatting', defaultMessage: 'URL is not formatted correctly.', }); } if (!isValidURL(fullURL)) { return formatMessage({ - id: 'renderer.components.newTeamModal.error.urlNeedsHttp', + id: 'renderer.components.newServerModal.error.urlNeedsHttp', defaultMessage: 'URL should start with http:// or https://.', }); } - if (currentTeams.find(({url: existingURL}) => parseURL(existingURL)?.toString === parseURL(fullURL)?.toString())) { + if (currentServers.find(({url: existingURL}) => parseURL(existingURL)?.toString === parseURL(fullURL)?.toString())) { return formatMessage({ - id: 'renderer.components.newTeamModal.error.serverUrlExists', + id: 'renderer.components.newServerModal.error.serverUrlExists', defaultMessage: 'A server with the same URL already exists.', }); } diff --git a/src/renderer/components/MainPage.tsx b/src/renderer/components/MainPage.tsx index 92b670b4..98a7b22d 100644 --- a/src/renderer/components/MainPage.tsx +++ b/src/renderer/components/MainPage.tsx @@ -10,7 +10,7 @@ import {Container, Row} from 'react-bootstrap'; import {DropResult} from 'react-beautiful-dnd'; import {injectIntl, IntlShape} from 'react-intl'; -import {MattermostTab, MattermostTeam} from 'types/config'; +import {UniqueView, UniqueServer} from 'types/config'; import {DownloadedItems} from 'types/downloads'; import restoreButton from '../../assets/titlebar/chrome-restore.svg'; @@ -23,7 +23,7 @@ import {playSound} from '../notificationSounds'; import TabBar from './TabBar'; import ExtraBar from './ExtraBar'; import ErrorView from './ErrorView'; -import TeamDropdownButton from './TeamDropdownButton'; +import ServerDropdownButton from './ServerDropdownButton'; import DownloadsDropdownButton from './DownloadsDropdown/DownloadsDropdownButton'; import '../css/components/UpgradeButton.scss'; @@ -47,8 +47,8 @@ type Props = { type State = { activeServerId?: string; activeTabId?: string; - servers: MattermostTeam[]; - tabs: Map; + servers: UniqueServer[]; + tabs: Map; sessionsExpired: Record; unreadCounts: Record; mentionCounts: Record; @@ -147,7 +147,7 @@ class MainPage extends React.PureComponent { setInitialActiveTab = async () => { const lastActive = await window.desktop.getLastActive(); - this.setActiveView(lastActive.server, lastActive.tab); + this.setActiveView(lastActive.server, lastActive.view); } updateServers = async () => { @@ -239,11 +239,11 @@ class MainPage extends React.PureComponent { this.setState({unreadCounts: newUnreads, mentionCounts: newMentionCounts, sessionsExpired: expired}); }); - window.desktop.onCloseTeamsDropdown(() => { + window.desktop.onCloseServersDropdown(() => { this.setState({isMenuOpen: false}); }); - window.desktop.onOpenTeamsDropdown(() => { + window.desktop.onOpenServersDropdown(() => { this.setState({isMenuOpen: true}); }); @@ -290,7 +290,7 @@ class MainPage extends React.PureComponent { } handleCloseDropdowns = () => { - window.desktop.closeTeamsDropdown(); + window.desktop.closeServersDropdown(); this.closeDownloadsDropdown(); } @@ -307,7 +307,7 @@ class MainPage extends React.PureComponent { } handleCloseTab = (tabId: string) => { - window.desktop.closeTab(tabId); + window.desktop.closeView(tabId); } handleDragAndDrop = async (dropResult: DropResult) => { @@ -399,7 +399,7 @@ class MainPage extends React.PureComponent { render() { const {intl} = this.props; - let currentTabs: MattermostTab[] = []; + let currentTabs: UniqueView[] = []; if (this.state.activeServerId) { currentTabs = this.state.tabs.get(this.state.activeServerId) ?? []; } @@ -538,7 +538,7 @@ class MainPage extends React.PureComponent { /> {activeServer && ( - void; - onSave?: (team: MattermostTeam) => void; - team?: MattermostTeam; - currentTeams?: MattermostTeam[]; + onSave?: (server: UniqueServer) => void; + server?: UniqueServer; + currentServers?: UniqueServer[]; editMode?: boolean; show?: boolean; restoreFocus?: boolean; @@ -24,16 +24,16 @@ type Props = { }; type State = { - teamName: string; - teamUrl: string; - teamId?: string; - teamOrder: number; + serverName: string; + serverUrl: string; + serverId?: string; + serverOrder: number; saveStarted: boolean; } -class NewTeamModal extends React.PureComponent { +class NewServerModal extends React.PureComponent { wasShown?: boolean; - teamUrlInputRef?: HTMLInputElement; + serverUrlInputRef?: HTMLInputElement; static defaultProps = { restoreFocus: true, @@ -44,90 +44,90 @@ class NewTeamModal extends React.PureComponent { this.wasShown = false; this.state = { - teamName: '', - teamUrl: '', - teamOrder: props.currentOrder || 0, + serverName: '', + serverUrl: '', + serverOrder: props.currentOrder || 0, saveStarted: false, }; } initializeOnShow() { this.setState({ - teamName: this.props.team ? this.props.team.name : '', - teamUrl: this.props.team ? this.props.team.url : '', - teamId: this.props.team?.id, + serverName: this.props.server ? this.props.server.name : '', + serverUrl: this.props.server ? this.props.server.url : '', + serverId: this.props.server?.id, saveStarted: false, }); } - getTeamNameValidationError() { + getServerNameValidationError() { if (!this.state.saveStarted) { return null; } - if (this.props.currentTeams) { - const currentTeams = [...this.props.currentTeams]; - if (currentTeams.find((team) => team.id !== this.state.teamId && team.name === this.state.teamName)) { + if (this.props.currentServers) { + const currentServers = [...this.props.currentServers]; + if (currentServers.find((server) => server.id !== this.state.serverId && server.name === this.state.serverName)) { return ( ); } } - return this.state.teamName.length > 0 ? null : ( + return this.state.serverName.length > 0 ? null : ( ); } - getTeamNameValidationState() { - return this.getTeamNameValidationError() === null ? null : 'error'; + getServerNameValidationState() { + return this.getServerNameValidationError() === null ? null : 'error'; } - handleTeamNameChange = (e: React.ChangeEvent) => { + handleServerNameChange = (e: React.ChangeEvent) => { this.setState({ - teamName: e.target.value, + serverName: e.target.value, }); } - getTeamUrlValidationError() { + getServerUrlValidationError() { if (!this.state.saveStarted) { return null; } - if (this.props.currentTeams) { - const currentTeams = [...this.props.currentTeams]; - if (currentTeams.find((team) => team.id !== this.state.teamId && team.url === this.state.teamUrl)) { + if (this.props.currentServers) { + const currentServers = [...this.props.currentServers]; + if (currentServers.find((server) => server.id !== this.state.serverId && server.url === this.state.serverUrl)) { return ( ); } } - if (this.state.teamUrl.length === 0) { + if (this.state.serverUrl.length === 0) { return ( ); } - if (!(/^https?:\/\/.*/).test(this.state.teamUrl.trim())) { + if (!(/^https?:\/\/.*/).test(this.state.serverUrl.trim())) { return ( ); } - if (!isValidURL(this.state.teamUrl.trim())) { + if (!isValidURL(this.state.serverUrl.trim())) { return ( ); @@ -135,32 +135,32 @@ class NewTeamModal extends React.PureComponent { return null; } - getTeamUrlValidationState() { - return this.getTeamUrlValidationError() === null ? null : 'error'; + getServerUrlValidationState() { + return this.getServerUrlValidationError() === null ? null : 'error'; } - handleTeamUrlChange = (e: React.ChangeEvent) => { - const teamUrl = e.target.value; - this.setState({teamUrl}); + handleServerUrlChange = (e: React.ChangeEvent) => { + const serverUrl = e.target.value; + this.setState({serverUrl}); } - addProtocolToUrl = (teamUrl: string): Promise => { - if (teamUrl.startsWith('http://') || teamUrl.startsWith('https://')) { + addProtocolToUrl = (serverUrl: string): Promise => { + if (serverUrl.startsWith('http://') || serverUrl.startsWith('https://')) { return Promise.resolve(undefined); } - return window.desktop.modals.pingDomain(teamUrl). + return window.desktop.modals.pingDomain(serverUrl). then((result: string) => { - this.setState({teamUrl: `${result}://${this.state.teamUrl}`}); + this.setState({serverUrl: `${result}://${this.state.serverUrl}`}); }). catch(() => { - console.error(`Could not ping url: ${teamUrl}`); + console.error(`Could not ping url: ${serverUrl}`); }); } getError() { - const nameError = this.getTeamNameValidationError(); - const urlError = this.getTeamUrlValidationError(); + const nameError = this.getServerNameValidationError(); + const urlError = this.getServerUrlValidationError(); if (nameError && urlError) { return ( @@ -179,20 +179,20 @@ class NewTeamModal extends React.PureComponent { } validateForm() { - return this.getTeamNameValidationState() === null && - this.getTeamUrlValidationState() === null; + return this.getServerNameValidationState() === null && + this.getServerUrlValidationState() === null; } save = async () => { - await this.addProtocolToUrl(this.state.teamUrl); + await this.addProtocolToUrl(this.state.serverUrl); this.setState({ saveStarted: true, }, () => { if (this.validateForm()) { this.props.onSave?.({ - url: this.state.teamUrl, - name: this.state.teamName, - id: this.state.teamId, + url: this.state.serverUrl, + name: this.state.serverName, + id: this.state.serverId, }); } }); @@ -219,14 +219,14 @@ class NewTeamModal extends React.PureComponent { if (this.props.editMode) { return ( ); } return ( ); @@ -241,11 +241,11 @@ class NewTeamModal extends React.PureComponent { return ( this.teamUrlInputRef?.focus()} + onEntered={() => this.serverUrlInputRef?.focus()} onHide={this.props.onClose} restoreFocus={this.props.restoreFocus} onKeyDown={(e: React.KeyboardEvent) => { @@ -272,58 +272,58 @@ class NewTeamModal extends React.PureComponent { ) => { e.stopPropagation(); }} ref={(ref: HTMLInputElement) => { - this.teamUrlInputRef = ref; + this.serverUrlInputRef = ref; if (this.props.setInputRef) { this.props.setInputRef(ref); } }} - isInvalid={Boolean(this.getTeamUrlValidationState())} + isInvalid={Boolean(this.getServerUrlValidationState())} autoFocus={true} /> - + ) => { e.stopPropagation(); }} - isInvalid={Boolean(this.getTeamNameValidationState())} + isInvalid={Boolean(this.getServerNameValidationState())} /> - + @@ -367,4 +367,4 @@ class NewTeamModal extends React.PureComponent { } } -export default injectIntl(NewTeamModal); +export default injectIntl(NewServerModal); diff --git a/src/renderer/components/TeamDropdownButton.tsx b/src/renderer/components/ServerDropdownButton.tsx similarity index 76% rename from src/renderer/components/TeamDropdownButton.tsx rename to src/renderer/components/ServerDropdownButton.tsx index 44794d9e..76dca821 100644 --- a/src/renderer/components/TeamDropdownButton.tsx +++ b/src/renderer/components/ServerDropdownButton.tsx @@ -5,7 +5,7 @@ import classNames from 'classnames'; import React, {useEffect} from 'react'; import {FormattedMessage} from 'react-intl'; -import '../css/components/TeamDropdownButton.scss'; +import '../css/components/ServerDropdownButton.scss'; type Props = { isDisabled?: boolean; @@ -16,7 +16,7 @@ type Props = { darkMode: boolean; } -const TeamDropdownButton: React.FC = (props: Props) => { +const ServerDropdownButton: React.FC = (props: Props) => { const {isDisabled, activeServerName, totalMentionCount, hasUnreads, isMenuOpen, darkMode} = props; const buttonRef: React.RefObject = React.createRef(); @@ -30,22 +30,22 @@ const TeamDropdownButton: React.FC = (props: Props) => { event.preventDefault(); event.stopPropagation(); if (isMenuOpen) { - window.desktop.closeTeamsDropdown(); + window.desktop.closeServersDropdown(); } else { - window.desktop.openTeamsDropdown(); + window.desktop.openServersDropdown(); } }; let badgeDiv: React.ReactNode; if (totalMentionCount > 0) { badgeDiv = ( -
+
{totalMentionCount > 99 ? '99+' : totalMentionCount}
); } else if (hasUnreads) { badgeDiv = ( -
+
); } @@ -53,7 +53,7 @@ const TeamDropdownButton: React.FC = (props: Props) => { - {badgeDiv &&
+ {badgeDiv &&
{badgeDiv}
}
} @@ -350,13 +350,13 @@ class TeamDropdown extends React.PureComponent, State> { )} -
+
{this.state.enableServerManagement &&