[MM-52696] Upgrade and clean up Desktop App dev dependencies (#2970)

* Upgrade to ESLint v8

* Upgrade TypeScript, api-types, react-intl

* Remove unnecessary dependencies

* Update to React 17.0.2

* npm audit fixes, remove storybook

* Lock some packages

* Remove nan patch

* Remove some deprecated dependencies

* Fix lint/type/tests

* Merge'd

* Fix bad use of spawn

* Fix notarize

* Fix afterpack, switch to tsc es2020

* Fix api types

* Use @mattermost/eslint-plugin
This commit is contained in:
Devin Binnie 2024-03-07 15:55:33 -05:00 committed by GitHub
parent 12d59cd81c
commit 9b36c25e4e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
198 changed files with 4997 additions and 17374 deletions

View file

@ -1,162 +0,0 @@
{
"root": true,
"extends": [
"plugin:mattermost/react",
"plugin:cypress/recommended",
"plugin:react-hooks/recommended"
],
"plugins": [
"babel",
"mattermost",
"import",
"cypress",
"no-only-tests",
"@typescript-eslint"
],
"parser": "@typescript-eslint/parser",
"env": {
"jest": true,
"cypress/globals": true
},
"settings": {
"import/resolver": "webpack",
"react": {
"pragma": "React",
"version": "detect"
}
},
"rules": {
"max-nested-callbacks": ["error", 10],
"no-unused-expressions": 0,
"babel/no-unused-expressions": 2,
"eol-last": ["error", "always"],
"import/no-unresolved": 2,
"import/order": [
2,
{
"newlines-between": "always-and-inside-groups",
"groups": [
"builtin",
"external",
[
"internal",
"parent"
],
"sibling",
"index"
]
}
],
"no-undefined": 0,
"no-use-before-define": 0,
"react/jsx-filename-extension": 0,
"react/prop-types": [
2,
{
"ignore": [
"location",
"history",
"component"
]
}
],
"react/no-string-refs": 2,
"no-only-tests/no-only-tests": ["error", {"focus": ["only", "skip"]}],
"react/style-prop-object": [2, {
"allow": ["Timestamp"]
}],
"no-restricted-imports": ["error", {
"paths": [
{"name": "react-bootstrap", "importNames": ["OverlayTrigger"], "message": "Please use OverlayTrigger from '/components/overlay_trigger' instead"}
]
}]
},
"overrides": [
{
"files": ["**/*.tsx", "**/*.ts"],
"extends": [
"plugin:@typescript-eslint/recommended"
],
"rules": {
"camelcase": 0,
"no-shadow": 0,
"import/no-unresolved": 0, // ts handles this better
"@typescript-eslint/naming-convention": [
2,
{
"selector": "function",
"format": ["camelCase", "PascalCase"]
},
{
"selector": "variable",
"format": ["camelCase", "PascalCase", "UPPER_CASE"]
},
{
"selector": "parameter",
"format": ["camelCase", "PascalCase"],
"leadingUnderscore": "allow"
},
{
"selector": "typeLike",
"format": ["PascalCase"]
}
],
"@typescript-eslint/no-non-null-assertion": 0,
"@typescript-eslint/no-unused-vars": [
2,
{
"vars": "all",
"args": "after-used"
}
],
"@typescript-eslint/no-var-requires": 0,
"@typescript-eslint/no-empty-function": 0,
"@typescript-eslint/prefer-interface": 0,
"@typescript-eslint/explicit-function-return-type": 0,
"@typescript-eslint/explicit-module-boundary-types": 0,
"@typescript-eslint/indent": [
2,
4,
{
"SwitchCase": 0
}
],
"@typescript-eslint/no-use-before-define": [
2,
{
"classes": false,
"functions": false,
"variables": false
}
]
}
},
{
"files": ["tests/**", "**/*.test.*", "tests/*.js", "packages/mattermost-redux/test/*"],
"env": {
"jest": true
},
"rules": {
"func-names": 0,
"global-require": 0,
"max-lines": 0,
"new-cap": 0,
"no-empty-function": 0,
"no-import-assign": 0,
"no-process-env": 0,
"prefer-arrow-callback": 0
}
},
{
"files": ["e2e/**"],
"rules": {
"babel/no-unused-expressions": 0,
"func-names": 0,
"import/no-unresolved": 0,
"max-nested-callbacks": 0,
"no-process-env": 0,
"no-unused-expressions": 0
}
}
]
}

View file

@ -1,10 +1,12 @@
{ {
"root": true,
"extends": [ "extends": [
"./.eslintrc-webapp.json" "plugin:@mattermost/react"
],
"plugins": [
"formatjs",
"no-only-tests"
], ],
"parserOptions": {
"ecmaVersion": 2017
},
"settings": { "settings": {
"import/resolver": { "import/resolver": {
"webpack": { "webpack": {
@ -27,7 +29,8 @@
"react/no-find-dom-node": 2, "react/no-find-dom-node": 2,
"multiline-ternary": 0, "multiline-ternary": 0,
"max-lines": ["warn", 650], "max-lines": ["warn", 650],
"no-underscore-dangle": ["warn"] "no-underscore-dangle": ["warn"],
"@mattermost/use-external-link": 0
}, },
"overrides": [ "overrides": [
{ {

4
.vscode/launch.json vendored
View file

@ -38,8 +38,6 @@
"name": "E2E Tests", "name": "E2E Tests",
"program": "${workspaceRoot}/node_modules/electron-mocha/bin/electron-mocha", "program": "${workspaceRoot}/node_modules/electron-mocha/bin/electron-mocha",
"args": [ "args": [
"-r",
"@babel/register",
"--recursive", "--recursive",
"--timeout", "--timeout",
"999999", "999999",
@ -55,8 +53,6 @@
"name": "E2E Performance Tests", "name": "E2E Performance Tests",
"program": "${workspaceRoot}/node_modules/electron-mocha/bin/electron-mocha", "program": "${workspaceRoot}/node_modules/electron-mocha/bin/electron-mocha",
"args": [ "args": [
"-r",
"@babel/register",
"--recursive", "--recursive",
"--timeout", "--timeout",
"999999", "999999",

View file

@ -676,40 +676,6 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--- ---
## @babel/register
This product contains '@babel/register' by Babel.
One of the ways you can use Babel is through the require hook.
* HOMEPAGE:
* https://babel.dev/docs/babel-register
* LICENSE: MIT License
Copyright (c) 2014-present Sebastian McKenzie and other contributors
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
---
## @electron/fuses ## @electron/fuses
This product contains '@electron/fuses' by Electron. This product contains '@electron/fuses' by Electron.
@ -744,39 +710,6 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--- ---
## @electron/universal
This product contains '@electron/universal' by Electron.
Create universal macOS Electron applications.
* HOMEPAGE:
* https://github.com/electron/universal
* LICENSE: MIT License
Copyright (c) Contributors to the Electron project
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
---
## @mattermost/compass-icons ## @mattermost/compass-icons
This product contains '@mattermost/compass-icons' by Mattermost. This product contains '@mattermost/compass-icons' by Mattermost.
@ -1187,38 +1120,6 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
--- ---
## babel-eslint
This product contains 'babel-eslint' by Babel.
@babel/eslint-parser allows you to lint ALL valid Babel code with the fantastic ESLint.
* HOMEPAGE:
* https://github.com/babel/babel/tree/main/eslint/babel-eslint-parser
* LICENSE: MIT License
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
---
## babel-loader ## babel-loader
This product contains 'babel-loader' by Babel. This product contains 'babel-loader' by Babel.
@ -1864,78 +1765,6 @@ SOFTWARE.
--- ---
## eslint-plugin-babel
This product contains 'eslint-plugin-babel' by Babel.
Companion rules for @babel/eslint-parser.
* HOMEPAGE:
* https://github.com/babel/babel/tree/main/eslint/babel-eslint-plugin
* LICENSE: MIT
Copyright (c) 2014-2015 Jason Quense <jason@quense.me>
Original work by respective rule authors; copywrites noted in files.
MIT License
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
---
## eslint-plugin-cypress
This product contains 'eslint-plugin-cypress' by Cypress.io.
An ESLint plugin for your Cypress tests.
* HOMEPAGE:
* https://github.com/cypress-io/eslint-plugin-cypress
* LICENSE: MIT License
MIT License
Copyright (c) 2019 Cypress.io
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
---
## eslint-plugin-header ## eslint-plugin-header
This product contains 'eslint-plugin-header' by Stuart Knightley. This product contains 'eslint-plugin-header' by Stuart Knightley.
@ -2695,39 +2524,6 @@ Set of utilities to help in mattermost development.
--- ---
## mocha-circleci-reporter
This product contains 'mocha-circleci-reporter' by Glenn Morton.
A Mocha reporter specifically for Circle CI.
* HOMEPAGE:
* https://github.com/sandcastle/mocha-circleci-reporter
* LICENSE: The MIT License (MIT)
Copyright (c) 2015 Glenn Morton
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
---
## mochawesome ## mochawesome
This product contains 'mochawesome' by Adam Gruber. This product contains 'mochawesome' by Adam Gruber.
@ -3519,39 +3315,6 @@ IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
--- ---
## shebang-loader
This product contains 'shebang-loader' by Javascript is Magic.
shebang loader for webpack
* HOMEPAGE:
* https://github.com/javascriptismagic/shebang-loader
* LICENSE: The MIT License (MIT)
Copyright (c) 2016 unicorn.coffee
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
---
## style-loader ## style-loader
This product contains 'style-loader' by devrafalko. This product contains 'style-loader' by devrafalko.

View file

@ -1,15 +1,15 @@
{ {
"name": "@mattermost/desktop-api", "name": "@mattermost/desktop-api",
"version": "5.7.0-3", "version": "5.8.0-1",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "@mattermost/desktop-api", "name": "@mattermost/desktop-api",
"version": "5.7.0-3", "version": "5.8.0-1",
"license": "MIT", "license": "MIT",
"peerDependencies": { "peerDependencies": {
"typescript": "^4.3" "typescript": "^4.3.0 || ^5.0.0"
}, },
"peerDependenciesMeta": { "peerDependenciesMeta": {
"typescript": { "typescript": {

View file

@ -1,6 +1,6 @@
{ {
"name": "@mattermost/desktop-api", "name": "@mattermost/desktop-api",
"version": "5.7.0-3", "version": "5.8.0-1",
"description": "Shared types for the Desktop App API provided to the Web App", "description": "Shared types for the Desktop App API provided to the Web App",
"keywords": [ "keywords": [
"mattermost" "mattermost"
@ -18,7 +18,7 @@
"directory": "api-types" "directory": "api-types"
}, },
"peerDependencies": { "peerDependencies": {
"typescript": "^4.3" "typescript": "^4.3.0 || ^5.0.0"
}, },
"peerDependenciesMeta": { "peerDependenciesMeta": {
"typescript": { "typescript": {

View file

@ -8,8 +8,8 @@ module.exports = (api) => { // eslint-disable-line import/no-commonjs
presets: [ presets: [
['@babel/preset-env', { ['@babel/preset-env', {
targets: { targets: {
browsers: ['Electron >= 2.0'], browsers: ['Electron >= 29.0'],
node: '8.9', node: '20.9',
}, },
}], }],
'@babel/preset-react', '@babel/preset-react',
@ -18,6 +18,10 @@ module.exports = (api) => { // eslint-disable-line import/no-commonjs
isTSX: true, isTSX: true,
}], }],
], ],
plugins: ['@babel/plugin-proposal-object-rest-spread', '@babel/plugin-proposal-class-properties'], plugins: [
'@babel/plugin-transform-object-rest-spread',
'@babel/plugin-transform-class-properties',
'@babel/plugin-transform-private-methods',
],
}; };
}; };

View file

@ -4,18 +4,16 @@
'use strict'; 'use strict';
const fs = require('fs'); const fs = require('fs');
const path = require('path'); const path = require('path');
const ps = require('ps-node');
const {_electron: electron} = require('playwright');
const chai = require('chai'); const chai = require('chai');
const {ipcRenderer} = require('electron'); const {ipcRenderer} = require('electron');
const {_electron: electron} = require('playwright');
const {SHOW_SETTINGS_WINDOW} = require('../../src/common/communication'); const ps = require('ps-node');
const {asyncSleep, mkDirAsync, rmDirAsync, unlinkAsync} = require('./utils'); const {asyncSleep, mkDirAsync, rmDirAsync, unlinkAsync} = require('./utils');
const {SHOW_SETTINGS_WINDOW} = require('../../src/common/communication');
chai.should(); chai.should();
const sourceRootDir = path.join(__dirname, '../..'); const sourceRootDir = path.join(__dirname, '../..');

View file

@ -29,9 +29,10 @@
const path = require('path'); const path = require('path');
const chai = require('chai');
const generator = require('mochawesome-report-generator'); const generator = require('mochawesome-report-generator');
const {saveArtifacts} = require('./utils/artifacts');
const {MOCHAWESOME_REPORT_DIR} = require('./utils/constants');
const { const {
generateShortSummary, generateShortSummary,
generateTestReport, generateTestReport,
@ -40,8 +41,6 @@ const {
readJsonFromFile, readJsonFromFile,
writeJsonToFile, writeJsonToFile,
} = require('./utils/report'); } = require('./utils/report');
const {saveArtifacts} = require('./utils/artifacts');
const {MOCHAWESOME_REPORT_DIR} = require('./utils/constants');
const {createTestCycle, createTestExecutions} = require('./utils/test_cases'); const {createTestCycle, createTestExecutions} = require('./utils/test_cases');
require('dotenv').config(); require('dotenv').config();
@ -51,7 +50,6 @@ const saveReport = async () => {
BRANCH, BRANCH,
BUILD_ID, BUILD_ID,
BUILD_TAG, BUILD_TAG,
FAILURE_MESSAGE,
ZEPHYR_ENABLE, ZEPHYR_ENABLE,
ZEPHYR_CYCLE_KEY, ZEPHYR_CYCLE_KEY,
TYPE, TYPE,

View file

@ -7,7 +7,6 @@ const fs = require('fs');
const robot = require('robotjs'); const robot = require('robotjs');
const {SHOW_SETTINGS_WINDOW} = require('../../src/common/communication'); const {SHOW_SETTINGS_WINDOW} = require('../../src/common/communication');
const env = require('../modules/environment'); const env = require('../modules/environment');
const {asyncSleep} = require('../modules/utils'); const {asyncSleep} = require('../modules/utils');

View file

@ -35,8 +35,10 @@ describe('history_menu', function desc() {
const firstServer = this.serverMap[`${config.teams[0].name}___TAB_MESSAGING`].win; const firstServer = this.serverMap[`${config.teams[0].name}___TAB_MESSAGING`].win;
await env.loginToMattermost(firstServer); await env.loginToMattermost(firstServer);
await firstServer.waitForSelector('#sidebarItem_off-topic'); await firstServer.waitForSelector('#sidebarItem_off-topic');
// click on Off topic channel // click on Off topic channel
await firstServer.click('#sidebarItem_off-topic'); await firstServer.click('#sidebarItem_off-topic');
// click on town square channel // click on town square channel
await firstServer.click('#sidebarItem_town-square'); await firstServer.click('#sidebarItem_town-square');
await firstServer.locator('[aria-label="Back"]').click(); await firstServer.locator('[aria-label="Back"]').click();

View file

@ -7,7 +7,6 @@
const fs = require('fs'); const fs = require('fs');
const {SHOW_SETTINGS_WINDOW} = require('../../src/common/communication'); const {SHOW_SETTINGS_WINDOW} = require('../../src/common/communication');
const env = require('../modules/environment'); const env = require('../modules/environment');
const {asyncSleep} = require('../modules/utils'); const {asyncSleep} = require('../modules/utils');

View file

@ -8,7 +8,6 @@ const fs = require('fs');
const robot = require('robotjs'); const robot = require('robotjs');
const {SHOW_SETTINGS_WINDOW} = require('../../../src/common/communication'); const {SHOW_SETTINGS_WINDOW} = require('../../../src/common/communication');
const env = require('../../modules/environment'); const env = require('../../modules/environment');
const {asyncSleep} = require('../../modules/utils'); const {asyncSleep} = require('../../modules/utils');

View file

@ -4,12 +4,11 @@
/* eslint-disable no-console,consistent-return */ /* eslint-disable no-console,consistent-return */
const fs = require('fs'); const fs = require('fs');
const path = require('path'); const path = require('path');
const async = require('async');
const {Upload} = require('@aws-sdk/lib-storage');
const {S3} = require('@aws-sdk/client-s3'); const {S3} = require('@aws-sdk/client-s3');
const {Upload} = require('@aws-sdk/lib-storage');
const async = require('async');
const mime = require('mime-types'); const mime = require('mime-types');
const readdir = require('recursive-readdir'); const readdir = require('recursive-readdir');
@ -29,7 +28,7 @@ const {
const s3 = new S3({ const s3 = new S3({
credentials: { credentials: {
accessKeyId: AWS_ACCESS_KEY_ID, accessKeyId: AWS_ACCESS_KEY_ID,
secretAccessKey: AWS_SECRET_ACCESS_KEY secretAccessKey: AWS_SECRET_ACCESS_KEY,
}, },
}); });

View file

@ -8,10 +8,10 @@ const os = require('os');
const axios = require('axios'); const axios = require('axios');
const fse = require('fs-extra'); const fse = require('fs-extra');
const package = require('../../package.json');
const {MOCHAWESOME_REPORT_DIR} = require('./constants'); const {MOCHAWESOME_REPORT_DIR} = require('./constants');
const package = require('../../package.json');
const MAX_FAILED_TITLES = 5; const MAX_FAILED_TITLES = 5;
let incrementalDuration = 0; let incrementalDuration = 0;
@ -116,11 +116,11 @@ function getOS() {
function getEnvironmentValues() { function getEnvironmentValues() {
return { return {
playwright_version: package.devDependencies.playwright, playwrightVersion: package.devDependencies.playwright,
electron_version: package.devDependencies.electron, electronVersion: package.devDependencies.electron,
os_name: getOS(), osName: getOS(),
os_version: os.release(), osVersion: os.release(),
node_version: process.version, nodeVersion: process.version,
}; };
} }
@ -138,11 +138,11 @@ function generateTestReport(summary, isUploadedToS3, reportLink, testCycleKey) {
} = process.env; } = process.env;
const {statsFieldValue, stats} = summary; const {statsFieldValue, stats} = summary;
const { const {
playwright_version, playwrightVersion,
electron_version, electronVersion,
os_name, osName,
os_version, osVersion,
node_version, nodeVersion,
} = getEnvironmentValues(); } = getEnvironmentValues();
let testResult; let testResult;
@ -154,7 +154,7 @@ function generateTestReport(summary, isUploadedToS3, reportLink, testCycleKey) {
} }
const title = generateTitle(); const title = generateTitle();
const envValue = `playwright@${playwright_version} | node@${node_version} | electron@${electron_version} | ${os_name}@${os_version}`; const envValue = `playwright@${playwrightVersion} | node@${nodeVersion} | electron@${electronVersion} | ${osName}@${osVersion}`;
if (FULL_REPORT === 'true') { if (FULL_REPORT === 'true') {
let reportField; let reportField;

19790
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -46,8 +46,8 @@
"test:e2e:nobuild": "cross-env NODE_ENV=test npm-run-all test:e2e:build test:e2e:run", "test:e2e:nobuild": "cross-env NODE_ENV=test npm-run-all test:e2e:build test:e2e:run",
"test:e2e:build": "webpack-cli --config webpack.config.test.js", "test:e2e:build": "webpack-cli --config webpack.config.test.js",
"test:e2e:build-performance": "webpack-cli --config webpack.config.performance.test.js", "test:e2e:build-performance": "webpack-cli --config webpack.config.performance.test.js",
"test:e2e:run-performance": "electron-mocha -r @babel/register --reporter json --reporter-option output=./e2e/performance/perf-test-report.json dist/tests/e2e_bundle.js", "test:e2e:run-performance": "electron-mocha --reporter json --reporter-option output=./e2e/performance/perf-test-report.json dist/tests/e2e_bundle.js",
"test:e2e:run": "electron-mocha -r @babel/register --reporter mochawesome dist/tests/e2e_bundle.js", "test:e2e:run": "electron-mocha --reporter mochawesome dist/tests/e2e_bundle.js",
"test:e2e:send-report": "node ./e2e/save_report.js", "test:e2e:send-report": "node ./e2e/save_report.js",
"test:unit": "cross-env NODE_ENV=jest jest", "test:unit": "cross-env NODE_ENV=jest jest",
"test:unit-ci": "cross-env NODE_ENV=jest jest", "test:unit-ci": "cross-env NODE_ENV=jest jest",
@ -71,12 +71,12 @@
"fix:js": "eslint --ignore-path .gitignore --ignore-pattern node_modules --quiet --ext .js --ext .jsx --ext .ts --ext .tsx . --fix", "fix:js": "eslint --ignore-path .gitignore --ignore-pattern node_modules --quiet --ext .js --ext .jsx --ext .ts --ext .tsx . --fix",
"check-build-config": "npm-run-all check-build-config:build check-build-config:run", "check-build-config": "npm-run-all check-build-config:build check-build-config:run",
"check-build-config:build": "babel ./src/common/config/buildConfig.ts -o ./dist/buildConfig.js", "check-build-config:build": "babel ./src/common/config/buildConfig.ts -o ./dist/buildConfig.js",
"check-build-config:run": "node -r @babel/register scripts/check_build_config.js", "check-build-config:run": "node scripts/check_build_config.js",
"check-types": "tsc", "check-types": "tsc",
"prune": "ts-prune", "prune": "ts-prune",
"mmjstool": "mmjstool", "mmjstool": "mmjstool",
"i18n-extract": "npm run mmjstool -- i18n extract-desktop", "i18n-extract": "npm run mmjstool -- i18n extract-desktop",
"postinstall": "node scripts/postinstall.js && patch-package && electron-builder install-app-deps" "postinstall": "node scripts/postinstall.js && electron-builder install-app-deps"
}, },
"jest": { "jest": {
"clearMocks": true, "clearMocks": true,
@ -135,36 +135,28 @@
"devDependencies": { "devDependencies": {
"@aws-sdk/client-s3": "3.445.0", "@aws-sdk/client-s3": "3.445.0",
"@aws-sdk/lib-storage": "3.445.0", "@aws-sdk/lib-storage": "3.445.0",
"@babel/cli": "7.17.6", "@babel/cli": "7.23.9",
"@babel/core": "7.17.8", "@babel/preset-env": "7.24.0",
"@babel/plugin-proposal-class-properties": "7.16.7", "@babel/preset-react": "7.23.3",
"@babel/plugin-proposal-object-rest-spread": "7.17.3", "@babel/preset-typescript": "7.23.3",
"@babel/preset-env": "7.16.11",
"@babel/preset-react": "7.16.7",
"@babel/register": "7.17.7",
"@electron/fuses": "1.6.0", "@electron/fuses": "1.6.0",
"@electron/notarize": "2.3.0",
"@electron/rebuild": "3.6.0", "@electron/rebuild": "3.6.0",
"@electron/universal": "1.3.1",
"@mattermost/compass-icons": "0.1.32", "@mattermost/compass-icons": "0.1.32",
"@mattermost/desktop-api": "*", "@mattermost/desktop-api": "*",
"@storybook/addon-actions": "6.4.20", "@mattermost/eslint-plugin": "1.1.0-0",
"@storybook/react": "6.4.20", "@types/auto-launch": "5.0.5",
"@types/auto-launch": "5.0.2", "@types/jest": "29.4.1",
"@types/electron-devtools-installer": "2.2.1",
"@types/jest": "^29.0.0",
"@types/react": "17.0.43", "@types/react": "17.0.43",
"@types/react-beautiful-dnd": "13.0.0", "@types/react-beautiful-dnd": "13.1.8",
"@types/react-dom": "17.0.14", "@types/react-dom": "17.0.14",
"@types/uuid": "^9.0.1", "@types/uuid": "9.0.8",
"@types/valid-url": "1.0.3", "@types/valid-url": "1.0.7",
"@types/winreg": "1.2.31", "@types/winreg": "1.2.36",
"@typescript-eslint/eslint-plugin": "5.18.0",
"@typescript-eslint/parser": "5.18.0",
"7zip-bin": "5.1.1", "7zip-bin": "5.1.1",
"auto-launch": "5.0.5", "auto-launch": "5.0.5",
"axios": "0.26.1", "axios": "1.6.7",
"babel-eslint": "10.1.0", "babel-loader": "9.1.3",
"babel-loader": "8.2.4",
"bootstrap": "4.6.1", "bootstrap": "4.6.1",
"bootstrap-dark": "1.0.3", "bootstrap-dark": "1.0.3",
"chai": "4.3.6", "chai": "4.3.6",
@ -173,61 +165,54 @@
"cross-env": "7.0.3", "cross-env": "7.0.3",
"css-loader": "6.7.1", "css-loader": "6.7.1",
"electron": "29.0.0", "electron": "29.0.0",
"electron-builder": "24.12.0", "electron-builder": "24.13.3",
"electron-connect": "0.6.3", "electron-connect": "0.6.3",
"electron-context-menu": "3.6.1", "electron-context-menu": "3.6.1",
"electron-extension-installer": "1.2.0", "electron-extension-installer": "1.2.0",
"electron-is-dev": "2.0.0", "electron-is-dev": "2.0.0",
"electron-log": "4.4.8", "electron-log": "4.4.8",
"electron-mocha": "12.2.0", "electron-mocha": "12.2.0",
"electron-notarize": "1.2.2", "electron-updater": "6.1.8",
"electron-updater": "5.2.1", "eslint": "8.57.0",
"eslint": "7.29.0", "eslint-import-resolver-webpack": "0.13.8",
"eslint-import-resolver-webpack": "0.13.2", "eslint-plugin-formatjs": "4.12.2",
"eslint-plugin-babel": "5.3.1", "eslint-plugin-no-only-tests": "3.1.0",
"eslint-plugin-cypress": "2.11.3", "eslint-plugin-react": "7.34.0",
"eslint-plugin-header": "3.1.1", "eslint-plugin-react-hooks": "4.6.0",
"eslint-plugin-import": "2.25.4",
"eslint-plugin-mattermost": "github:mattermost/eslint-plugin-mattermost#5b0c972eacf19286e4c66221b39113bf8728a99e",
"eslint-plugin-no-only-tests": "2.6.0",
"eslint-plugin-react": "7.29.4",
"eslint-plugin-react-hooks": "4.4.0",
"fs-extra": "10.0.1", "fs-extra": "10.0.1",
"html-webpack-plugin": "5.5.0",
"jest": "29.4.1", "jest": "29.4.1",
"jest-junit": "13.1.0", "jest-junit": "13.1.0",
"joi": "17.6.0", "joi": "17.6.0",
"mini-css-extract-plugin": "2.6.0", "mini-css-extract-plugin": "2.6.0",
"mmjstool": "github:mattermost/mattermost-utilities#3b4506b0f6b14fbb402f9f8ef932370e459e3773", "mmjstool": "github:mattermost/mattermost-utilities#3b4506b0f6b14fbb402f9f8ef932370e459e3773",
"mocha-circleci-reporter": "0.0.3",
"mochawesome": "7.1.3", "mochawesome": "7.1.3",
"nan": "2.18.0", "nan": "2.19.0",
"node-abi": "3.56.0", "node-abi": "3.56.0",
"node-gyp": "10.0.1", "node-gyp": "10.0.1",
"node-jq": "2.3.4", "node-jq": "4.3.1",
"node-loader": "2.0.0", "node-loader": "2.0.0",
"npm-run-all": "4.1.5", "npm-run-all": "4.1.5",
"patch-package": "^8.0.0",
"playwright": "1.42.0", "playwright": "1.42.0",
"pretty-bytes": "6.0.0", "pretty-bytes": "6.0.0",
"ps-node": "^0.1.6", "ps-node": "0.1.6",
"react": "16.14.0", "react": "17.0.2",
"react-beautiful-dnd": "13.1.0", "react-beautiful-dnd": "13.1.0",
"react-bootstrap": "1.6.4", "react-bootstrap": "1.6.4",
"react-dom": "16.14.0", "react-dom": "17.0.2",
"react-intl": "5.20.10", "react-intl": "6.6.2",
"react-select": "5.2.2", "react-select": "5.2.2",
"recursive-readdir": "^2.2.2", "recursive-readdir": "2.2.3",
"robotjs": "0.6.0", "robotjs": "0.6.0",
"sass": "1.49.11", "sass": "1.49.11",
"sass-loader": "12.6.0", "sass-loader": "12.6.0",
"semver": "7.3.5", "semver": "7.6.0",
"shebang-loader": "0.0.1",
"style-loader": "3.3.1", "style-loader": "3.3.1",
"ts-prune": "0.10.3", "ts-prune": "0.10.3",
"typescript": "4.6.3", "typescript": "5.3.3",
"uuid": "9.0.0", "uuid": "9.0.0",
"valid-url": "1.0.9", "valid-url": "1.0.9",
"webpack": "5.71.0", "webpack": "5.90.3",
"webpack-cli": "4.10.0", "webpack-cli": "4.10.0",
"webpack-dev-server": "4.8.0", "webpack-dev-server": "4.8.0",
"webpack-merge": "5.8.0", "webpack-merge": "5.8.0",
@ -237,8 +222,5 @@
"dependencies": { "dependencies": {
"macos-notification-state": "2.0.2", "macos-notification-state": "2.0.2",
"windows-focus-assist": "1.3.0" "windows-focus-assist": "1.3.0"
},
"overrides": {
"@electron/universal": "1.3.1"
} }
} }

View file

@ -1,24 +0,0 @@
diff --git a/node_modules/nan/nan.h b/node_modules/nan/nan.h
index 2a68349..9c75907 100644
--- a/node_modules/nan/nan.h
+++ b/node_modules/nan/nan.h
@@ -2550,7 +2550,9 @@ NAN_DEPRECATED inline void SetAccessor(
, getter_
, setter_
, obj
+#if !defined(V8_MAJOR_VERSION) || V8_MAJOR_VERSION < 12
, settings
+#endif
, attribute
#if (NODE_MODULE_VERSION < NODE_16_0_MODULE_VERSION)
, signature
@@ -2596,7 +2598,9 @@ inline void SetAccessor(
, getter_
, setter_
, obj
+#if !defined(V8_MAJOR_VERSION) || V8_MAJOR_VERSION < 12
, settings
+#endif
, attribute
);
}

View file

@ -3,12 +3,11 @@
const path = require('path'); const path = require('path');
const {spawn} = require('electron-notarize/lib/spawn.js'); const {flipFuses, FuseVersion, FuseV1Options} = require('@electron/fuses');
const {spawn} = require('@electron/notarize/lib/spawn.js');
const SETUID_PERMISSIONS = '4755'; const SETUID_PERMISSIONS = '4755';
const {flipFuses, FuseVersion, FuseV1Options} = require('@electron/fuses');
function fixSetuid(context) { function fixSetuid(context) {
return async (target) => { return async (target) => {
if (!['appimage', 'snap'].includes(target.name.toLowerCase())) { if (!['appimage', 'snap'].includes(target.name.toLowerCase())) {

View file

@ -4,7 +4,6 @@
'use strict'; 'use strict';
const spawnSync = require('child_process').spawnSync; const spawnSync = require('child_process').spawnSync;
const path = require('path'); const path = require('path');
const path7za = require('7zip-bin').path7za; const path7za = require('7zip-bin').path7za;

View file

@ -3,7 +3,7 @@
// inspired by https://kilianvalkhof.com/2019/electron/notarizing-your-electron-application/ // inspired by https://kilianvalkhof.com/2019/electron/notarizing-your-electron-application/
require('dotenv').config(); require('dotenv').config();
const {notarize} = require('electron-notarize'); const {notarize} = require('@electron/notarize');
const config = require('../electron-builder.json'); const config = require('../electron-builder.json');

View file

@ -2,9 +2,10 @@
// See LICENSE.txt for license information. // See LICENSE.txt for license information.
const fs = require('fs'); const fs = require('fs');
const jq = require('node-jq');
const path = require('path'); const path = require('path');
const jq = require('node-jq');
// Patch the macos-notification-state library so we can build correctly // Patch the macos-notification-state library so we can build correctly
jq.run( jq.run(
'.scripts.install = "node-gyp rebuild"', '.scripts.install = "node-gyp rebuild"',
@ -22,7 +23,7 @@ if (process.platform === 'linux') {
if (fs.existsSync(xdgDir) && !fs.existsSync(path.resolve(xdgDir, 'mattermost-desktop-dev.desktop'))) { if (fs.existsSync(xdgDir) && !fs.existsSync(path.resolve(xdgDir, 'mattermost-desktop-dev.desktop'))) {
fs.writeFileSync( fs.writeFileSync(
path.resolve(xdgDir, 'mattermost-desktop-dev.desktop'), path.resolve(xdgDir, 'mattermost-desktop-dev.desktop'),
`[Desktop Entry] `[Desktop Entry]
Name=Mattermost.Dev Name=Mattermost.Dev
Exec=${path.resolve(process.cwd(), 'node_modules/electron/dist/electron')} ${path.resolve(process.cwd(), 'dist')} %U Exec=${path.resolve(process.cwd(), 'node_modules/electron/dist/electron')} ${path.resolve(process.cwd(), 'dist')} %U
Terminal=false Terminal=false
@ -32,7 +33,7 @@ StartupWMClass=Mattermost
Comment=Mattermost Comment=Mattermost
MimeType=x-scheme-handler/mattermost-dev; MimeType=x-scheme-handler/mattermost-dev;
Categories=contrib/net; Categories=contrib/net;
` `,
); );
const defaultsListPath = path.resolve(xdgDir, 'defaults.list'); const defaultsListPath = path.resolve(xdgDir, 'defaults.list');

View file

@ -1,8 +1,8 @@
// Copyright (c) 2015-2016 Yuya Ochiai // Copyright (c) 2015-2016 Yuya Ochiai
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved. // Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information. // See LICENSE.txt for license information.
const webpack = require('webpack');
const electron = require('electron-connect').server.create({path: 'dist/'}); const electron = require('electron-connect').server.create({path: 'dist/'});
const webpack = require('webpack');
const mainConfig = require('../webpack.config.main.js'); const mainConfig = require('../webpack.config.main.js');
const rendererConfig = require('../webpack.config.renderer.js'); const rendererConfig = require('../webpack.config.renderer.js');

View file

@ -1 +0,0 @@
import '@storybook/addon-actions/register';

View file

@ -1,10 +0,0 @@
import {configure} from '@storybook/react';
import 'bootstrap/dist/css/bootstrap.min.css';
const req = require.context('../browser/components', true, /\.stories\.jsx$/)
function loadStories() {
req.keys().forEach((filename) => req(filename))
}
configure(loadStories, module);

View file

@ -1,18 +0,0 @@
const path = require("path");
const rendererConfig = require('../../webpack.config.renderer');
// https://storybook.js.org/configurations/custom-webpack-config/#full-control-mode--default
module.exports = (storybookBaseConfig, configType) => {
// Avoid conflicting two instances of React due to two package.json structure
storybookBaseConfig.resolve.modules.unshift(path.resolve(__dirname, '../node_modules'));
// Use same rules
storybookBaseConfig.module.rules = rendererConfig.module.rules.concat({
test: /\.(ttf|woff2?|eot|svg)/,
use: {
loader: 'file-loader'
}
});
return storybookBaseConfig;
}

View file

@ -5,12 +5,11 @@ import {MattermostServer} from 'common/servers/MattermostServer';
import ServerManager from 'common/servers/serverManager'; import ServerManager from 'common/servers/serverManager';
import {URLValidationStatus} from 'common/utils/constants'; import {URLValidationStatus} from 'common/utils/constants';
import {getDefaultViewsForConfigServer} from 'common/views/View'; import {getDefaultViewsForConfigServer} from 'common/views/View';
import {ServerInfo} from 'main/server/serverInfo'; import {ServerInfo} from 'main/server/serverInfo';
import ModalManager from 'main/views/modalManager';
import {getLocalURLString, getLocalPreload} from 'main/utils'; import {getLocalURLString, getLocalPreload} from 'main/utils';
import MainWindow from 'main/windows/mainWindow'; import ModalManager from 'main/views/modalManager';
import ViewManager from 'main/views/viewManager'; import ViewManager from 'main/views/viewManager';
import MainWindow from 'main/windows/mainWindow';
import {ServerViewState} from './serverViewState'; import {ServerViewState} from './serverViewState';

View file

@ -1,10 +1,8 @@
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved. // Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information. // See LICENSE.txt for license information.
import {IpcMainEvent, IpcMainInvokeEvent, ipcMain} from 'electron'; import type {IpcMainEvent, IpcMainInvokeEvent} from 'electron';
import {ipcMain} from 'electron';
import {UniqueServer, Server} from 'types/config';
import {URLValidationResult} from 'types/server';
import { import {
CLOSE_VIEW, CLOSE_VIEW,
@ -22,18 +20,20 @@ import {
UPDATE_TAB_ORDER, UPDATE_TAB_ORDER,
VALIDATE_SERVER_URL, VALIDATE_SERVER_URL,
} from 'common/communication'; } from 'common/communication';
import {Logger} from 'common/log';
import ServerManager from 'common/servers/serverManager';
import {MattermostServer} from 'common/servers/MattermostServer';
import {isValidURI, isValidURL, parseURL} from 'common/utils/url';
import {URLValidationStatus} from 'common/utils/constants';
import Config from 'common/config'; import Config from 'common/config';
import {Logger} from 'common/log';
import ViewManager from 'main/views/viewManager'; import {MattermostServer} from 'common/servers/MattermostServer';
import ModalManager from 'main/views/modalManager'; import ServerManager from 'common/servers/serverManager';
import MainWindow from 'main/windows/mainWindow'; import {URLValidationStatus} from 'common/utils/constants';
import {getLocalPreload, getLocalURLString} from 'main/utils'; import {isValidURI, isValidURL, parseURL} from 'common/utils/url';
import {ServerInfo} from 'main/server/serverInfo'; import {ServerInfo} from 'main/server/serverInfo';
import {getLocalPreload, getLocalURLString} from 'main/utils';
import ModalManager from 'main/views/modalManager';
import ViewManager from 'main/views/viewManager';
import MainWindow from 'main/windows/mainWindow';
import type {UniqueServer, Server} from 'types/config';
import type {URLValidationResult} from 'types/server';
const log = new Logger('App', 'ServerViewState'); const log = new Logger('App', 'ServerViewState');
@ -65,7 +65,7 @@ export class ServerViewState {
this.currentServerId = orderedServers[0].id; this.currentServerId = orderedServers[0].id;
} }
} }
} };
getCurrentServer = () => { getCurrentServer = () => {
log.silly('getCurrentServer'); log.silly('getCurrentServer');
@ -78,7 +78,7 @@ export class ServerViewState {
throw new Error('Current server does not exist'); throw new Error('Current server does not exist');
} }
return server; return server;
} };
switchServer = (serverId: string, waitForViewToExist = false) => { switchServer = (serverId: string, waitForViewToExist = false) => {
ServerManager.getServerLog(serverId, 'WindowManager').debug('switchServer'); ServerManager.getServerLog(serverId, 'WindowManager').debug('switchServer');
@ -102,7 +102,7 @@ export class ServerViewState {
ViewManager.showById(nextView.id); ViewManager.showById(nextView.id);
} }
ipcMain.emit(UPDATE_SHORTCUT_MENU); ipcMain.emit(UPDATE_SHORTCUT_MENU);
} };
selectNextView = () => { selectNextView = () => {
this.selectView((order) => order + 1); this.selectView((order) => order + 1);
@ -115,7 +115,7 @@ export class ServerViewState {
updateCurrentView = (serverId: string, viewId: string) => { updateCurrentView = (serverId: string, viewId: string) => {
this.currentServerId = serverId; this.currentServerId = serverId;
ServerManager.updateLastActive(viewId); ServerManager.updateLastActive(viewId);
} };
/** /**
* Server Modals * Server Modals

View file

@ -3,17 +3,17 @@
import Joi from 'joi'; import Joi from 'joi';
import {Args} from 'types/args';
import {AnyConfig, ConfigV0, ConfigV1, ConfigV2, ConfigV3, ConfigServer} from 'types/config';
import {DownloadedItems} from 'types/downloads';
import {SavedWindowState} from 'types/mainWindow';
import {AppState} from 'types/appState';
import {ComparableCertificate} from 'types/certificate';
import {PermissionType, TrustedOrigin} from 'types/trustedOrigin';
import {Logger} from 'common/log'; import {Logger} from 'common/log';
import {TAB_MESSAGING} from 'common/views/View';
import {isValidURL} from 'common/utils/url'; import {isValidURL} from 'common/utils/url';
import {TAB_MESSAGING} from 'common/views/View';
import type {AppState} from 'types/appState';
import type {Args} from 'types/args';
import type {ComparableCertificate} from 'types/certificate';
import type {AnyConfig, ConfigV0, ConfigV1, ConfigV2, ConfigV3, ConfigServer} from 'types/config';
import type {DownloadedItems} from 'types/downloads';
import type {SavedWindowState} from 'types/mainWindow';
import type {PermissionType, TrustedOrigin} from 'types/trustedOrigin';
const log = new Logger('Validator'); const log = new Logger('Validator');
const defaultOptions = { const defaultOptions = {

View file

@ -4,8 +4,8 @@
import {EventEmitter} from 'events'; import {EventEmitter} from 'events';
import {UPDATE_APPSTATE, UPDATE_APPSTATE_TOTALS, UPDATE_APPSTATE_FOR_VIEW_ID} from 'common/communication'; import {UPDATE_APPSTATE, UPDATE_APPSTATE_TOTALS, UPDATE_APPSTATE_FOR_VIEW_ID} from 'common/communication';
import ServerManager from 'common/servers/serverManager';
import {Logger} from 'common/log'; import {Logger} from 'common/log';
import ServerManager from 'common/servers/serverManager';
const log = new Logger('AppState'); const log = new Logger('AppState');
@ -27,7 +27,7 @@ export class AppState extends EventEmitter {
this.expired.set(viewId, expired); this.expired.set(viewId, expired);
this.emitStatusForView(viewId); this.emitStatusForView(viewId);
} };
updateMentions = (viewId: string, mentions: number) => { updateMentions = (viewId: string, mentions: number) => {
ServerManager.getViewLog(viewId, 'AppState').silly('updateMentions', mentions); ServerManager.getViewLog(viewId, 'AppState').silly('updateMentions', mentions);
@ -49,7 +49,7 @@ export class AppState extends EventEmitter {
this.expired.delete(viewId); this.expired.delete(viewId);
this.mentions.delete(viewId); this.mentions.delete(viewId);
this.unreads.delete(viewId); this.unreads.delete(viewId);
} };
emitStatus = () => { emitStatus = () => {
log.silly('emitStatus'); log.silly('emitStatus');

View file

@ -6,10 +6,10 @@ import {EventEmitter} from 'events';
import WindowsRegistry from 'winreg'; import WindowsRegistry from 'winreg';
import WindowsRegistryUTF8 from 'winreg-utf8'; import WindowsRegistryUTF8 from 'winreg-utf8';
import {RegistryConfig as RegistryConfigType, Server} from 'types/config';
import {Logger} from 'common/log'; import {Logger} from 'common/log';
import type {RegistryConfig as RegistryConfigType, Server} from 'types/config';
const log = new Logger('RegistryConfig'); const log = new Logger('RegistryConfig');
const REGISTRY_HIVE_LIST = [WindowsRegistry.HKLM, WindowsRegistry.HKCU]; const REGISTRY_HIVE_LIST = [WindowsRegistry.HKLM, WindowsRegistry.HKCU];
const BASE_REGISTRY_KEY_PATH = '\\Software\\Policies\\Mattermost'; const BASE_REGISTRY_KEY_PATH = '\\Software\\Policies\\Mattermost';

View file

@ -2,7 +2,7 @@
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved. // Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information. // See LICENSE.txt for license information.
import {BuildConfig} from 'types/config'; import type {BuildConfig} from 'types/config';
// For detailed guides, please refer to https://docs.mattermost.com/deployment/desktop-app-deployment.html // For detailed guides, please refer to https://docs.mattermost.com/deployment/desktop-app-deployment.html

View file

@ -2,15 +2,15 @@
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved. // Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information. // See LICENSE.txt for license information.
import path from 'path';
import os from 'os'; import os from 'os';
import path from 'path';
/** /**
* Default user preferences. End-users can change these parameters by editing config.json * Default user preferences. End-users can change these parameters by editing config.json
* @param {number} version - Scheme version. (Not application version) * @param {number} version - Scheme version. (Not application version)
*/ */
import {ConfigV3} from 'types/config'; import type {ConfigV3} from 'types/config';
export const getDefaultDownloadLocation = (): string | undefined => { export const getDefaultDownloadLocation = (): string | undefined => {
// eslint-disable-next-line no-undef // eslint-disable-next-line no-undef

View file

@ -2,13 +2,17 @@
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved. // Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information. // See LICENSE.txt for license information.
import fs from 'fs'; import fs from 'fs';
import os from 'os'; import os from 'os';
import path from 'path'; import path from 'path';
import {EventEmitter} from 'events'; import {EventEmitter} from 'events';
import { import {Logger} from 'common/log';
import Utils, {copy} from 'common/utils/util';
import * as Validator from 'common/Validator';
import {getDefaultViewsForConfigServer} from 'common/views/View';
import type {
AnyConfig, AnyConfig,
BuildConfig, BuildConfig,
CombinedConfig, CombinedConfig,
@ -17,16 +21,11 @@ import {
RegistryConfig as RegistryConfigType, RegistryConfig as RegistryConfigType,
} from 'types/config'; } from 'types/config';
import {Logger} from 'common/log';
import {getDefaultViewsForConfigServer} from 'common/views/View';
import Utils, {copy} from 'common/utils/util';
import * as Validator from 'common/Validator';
import defaultPreferences, {getDefaultDownloadLocation} from './defaultPreferences';
import upgradeConfigData from './upgradePreferences';
import buildConfig from './buildConfig'; import buildConfig from './buildConfig';
import RegistryConfig, {REGISTRY_READ_EVENT} from './RegistryConfig'; import defaultPreferences, {getDefaultDownloadLocation} from './defaultPreferences';
import migrateConfigItems from './migrationPreferences'; import migrateConfigItems from './migrationPreferences';
import RegistryConfig, {REGISTRY_READ_EVENT} from './RegistryConfig';
import upgradeConfigData from './upgradePreferences';
const log = new Logger('Config'); const log = new Logger('Config');
@ -67,7 +66,7 @@ export class Config extends EventEmitter {
this.canUpgradeValue = this.checkWriteableApp(); this.canUpgradeValue = this.checkWriteableApp();
this.reload(); this.reload();
} };
initRegistry = () => { initRegistry = () => {
if (process.platform !== 'win32') { if (process.platform !== 'win32') {
@ -82,7 +81,7 @@ export class Config extends EventEmitter {
}); });
this.registryConfig.init(); this.registryConfig.init();
}); });
} };
/** /**
* Reload all sources of config data * Reload all sources of config data
@ -101,7 +100,7 @@ export class Config extends EventEmitter {
this.regenerateCombinedConfigData(); this.regenerateCombinedConfigData();
this.emit('update', this.combinedData); this.emit('update', this.combinedData);
} };
/********************* /*********************
* Setters and Getters * Setters and Getters
@ -116,11 +115,11 @@ export class Config extends EventEmitter {
set = (key: keyof ConfigType, data: ConfigType[keyof ConfigType]): void => { set = (key: keyof ConfigType, data: ConfigType[keyof ConfigType]): void => {
log.debug('set'); log.debug('set');
this.setMultiple({[key]: data}); this.setMultiple({[key]: data});
} };
setConfigPath = (configPath: string) => { setConfigPath = (configPath: string) => {
this.configFilePath = configPath; this.configFilePath = configPath;
} };
/** /**
* Used to save an array of config properties in one go * Used to save an array of config properties in one go
@ -136,7 +135,7 @@ export class Config extends EventEmitter {
this.localConfigData = Object.assign({}, this.localConfigData, {...newData, teams: this.localConfigData?.teams}); this.localConfigData = Object.assign({}, this.localConfigData, {...newData, teams: this.localConfigData?.teams});
this.regenerateCombinedConfigData(); this.regenerateCombinedConfigData();
this.saveLocalConfigData(); this.saveLocalConfigData();
} };
setServers = (servers: ConfigServer[], lastActiveServer?: number) => { setServers = (servers: ConfigServer[], lastActiveServer?: number) => {
log.debug('setServers', servers, lastActiveServer); log.debug('setServers', servers, lastActiveServer);
@ -144,7 +143,7 @@ export class Config extends EventEmitter {
this.localConfigData = Object.assign({}, this.localConfigData, {teams: servers, lastActiveTeam: lastActiveServer ?? this.localConfigData?.lastActiveTeam}); this.localConfigData = Object.assign({}, this.localConfigData, {teams: servers, lastActiveTeam: lastActiveServer ?? this.localConfigData?.lastActiveTeam});
this.regenerateCombinedConfigData(); this.regenerateCombinedConfigData();
this.saveLocalConfigData(); this.saveLocalConfigData();
} };
// getters for accessing the various config data inputs // getters for accessing the various config data inputs
@ -265,7 +264,7 @@ export class Config extends EventEmitter {
this._predefinedServers.push(...this.registryConfigData.servers.map((server, index) => getDefaultViewsForConfigServer({...server, order: index}))); this._predefinedServers.push(...this.registryConfigData.servers.map((server, index) => getDefaultViewsForConfigServer({...server, order: index})));
} }
this.reload(); this.reload();
} };
/** /**
* Config file loading methods * Config file loading methods
@ -299,7 +298,7 @@ export class Config extends EventEmitter {
} catch (error) { } catch (error) {
this.emit('error', error); this.emit('error', error);
} }
} };
/** /**
* Loads and returns locally stored config data from the filesystem or returns app defaults if no file is found * Loads and returns locally stored config data from the filesystem or returns app defaults if no file is found
@ -326,7 +325,7 @@ export class Config extends EventEmitter {
this.writeFile(this.configFilePath, configData); this.writeFile(this.configFilePath, configData);
} }
return configData; return configData;
} };
/** /**
* Determines if locally stored data needs to be updated and upgrades as needed * Determines if locally stored data needs to be updated and upgrades as needed
@ -357,7 +356,7 @@ export class Config extends EventEmitter {
} }
return configData as ConfigType; return configData as ConfigType;
} };
/** /**
* Properly combines all sources of data into a single, manageable set of all config data * Properly combines all sources of data into a single, manageable set of all config data
@ -384,7 +383,7 @@ export class Config extends EventEmitter {
if (this.combinedData) { if (this.combinedData) {
this.combinedData.appName = this.appName; this.combinedData.appName = this.appName;
} }
} };
// helper functions // helper functions
private writeFile = (filePath: string, configData: Partial<ConfigType>, callback?: fs.NoParamCallback) => { private writeFile = (filePath: string, configData: Partial<ConfigType>, callback?: fs.NoParamCallback) => {
@ -407,7 +406,7 @@ export class Config extends EventEmitter {
fs.writeFileSync(filePath, json, 'utf8'); fs.writeFileSync(filePath, json, 'utf8');
} }
} };
private checkWriteableApp = () => { private checkWriteableApp = () => {
if (!this.appPath) { if (!this.appPath) {
@ -440,7 +439,7 @@ export class Config extends EventEmitter {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment // eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore // @ts-ignore
return process.platform !== 'darwin' && __CAN_UPGRADE__; return process.platform !== 'darwin' && __CAN_UPGRADE__;
} };
} }
const config = new Config(); const config = new Config();

View file

@ -1,13 +1,12 @@
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved. // Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information. // See LICENSE.txt for license information.
import {Config, MigrationInfo} from 'types/config';
import JsonFileManager from 'common/JsonFileManager'; import JsonFileManager from 'common/JsonFileManager';
import {TAB_MESSAGING} from 'common/views/View'; import {TAB_MESSAGING} from 'common/views/View';
import {migrationInfoPath} from 'main/constants'; import {migrationInfoPath} from 'main/constants';
import type {Config, MigrationInfo} from 'types/config';
export default function migrateConfigItems(config: Config) { export default function migrateConfigItems(config: Config) {
const migrationPrefs = new JsonFileManager<MigrationInfo>(migrationInfoPath); const migrationPrefs = new JsonFileManager<MigrationInfo>(migrationInfoPath);
let didMigrate = false; let didMigrate = false;

View file

@ -1,7 +1,7 @@
// Copyright (c) 2015-2016 Yuya Ochiai // Copyright (c) 2015-2016 Yuya Ochiai
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved. // Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information. // See LICENSE.txt for license information.
import {ConfigV0, ConfigV1, ConfigV2} from 'types/config'; import type {ConfigV0, ConfigV1, ConfigV2} from 'types/config';
import defaultPreferences, {getDefaultDownloadLocation} from './defaultPreferences'; import defaultPreferences, {getDefaultDownloadLocation} from './defaultPreferences';

View file

@ -1,8 +1,8 @@
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved. // Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information. // See LICENSE.txt for license information.
import {upgradeV0toV1, upgradeV1toV2, upgradeV2toV3} from 'common/config/upgradePreferences';
import pastDefaultPreferences from 'common/config/pastDefaultPreferences'; import pastDefaultPreferences from 'common/config/pastDefaultPreferences';
import {upgradeV0toV1, upgradeV1toV2, upgradeV2toV3} from 'common/config/upgradePreferences';
jest.mock('common/views/View', () => ({ jest.mock('common/views/View', () => ({
getDefaultViewsForConfigServer: (value) => ({ getDefaultViewsForConfigServer: (value) => ({

View file

@ -2,10 +2,10 @@
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved. // Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information. // See LICENSE.txt for license information.
import {ConfigV3, ConfigV2, ConfigV1, ConfigV0, AnyConfig} from 'types/config';
import {getDefaultViewsForConfigServer} from 'common/views/View'; import {getDefaultViewsForConfigServer} from 'common/views/View';
import type {ConfigV3, ConfigV2, ConfigV1, ConfigV0, AnyConfig} from 'types/config';
import pastDefaultPreferences from './pastDefaultPreferences'; import pastDefaultPreferences from './pastDefaultPreferences';
function deepCopy<T>(object: T): T { function deepCopy<T>(object: T): T {

View file

@ -1,9 +1,9 @@
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved. // Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information. // See LICENSE.txt for license information.
import {DownloadedItem} from 'types/downloads'; import type {DownloadItemTypeEnum} from 'main/downloadsManager';
import {DownloadItemTypeEnum} from 'main/downloadsManager'; import type {DownloadedItem} from 'types/downloads';
/** /**
* This string includes special characters so that it's not confused with * This string includes special characters so that it's not confused with

View file

@ -1,7 +1,8 @@
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved. // Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information. // See LICENSE.txt for license information.
import log, {LevelOption} from 'electron-log'; import type {LevelOption} from 'electron-log';
import log from 'electron-log';
import Util from 'common/utils/util'; import Util from 'common/utils/util';
@ -37,15 +38,15 @@ export class Logger {
silly: this.prefixed(log.silly, ...prefixes), silly: this.prefixed(log.silly, ...prefixes),
log: this.prefixed(log.log, ...prefixes), log: this.prefixed(log.log, ...prefixes),
}; };
} };
private prefixed = (func: (...args: any[]) => void, ...additionalPrefixes: string[]) => { private prefixed = (func: (...args: any[]) => void, ...additionalPrefixes: string[]) => {
return (...args: any[]) => func(...this.prefixes, ...this.shortenPrefixes(...additionalPrefixes), ...args); return (...args: any[]) => func(...this.prefixes, ...this.shortenPrefixes(...additionalPrefixes), ...args);
} };
private shortenPrefixes = (...prefixes: string[]) => { private shortenPrefixes = (...prefixes: string[]) => {
return prefixes.map((prefix) => `[${Util.shorten(prefix)}]`); return prefixes.map((prefix) => `[${Util.shorten(prefix)}]`);
} };
error = this.prefixed(log.error); error = this.prefixed(log.error);
warn = this.prefixed(log.warn); warn = this.prefixed(log.warn);

View file

@ -3,10 +3,10 @@
import {v4 as uuid} from 'uuid'; import {v4 as uuid} from 'uuid';
import {UniqueServer, Server} from 'types/config';
import {parseURL} from 'common/utils/url'; import {parseURL} from 'common/utils/url';
import type {UniqueServer, Server} from 'types/config';
export class MattermostServer { export class MattermostServer {
id: string; id: string;
name: string; name: string;
@ -27,7 +27,7 @@ export class MattermostServer {
if (!this.url) { if (!this.url) {
throw new Error('Invalid url for creating a server'); throw new Error('Invalid url for creating a server');
} }
} };
toUniqueServer = (): UniqueServer => { toUniqueServer = (): UniqueServer => {
return { return {
@ -36,5 +36,5 @@ export class MattermostServer {
id: this.id, id: this.id,
isPredefined: this.isPredefined, isPredefined: this.isPredefined,
}; };
} };
} }

View file

@ -1,9 +1,9 @@
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved. // Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information. // See LICENSE.txt for license information.
import {TAB_MESSAGING, TAB_FOCALBOARD, TAB_PLAYBOOKS} from 'common/views/View';
import {parseURL, isInternalURL} from 'common/utils/url'; import {parseURL, isInternalURL} from 'common/utils/url';
import Utils from 'common/utils/util'; import Utils from 'common/utils/util';
import {TAB_MESSAGING, TAB_FOCALBOARD, TAB_PLAYBOOKS} from 'common/views/View';
import {ServerManager} from './serverManager'; import {ServerManager} from './serverManager';

View file

@ -3,21 +3,22 @@
import EventEmitter from 'events'; import EventEmitter from 'events';
import {Server, ConfigServer, ConfigView} from 'types/config';
import {RemoteInfo} from 'types/server';
import Config from 'common/config';
import { import {
SERVERS_URL_MODIFIED, SERVERS_URL_MODIFIED,
SERVERS_UPDATE, SERVERS_UPDATE,
} from 'common/communication'; } from 'common/communication';
import Config from 'common/config';
import {Logger, getLevel} from 'common/log'; import {Logger, getLevel} from 'common/log';
import {MattermostServer} from 'common/servers/MattermostServer'; import {MattermostServer} from 'common/servers/MattermostServer';
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 {getFormattedPathName, isInternalURL, parseURL} from 'common/utils/url'; import {getFormattedPathName, isInternalURL, parseURL} from 'common/utils/url';
import FocalboardView from 'common/views/FocalboardView';
import MessagingView from 'common/views/MessagingView';
import PlaybooksView from 'common/views/PlaybooksView';
import type {MattermostView} from 'common/views/View';
import {TAB_FOCALBOARD, TAB_MESSAGING, TAB_PLAYBOOKS, getDefaultViews} from 'common/views/View';
import type {Server, ConfigServer, ConfigView} from 'types/config';
import type {RemoteInfo} from 'types/server';
const log = new Logger('ServerManager'); const log = new Logger('ServerManager');
@ -55,7 +56,7 @@ export class ServerManager extends EventEmitter {
} }
return views; return views;
}, [] as MattermostView[]); }, [] as MattermostView[]);
} };
getOrderedServers = () => { getOrderedServers = () => {
log.debug('getOrderedServers'); log.debug('getOrderedServers');
@ -67,7 +68,7 @@ export class ServerManager extends EventEmitter {
} }
return servers; return servers;
}, [] as MattermostServer[]); }, [] as MattermostServer[]);
} };
getLastActiveTabForServer = (serverId: string) => { getLastActiveTabForServer = (serverId: string) => {
log.withPrefix(serverId).debug('getLastActiveTabForServer'); log.withPrefix(serverId).debug('getLastActiveTabForServer');
@ -80,27 +81,27 @@ export class ServerManager extends EventEmitter {
} }
} }
return this.getFirstOpenViewForServer(serverId); return this.getFirstOpenViewForServer(serverId);
} };
getServer = (id: string) => { getServer = (id: string) => {
return this.servers.get(id); return this.servers.get(id);
} };
getView = (id: string) => { getView = (id: string) => {
return this.views.get(id); return this.views.get(id);
} };
getAllServers = () => { getAllServers = () => {
return [...this.servers.values()]; return [...this.servers.values()];
} };
hasServers = () => { hasServers = () => {
return Boolean(this.servers.size); return Boolean(this.servers.size);
} };
getRemoteInfo = (serverId: string) => { getRemoteInfo = (serverId: string) => {
return this.remoteInfo.get(serverId); return this.remoteInfo.get(serverId);
} };
updateRemoteInfos = (remoteInfos: Map<string, RemoteInfo>) => { updateRemoteInfos = (remoteInfos: Map<string, RemoteInfo>) => {
let hasUpdates = false; let hasUpdates = false;
@ -112,7 +113,7 @@ export class ServerManager extends EventEmitter {
if (hasUpdates) { if (hasUpdates) {
this.persistServers(); this.persistServers();
} }
} };
lookupViewByURL = (inputURL: URL | string, ignoreScheme = false) => { lookupViewByURL = (inputURL: URL | string, ignoreScheme = false) => {
log.silly('lookupViewByURL', `${inputURL}`, ignoreScheme); log.silly('lookupViewByURL', `${inputURL}`, ignoreScheme);
@ -139,21 +140,21 @@ export class ServerManager extends EventEmitter {
} }
}); });
return selectedView; return selectedView;
} };
updateServerOrder = (serverOrder: string[]) => { updateServerOrder = (serverOrder: string[]) => {
log.debug('updateServerOrder', serverOrder); log.debug('updateServerOrder', serverOrder);
this.serverOrder = serverOrder; this.serverOrder = serverOrder;
this.persistServers(); this.persistServers();
} };
updateTabOrder = (serverId: string, viewOrder: string[]) => { updateTabOrder = (serverId: string, viewOrder: string[]) => {
log.withPrefix(serverId).debug('updateTabOrder', viewOrder); log.withPrefix(serverId).debug('updateTabOrder', viewOrder);
this.viewOrder.set(serverId, viewOrder); this.viewOrder.set(serverId, viewOrder);
this.persistServers(); this.persistServers();
} };
addServer = (server: Server) => { addServer = (server: Server) => {
const newServer = new MattermostServer(server, false); const newServer = new MattermostServer(server, false);
@ -176,7 +177,7 @@ export class ServerManager extends EventEmitter {
this.emit(SERVERS_URL_MODIFIED, [newServer.id]); this.emit(SERVERS_URL_MODIFIED, [newServer.id]);
this.persistServers(); this.persistServers();
return newServer; return newServer;
} };
editServer = (serverId: string, server: Server) => { editServer = (serverId: string, server: Server) => {
const existingServer = this.servers.get(serverId); const existingServer = this.servers.get(serverId);
@ -203,7 +204,7 @@ export class ServerManager extends EventEmitter {
urlModified?.(); urlModified?.();
this.persistServers(); this.persistServers();
} };
removeServer = (serverId: string) => { removeServer = (serverId: string) => {
this.viewOrder.get(serverId)?.forEach((viewId) => this.views.delete(viewId)); this.viewOrder.get(serverId)?.forEach((viewId) => this.views.delete(viewId));
@ -216,7 +217,7 @@ export class ServerManager extends EventEmitter {
this.servers.delete(serverId); this.servers.delete(serverId);
this.persistServers(); this.persistServers();
} };
setViewIsOpen = (viewId: string, isOpen: boolean) => { setViewIsOpen = (viewId: string, isOpen: boolean) => {
const view = this.views.get(viewId); const view = this.views.get(viewId);
@ -226,7 +227,7 @@ export class ServerManager extends EventEmitter {
view.isOpen = isOpen; view.isOpen = isOpen;
this.persistServers(); this.persistServers();
} };
updateLastActive = (viewId: string) => { updateLastActive = (viewId: string) => {
const view = this.views.get(viewId); const view = this.views.get(viewId);
@ -241,7 +242,7 @@ export class ServerManager extends EventEmitter {
} }
this.persistServers(serverOrder); this.persistServers(serverOrder);
} };
reloadFromConfig = () => { reloadFromConfig = () => {
const serverOrder: string[] = []; const serverOrder: string[] = [];
@ -257,7 +258,7 @@ export class ServerManager extends EventEmitter {
} }
this.filterOutDuplicateServers(); this.filterOutDuplicateServers();
this.serverOrder = serverOrder; this.serverOrder = serverOrder;
} };
private filterOutDuplicateServers = () => { private filterOutDuplicateServers = () => {
const servers = [...this.servers.keys()].map((key) => ({key, value: this.servers.get(key)!})); const servers = [...this.servers.keys()].map((key) => ({key, value: this.servers.get(key)!}));
@ -269,7 +270,7 @@ export class ServerManager extends EventEmitter {
uniqueServers.add(`${server.value.name}:${server.value.url}`); uniqueServers.add(`${server.value.name}:${server.value.url}`);
} }
}); });
} };
private initServer = (configServer: ConfigServer, isPredefined: boolean) => { private initServer = (configServer: ConfigServer, isPredefined: boolean) => {
const server = new MattermostServer(configServer, isPredefined); const server = new MattermostServer(configServer, isPredefined);
@ -290,7 +291,7 @@ export class ServerManager extends EventEmitter {
this.lastActiveView.set(server.id, viewOrder[configServer.lastActiveTab]); this.lastActiveView.set(server.id, viewOrder[configServer.lastActiveTab]);
} }
return server.id; return server.id;
} };
private getFirstOpenViewForServer = (serverId: string) => { private getFirstOpenViewForServer = (serverId: string) => {
const viewOrder = this.getOrderedTabsForServer(serverId); const viewOrder = this.getOrderedTabsForServer(serverId);
@ -300,7 +301,7 @@ export class ServerManager extends EventEmitter {
throw new Error(`No views open for server id ${serverId}`); throw new Error(`No views open for server id ${serverId}`);
} }
return firstView; return firstView;
} };
private persistServers = async (lastActiveServer?: number) => { private persistServers = async (lastActiveServer?: number) => {
this.emit(SERVERS_UPDATE); this.emit(SERVERS_UPDATE);
@ -314,7 +315,7 @@ export class ServerManager extends EventEmitter {
return servers; return servers;
}, [] as ConfigServer[]); }, [] as ConfigServer[]);
await Config.setServers(localServers, lastActiveServer); await Config.setServers(localServers, lastActiveServer);
} };
private getLastActiveView = (serverId: string) => { private getLastActiveView = (serverId: string) => {
let lastActiveView: number | undefined; let lastActiveView: number | undefined;
@ -325,7 +326,7 @@ export class ServerManager extends EventEmitter {
} }
} }
return lastActiveView; return lastActiveView;
} };
private toConfigServer = (server: MattermostServer): ConfigServer => { private toConfigServer = (server: MattermostServer): ConfigServer => {
return { return {
@ -346,7 +347,7 @@ export class ServerManager extends EventEmitter {
return views; return views;
}, [] as ConfigView[]) ?? [], }, [] as ConfigView[]) ?? [],
}; };
} };
private getNewView = (srv: MattermostServer, viewName: string, isOpen?: boolean) => { private getNewView = (srv: MattermostServer, viewName: string, isOpen?: boolean) => {
switch (viewName) { switch (viewName) {
@ -359,7 +360,7 @@ export class ServerManager extends EventEmitter {
default: default:
throw new Error('Not implemeneted'); throw new Error('Not implemeneted');
} }
} };
private updateServerURL = (serverId: string) => { private updateServerURL = (serverId: string) => {
const server = this.servers.get(serverId); const server = this.servers.get(serverId);
@ -375,7 +376,7 @@ export class ServerManager extends EventEmitter {
return true; return true;
} }
return false; return false;
} };
private includeId = (id: string, ...prefixes: string[]) => { private includeId = (id: string, ...prefixes: string[]) => {
const shouldInclude = ['debug', 'silly'].includes(getLevel()); const shouldInclude = ['debug', 'silly'].includes(getLevel());

View file

@ -2,7 +2,7 @@
// See LICENSE.txt for license information. // See LICENSE.txt for license information.
// Copyright (c) 2015-2016 Yuya Ochiai // Copyright (c) 2015-2016 Yuya Ochiai
import {Rectangle} from 'electron'; import type {Rectangle} from 'electron';
import {DEVELOPMENT, PRODUCTION} from './constants'; import {DEVELOPMENT, PRODUCTION} from './constants';

View file

@ -3,11 +3,11 @@
import {v4 as uuid} from 'uuid'; import {v4 as uuid} from 'uuid';
import {UniqueView} from 'types/config'; import type {MattermostServer} from 'common/servers/MattermostServer';
import {MattermostServer} from 'common/servers/MattermostServer'; import type {UniqueView} from 'types/config';
import {ViewType, MattermostView} from './View'; import type {ViewType, MattermostView} from './View';
export default abstract class BaseView implements MattermostView { export default abstract class BaseView implements MattermostView {
id: string; id: string;
@ -35,5 +35,5 @@ export default abstract class BaseView implements MattermostView {
name: this.type, name: this.type,
isOpen: this.isOpen, isOpen: this.isOpen,
}; };
} };
} }

View file

@ -4,7 +4,8 @@
import {getFormattedPathName} from 'common/utils/url'; import {getFormattedPathName} from 'common/utils/url';
import BaseView from './BaseView'; import BaseView from './BaseView';
import {ViewType, TAB_FOCALBOARD} from './View'; import type {ViewType} from './View';
import {TAB_FOCALBOARD} from './View';
export default class FocalboardView extends BaseView { export default class FocalboardView extends BaseView {
get url(): URL { get url(): URL {

View file

@ -2,7 +2,8 @@
// See LICENSE.txt for license information. // See LICENSE.txt for license information.
import BaseView from './BaseView'; import BaseView from './BaseView';
import {ViewType, TAB_MESSAGING} from './View'; import type {ViewType} from './View';
import {TAB_MESSAGING} from './View';
export default class MessagingView extends BaseView { export default class MessagingView extends BaseView {
get url(): URL { get url(): URL {

View file

@ -4,7 +4,8 @@
import {getFormattedPathName} from 'common/utils/url'; import {getFormattedPathName} from 'common/utils/url';
import BaseView from './BaseView'; import BaseView from './BaseView';
import {ViewType, TAB_PLAYBOOKS} from './View'; import type {ViewType} from './View';
import {TAB_PLAYBOOKS} from './View';
export default class PlaybooksView extends BaseView { export default class PlaybooksView extends BaseView {
get url(): URL { get url(): URL {

View file

@ -1,9 +1,9 @@
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved. // Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information. // See LICENSE.txt for license information.
import {UniqueView, Server} from 'types/config'; import type {MattermostServer} from 'common/servers/MattermostServer';
import {MattermostServer} from 'common/servers/MattermostServer'; import type {UniqueView, Server} from 'types/config';
export const TAB_MESSAGING = 'TAB_MESSAGING'; export const TAB_MESSAGING = 'TAB_MESSAGING';
export const TAB_FOCALBOARD = 'TAB_FOCALBOARD'; export const TAB_FOCALBOARD = 'TAB_FOCALBOARD';

View file

@ -1,6 +1,8 @@
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved. // Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information. // See LICENSE.txt for license information.
/* eslint-disable no-undef */
jest.mock('main/constants', () => ({ jest.mock('main/constants', () => ({
configPath: 'configPath', configPath: 'configPath',
allowedProtocolFile: 'allowedProtocolFile', allowedProtocolFile: 'allowedProtocolFile',

View file

@ -1,6 +1,8 @@
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved. // Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information. // See LICENSE.txt for license information.
/* eslint-disable no-undef */
function toContainObject(received, argument) { function toContainObject(received, argument) {
const pass = this.equals(received, const pass = this.equals(received,
expect.arrayContaining([ expect.arrayContaining([

View file

@ -27,7 +27,7 @@ describe('main/AppVersionManager', () => {
fs.readFileSync.mockReturnValue('some bad JSON'); fs.readFileSync.mockReturnValue('some bad JSON');
Validator.validateAppState.mockReturnValue(false); Validator.validateAppState.mockReturnValue(false);
// eslint-disable-next-line no-unused-vars // eslint-disable-next-line @typescript-eslint/no-unused-vars
const appVersionManager = new AppVersionManager('somefilename.txt'); const appVersionManager = new AppVersionManager('somefilename.txt');
expect(fs.writeFile).toBeCalledWith('somefilename.txt', '{}', expect.any(Function)); expect(fs.writeFile).toBeCalledWith('somefilename.txt', '{}', expect.any(Function));

View file

@ -4,14 +4,13 @@
import {ipcMain} from 'electron'; import {ipcMain} from 'electron';
import {AppState} from 'types/appState';
import {UPDATE_PATHS} from 'common/communication'; import {UPDATE_PATHS} from 'common/communication';
import JsonFileManager from 'common/JsonFileManager'; import JsonFileManager from 'common/JsonFileManager';
import * as Validator from 'common/Validator'; import * as Validator from 'common/Validator';
import {appVersionJson} from 'main/constants'; import {appVersionJson} from 'main/constants';
import type {AppState} from 'types/appState';
export class AppVersionManager extends JsonFileManager<AppState> { export class AppVersionManager extends JsonFileManager<AppState> {
constructor(file: string) { constructor(file: string) {
super(file); super(file);
@ -24,7 +23,7 @@ export class AppVersionManager extends JsonFileManager<AppState> {
if (!validatedJSON) { if (!validatedJSON) {
this.setJson({}); this.setJson({});
} }
} };
set lastAppVersion(version) { set lastAppVersion(version) {
this.setValue('lastAppVersion', version); this.setValue('lastAppVersion', version);

View file

@ -3,7 +3,6 @@
'use strict'; 'use strict';
import {spawn} from 'child_process'; import {spawn} from 'child_process';
import path from 'path'; import path from 'path';
import {app, dialog} from 'electron'; import {app, dialog} from 'electron';

View file

@ -3,14 +3,12 @@
// See LICENSE.txt for license information. // See LICENSE.txt for license information.
import {spawn} from 'child_process'; import {spawn} from 'child_process';
import fs from 'fs'; import fs from 'fs';
import os from 'os'; import os from 'os';
import path from 'path'; import path from 'path';
import {app, dialog} from 'electron'; import {app, dialog} from 'electron';
import {Logger} from 'common/log'; import {Logger} from 'common/log';
import {localizeMessage} from 'main/i18nManager'; import {localizeMessage} from 'main/i18nManager';
const log = new Logger('CriticalErrorHandler'); const log = new Logger('CriticalErrorHandler');
@ -19,7 +17,7 @@ export class CriticalErrorHandler {
init = () => { init = () => {
process.on('unhandledRejection', this.processUncaughtExceptionHandler); process.on('unhandledRejection', this.processUncaughtExceptionHandler);
process.on('uncaughtException', this.processUncaughtExceptionHandler); process.on('uncaughtException', this.processUncaughtExceptionHandler);
} };
private processUncaughtExceptionHandler = (err: Error) => { private processUncaughtExceptionHandler = (err: Error) => {
if (process.env.NODE_ENV === 'test') { if (process.env.NODE_ENV === 'test') {
@ -33,7 +31,7 @@ export class CriticalErrorHandler {
this.showExceptionDialog(err); this.showExceptionDialog(err);
}); });
} }
} };
private showExceptionDialog = (err: Error) => { private showExceptionDialog = (err: Error) => {
const file = path.join(app.getPath('userData'), `uncaughtException-${Date.now()}.txt`); const file = path.join(app.getPath('userData'), `uncaughtException-${Date.now()}.txt`);
@ -91,7 +89,7 @@ export class CriticalErrorHandler {
} }
app.exit(-1); app.exit(-1);
}); });
} };
private openDetachedExternal = (url: string) => { private openDetachedExternal = (url: string) => {
const spawnOption = {detached: true, stdio: 'ignore' as const}; const spawnOption = {detached: true, stdio: 'ignore' as const};
@ -105,7 +103,7 @@ export class CriticalErrorHandler {
default: default:
return undefined; return undefined;
} }
} };
private createErrorReport = (err: Error) => { private createErrorReport = (err: Error) => {
// eslint-disable-next-line no-undef // eslint-disable-next-line no-undef
@ -114,7 +112,7 @@ export class CriticalErrorHandler {
return `Application: ${app.name} ${app.getVersion()}${__HASH_VERSION__ ? ` [commit: ${__HASH_VERSION__}]` : ''}\n` + return `Application: ${app.name} ${app.getVersion()}${__HASH_VERSION__ ? ` [commit: ${__HASH_VERSION__}]` : ''}\n` +
`Platform: ${os.type()} ${os.release()} ${os.arch()}\n` + `Platform: ${os.type()} ${os.release()} ${os.arch()}\n` +
`${err.stack}`; `${err.stack}`;
} };
} }
const criticalErrorHandler = new CriticalErrorHandler(); const criticalErrorHandler = new CriticalErrorHandler();

View file

@ -2,13 +2,14 @@
// See LICENSE.txt for license information. // See LICENSE.txt for license information.
import {app} from 'electron'; import {app} from 'electron';
import {Args} from 'types/args';
import yargs from 'yargs'; import yargs from 'yargs';
import {protocols} from '../../electron-builder.json';
import * as Validator from 'common/Validator'; import * as Validator from 'common/Validator';
import type {Args} from 'types/args';
import {protocols} from '../../electron-builder.json';
export default function parse(args: string[]) { export default function parse(args: string[]) {
return validateArgs(parseArgs(triageArgs(args))); return validateArgs(parseArgs(triageArgs(args)));
} }

View file

@ -1,9 +1,8 @@
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved. // Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information. // See LICENSE.txt for license information.
import {EventEmitter} from 'events';
import {app, powerMonitor} from 'electron'; import {app, powerMonitor} from 'electron';
import {EventEmitter} from 'events';
import {Logger} from 'common/log'; import {Logger} from 'common/log';

View file

@ -6,9 +6,8 @@ import fs from 'fs';
import {shell, dialog} from 'electron'; import {shell, dialog} from 'electron';
import MainWindow from './windows/mainWindow';
import {AllowProtocolDialog} from './allowProtocolDialog'; import {AllowProtocolDialog} from './allowProtocolDialog';
import MainWindow from './windows/mainWindow';
jest.mock('fs', () => ({ jest.mock('fs', () => ({
readFile: jest.fn(), readFile: jest.fn(),

View file

@ -7,14 +7,13 @@ import fs from 'fs';
import {dialog, shell} from 'electron'; import {dialog, shell} from 'electron';
import {localizeMessage} from 'main/i18nManager';
import buildConfig from 'common/config/buildConfig'; import buildConfig from 'common/config/buildConfig';
import {Logger} from 'common/log'; import {Logger} from 'common/log';
import * as Validator from 'common/Validator'; import * as Validator from 'common/Validator';
import {localizeMessage} from 'main/i18nManager';
import MainWindow from './windows/mainWindow';
import {allowedProtocolFile} from './constants'; import {allowedProtocolFile} from './constants';
import MainWindow from './windows/mainWindow';
const log = new Logger('AllowProtocolDialog'); const log = new Logger('AllowProtocolDialog');
@ -35,14 +34,14 @@ export class AllowProtocolDialog {
this.addScheme('https'); this.addScheme('https');
buildConfig.allowedProtocols.forEach(this.addScheme); buildConfig.allowedProtocols.forEach(this.addScheme);
}); });
} };
addScheme = (scheme: string) => { addScheme = (scheme: string) => {
const proto = `${scheme}:`; const proto = `${scheme}:`;
if (!this.allowedProtocols.includes(proto)) { if (!this.allowedProtocols.includes(proto)) {
this.allowedProtocols.push(proto); this.allowedProtocols.push(proto);
} }
} };
handleDialogEvent = async (protocol: string, URL: string) => { handleDialogEvent = async (protocol: string, URL: string) => {
try { try {
@ -88,7 +87,7 @@ export class AllowProtocolDialog {
} catch (error) { } catch (error) {
log.warn('Could not open external URL', error); log.warn('Could not open external URL', error);
} }
} };
} }
const allowProtocolDialog = new AllowProtocolDialog(); const allowProtocolDialog = new AllowProtocolDialog();

View file

@ -3,12 +3,11 @@
import {app, dialog} from 'electron'; import {app, dialog} from 'electron';
import CertificateStore from 'main/certificateStore';
import MainWindow from 'main/windows/mainWindow';
import ViewManager from 'main/views/viewManager';
import {handleAppWillFinishLaunching, handleAppCertificateError, certificateErrorCallbacks} from 'main/app/app'; import {handleAppWillFinishLaunching, handleAppCertificateError, certificateErrorCallbacks} from 'main/app/app';
import {getDeeplinkingURL, openDeepLink} from 'main/app/utils'; import {getDeeplinkingURL, openDeepLink} from 'main/app/utils';
import CertificateStore from 'main/certificateStore';
import ViewManager from 'main/views/viewManager';
import MainWindow from 'main/windows/mainWindow';
jest.mock('electron', () => ({ jest.mock('electron', () => ({
app: { app: {

View file

@ -1,11 +1,11 @@
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved. // Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information. // See LICENSE.txt for license information.
import {app, BrowserWindow, Event, dialog, WebContents, Certificate, Details} from 'electron'; import type {BrowserWindow, Event, WebContents, Certificate, Details} from 'electron';
import {app, dialog} from 'electron';
import {Logger} from 'common/log'; import {Logger} from 'common/log';
import {parseURL} from 'common/utils/url'; import {parseURL} from 'common/utils/url';
import updateManager from 'main/autoUpdater'; import updateManager from 'main/autoUpdater';
import CertificateStore from 'main/certificateStore'; import CertificateStore from 'main/certificateStore';
import {localizeMessage} from 'main/i18nManager'; import {localizeMessage} from 'main/i18nManager';

View file

@ -6,12 +6,10 @@ import {app} from 'electron';
import {RELOAD_CONFIGURATION} from 'common/communication'; import {RELOAD_CONFIGURATION} from 'common/communication';
import Config from 'common/config'; import Config from 'common/config';
import {setLoggingLevel} from 'common/log'; import {setLoggingLevel} from 'common/log';
import {handleConfigUpdate} from 'main/app/config'; import {handleConfigUpdate} from 'main/app/config';
import {handleMainWindowIsShown} from 'main/app/intercom'; import {handleMainWindowIsShown} from 'main/app/intercom';
import MainWindow from 'main/windows/mainWindow';
import AutoLauncher from 'main/AutoLauncher'; import AutoLauncher from 'main/AutoLauncher';
import MainWindow from 'main/windows/mainWindow';
jest.mock('electron', () => ({ jest.mock('electron', () => ({
app: { app: {

View file

@ -3,12 +3,9 @@
import {app, ipcMain, nativeTheme} from 'electron'; import {app, ipcMain, nativeTheme} from 'electron';
import {CombinedConfig, Config as ConfigType} from 'types/config';
import {DARK_MODE_CHANGE, EMIT_CONFIGURATION, RELOAD_CONFIGURATION} from 'common/communication'; import {DARK_MODE_CHANGE, EMIT_CONFIGURATION, RELOAD_CONFIGURATION} from 'common/communication';
import Config from 'common/config'; import Config from 'common/config';
import {Logger, setLoggingLevel} from 'common/log'; import {Logger, setLoggingLevel} from 'common/log';
import AutoLauncher from 'main/AutoLauncher'; import AutoLauncher from 'main/AutoLauncher';
import {setUnreadBadgeSetting} from 'main/badge'; import {setUnreadBadgeSetting} from 'main/badge';
import Tray from 'main/tray/tray'; import Tray from 'main/tray/tray';
@ -16,6 +13,8 @@ import LoadingScreen from 'main/views/loadingScreen';
import MainWindow from 'main/windows/mainWindow'; import MainWindow from 'main/windows/mainWindow';
import SettingsWindow from 'main/windows/settingsWindow'; import SettingsWindow from 'main/windows/settingsWindow';
import type {CombinedConfig, Config as ConfigType} from 'types/config';
import {handleMainWindowIsShown} from './intercom'; import {handleMainWindowIsShown} from './intercom';
import {handleUpdateMenuEvent, updateSpellCheckerLocales} from './utils'; import {handleUpdateMenuEvent, updateSpellCheckerLocales} from './utils';

View file

@ -10,10 +10,6 @@ import('main/views/serverDropdownView');
import('main/views/downloadsDropdownMenuView'); import('main/views/downloadsDropdownMenuView');
import('main/views/downloadsDropdownView'); import('main/views/downloadsDropdownView');
if (process.env.NODE_ENV !== 'production' && module.hot) {
module.hot.accept();
}
// attempt to initialize the application // attempt to initialize the application
try { try {
initialize(); initialize();

View file

@ -6,7 +6,6 @@ import path from 'path';
import {app, session} from 'electron'; import {app, session} from 'electron';
import Config from 'common/config'; import Config from 'common/config';
import parseArgs from 'main/ParseArgs'; import parseArgs from 'main/ParseArgs';
import ViewManager from 'main/views/viewManager'; import ViewManager from 'main/views/viewManager';

View file

@ -34,7 +34,7 @@ import {
} from 'common/communication'; } from 'common/communication';
import Config from 'common/config'; import Config from 'common/config';
import {Logger} from 'common/log'; import {Logger} from 'common/log';
import ServerManager from 'common/servers/serverManager';
import AllowProtocolDialog from 'main/allowProtocolDialog'; import AllowProtocolDialog from 'main/allowProtocolDialog';
import AppVersionManager from 'main/AppVersionManager'; import AppVersionManager from 'main/AppVersionManager';
import AuthManager from 'main/authManager'; import AuthManager from 'main/authManager';
@ -48,15 +48,12 @@ import downloadsManager from 'main/downloadsManager';
import i18nManager from 'main/i18nManager'; import i18nManager from 'main/i18nManager';
import parseArgs from 'main/ParseArgs'; import parseArgs from 'main/ParseArgs';
import PermissionsManager from 'main/permissionsManager'; import PermissionsManager from 'main/permissionsManager';
import ServerManager from 'common/servers/serverManager';
import TrustedOriginsStore from 'main/trustedOrigins';
import Tray from 'main/tray/tray'; import Tray from 'main/tray/tray';
import TrustedOriginsStore from 'main/trustedOrigins';
import UserActivityMonitor from 'main/UserActivityMonitor'; import UserActivityMonitor from 'main/UserActivityMonitor';
import ViewManager from 'main/views/viewManager'; import ViewManager from 'main/views/viewManager';
import MainWindow from 'main/windows/mainWindow'; import MainWindow from 'main/windows/mainWindow';
import {protocols} from '../../../electron-builder.json';
import { import {
handleAppBeforeQuit, handleAppBeforeQuit,
handleAppBrowserWindowCreated, handleAppBrowserWindowCreated,
@ -103,6 +100,8 @@ import {
handleRestore, handleRestore,
} from './windows'; } from './windows';
import {protocols} from '../../../electron-builder.json';
export const mainProtocol = protocols?.[0]?.schemes?.[0]; export const mainProtocol = protocols?.[0]?.schemes?.[0];
const log = new Logger('App.Initialize'); const log = new Logger('App.Initialize');

View file

@ -3,10 +3,10 @@
import {app} from 'electron'; import {app} from 'electron';
import {getLocalURLString, getLocalPreload} from 'main/utils';
import ServerManager from 'common/servers/serverManager'; import ServerManager from 'common/servers/serverManager';
import MainWindow from 'main/windows/mainWindow'; import {getLocalURLString, getLocalPreload} from 'main/utils';
import ModalManager from 'main/views/modalManager'; import ModalManager from 'main/views/modalManager';
import MainWindow from 'main/windows/mainWindow';
import { import {
handleWelcomeScreenModal, handleWelcomeScreenModal,

View file

@ -1,21 +1,20 @@
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved. // Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information. // See LICENSE.txt for license information.
import {app, IpcMainEvent, IpcMainInvokeEvent, Menu} from 'electron'; import type {IpcMainEvent, IpcMainInvokeEvent} from 'electron';
import {app, Menu} from 'electron';
import {UniqueServer} from 'types/config';
import ServerViewState from 'app/serverViewState'; import ServerViewState from 'app/serverViewState';
import {Logger} from 'common/log'; import {Logger} from 'common/log';
import ServerManager from 'common/servers/serverManager'; import ServerManager from 'common/servers/serverManager';
import {ping} from 'common/utils/requests'; import {ping} from 'common/utils/requests';
import NotificationManager from 'main/notifications'; import NotificationManager from 'main/notifications';
import {getLocalPreload, getLocalURLString} from 'main/utils'; import {getLocalPreload, getLocalURLString} from 'main/utils';
import ModalManager from 'main/views/modalManager'; import ModalManager from 'main/views/modalManager';
import MainWindow from 'main/windows/mainWindow'; import MainWindow from 'main/windows/mainWindow';
import type {UniqueServer} from 'types/config';
import {handleAppBeforeQuit} from './app'; import {handleAppBeforeQuit} from './app';
const log = new Logger('App.Intercom'); const log = new Logger('App.Intercom');

View file

@ -1,12 +1,10 @@
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved. // Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information. // See LICENSE.txt for license information.
import {dialog, screen} from 'electron';
import fs from 'fs-extra'; import fs from 'fs-extra';
import {dialog, screen} from 'electron';
import JsonFileManager from 'common/JsonFileManager'; import JsonFileManager from 'common/JsonFileManager';
import {updatePaths} from 'main/constants'; import {updatePaths} from 'main/constants';
import {getDeeplinkingURL, resizeScreen, migrateMacAppStore} from './utils'; import {getDeeplinkingURL, resizeScreen, migrateMacAppStore} from './utils';

View file

@ -3,23 +3,18 @@
import path from 'path'; import path from 'path';
import type {BrowserWindow, Rectangle, Session} from 'electron';
import {app, Menu, session, dialog, nativeImage, screen} from 'electron';
import isDev from 'electron-is-dev';
import fs from 'fs-extra'; import fs from 'fs-extra';
import {app, BrowserWindow, Menu, Rectangle, Session, session, dialog, nativeImage, screen} from 'electron';
import isDev from 'electron-is-dev';
import {MigrationInfo} from 'types/config';
import {RemoteInfo} from 'types/server';
import {Boundaries} from 'types/utils';
import Config from 'common/config';
import {Logger} from 'common/log';
import JsonFileManager from 'common/JsonFileManager';
import ServerManager from 'common/servers/serverManager';
import {MattermostServer} from 'common/servers/MattermostServer';
import {APP_MENU_WILL_CLOSE} from 'common/communication'; import {APP_MENU_WILL_CLOSE} from 'common/communication';
import Config from 'common/config';
import JsonFileManager from 'common/JsonFileManager';
import {Logger} from 'common/log';
import type {MattermostServer} from 'common/servers/MattermostServer';
import ServerManager from 'common/servers/serverManager';
import {isValidURI} from 'common/utils/url'; import {isValidURI} from 'common/utils/url';
import updateManager from 'main/autoUpdater'; import updateManager from 'main/autoUpdater';
import {migrationInfoPath, updatePaths} from 'main/constants'; import {migrationInfoPath, updatePaths} from 'main/constants';
import {localizeMessage} from 'main/i18nManager'; import {localizeMessage} from 'main/i18nManager';
@ -30,6 +25,10 @@ import Tray from 'main/tray/tray';
import ViewManager from 'main/views/viewManager'; import ViewManager from 'main/views/viewManager';
import MainWindow from 'main/windows/mainWindow'; import MainWindow from 'main/windows/mainWindow';
import type {MigrationInfo} from 'types/config';
import type {RemoteInfo} from 'types/server';
import type {Boundaries} from 'types/utils';
import {mainProtocol} from './initialize'; import {mainProtocol} from './initialize';
const assetsDir = path.resolve(app.getAppPath(), 'assets'); const assetsDir = path.resolve(app.getAppPath(), 'assets');

View file

@ -1,10 +1,11 @@
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved. // Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information. // See LICENSE.txt for license information.
import {BrowserWindow, IpcMainEvent, systemPreferences} from 'electron'; import type {IpcMainEvent} from 'electron';
import {BrowserWindow, systemPreferences} from 'electron';
import {Logger} from 'common/log';
import Config from 'common/config'; import Config from 'common/config';
import {Logger} from 'common/log';
const log = new Logger('App.Windows'); const log = new Logger('App.Windows');

View file

@ -3,9 +3,9 @@
'use strict'; 'use strict';
import {AuthManager} from 'main/authManager'; import {AuthManager} from 'main/authManager';
import MainWindow from 'main/windows/mainWindow';
import ModalManager from 'main/views/modalManager'; import ModalManager from 'main/views/modalManager';
import ViewManager from 'main/views/viewManager'; import ViewManager from 'main/views/viewManager';
import MainWindow from 'main/windows/mainWindow';
jest.mock('common/utils/url', () => { jest.mock('common/utils/url', () => {
const actualUrl = jest.requireActual('common/utils/url'); const actualUrl = jest.requireActual('common/utils/url');

View file

@ -1,19 +1,18 @@
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved. // Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information. // See LICENSE.txt for license information.
import {AuthenticationResponseDetails, AuthInfo, WebContents, Event} from 'electron'; import type {AuthenticationResponseDetails, AuthInfo, WebContents, Event} from 'electron';
import {PermissionType} from 'types/trustedOrigin';
import {LoginModalData} from 'types/auth';
import {Logger} from 'common/log'; import {Logger} from 'common/log';
import {BASIC_AUTH_PERMISSION} from 'common/permissions'; import {BASIC_AUTH_PERMISSION} from 'common/permissions';
import {isCustomLoginURL, isTrustedURL, parseURL} from 'common/utils/url'; import {isCustomLoginURL, isTrustedURL, parseURL} from 'common/utils/url';
import modalManager from 'main/views/modalManager';
import TrustedOriginsStore from 'main/trustedOrigins'; import TrustedOriginsStore from 'main/trustedOrigins';
import {getLocalURLString, getLocalPreload} from 'main/utils'; import {getLocalURLString, getLocalPreload} from 'main/utils';
import MainWindow from 'main/windows/mainWindow'; import modalManager from 'main/views/modalManager';
import ViewManager from 'main/views/viewManager'; import ViewManager from 'main/views/viewManager';
import MainWindow from 'main/windows/mainWindow';
import type {LoginModalData} from 'types/auth';
import type {PermissionType} from 'types/trustedOrigin';
const log = new Logger('AuthManager'); const log = new Logger('AuthManager');
const preload = getLocalPreload('internalAPI.js'); const preload = getLocalPreload('internalAPI.js');
@ -51,7 +50,7 @@ export class AuthManager {
} else { } else {
this.popPermissionModal(request, authInfo, BASIC_AUTH_PERMISSION); this.popPermissionModal(request, authInfo, BASIC_AUTH_PERMISSION);
} }
} };
popLoginModal = (request: AuthenticationResponseDetails, authInfo: AuthInfo) => { popLoginModal = (request: AuthenticationResponseDetails, authInfo: AuthInfo) => {
const mainWindow = MainWindow.get(); const mainWindow = MainWindow.get();
@ -70,7 +69,7 @@ export class AuthManager {
this.handleCancelLoginEvent(request); this.handleCancelLoginEvent(request);
}); });
} }
} };
popPermissionModal = (request: AuthenticationResponseDetails, authInfo: AuthInfo, permission: PermissionType) => { popPermissionModal = (request: AuthenticationResponseDetails, authInfo: AuthInfo, permission: PermissionType) => {
const mainWindow = MainWindow.get(); const mainWindow = MainWindow.get();
@ -89,7 +88,7 @@ export class AuthManager {
this.handleCancelLoginEvent(request); this.handleCancelLoginEvent(request);
}); });
} }
} };
handleLoginCredentialsEvent = (request: AuthenticationResponseDetails, username?: string, password?: string) => { handleLoginCredentialsEvent = (request: AuthenticationResponseDetails, username?: string, password?: string) => {
const callback = this.loginCallbackMap.get(request.url); const callback = this.loginCallbackMap.get(request.url);
@ -101,12 +100,12 @@ export class AuthManager {
callback(username, password); callback(username, password);
} }
this.loginCallbackMap.delete(request.url); this.loginCallbackMap.delete(request.url);
} };
handleCancelLoginEvent = (request: AuthenticationResponseDetails) => { handleCancelLoginEvent = (request: AuthenticationResponseDetails) => {
log.info(`Cancelling request for ${request ? request.url : 'unknown'}`); log.info(`Cancelling request for ${request ? request.url : 'unknown'}`);
this.handleLoginCredentialsEvent(request); // we use undefined to cancel the request this.handleLoginCredentialsEvent(request); // we use undefined to cancel the request
} };
handlePermissionGranted(url: string, permission: PermissionType) { handlePermissionGranted(url: string, permission: PermissionType) {
const parsedURL = parseURL(url); const parsedURL = parseURL(url);

View file

@ -5,7 +5,6 @@ import {ipcMain as notMockedIpcMain} from 'electron';
import {autoUpdater as notMockedAutoUpdater} from 'electron-updater'; import {autoUpdater as notMockedAutoUpdater} from 'electron-updater';
import {CHECK_FOR_UPDATES} from 'common/communication'; import {CHECK_FOR_UPDATES} from 'common/communication';
import NotificationManager from 'main/notifications'; import NotificationManager from 'main/notifications';
import {UpdateManager} from './autoUpdater'; import {UpdateManager} from './autoUpdater';

View file

@ -4,13 +4,8 @@
import path from 'path'; import path from 'path';
import {dialog, ipcMain, app, nativeImage} from 'electron'; import {dialog, ipcMain, app, nativeImage} from 'electron';
import {autoUpdater, CancellationToken, ProgressInfo, UpdateInfo} from 'electron-updater'; import type {ProgressInfo, UpdateInfo} from 'electron-updater';
import {autoUpdater, CancellationToken} from 'electron-updater';
import {Logger} from 'common/log';
import downloadsManager from 'main/downloadsManager';
import {localizeMessage} from 'main/i18nManager';
import NotificationManager from 'main/notifications';
import { import {
CANCEL_UPGRADE, CANCEL_UPGRADE,
@ -24,6 +19,10 @@ import {
UPDATE_REMIND_LATER, UPDATE_REMIND_LATER,
} from 'common/communication'; } from 'common/communication';
import Config from 'common/config'; import Config from 'common/config';
import {Logger} from 'common/log';
import downloadsManager from 'main/downloadsManager';
import {localizeMessage} from 'main/i18nManager';
import NotificationManager from 'main/notifications';
const NEXT_NOTIFY = 86400000; // 24 hours const NEXT_NOTIFY = 86400000; // 24 hours
const NEXT_CHECK = 3600000; // 1 hour const NEXT_CHECK = 3600000; // 1 hour
@ -109,44 +108,44 @@ export class UpdateManager {
} else if (this.versionAvailable) { } else if (this.versionAvailable) {
this.notifyUpgrade(); this.notifyUpgrade();
} }
} };
notifyUpgrade = (): void => { notifyUpgrade = (): void => {
ipcMain.emit(UPDATE_AVAILABLE, null, this.versionAvailable); ipcMain.emit(UPDATE_AVAILABLE, null, this.versionAvailable);
NotificationManager.displayUpgrade(this.versionAvailable || 'unknown', this.handleDownload); NotificationManager.displayUpgrade(this.versionAvailable || 'unknown', this.handleDownload);
} };
notifyDownloaded = (): void => { notifyDownloaded = (): void => {
ipcMain.emit(UPDATE_DOWNLOADED, null, this.downloadedInfo); ipcMain.emit(UPDATE_DOWNLOADED, null, this.downloadedInfo);
NotificationManager.displayRestartToUpgrade(this.versionDownloaded || 'unknown', this.handleUpdate); NotificationManager.displayRestartToUpgrade(this.versionDownloaded || 'unknown', this.handleUpdate);
} };
handleDownload = (): void => { handleDownload = (): void => {
if (this.lastCheck) { if (this.lastCheck) {
clearTimeout(this.lastCheck); clearTimeout(this.lastCheck);
} }
autoUpdater.downloadUpdate(this.cancellationToken); autoUpdater.downloadUpdate(this.cancellationToken);
} };
handleCancelDownload = (): void => { handleCancelDownload = (): void => {
this.cancellationToken?.cancel(); this.cancellationToken?.cancel();
this.cancellationToken = new CancellationToken(); this.cancellationToken = new CancellationToken();
} };
handleRemindLater = (): void => { handleRemindLater = (): void => {
// TODO // TODO
} };
handleOnQuit = (): void => { handleOnQuit = (): void => {
if (this.versionDownloaded) { if (this.versionDownloaded) {
autoUpdater.quitAndInstall(true, false); autoUpdater.quitAndInstall(true, false);
} }
} };
handleUpdate = (): void => { handleUpdate = (): void => {
downloadsManager.removeUpdateBeforeRestart(); downloadsManager.removeUpdateBeforeRestart();
autoUpdater.quitAndInstall(); autoUpdater.quitAndInstall();
} };
displayNoUpgrade = (): void => { displayNoUpgrade = (): void => {
const version = app.getVersion(); const version = app.getVersion();
@ -159,7 +158,7 @@ export class UpdateManager {
buttons: [localizeMessage('label.ok', 'OK')], buttons: [localizeMessage('label.ok', 'OK')],
detail: localizeMessage('main.autoUpdater.noUpdate.detail', 'You are using the latest version of the {appName} Desktop App (version {version}). You\'ll be notified when a new version is available to install.', {appName: app.name, version}), detail: localizeMessage('main.autoUpdater.noUpdate.detail', 'You are using the latest version of the {appName} Desktop App (version {version}). You\'ll be notified when a new version is available to install.', {appName: app.name, version}),
}); });
} };
checkForUpdates = (manually: boolean): void => { checkForUpdates = (manually: boolean): void => {
if (!Config.canUpgrade) { if (!Config.canUpgrade) {
@ -183,7 +182,7 @@ export class UpdateManager {
}); });
this.lastCheck = setTimeout(() => this.checkForUpdates(false), NEXT_CHECK); this.lastCheck = setTimeout(() => this.checkForUpdates(false), NEXT_CHECK);
} }
} };
} }
const updateManager = new UpdateManager(); const updateManager = new UpdateManager();

View file

@ -4,9 +4,8 @@
import {app, nativeImage} from 'electron'; import {app, nativeImage} from 'electron';
import MainWindow from './windows/mainWindow';
import * as Badge from './badge'; import * as Badge from './badge';
import MainWindow from './windows/mainWindow';
jest.mock('electron', () => ({ jest.mock('electron', () => ({
app: { app: {

View file

@ -2,12 +2,12 @@
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved. // Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information. // See LICENSE.txt for license information.
import {BrowserWindow, app, nativeImage} from 'electron'; import type {BrowserWindow} from 'electron';
import {app, nativeImage} from 'electron';
import AppState from 'common/appState'; import AppState from 'common/appState';
import {UPDATE_APPSTATE_TOTALS} from 'common/communication'; import {UPDATE_APPSTATE_TOTALS} from 'common/communication';
import {Logger} from 'common/log'; import {Logger} from 'common/log';
import {localizeMessage} from 'main/i18nManager'; import {localizeMessage} from 'main/i18nManager';
import MainWindow from './windows/mainWindow'; import MainWindow from './windows/mainWindow';

View file

@ -2,9 +2,9 @@
// See LICENSE.txt for license information. // See LICENSE.txt for license information.
'use strict'; 'use strict';
import MainWindow from 'main/windows/mainWindow';
import ModalManager from 'main/views/modalManager';
import {CertificateManager} from 'main/certificateManager'; import {CertificateManager} from 'main/certificateManager';
import ModalManager from 'main/views/modalManager';
import MainWindow from 'main/windows/mainWindow';
jest.mock('main/windows/mainWindow', () => ({ jest.mock('main/windows/mainWindow', () => ({
get: jest.fn().mockImplementation(() => ({})), get: jest.fn().mockImplementation(() => ({})),

View file

@ -1,14 +1,14 @@
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved. // Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information. // See LICENSE.txt for license information.
import {Certificate, WebContents, Event} from 'electron'; import type {Certificate, WebContents, Event} from 'electron';
import {CertificateModalData} from 'types/certificate';
import {Logger} from 'common/log'; import {Logger} from 'common/log';
import modalManager from './views/modalManager'; import type {CertificateModalData} from 'types/certificate';
import {getLocalURLString, getLocalPreload} from './utils'; import {getLocalURLString, getLocalPreload} from './utils';
import modalManager from './views/modalManager';
import MainWindow from './windows/mainWindow'; import MainWindow from './windows/mainWindow';
const log = new Logger('CertificateManager'); const log = new Logger('CertificateManager');
@ -38,7 +38,7 @@ export class CertificateManager {
} else { } else {
log.info(`There were ${list.length} candidate certificates. Skipping certificate selection`); log.info(`There were ${list.length} candidate certificates. Skipping certificate selection`);
} }
} };
popCertificateModal = (url: string, list: Certificate[]) => { popCertificateModal = (url: string, list: Certificate[]) => {
const mainWindow = MainWindow.get(); const mainWindow = MainWindow.get();
@ -57,7 +57,7 @@ export class CertificateManager {
this.handleSelectedCertificate(url); this.handleSelectedCertificate(url);
}); });
} }
} };
handleSelectedCertificate = (server: string, cert?: Certificate) => { handleSelectedCertificate = (server: string, cert?: Certificate) => {
const callback = this.certificateRequestCallbackMap.get(server); const callback = this.certificateRequestCallbackMap.get(server);
@ -75,7 +75,7 @@ export class CertificateManager {
} }
} }
this.certificateRequestCallbackMap.delete(server); this.certificateRequestCallbackMap.delete(server);
} };
} }
const certificateManager = new CertificateManager(); const certificateManager = new CertificateManager();

View file

@ -5,14 +5,15 @@
import fs from 'fs'; import fs from 'fs';
import {Certificate, ipcMain} from 'electron'; import type {Certificate} from 'electron';
import {ipcMain} from 'electron';
import {ComparableCertificate} from 'types/certificate';
import {UPDATE_PATHS} from 'common/communication'; import {UPDATE_PATHS} from 'common/communication';
import {Logger} from 'common/log'; import {Logger} from 'common/log';
import * as Validator from 'common/Validator'; import * as Validator from 'common/Validator';
import type {ComparableCertificate} from 'types/certificate';
import {certificateStorePath} from './constants'; import {certificateStorePath} from './constants';
function comparableCertificate(certificate: Certificate, dontTrust = false): ComparableCertificate { function comparableCertificate(certificate: Certificate, dontTrust = false): ComparableCertificate {
@ -83,7 +84,7 @@ export class CertificateStore {
// clicking "Don't ask again" checkbox before cancelling the connection. // clicking "Don't ask again" checkbox before cancelling the connection.
const dontTrust = this.data[targetURL.origin]?.dontTrust; const dontTrust = this.data[targetURL.origin]?.dontTrust;
return dontTrust === undefined ? false : dontTrust; return dontTrust === undefined ? false : dontTrust;
} };
} }
let certificateStore = new CertificateStore(certificateStorePath); let certificateStore = new CertificateStore(certificateStorePath);

View file

@ -2,8 +2,9 @@
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved. // Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information. // See LICENSE.txt for license information.
import {BrowserView, BrowserWindow, ContextMenuParams, Event} from 'electron'; import type {BrowserView, BrowserWindow, ContextMenuParams, Event} from 'electron';
import electronContextMenu, {Options} from 'electron-context-menu'; import type {Options} from 'electron-context-menu';
import electronContextMenu from 'electron-context-menu';
import {parseURL} from 'common/utils/url'; import {parseURL} from 'common/utils/url';
@ -46,12 +47,12 @@ export default class ContextMenu {
this.menuDispose(); this.menuDispose();
delete this.menuDispose; delete this.menuDispose;
} }
} };
reload = () => { reload = () => {
this.dispose(); this.dispose();
const options = {window: this.view, ...this.menuOptions}; const options = {window: this.view, ...this.menuOptions};
this.menuDispose = electronContextMenu(options); this.menuDispose = electronContextMenu(options);
} };
} }

View file

@ -1,7 +1,7 @@
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved. // Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information. // See LICENSE.txt for license information.
import {DiagnosticsStepConstructorPayload} from 'types/diagnostics'; import type {DiagnosticsStepConstructorPayload} from 'types/diagnostics';
import {addDurationToFnReturnObject} from './steps/internal/utils'; import {addDurationToFnReturnObject} from './steps/internal/utils';

View file

@ -2,11 +2,12 @@
// See LICENSE.txt for license information. // See LICENSE.txt for license information.
import {shell} from 'electron'; import {shell} from 'electron';
import log, {ElectronLog} from 'electron-log'; import type {ElectronLog} from 'electron-log';
import {DiagnosticsReport} from 'types/diagnostics'; import log from 'electron-log';
import type {DiagnosticsReport} from 'types/diagnostics';
import DiagnosticsStep from './DiagnosticStep'; import DiagnosticsStep from './DiagnosticStep';
import Step0 from './steps/step0.logLevel'; import Step0 from './steps/step0.logLevel';
import Step1 from './steps/step1.internetConnection'; import Step1 from './steps/step1.internetConnection';
import Step10 from './steps/step10.crashReports'; import Step10 from './steps/step10.crashReports';
@ -62,7 +63,7 @@ class DiagnosticsModule {
this.logger.error('Diagnostics.run Error: ', {error}); this.logger.error('Diagnostics.run Error: ', {error});
this.initializeValues(true); this.initializeValues(true);
} }
} };
initializeValues = (clear = false) => { initializeValues = (clear = false) => {
this.logger.transports.file.level = 'silly'; this.logger.transports.file.level = 'silly';
@ -72,14 +73,14 @@ class DiagnosticsModule {
this.stepCurrent = 0; this.stepCurrent = 0;
this.stepTotal = clear ? 0 : this.getStepCount(); this.stepTotal = clear ? 0 : this.getStepCount();
this.report = []; this.report = [];
} };
getStepCount = () => { getStepCount = () => {
const stepsCount = SORTED_STEPS.length; const stepsCount = SORTED_STEPS.length;
this.logger.debug('Diagnostics.getStepCount', {stepsCount}); this.logger.debug('Diagnostics.getStepCount', {stepsCount});
return stepsCount; return stepsCount;
} };
executeSteps = async () => { executeSteps = async () => {
this.logger.info('Diagnostics.executeSteps Started'); this.logger.info('Diagnostics.executeSteps Started');
@ -112,7 +113,7 @@ class DiagnosticsModule {
this.stepCurrent = index; this.stepCurrent = index;
} }
this.logger.info('Diagnostics.executeSteps Finished'); this.logger.info('Diagnostics.executeSteps Finished');
} };
printReport = () => { printReport = () => {
const totalStepsCount = this.getStepCount(); const totalStepsCount = this.getStepCount();
@ -129,42 +130,42 @@ class DiagnosticsModule {
this.logger.info(`| ---${this.fillSpaces(3)}| ---${this.fillSpaces(maxStepNameLength - 3)} | ---${this.fillSpaces(7)}|`); this.logger.info(`| ---${this.fillSpaces(3)}| ---${this.fillSpaces(maxStepNameLength - 3)} | ---${this.fillSpaces(7)}|`);
this.logger.info(`${successfulStepsCount} out of ${totalStepsCount} steps succeeded`); this.logger.info(`${successfulStepsCount} out of ${totalStepsCount} steps succeeded`);
this.printStepEnd('Report'); this.printStepEnd('Report');
} };
showLogFile = () => { showLogFile = () => {
const pathToFile = this.getLoggerFilePath(); const pathToFile = this.getLoggerFilePath();
this.logger.debug('Diagnostics.showLogFile', {pathToFile}); this.logger.debug('Diagnostics.showLogFile', {pathToFile});
shell.showItemInFolder(pathToFile); shell.showItemInFolder(pathToFile);
} };
sendNotificationDiagnosticsStarted = () => { sendNotificationDiagnosticsStarted = () => {
this.logger.debug('Diagnostics sendNotification DiagnosticsStarted'); this.logger.debug('Diagnostics sendNotification DiagnosticsStarted');
} };
isValidStep = (step: unknown) => { isValidStep = (step: unknown) => {
return step instanceof DiagnosticsStep; return step instanceof DiagnosticsStep;
} };
getLoggerFilePath = () => { getLoggerFilePath = () => {
return this.logger.transports.file.getFile()?.path; return this.logger.transports.file.getFile()?.path;
} };
isRunning = () => { isRunning = () => {
return this.stepTotal > 0 && this.stepCurrent >= 0; return this.stepTotal > 0 && this.stepCurrent >= 0;
} };
getSuccessfulStepsCount = () => { getSuccessfulStepsCount = () => {
return this.report.filter((step) => step.succeeded).length; return this.report.filter((step) => step.succeeded).length;
} };
private printStepStart = (name: string) => { private printStepStart = (name: string) => {
this.logger.info(`${HASHTAGS} ${name} START ${HASHTAGS}`); this.logger.info(`${HASHTAGS} ${name} START ${HASHTAGS}`);
} };
private printStepEnd = (name: string) => { private printStepEnd = (name: string) => {
this.logger.info(`${HASHTAGS} ${name} END ${HASHTAGS}`); this.logger.info(`${HASHTAGS} ${name} END ${HASHTAGS}`);
} };
private addToReport(data: DiagnosticsReport[number]): void { private addToReport(data: DiagnosticsReport[number]): void {
this.report = [ this.report = [
@ -178,7 +179,7 @@ class DiagnosticsModule {
return ''; return '';
} }
return ' '.repeat(i); return ' '.repeat(i);
} };
} }
const Diagnostics = new DiagnosticsModule(); const Diagnostics = new DiagnosticsModule();

View file

@ -1,7 +1,7 @@
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved. // Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information. // See LICENSE.txt for license information.
import {ElectronLog} from 'electron-log'; import type {ElectronLog} from 'electron-log';
import {obfuscateByType} from './obfuscators'; import {obfuscateByType} from './obfuscators';

View file

@ -4,12 +4,14 @@ import fs from 'fs';
import https from 'https'; import https from 'https';
import readline from 'readline'; import readline from 'readline';
import {BrowserWindow, Rectangle, WebContents} from 'electron'; import type {BrowserWindow, Rectangle, WebContents} from 'electron';
import log, {ElectronLog, LogLevel} from 'electron-log'; import type {ElectronLog, LogLevel} from 'electron-log';
import {AddDurationToFnReturnObject, LogFileLineData, LogLevelAmounts, WindowStatus} from 'types/diagnostics'; import log from 'electron-log';
import {IS_ONLINE_ENDPOINT, LOGS_MAX_STRING_LENGTH, REGEX_LOG_FILE_LINE} from 'common/constants'; import {IS_ONLINE_ENDPOINT, LOGS_MAX_STRING_LENGTH, REGEX_LOG_FILE_LINE} from 'common/constants';
import type {AddDurationToFnReturnObject, LogFileLineData, LogLevelAmounts, WindowStatus} from 'types/diagnostics';
export function dateTimeInFilename(date?: Date) { export function dateTimeInFilename(date?: Date) {
const now = date ?? new Date(); const now = date ?? new Date();
return `${now.getDate()}-${now.getMonth()}-${now.getFullYear()}_${now.getHours()}-${now.getMinutes()}-${now.getSeconds()}-${now.getMilliseconds()}`; return `${now.getDate()}-${now.getMonth()}-${now.getFullYear()}_${now.getHours()}-${now.getMinutes()}-${now.getSeconds()}-${now.getMilliseconds()}`;
@ -79,7 +81,7 @@ export async function isOnline(logger: ElectronLog = log, url = IS_ONLINE_ENDPOI
return; return;
} }
} catch (e) { } catch (e) {
logger.error('Cannot parse response') logger.error('Cannot parse response');
} }
} }
resolve(false); resolve(false);

View file

@ -1,8 +1,9 @@
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved. // Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information. // See LICENSE.txt for license information.
import {ElectronLog} from 'electron-log'; import type {ElectronLog} from 'electron-log';
import {DiagnosticStepResponse} from 'types/diagnostics';
import type {DiagnosticStepResponse} from 'types/diagnostics';
import DiagnosticsStep from '../DiagnosticStep'; import DiagnosticsStep from '../DiagnosticStep';

View file

@ -4,15 +4,15 @@
import path from 'path'; import path from 'path';
import {app} from 'electron'; import {app} from 'electron';
import {ElectronLog} from 'electron-log'; import type {ElectronLog} from 'electron-log';
import {DiagnosticStepResponse} from 'types/diagnostics'; import type {DiagnosticStepResponse} from 'types/diagnostics';
import DiagnosticsStep from '../DiagnosticStep';
import loggerHooks from './internal/loggerHooks'; import loggerHooks from './internal/loggerHooks';
import {dateTimeInFilename} from './internal/utils'; import {dateTimeInFilename} from './internal/utils';
import DiagnosticsStep from '../DiagnosticStep';
const stepName = 'Step-0'; const stepName = 'Step-0';
const stepDescriptiveName = 'logConfig'; const stepDescriptiveName = 'logConfig';

View file

@ -1,13 +1,14 @@
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved. // Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information. // See LICENSE.txt for license information.
import {ElectronLog} from 'electron-log'; import type {ElectronLog} from 'electron-log';
import {DiagnosticStepResponse} from 'types/diagnostics';
import DiagnosticsStep from '../DiagnosticStep'; import type {DiagnosticStepResponse} from 'types/diagnostics';
import {isOnline} from './internal/utils'; import {isOnline} from './internal/utils';
import DiagnosticsStep from '../DiagnosticStep';
const stepName = 'Step-1'; const stepName = 'Step-1';
const stepDescriptiveName = 'internetConnection'; const stepDescriptiveName = 'internetConnection';

View file

@ -4,8 +4,9 @@ import fs from 'fs';
import path from 'path'; import path from 'path';
import {app} from 'electron'; import {app} from 'electron';
import {ElectronLog} from 'electron-log'; import type {ElectronLog} from 'electron-log';
import {DiagnosticStepResponse} from 'types/diagnostics';
import type {DiagnosticStepResponse} from 'types/diagnostics';
import DiagnosticsStep from '../DiagnosticStep'; import DiagnosticsStep from '../DiagnosticStep';

View file

@ -2,8 +2,9 @@
// See LICENSE.txt for license information. // See LICENSE.txt for license information.
import {session} from 'electron'; import {session} from 'electron';
import {ElectronLog} from 'electron-log'; import type {ElectronLog} from 'electron-log';
import {DiagnosticStepResponse} from 'types/diagnostics';
import type {DiagnosticStepResponse} from 'types/diagnostics';
import DiagnosticsStep from '../DiagnosticStep'; import DiagnosticsStep from '../DiagnosticStep';

View file

@ -2,14 +2,14 @@
// See LICENSE.txt for license information. // See LICENSE.txt for license information.
import fs from 'fs'; import fs from 'fs';
import {ElectronLog} from 'electron-log'; import type {ElectronLog} from 'electron-log';
import {DiagnosticStepResponse} from 'types/diagnostics';
import Config from 'common/config'; import Config from 'common/config';
import * as Validator from 'common/Validator'; import * as Validator from 'common/Validator';
import {configPath} from 'main/constants'; import {configPath} from 'main/constants';
import type {DiagnosticStepResponse} from 'types/diagnostics';
import DiagnosticsStep from '../DiagnosticStep'; import DiagnosticsStep from '../DiagnosticStep';
const stepName = 'Step-2'; const stepName = 'Step-2';

View file

@ -1,16 +1,17 @@
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved. // Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information. // See LICENSE.txt for license information.
import {ElectronLog} from 'electron-log'; import type {ElectronLog} from 'electron-log';
import {DiagnosticStepResponse} from 'types/diagnostics';
import ServerManager from 'common/servers/serverManager'; import ServerManager from 'common/servers/serverManager';
import {parseURL} from 'common/utils/url'; import {parseURL} from 'common/utils/url';
import DiagnosticsStep from '../DiagnosticStep'; import type {DiagnosticStepResponse} from 'types/diagnostics';
import {isOnline} from './internal/utils'; import {isOnline} from './internal/utils';
import DiagnosticsStep from '../DiagnosticStep';
const stepName = 'Step-3'; const stepName = 'Step-3';
const stepDescriptiveName = 'serverConnectivity'; const stepDescriptiveName = 'serverConnectivity';

View file

@ -2,11 +2,12 @@
// See LICENSE.txt for license information. // See LICENSE.txt for license information.
import {session} from 'electron'; import {session} from 'electron';
import {ElectronLog} from 'electron-log'; import type {ElectronLog} from 'electron-log';
import {DiagnosticStepResponse} from 'types/diagnostics';
import {COOKIE_NAME_AUTH_TOKEN, COOKIE_NAME_CSRF, COOKIE_NAME_USER_ID} from 'common/constants'; import {COOKIE_NAME_AUTH_TOKEN, COOKIE_NAME_CSRF, COOKIE_NAME_USER_ID} from 'common/constants';
import type {DiagnosticStepResponse} from 'types/diagnostics';
import DiagnosticsStep from '../DiagnosticStep'; import DiagnosticsStep from '../DiagnosticStep';
const stepName = 'Step-4'; const stepName = 'Step-4';

View file

@ -1,16 +1,16 @@
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved. // Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information. // See LICENSE.txt for license information.
import {ElectronLog} from 'electron-log'; import type {ElectronLog} from 'electron-log';
import {DiagnosticStepResponse} from 'types/diagnostics';
import MainWindow from 'main/windows/mainWindow'; import MainWindow from 'main/windows/mainWindow';
import DiagnosticsStep from '../DiagnosticStep'; import type {DiagnosticStepResponse} from 'types/diagnostics';
import {browserWindowVisibilityStatus, webContentsCheck} from './internal/utils'; import {browserWindowVisibilityStatus, webContentsCheck} from './internal/utils';
import DiagnosticsStep from '../DiagnosticStep';
const stepName = 'Step-5'; const stepName = 'Step-5';
const stepDescriptiveName = 'BrowserWindowsChecks'; const stepDescriptiveName = 'BrowserWindowsChecks';

View file

@ -3,14 +3,17 @@
import fs from 'fs'; import fs from 'fs';
import {Notification, systemPreferences} from 'electron'; import {Notification, systemPreferences} from 'electron';
import log, {ElectronLog} from 'electron-log'; import type {ElectronLog} from 'electron-log';
import {DiagnosticStepResponse} from 'types/diagnostics'; import log from 'electron-log';
import DiagnosticsStep from '../DiagnosticStep';
import config from 'common/config'; import config from 'common/config';
import type {DiagnosticStepResponse} from 'types/diagnostics';
import {checkPathPermissions} from './internal/utils'; import {checkPathPermissions} from './internal/utils';
import DiagnosticsStep from '../DiagnosticStep';
const stepName = 'Step-6'; const stepName = 'Step-6';
const stepDescriptiveName = 'PermissionsCheck'; const stepDescriptiveName = 'PermissionsCheck';

View file

@ -3,13 +3,14 @@
import path from 'path'; import path from 'path';
import {app, powerMonitor} from 'electron'; import {app, powerMonitor} from 'electron';
import {ElectronLog} from 'electron-log'; import type {ElectronLog} from 'electron-log';
import {DiagnosticStepResponse} from 'types/diagnostics';
import DiagnosticsStep from '../DiagnosticStep'; import type {DiagnosticStepResponse} from 'types/diagnostics';
import {dateTimeInFilename} from './internal/utils'; import {dateTimeInFilename} from './internal/utils';
import DiagnosticsStep from '../DiagnosticStep';
const stepName = 'Step-7'; const stepName = 'Step-7';
const stepDescriptiveName = 'PerformanceAndMemory'; const stepDescriptiveName = 'PerformanceAndMemory';

View file

@ -1,16 +1,17 @@
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved. // Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information. // See LICENSE.txt for license information.
import log, {ElectronLog} from 'electron-log'; import type {ElectronLog} from 'electron-log';
import log from 'electron-log';
import {DiagnosticStepResponse} from 'types/diagnostics';
import {getPercentage} from 'main/utils'; import {getPercentage} from 'main/utils';
import DiagnosticsStep from '../DiagnosticStep'; import type {DiagnosticStepResponse} from 'types/diagnostics';
import {readFileLineByLine} from './internal/utils'; import {readFileLineByLine} from './internal/utils';
import DiagnosticsStep from '../DiagnosticStep';
const stepName = 'Step-8'; const stepName = 'Step-8';
const stepDescriptiveName = 'LogHeuristics'; const stepDescriptiveName = 'LogHeuristics';

View file

@ -1,11 +1,12 @@
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved. // Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information. // See LICENSE.txt for license information.
import {ElectronLog} from 'electron-log'; import type {ElectronLog} from 'electron-log';
import {DiagnosticStepResponse} from 'types/diagnostics';
import config from 'common/config'; import config from 'common/config';
import type {DiagnosticStepResponse} from 'types/diagnostics';
import DiagnosticsStep from '../DiagnosticStep'; import DiagnosticsStep from '../DiagnosticStep';
const stepName = 'Step-9'; const stepName = 'Step-9';

View file

@ -1,15 +1,13 @@
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved. // Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information. // See LICENSE.txt for license information.
import path from 'path';
import fs from 'fs'; import fs from 'fs';
import path from 'path';
import {shell} from 'electron'; import {shell} from 'electron';
import {getDoNotDisturb as getDarwinDoNotDisturb} from 'macos-notification-state'; import {getDoNotDisturb as getDarwinDoNotDisturb} from 'macos-notification-state';
import Config from 'common/config'; import Config from 'common/config';
import {APP_UPDATE_KEY} from 'common/constants'; import {APP_UPDATE_KEY} from 'common/constants';
import {DownloadsManager} from 'main/downloadsManager'; import {DownloadsManager} from 'main/downloadsManager';
const downloadLocationMock = '/path/to/downloads'; const downloadLocationMock = '/path/to/downloads';

View file

@ -1,11 +1,11 @@
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved. // Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information. // See LICENSE.txt for license information.
import path from 'path';
import fs from 'fs'; import fs from 'fs';
import path from 'path';
import {DownloadItem, Event, WebContents, FileFilter, ipcMain, dialog, shell, Menu, app, IpcMainInvokeEvent} from 'electron'; import type {DownloadItem, Event, WebContents, FileFilter, IpcMainInvokeEvent} from 'electron';
import {ProgressInfo, UpdateInfo} from 'electron-updater'; import {ipcMain, dialog, shell, Menu, app} from 'electron';
import {DownloadedItem, DownloadItemDoneEventState, DownloadedItems, DownloadItemState, DownloadItemUpdatedEventState} from 'types/downloads'; import type {ProgressInfo, UpdateInfo} from 'electron-updater';
import { import {
CANCEL_UPDATE_DOWNLOAD, CANCEL_UPDATE_DOWNLOAD,
@ -25,16 +25,18 @@ import {
UPDATE_PROGRESS, UPDATE_PROGRESS,
} from 'common/communication'; } from 'common/communication';
import Config from 'common/config'; import Config from 'common/config';
import {APP_UPDATE_KEY, UPDATE_DOWNLOAD_ITEM} from 'common/constants';
import JsonFileManager from 'common/JsonFileManager'; import JsonFileManager from 'common/JsonFileManager';
import {Logger} from 'common/log'; import {Logger} from 'common/log';
import {APP_UPDATE_KEY, UPDATE_DOWNLOAD_ITEM} from 'common/constants';
import {DOWNLOADS_DROPDOWN_AUTOCLOSE_TIMEOUT, DOWNLOADS_DROPDOWN_MAX_ITEMS} from 'common/utils/constants'; import {DOWNLOADS_DROPDOWN_AUTOCLOSE_TIMEOUT, DOWNLOADS_DROPDOWN_MAX_ITEMS} from 'common/utils/constants';
import * as Validator from 'common/Validator'; import * as Validator from 'common/Validator';
import {localizeMessage} from 'main/i18nManager'; import {localizeMessage} from 'main/i18nManager';
import NotificationManager from 'main/notifications'; import NotificationManager from 'main/notifications';
import {doubleSecToMs, getPercentage, isStringWithLength, readFilenameFromContentDispositionHeader, shouldIncrementFilename} from 'main/utils';
import ViewManager from 'main/views/viewManager'; import ViewManager from 'main/views/viewManager';
import MainWindow from 'main/windows/mainWindow'; import MainWindow from 'main/windows/mainWindow';
import {doubleSecToMs, getPercentage, isStringWithLength, readFilenameFromContentDispositionHeader, shouldIncrementFilename} from 'main/utils';
import type {DownloadedItem, DownloadItemDoneEventState, DownloadedItems, DownloadItemState, DownloadItemUpdatedEventState} from 'types/downloads';
import appVersionManager from './AppVersionManager'; import appVersionManager from './AppVersionManager';
import {downloadsJson} from './constants'; import {downloadsJson} from './constants';
@ -189,7 +191,7 @@ export class DownloadsManager extends JsonFileManager<DownloadedItems> {
this.clearFile(file); this.clearFile(file);
} }
} }
} };
checkForDeletedFiles = () => { checkForDeletedFiles = () => {
log.debug('checkForDeletedFiles'); log.debug('checkForDeletedFiles');
@ -388,7 +390,7 @@ export class DownloadsManager extends JsonFileManager<DownloadedItems> {
startFrom, startFrom,
localizeMessage('main.downloadsManager.specifyDownloadsFolder', 'Specify the folder where files will download'), localizeMessage('main.downloadsManager.specifyDownloadsFolder', 'Specify the folder where files will download'),
); );
} };
private selectDefaultDownloadDirectory = async (startFrom: string, message: string) => { private selectDefaultDownloadDirectory = async (startFrom: string, message: string) => {
log.debug('handleSelectDownload', startFrom); log.debug('handleSelectDownload', startFrom);
@ -398,7 +400,7 @@ export class DownloadsManager extends JsonFileManager<DownloadedItems> {
properties: properties:
['openDirectory', 'createDirectory', 'dontAddToRecent', 'promptToCreate']}); ['openDirectory', 'createDirectory', 'dontAddToRecent', 'promptToCreate']});
return result.filePaths[0]; return result.filePaths[0];
} };
private verifyMacAppStoreDownloadFolder = async (fileName: string) => { private verifyMacAppStoreDownloadFolder = async (fileName: string) => {
let downloadLocation = Config.downloadLocation; let downloadLocation = Config.downloadLocation;
@ -421,7 +423,7 @@ export class DownloadsManager extends JsonFileManager<DownloadedItems> {
} }
return downloadLocation; return downloadLocation;
} };
private markFileAsDeleted = (item: DownloadedItem) => { private markFileAsDeleted = (item: DownloadedItem) => {
const fileId = this.getDownloadedFileId(item); const fileId = this.getDownloadedFileId(item);
@ -647,7 +649,7 @@ export class DownloadsManager extends JsonFileManager<DownloadedItems> {
private getBookmark = (item: DownloadItem) => { private getBookmark = (item: DownloadItem) => {
return this.bookmarks.get(this.getFileId(item))?.bookmark; return this.bookmarks.get(this.getFileId(item))?.bookmark;
} };
private getFileSize = (item: DownloadItem) => { private getFileSize = (item: DownloadItem) => {
const itemTotalBytes = item.getTotalBytes(); const itemTotalBytes = item.getTotalBytes();

Some files were not shown because too many files have changed in this diff Show more