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

4
.vscode/launch.json vendored
View file

@ -38,8 +38,6 @@
"name": "E2E Tests",
"program": "${workspaceRoot}/node_modules/electron-mocha/bin/electron-mocha",
"args": [
"-r",
"@babel/register",
"--recursive",
"--timeout",
"999999",
@ -55,8 +53,6 @@
"name": "E2E Performance Tests",
"program": "${workspaceRoot}/node_modules/electron-mocha/bin/electron-mocha",
"args": [
"-r",
"@babel/register",
"--recursive",
"--timeout",
"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
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
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
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
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
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
This product contains 'style-loader' by devrafalko.

View file

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

View file

@ -1,6 +1,6 @@
{
"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",
"keywords": [
"mattermost"
@ -18,7 +18,7 @@
"directory": "api-types"
},
"peerDependencies": {
"typescript": "^4.3"
"typescript": "^4.3.0 || ^5.0.0"
},
"peerDependenciesMeta": {
"typescript": {

View file

@ -8,8 +8,8 @@ module.exports = (api) => { // eslint-disable-line import/no-commonjs
presets: [
['@babel/preset-env', {
targets: {
browsers: ['Electron >= 2.0'],
node: '8.9',
browsers: ['Electron >= 29.0'],
node: '20.9',
},
}],
'@babel/preset-react',
@ -18,6 +18,10 @@ module.exports = (api) => { // eslint-disable-line import/no-commonjs
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';
const fs = require('fs');
const path = require('path');
const ps = require('ps-node');
const {_electron: electron} = require('playwright');
const chai = require('chai');
const {ipcRenderer} = require('electron');
const {SHOW_SETTINGS_WINDOW} = require('../../src/common/communication');
const {_electron: electron} = require('playwright');
const ps = require('ps-node');
const {asyncSleep, mkDirAsync, rmDirAsync, unlinkAsync} = require('./utils');
const {SHOW_SETTINGS_WINDOW} = require('../../src/common/communication');
chai.should();
const sourceRootDir = path.join(__dirname, '../..');

View file

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

View file

@ -7,7 +7,6 @@ const fs = require('fs');
const robot = require('robotjs');
const {SHOW_SETTINGS_WINDOW} = require('../../src/common/communication');
const env = require('../modules/environment');
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;
await env.loginToMattermost(firstServer);
await firstServer.waitForSelector('#sidebarItem_off-topic');
// click on Off topic channel
await firstServer.click('#sidebarItem_off-topic');
// click on town square channel
await firstServer.click('#sidebarItem_town-square');
await firstServer.locator('[aria-label="Back"]').click();

View file

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

View file

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

View file

@ -4,12 +4,11 @@
/* eslint-disable no-console,consistent-return */
const fs = require('fs');
const path = require('path');
const async = require('async');
const {Upload} = require('@aws-sdk/lib-storage');
const {S3} = require('@aws-sdk/client-s3');
const {Upload} = require('@aws-sdk/lib-storage');
const async = require('async');
const mime = require('mime-types');
const readdir = require('recursive-readdir');
@ -29,7 +28,7 @@ const {
const s3 = new S3({
credentials: {
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 fse = require('fs-extra');
const package = require('../../package.json');
const {MOCHAWESOME_REPORT_DIR} = require('./constants');
const package = require('../../package.json');
const MAX_FAILED_TITLES = 5;
let incrementalDuration = 0;
@ -116,11 +116,11 @@ function getOS() {
function getEnvironmentValues() {
return {
playwright_version: package.devDependencies.playwright,
electron_version: package.devDependencies.electron,
os_name: getOS(),
os_version: os.release(),
node_version: process.version,
playwrightVersion: package.devDependencies.playwright,
electronVersion: package.devDependencies.electron,
osName: getOS(),
osVersion: os.release(),
nodeVersion: process.version,
};
}
@ -138,11 +138,11 @@ function generateTestReport(summary, isUploadedToS3, reportLink, testCycleKey) {
} = process.env;
const {statsFieldValue, stats} = summary;
const {
playwright_version,
electron_version,
os_name,
os_version,
node_version,
playwrightVersion,
electronVersion,
osName,
osVersion,
nodeVersion,
} = getEnvironmentValues();
let testResult;
@ -154,7 +154,7 @@ function generateTestReport(summary, isUploadedToS3, reportLink, testCycleKey) {
}
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') {
let reportField;

19786
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:build": "webpack-cli --config webpack.config.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": "electron-mocha -r @babel/register --reporter mochawesome 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 --reporter mochawesome dist/tests/e2e_bundle.js",
"test:e2e:send-report": "node ./e2e/save_report.js",
"test:unit": "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",
"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:run": "node -r @babel/register scripts/check_build_config.js",
"check-build-config:run": "node scripts/check_build_config.js",
"check-types": "tsc",
"prune": "ts-prune",
"mmjstool": "mmjstool",
"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": {
"clearMocks": true,
@ -135,36 +135,28 @@
"devDependencies": {
"@aws-sdk/client-s3": "3.445.0",
"@aws-sdk/lib-storage": "3.445.0",
"@babel/cli": "7.17.6",
"@babel/core": "7.17.8",
"@babel/plugin-proposal-class-properties": "7.16.7",
"@babel/plugin-proposal-object-rest-spread": "7.17.3",
"@babel/preset-env": "7.16.11",
"@babel/preset-react": "7.16.7",
"@babel/register": "7.17.7",
"@babel/cli": "7.23.9",
"@babel/preset-env": "7.24.0",
"@babel/preset-react": "7.23.3",
"@babel/preset-typescript": "7.23.3",
"@electron/fuses": "1.6.0",
"@electron/notarize": "2.3.0",
"@electron/rebuild": "3.6.0",
"@electron/universal": "1.3.1",
"@mattermost/compass-icons": "0.1.32",
"@mattermost/desktop-api": "*",
"@storybook/addon-actions": "6.4.20",
"@storybook/react": "6.4.20",
"@types/auto-launch": "5.0.2",
"@types/electron-devtools-installer": "2.2.1",
"@types/jest": "^29.0.0",
"@mattermost/eslint-plugin": "1.1.0-0",
"@types/auto-launch": "5.0.5",
"@types/jest": "29.4.1",
"@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/uuid": "^9.0.1",
"@types/valid-url": "1.0.3",
"@types/winreg": "1.2.31",
"@typescript-eslint/eslint-plugin": "5.18.0",
"@typescript-eslint/parser": "5.18.0",
"@types/uuid": "9.0.8",
"@types/valid-url": "1.0.7",
"@types/winreg": "1.2.36",
"7zip-bin": "5.1.1",
"auto-launch": "5.0.5",
"axios": "0.26.1",
"babel-eslint": "10.1.0",
"babel-loader": "8.2.4",
"axios": "1.6.7",
"babel-loader": "9.1.3",
"bootstrap": "4.6.1",
"bootstrap-dark": "1.0.3",
"chai": "4.3.6",
@ -173,61 +165,54 @@
"cross-env": "7.0.3",
"css-loader": "6.7.1",
"electron": "29.0.0",
"electron-builder": "24.12.0",
"electron-builder": "24.13.3",
"electron-connect": "0.6.3",
"electron-context-menu": "3.6.1",
"electron-extension-installer": "1.2.0",
"electron-is-dev": "2.0.0",
"electron-log": "4.4.8",
"electron-mocha": "12.2.0",
"electron-notarize": "1.2.2",
"electron-updater": "5.2.1",
"eslint": "7.29.0",
"eslint-import-resolver-webpack": "0.13.2",
"eslint-plugin-babel": "5.3.1",
"eslint-plugin-cypress": "2.11.3",
"eslint-plugin-header": "3.1.1",
"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",
"electron-updater": "6.1.8",
"eslint": "8.57.0",
"eslint-import-resolver-webpack": "0.13.8",
"eslint-plugin-formatjs": "4.12.2",
"eslint-plugin-no-only-tests": "3.1.0",
"eslint-plugin-react": "7.34.0",
"eslint-plugin-react-hooks": "4.6.0",
"fs-extra": "10.0.1",
"html-webpack-plugin": "5.5.0",
"jest": "29.4.1",
"jest-junit": "13.1.0",
"joi": "17.6.0",
"mini-css-extract-plugin": "2.6.0",
"mmjstool": "github:mattermost/mattermost-utilities#3b4506b0f6b14fbb402f9f8ef932370e459e3773",
"mocha-circleci-reporter": "0.0.3",
"mochawesome": "7.1.3",
"nan": "2.18.0",
"nan": "2.19.0",
"node-abi": "3.56.0",
"node-gyp": "10.0.1",
"node-jq": "2.3.4",
"node-jq": "4.3.1",
"node-loader": "2.0.0",
"npm-run-all": "4.1.5",
"patch-package": "^8.0.0",
"playwright": "1.42.0",
"pretty-bytes": "6.0.0",
"ps-node": "^0.1.6",
"react": "16.14.0",
"ps-node": "0.1.6",
"react": "17.0.2",
"react-beautiful-dnd": "13.1.0",
"react-bootstrap": "1.6.4",
"react-dom": "16.14.0",
"react-intl": "5.20.10",
"react-dom": "17.0.2",
"react-intl": "6.6.2",
"react-select": "5.2.2",
"recursive-readdir": "^2.2.2",
"recursive-readdir": "2.2.3",
"robotjs": "0.6.0",
"sass": "1.49.11",
"sass-loader": "12.6.0",
"semver": "7.3.5",
"shebang-loader": "0.0.1",
"semver": "7.6.0",
"style-loader": "3.3.1",
"ts-prune": "0.10.3",
"typescript": "4.6.3",
"typescript": "5.3.3",
"uuid": "9.0.0",
"valid-url": "1.0.9",
"webpack": "5.71.0",
"webpack": "5.90.3",
"webpack-cli": "4.10.0",
"webpack-dev-server": "4.8.0",
"webpack-merge": "5.8.0",
@ -237,8 +222,5 @@
"dependencies": {
"macos-notification-state": "2.0.2",
"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 {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 {flipFuses, FuseVersion, FuseV1Options} = require('@electron/fuses');
function fixSetuid(context) {
return async (target) => {
if (!['appimage', 'snap'].includes(target.name.toLowerCase())) {

View file

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

View file

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

View file

@ -2,9 +2,10 @@
// See LICENSE.txt for license information.
const fs = require('fs');
const jq = require('node-jq');
const path = require('path');
const jq = require('node-jq');
// Patch the macos-notification-state library so we can build correctly
jq.run(
'.scripts.install = "node-gyp rebuild"',
@ -32,7 +33,7 @@ StartupWMClass=Mattermost
Comment=Mattermost
MimeType=x-scheme-handler/mattermost-dev;
Categories=contrib/net;
`
`,
);
const defaultsListPath = path.resolve(xdgDir, 'defaults.list');

View file

@ -1,8 +1,8 @@
// Copyright (c) 2015-2016 Yuya Ochiai
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
const webpack = require('webpack');
const electron = require('electron-connect').server.create({path: 'dist/'});
const webpack = require('webpack');
const mainConfig = require('../webpack.config.main.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 {URLValidationStatus} from 'common/utils/constants';
import {getDefaultViewsForConfigServer} from 'common/views/View';
import {ServerInfo} from 'main/server/serverInfo';
import ModalManager from 'main/views/modalManager';
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 MainWindow from 'main/windows/mainWindow';
import {ServerViewState} from './serverViewState';

View file

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

View file

@ -3,17 +3,17 @@
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 {TAB_MESSAGING} from 'common/views/View';
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 defaultOptions = {

View file

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

View file

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

View file

@ -2,7 +2,7 @@
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// 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

View file

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

View file

@ -2,13 +2,17 @@
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import fs from 'fs';
import os from 'os';
import path from 'path';
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,
BuildConfig,
CombinedConfig,
@ -17,16 +21,11 @@ import {
RegistryConfig as RegistryConfigType,
} 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 RegistryConfig, {REGISTRY_READ_EVENT} from './RegistryConfig';
import defaultPreferences, {getDefaultDownloadLocation} from './defaultPreferences';
import migrateConfigItems from './migrationPreferences';
import RegistryConfig, {REGISTRY_READ_EVENT} from './RegistryConfig';
import upgradeConfigData from './upgradePreferences';
const log = new Logger('Config');
@ -67,7 +66,7 @@ export class Config extends EventEmitter {
this.canUpgradeValue = this.checkWriteableApp();
this.reload();
}
};
initRegistry = () => {
if (process.platform !== 'win32') {
@ -82,7 +81,7 @@ export class Config extends EventEmitter {
});
this.registryConfig.init();
});
}
};
/**
* Reload all sources of config data
@ -101,7 +100,7 @@ export class Config extends EventEmitter {
this.regenerateCombinedConfigData();
this.emit('update', this.combinedData);
}
};
/*********************
* Setters and Getters
@ -116,11 +115,11 @@ export class Config extends EventEmitter {
set = (key: keyof ConfigType, data: ConfigType[keyof ConfigType]): void => {
log.debug('set');
this.setMultiple({[key]: data});
}
};
setConfigPath = (configPath: string) => {
this.configFilePath = configPath;
}
};
/**
* 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.regenerateCombinedConfigData();
this.saveLocalConfigData();
}
};
setServers = (servers: ConfigServer[], lastActiveServer?: number) => {
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.regenerateCombinedConfigData();
this.saveLocalConfigData();
}
};
// 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.reload();
}
};
/**
* Config file loading methods
@ -299,7 +298,7 @@ export class Config extends EventEmitter {
} catch (error) {
this.emit('error', error);
}
}
};
/**
* 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);
}
return configData;
}
};
/**
* 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;
}
};
/**
* 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) {
this.combinedData.appName = this.appName;
}
}
};
// helper functions
private writeFile = (filePath: string, configData: Partial<ConfigType>, callback?: fs.NoParamCallback) => {
@ -407,7 +406,7 @@ export class Config extends EventEmitter {
fs.writeFileSync(filePath, json, 'utf8');
}
}
};
private checkWriteableApp = () => {
if (!this.appPath) {
@ -440,7 +439,7 @@ export class Config extends EventEmitter {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
return process.platform !== 'darwin' && __CAN_UPGRADE__;
}
};
}
const config = new Config();

View file

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

View file

@ -1,7 +1,7 @@
// Copyright (c) 2015-2016 Yuya Ochiai
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// 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';

View file

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

View file

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

View file

@ -1,9 +1,9 @@
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// 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

View file

@ -1,7 +1,8 @@
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// 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';
@ -37,15 +38,15 @@ export class Logger {
silly: this.prefixed(log.silly, ...prefixes),
log: this.prefixed(log.log, ...prefixes),
};
}
};
private prefixed = (func: (...args: any[]) => void, ...additionalPrefixes: string[]) => {
return (...args: any[]) => func(...this.prefixes, ...this.shortenPrefixes(...additionalPrefixes), ...args);
}
};
private shortenPrefixes = (...prefixes: string[]) => {
return prefixes.map((prefix) => `[${Util.shorten(prefix)}]`);
}
};
error = this.prefixed(log.error);
warn = this.prefixed(log.warn);

View file

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

View file

@ -1,9 +1,9 @@
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// 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 Utils from 'common/utils/util';
import {TAB_MESSAGING, TAB_FOCALBOARD, TAB_PLAYBOOKS} from 'common/views/View';
import {ServerManager} from './serverManager';

View file

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

View file

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

View file

@ -3,11 +3,11 @@
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 {
id: string;
@ -35,5 +35,5 @@ export default abstract class BaseView implements MattermostView {
name: this.type,
isOpen: this.isOpen,
};
}
};
}

View file

@ -4,7 +4,8 @@
import {getFormattedPathName} from 'common/utils/url';
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 {
get url(): URL {

View file

@ -2,7 +2,8 @@
// See LICENSE.txt for license information.
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 {
get url(): URL {

View file

@ -4,7 +4,8 @@
import {getFormattedPathName} from 'common/utils/url';
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 {
get url(): URL {

View file

@ -1,9 +1,9 @@
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// 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_FOCALBOARD = 'TAB_FOCALBOARD';

View file

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

View file

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

View file

@ -27,7 +27,7 @@ describe('main/AppVersionManager', () => {
fs.readFileSync.mockReturnValue('some bad JSON');
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');
expect(fs.writeFile).toBeCalledWith('somefilename.txt', '{}', expect.any(Function));

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -3,12 +3,11 @@
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 {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', () => ({
app: {

View file

@ -1,11 +1,11 @@
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// 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 {parseURL} from 'common/utils/url';
import updateManager from 'main/autoUpdater';
import CertificateStore from 'main/certificateStore';
import {localizeMessage} from 'main/i18nManager';

View file

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

View file

@ -3,12 +3,9 @@
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 Config from 'common/config';
import {Logger, setLoggingLevel} from 'common/log';
import AutoLauncher from 'main/AutoLauncher';
import {setUnreadBadgeSetting} from 'main/badge';
import Tray from 'main/tray/tray';
@ -16,6 +13,8 @@ import LoadingScreen from 'main/views/loadingScreen';
import MainWindow from 'main/windows/mainWindow';
import SettingsWindow from 'main/windows/settingsWindow';
import type {CombinedConfig, Config as ConfigType} from 'types/config';
import {handleMainWindowIsShown} from './intercom';
import {handleUpdateMenuEvent, updateSpellCheckerLocales} from './utils';

View file

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

View file

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

View file

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

View file

@ -3,10 +3,10 @@
import {app} from 'electron';
import {getLocalURLString, getLocalPreload} from 'main/utils';
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 MainWindow from 'main/windows/mainWindow';
import {
handleWelcomeScreenModal,

View file

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

View file

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

View file

@ -3,23 +3,18 @@
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 {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 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 updateManager from 'main/autoUpdater';
import {migrationInfoPath, updatePaths} from 'main/constants';
import {localizeMessage} from 'main/i18nManager';
@ -30,6 +25,10 @@ import Tray from 'main/tray/tray';
import ViewManager from 'main/views/viewManager';
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';
const assetsDir = path.resolve(app.getAppPath(), 'assets');

View file

@ -1,10 +1,11 @@
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// 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 {Logger} from 'common/log';
const log = new Logger('App.Windows');

View file

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

View file

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

View file

@ -4,13 +4,8 @@
import path from 'path';
import {dialog, ipcMain, app, nativeImage} from 'electron';
import {autoUpdater, CancellationToken, ProgressInfo, UpdateInfo} from 'electron-updater';
import {Logger} from 'common/log';
import downloadsManager from 'main/downloadsManager';
import {localizeMessage} from 'main/i18nManager';
import NotificationManager from 'main/notifications';
import type {ProgressInfo, UpdateInfo} from 'electron-updater';
import {autoUpdater, CancellationToken} from 'electron-updater';
import {
CANCEL_UPGRADE,
@ -24,6 +19,10 @@ import {
UPDATE_REMIND_LATER,
} from 'common/communication';
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_CHECK = 3600000; // 1 hour
@ -109,44 +108,44 @@ export class UpdateManager {
} else if (this.versionAvailable) {
this.notifyUpgrade();
}
}
};
notifyUpgrade = (): void => {
ipcMain.emit(UPDATE_AVAILABLE, null, this.versionAvailable);
NotificationManager.displayUpgrade(this.versionAvailable || 'unknown', this.handleDownload);
}
};
notifyDownloaded = (): void => {
ipcMain.emit(UPDATE_DOWNLOADED, null, this.downloadedInfo);
NotificationManager.displayRestartToUpgrade(this.versionDownloaded || 'unknown', this.handleUpdate);
}
};
handleDownload = (): void => {
if (this.lastCheck) {
clearTimeout(this.lastCheck);
}
autoUpdater.downloadUpdate(this.cancellationToken);
}
};
handleCancelDownload = (): void => {
this.cancellationToken?.cancel();
this.cancellationToken = new CancellationToken();
}
};
handleRemindLater = (): void => {
// TODO
}
};
handleOnQuit = (): void => {
if (this.versionDownloaded) {
autoUpdater.quitAndInstall(true, false);
}
}
};
handleUpdate = (): void => {
downloadsManager.removeUpdateBeforeRestart();
autoUpdater.quitAndInstall();
}
};
displayNoUpgrade = (): void => {
const version = app.getVersion();
@ -159,7 +158,7 @@ export class UpdateManager {
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}),
});
}
};
checkForUpdates = (manually: boolean): void => {
if (!Config.canUpgrade) {
@ -183,7 +182,7 @@ export class UpdateManager {
});
this.lastCheck = setTimeout(() => this.checkForUpdates(false), NEXT_CHECK);
}
}
};
}
const updateManager = new UpdateManager();

View file

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

View file

@ -2,12 +2,12 @@
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// 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 {UPDATE_APPSTATE_TOTALS} from 'common/communication';
import {Logger} from 'common/log';
import {localizeMessage} from 'main/i18nManager';
import MainWindow from './windows/mainWindow';

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -4,12 +4,14 @@ import fs from 'fs';
import https from 'https';
import readline from 'readline';
import {BrowserWindow, Rectangle, WebContents} from 'electron';
import log, {ElectronLog, LogLevel} from 'electron-log';
import {AddDurationToFnReturnObject, LogFileLineData, LogLevelAmounts, WindowStatus} from 'types/diagnostics';
import type {BrowserWindow, Rectangle, WebContents} from 'electron';
import type {ElectronLog, LogLevel} from 'electron-log';
import log from 'electron-log';
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) {
const now = date ?? new Date();
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;
}
} catch (e) {
logger.error('Cannot parse response')
logger.error('Cannot parse response');
}
}
resolve(false);

View file

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

View file

@ -4,15 +4,15 @@
import path from 'path';
import {app} 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 loggerHooks from './internal/loggerHooks';
import {dateTimeInFilename} from './internal/utils';
import DiagnosticsStep from '../DiagnosticStep';
const stepName = 'Step-0';
const stepDescriptiveName = 'logConfig';

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -2,11 +2,12 @@
// See LICENSE.txt for license information.
import {session} from 'electron';
import {ElectronLog} from 'electron-log';
import {DiagnosticStepResponse} from 'types/diagnostics';
import type {ElectronLog} from 'electron-log';
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';
const stepName = 'Step-4';

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

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