[MM-23067] Browser View (#1514)

* Browser-view: initial architectural changes + webpack (#1358)

* reorder code to support webpack

* start backend changes

* remove simple-spellchecker

* wip

* first browserview run

* settings window routing

* wip

* back to webpack

* working build

* back to using electron-builder

* fix linting

* linting errors missed

* back to just 1 config

* missing changes

* refactor and have the settings in its own page

* reminder to restore disabling window.eval

* remove old webpack generated files

* add assets files

* more remove files and fix localurls

* CR changes

* Browserview settings window (#1362)

* reorder code to support webpack

* start backend changes

* remove simple-spellchecker

* wip

* first browserview run

* settings window routing

* wip

* back to webpack

* working build

* back to using electron-builder

* fix linting

* linting errors missed

* back to just 1 config

* missing changes

* refactor and have the settings in its own page

* reminder to restore disabling window.eval

* wip

* wip

* remove old webpack generated files

* add assets files

* more remove files and fix localurls

* wip settings, needs fixing saving prefs

* remove linting errors

* remove settings as a modal

* fix linting

* remove view from window on destroy

* restore visibility if reloaded

* debug log

* look for closed windows, remove managers from settings as it is a full window

* restore view on configuration save

* linting and debug

* remove debug message

* [BrowserView] renderer (#1378)

* reorder code to support webpack

* start backend changes

* remove simple-spellchecker

* wip

* first browserview run

* settings window routing

* wip

* back to webpack

* working build

* back to using electron-builder

* fix linting

* linting errors missed

* back to just 1 config

* missing changes

* refactor and have the settings in its own page

* reminder to restore disabling window.eval

* wip

* wip

* remove old webpack generated files

* add assets files

* more remove files and fix localurls

* wip settings, needs fixing saving prefs

* remove linting errors

* remove settings as a modal

* fix linting

* remove view from window on destroy

* restore visibility if reloaded

* debug log

* look for closed windows, remove managers from settings as it is a full window

* restore view on configuration save

* linting and debug

* remove debug message

* make eslint be aware of webpack aliases

* some extra disable lines

* move badge management to main

* remove unneded import

* fixing errors

* wip

* back to having tabs

* switch tab working

* wip

* wip

* wip

* fix quitting error

* back to a working config

* configure retries

* add darkmode

* wip

* add error/loading screens

* fix settings while removing remote usage

* wip

* fix lint, get preload to load

* remove unused import

* remove log statements

* Bv menus (#1387)

* reorder code to support webpack

* start backend changes

* remove simple-spellchecker

* wip

* first browserview run

* settings window routing

* wip

* back to webpack

* working build

* back to using electron-builder

* fix linting

* linting errors missed

* back to just 1 config

* missing changes

* refactor and have the settings in its own page

* reminder to restore disabling window.eval

* wip

* wip

* remove old webpack generated files

* add assets files

* more remove files and fix localurls

* wip settings, needs fixing saving prefs

* remove linting errors

* remove settings as a modal

* fix linting

* remove view from window on destroy

* restore visibility if reloaded

* debug log

* look for closed windows, remove managers from settings as it is a full window

* restore view on configuration save

* linting and debug

* remove debug message

* make eslint be aware of webpack aliases

* some extra disable lines

* move badge management to main

* remove unneded import

* fixing errors

* wip

* back to having tabs

* switch tab working

* wip

* wip

* wip

* fix quitting error

* back to a working config

* configure retries

* add darkmode

* wip

* add error/loading screens

* fix settings while removing remote usage

* wip

* fix lint, get preload to load

* remove unused import

* wip

* menus initially working as they should

* update deps, show context menu

* wip

* wip

* wip

* fix forward/back menu

* fix server menu

* allow navigating to external urls in the browser

* add defaults to menu

* fix logic

* set default options

* remove logs

* wip

* package.json

* fix merge results

* fix package-lock

* remove debug statements

* address CR requests

* [MM-22691][Browserview] fix tray icon (#1403)

* reorder code to support webpack

* start backend changes

* remove simple-spellchecker

* wip

* first browserview run

* settings window routing

* wip

* back to webpack

* working build

* back to using electron-builder

* fix linting

* linting errors missed

* back to just 1 config

* missing changes

* refactor and have the settings in its own page

* reminder to restore disabling window.eval

* wip

* wip

* remove old webpack generated files

* add assets files

* more remove files and fix localurls

* wip settings, needs fixing saving prefs

* remove linting errors

* remove settings as a modal

* fix linting

* remove view from window on destroy

* restore visibility if reloaded

* debug log

* look for closed windows, remove managers from settings as it is a full window

* restore view on configuration save

* linting and debug

* remove debug message

* make eslint be aware of webpack aliases

* some extra disable lines

* move badge management to main

* remove unneded import

* fixing errors

* wip

* back to having tabs

* switch tab working

* wip

* wip

* wip

* fix quitting error

* back to a working config

* configure retries

* add darkmode

* wip

* add error/loading screens

* fix settings while removing remote usage

* wip

* fix lint, get preload to load

* remove unused import

* wip

* menus initially working as they should

* update deps, show context menu

* wip

* wip

* wip

* fix forward/back menu

* fix server menu

* allow navigating to external urls in the browser

* add defaults to menu

* fix logic

* set default options

* remove logs

* wip

* fix webpack adding images to /dist so tray can render them

* wait for config, fix menutray calls

* remove .gitattributes from being tracked

* remove unused reject

* remove logs

* Update webpack.config.renderer.js

Co-authored-by: Devin Binnie <52460000+devinbinnie@users.noreply.github.com>

Co-authored-by: Devin Binnie <52460000+devinbinnie@users.noreply.github.com>

* Browserview URLHover (#1393)

* reorder code to support webpack

* start backend changes

* remove simple-spellchecker

* wip

* first browserview run

* settings window routing

* wip

* back to webpack

* working build

* back to using electron-builder

* fix linting

* linting errors missed

* back to just 1 config

* missing changes

* refactor and have the settings in its own page

* reminder to restore disabling window.eval

* wip

* wip

* remove old webpack generated files

* add assets files

* more remove files and fix localurls

* wip settings, needs fixing saving prefs

* remove linting errors

* remove settings as a modal

* fix linting

* remove view from window on destroy

* restore visibility if reloaded

* debug log

* look for closed windows, remove managers from settings as it is a full window

* restore view on configuration save

* linting and debug

* remove debug message

* make eslint be aware of webpack aliases

* some extra disable lines

* move badge management to main

* remove unneded import

* fixing errors

* wip

* back to having tabs

* switch tab working

* wip

* wip

* wip

* fix quitting error

* back to a working config

* configure retries

* add darkmode

* wip

* add error/loading screens

* fix settings while removing remote usage

* wip

* fix lint, get preload to load

* remove unused import

* wip

* menus initially working as they should

* update deps, show context menu

* wip

* wip

* wip

* fix forward/back menu

* fix server menu

* allow navigating to external urls in the browser

* add defaults to menu

* fix logic

* set default options

* remove logs

* wip

* wip

* wip urlview

* wip

* urlview when hovering on a link

* change how to detect when the mouse hovers

* [BrowserView] remove remote usage, fix menus and window buttons in Win (#1418)

* reorder code to support webpack

* start backend changes

* remove simple-spellchecker

* wip

* first browserview run

* settings window routing

* wip

* back to webpack

* working build

* back to using electron-builder

* fix linting

* linting errors missed

* back to just 1 config

* missing changes

* refactor and have the settings in its own page

* reminder to restore disabling window.eval

* wip

* wip

* remove old webpack generated files

* add assets files

* more remove files and fix localurls

* wip settings, needs fixing saving prefs

* remove linting errors

* remove settings as a modal

* fix linting

* remove view from window on destroy

* restore visibility if reloaded

* debug log

* look for closed windows, remove managers from settings as it is a full window

* restore view on configuration save

* linting and debug

* remove debug message

* make eslint be aware of webpack aliases

* some extra disable lines

* move badge management to main

* remove unneded import

* fixing errors

* wip

* back to having tabs

* switch tab working

* wip

* wip

* wip

* fix quitting error

* back to a working config

* configure retries

* add darkmode

* wip

* add error/loading screens

* fix settings while removing remote usage

* wip

* fix lint, get preload to load

* remove unused import

* wip

* menus initially working as they should

* update deps, show context menu

* wip

* wip

* wip

* fix forward/back menu

* fix server menu

* allow navigating to external urls in the browser

* add defaults to menu

* fix logic

* set default options

* remove logs

* wip

* fix webpack adding images to /dist so tray can render them

* wait for config, fix menutray calls

* remove .gitattributes from being tracked

* remove unused reject

* remove logs

* Update webpack.config.renderer.js

Co-authored-by: Devin Binnie <52460000+devinbinnie@users.noreply.github.com>

* fix three dot menu

* remove most remote usage, fix window buttons in Windows

Co-authored-by: Devin Binnie <52460000+devinbinnie@users.noreply.github.com>

* fix different errors when loading config (#1420)

* [BrowserView] Native modules & registry access (#1417)

* reorder code to support webpack

* start backend changes

* remove simple-spellchecker

* wip

* first browserview run

* settings window routing

* wip

* back to webpack

* working build

* back to using electron-builder

* fix linting

* linting errors missed

* back to just 1 config

* missing changes

* refactor and have the settings in its own page

* reminder to restore disabling window.eval

* wip

* wip

* remove old webpack generated files

* add assets files

* more remove files and fix localurls

* wip settings, needs fixing saving prefs

* remove linting errors

* remove settings as a modal

* fix linting

* remove view from window on destroy

* restore visibility if reloaded

* debug log

* look for closed windows, remove managers from settings as it is a full window

* restore view on configuration save

* linting and debug

* remove debug message

* make eslint be aware of webpack aliases

* some extra disable lines

* move badge management to main

* remove unneded import

* fixing errors

* wip

* back to having tabs

* switch tab working

* wip

* wip

* wip

* fix quitting error

* back to a working config

* configure retries

* add darkmode

* wip

* add error/loading screens

* fix settings while removing remote usage

* wip

* fix lint, get preload to load

* remove unused import

* wip

* menus initially working as they should

* update deps, show context menu

* wip

* wip

* wip

* fix forward/back menu

* fix server menu

* allow navigating to external urls in the browser

* add defaults to menu

* fix logic

* set default options

* remove logs

* wip

* fix webpack adding images to /dist so tray can render them

* wait for config, fix menutray calls

* remove .gitattributes from being tracked

* restart-working native modules

* setup env variables for installing native modules

* [browserview] Electron notifications (#1411)

* reorder code to support webpack

* start backend changes

* remove simple-spellchecker

* wip

* first browserview run

* settings window routing

* wip

* back to webpack

* working build

* back to using electron-builder

* fix linting

* linting errors missed

* back to just 1 config

* missing changes

* refactor and have the settings in its own page

* reminder to restore disabling window.eval

* wip

* wip

* remove old webpack generated files

* add assets files

* more remove files and fix localurls

* wip settings, needs fixing saving prefs

* remove linting errors

* remove settings as a modal

* fix linting

* remove view from window on destroy

* restore visibility if reloaded

* debug log

* look for closed windows, remove managers from settings as it is a full window

* restore view on configuration save

* linting and debug

* remove debug message

* make eslint be aware of webpack aliases

* some extra disable lines

* move badge management to main

* remove unneded import

* fixing errors

* wip

* back to having tabs

* switch tab working

* wip

* wip

* wip

* fix quitting error

* back to a working config

* configure retries

* add darkmode

* wip

* add error/loading screens

* fix settings while removing remote usage

* wip

* fix lint, get preload to load

* remove unused import

* wip

* menus initially working as they should

* update deps, show context menu

* wip

* wip

* wip

* fix forward/back menu

* fix server menu

* allow navigating to external urls in the browser

* add defaults to menu

* fix logic

* set default options

* remove logs

* wip

* wip

* move viewmanager into windowmanager

* working notifications

* remove logs, switch tab on notification click

* download notifications

* fix tray

* fix menu switch server

* fix error

* [MM-23078] TabBar fixes for BrowserView (#1423)

* [MM-23078] TabBar fixes for BrowserView

* Removing unnecessary logging

* [Browserview] 4.6 and 4.7 PRs (#1424)

* [MM-28620] allow navigating links to admin_console #1374

* [MM-25789] - Update default settings for new installations #1376

* [MM-27332] show window at autolaunch #1379

* Update NOTICE.txt (#1385)

* Update NOTICE.txt

* Update NOTICE.txt

* Update NOTICE.txt

* convert to markdown

* md linting

* Update NOTICE.md

* Revert "Update NOTICE.md"

This reverts commit 9381fca895c0677bcad1cf1c1071ca88afd6f486.

* Revert "md linting"

This reverts commit e7a68f120109d47b9849cf816d4fef79483ad22f.

* Revert "convert to markdown"

This reverts commit 1e7ed8a67c9c98cd0d0f3ff6cdc70782effb143d.

* add missing licenses to joi and jq

* Remove devDependencies

Co-authored-by: Guillermo Vaya <guivaya@gmail.com>

* Notification sounds, also added tab name to notification title

* [MM-22013] - Allow users to specify default download locations #1383

* [MM-21835] Use URL instead of the url library #1384

* remove debug console.log statements

Co-authored-by: Amy Blais <amy_blais@hotmail.com>

* [MM-31266] fix access url when it's not a mm server (#1431)

* [MM-31224] fix reloading servers and other tab issues (#1434)

* [MM-31224] fix reloading servers and other tab issues

* reload if url changes

* Change the dev server port to 9001 to avoid conflict with mattermost-minio (#1437)

* remove dev_web_server (#1438)

* [MM-31225][MM-31217][MM-31219][Browserview] fix linux compilation + other fixes (#1433)

* fix linux errors

* remove registry, remove env_vars

* devtools in separate window, prevent config errors

* fix registry path

* move dist to root when packaging

* make devtools dettached to avoid browserview

* remove unneeded comment

* use reject in case of registry failure

* fix handling results

* fix application menu

* make linter happy

* fix missing key on apt-get (#1440) (#1442)

see https://github.com/electron-userland/electron-builder/issues/5485#issuecomment-749244332

* [MM-31221][BrowserView] first modal: adding a server while in a server view (#1400)

* reorder code to support webpack

* start backend changes

* remove simple-spellchecker

* wip

* first browserview run

* settings window routing

* wip

* back to webpack

* working build

* back to using electron-builder

* fix linting

* linting errors missed

* back to just 1 config

* missing changes

* refactor and have the settings in its own page

* reminder to restore disabling window.eval

* wip

* wip

* remove old webpack generated files

* add assets files

* more remove files and fix localurls

* wip settings, needs fixing saving prefs

* remove linting errors

* remove settings as a modal

* fix linting

* remove view from window on destroy

* restore visibility if reloaded

* debug log

* look for closed windows, remove managers from settings as it is a full window

* restore view on configuration save

* linting and debug

* remove debug message

* make eslint be aware of webpack aliases

* some extra disable lines

* move badge management to main

* remove unneded import

* fixing errors

* wip

* back to having tabs

* switch tab working

* wip

* wip

* wip

* fix quitting error

* back to a working config

* configure retries

* add darkmode

* wip

* add error/loading screens

* fix settings while removing remote usage

* wip

* fix lint, get preload to load

* remove unused import

* wip

* menus initially working as they should

* update deps, show context menu

* wip

* wip

* wip

* fix forward/back menu

* fix server menu

* allow navigating to external urls in the browser

* add defaults to menu

* fix logic

* set default options

* remove logs

* wip

* wip

* wip urlview

* wip

* urlview when hovering on a link

* wip

* wip

* first working modal

* fix config loading

* upgrade electron to 10.1.5

* esc exits modals

* first modal

* add env variables for settings and modals devtools

* adress CSS review comments

* Address review comments

* fix dist in prod

* fix preload path on build

* [MM-31987] Allow camera use for jitsi (#1443) (#1450)

* [MM-31987] allow camera use for jitsi

* update message for access

* [MM-31261] Use manual resizing of BrowserViews on resize, maximize and full-screen (#1449)

* [MM-31261] Use manual resizing of BrowserViews on resize, maximize and full-screen

* Update src/main/windows/windowManager.js

Co-authored-by: Guillermo Vayá <guivaya@gmail.com>

Co-authored-by: Guillermo Vayá <guivaya@gmail.com>

* add own branch for testing (#1448)

* add own branch for testing

* remove signing for windows

* add message to channel

* Bv pipeline elisabeth (#1452)

* Add parameter and remove schedule

* Add jq

* Fix adding jq

* Fix adding jq

* Fix adding jq

* fix quotes

* upload as JSON

* use previous, parse json

* fixes

* use json

Co-authored-by: Elisabeth Kulzer <elikul@elikul.de>

* [MM-30144][MM-30145][MM-30146][MM-30147] Migrate auth and certificate modals to BrowserView (#1445)

* WIP

* WIP

* WIP

* WIP

* WIP

* [MM-30144][MM-30145] Migrate LoginModal and PermissionModal to BrowserView

* [MM-30146][MM-30147] Migrate certificate modals to BrowserView

* Fixed transparency on the bootstrap modals

* PR feedback

* Added better error reporting in case the modal promise fails

* [MM-31233] Reverse maximize logic typo (#1454)

* [browser view] MM-32277 bump version, exe, cache errrors (#1456)

* bump version

* enable msi and remove src/package*

* ensure variable exists

* remove cleanCache script

* default expansion for env variable

* add commit version, missing package-lock.json

* remove duplicated command

* [MM-31467] Move protocol handling over from original MattermostView into web contents handler (#1453)

* WIP

* WIP

* [MM-31467] Move protocol handling over from original MattermostView into web contents handler

* Remove log statement

* [MM-32392] prevent crash when checking a URL (#1457)

* [MM-31215][MM-31387] Fixes for bad tab navigation and dragging (#1461)

* [MM-31387] Send to renderer on clicking server from settings window

* Use different event name for sending switch server info to renderer

* Have the viewManager let the renderer know when the tab has changed

* Couple more fixes around tabs

* Simplify URL compare logic

* [MM-31650] Restore focus to active server on modal and settings window closure + other fixes (#1455)

* [MM-31650] Focus active server on settings window and modal closure

* Disable tabs when a modal is open

* Revert to using original NewTeamModal component

* fix resize (#1462)

* [MM-32424] fix server devtools being hidden by browserview (#1459)

* [MM-32424] fix server devtools being hidden by browserview

* reverse logic

* [MM-20227][MM-31388] move to roles and fix focus (#1463)

* [MM-31570] update mentions/unreads/session on jewel, tray and dock (#1460)

* [MM-32333] Open public links in the user's default browser (#1468)

* [MM-32333] Open public links in the user's default browser

* Removed commented code

* [MM-31232] fix urlview present with no content (#1467)

* [MM-31343] Migrate Finder to BrowserView (#1466)

* WIP

* WIP

* WIP

* [MM-31343] Migrate Finder to BrowserView

* PR feedback

* Removing reference to this in non-class file

* use electron to handle spellchecking (#1469)

* [MM-32382] Use resize event instead of will-resize for monitoring size of BV (#1470)

* [MM-32570] Use OpenSans as the font for the URL preview modal (#1471)

* [MM-32570] Use OpenSans as the font for the URL preview modal

* Don't use bootstrap

* Fix draw badge (#1477)

* use canvas from window

* fix errors

* fix errors

* safer code injection

* [MM-31554] Add listener for config synchronization on the settings window (#1473)

* [MM-31554] Add listener for config synchronization on the settings window

* Synchronize the config if updated from outside the settings window

* [MM-28541] restore deeplinking (#1475)

* handle deeplinking

* fix app handling deeplinking

* remove outdated comment

* address review comments

* MM-32765_prevent crash on checking unread state (#1479)

* MM-31383 make no the default when asking to add a protocol (#1481)

* [MM-31340] Resize browser view and show back button when on non-team URL (#1472)

* WIP

* [MM-31340] Resize browser view and show back button when on non-team URL

* Fixed issue where switching tabs and resizing hides the back button

* Add error checking around going back in history

* [MM-31399] Use webapp ESLint config in desktop app and resolve inconsistencies (#1482)

* Import webapp eslint and update packages

* FIrst pass with new ruleset

* Allow setState

* Fix rule for tests

* Comment out skippeed tests, removed some TODOs and fixed some warnings

* Remove errors from MainPage

* Use indenting profile from webapp

* Update editorconfig for new indenting

* Fix indenting for class properties

* Only disable no-console for renderer process and scripts

* Remove rule overrides and changes

* Fix merge issues

* PR feedback and fixed a bad merge

* [MM-25122] Use modded version of winreg that supports UTF-8 (#1488)

* fix appicon path resolution (#1484)

* [MM-33141] Fixed use of bad context in TeamList (#1487)

* [MM-33141] Fixed use of bad context in TeamList

* Refactor to pull the functions out

* Remove unnecessary props

* [MM-25355] Throttle notifications for Windows by channel id (#1486)

* [MM-25355] Throttle notifications for Windows

* Use teamId as well to key the notifications

* Merge'd

* Use Map instead of Set

* [MM-33050] move webcontent events out of main (#1489)

* wip

* wip

* fix webcontent events, move views to its own folder

* [MM-33238] Check for admin URL when toggling back bar (#1495)

* [MM-31342] fix "save image as" context menu crash (#1490)

* [MM-33231] update jewel on new mentions/when read (#1493)

* [MM-33231] update state properly for a purecomponent

* remove unneeded comment

* [MM-33032] Use `hidden` titleBarStyle value to fix macOS Catalina click issue (#1496)

* [MM-32809] Remove Toggle Dark Mode menu item for Windows, enable toggling on Linux (#1494)

* [MM-32809] Remove Toggle Dark Mode menu item for Windows

* Just check for !win32 and !darwin

* Enable correct dark mode functionality on non-macOS/non-Windows machines

* [MM-33334] Restore keyboard shortcuts for menu items moved to roles (#1499)

* [MM-33434] Upgrade to Electron v11, some other dependency upgrades (#1501)

* [MM-33434] Upgrade to Electron v11, some other dependency upgrades

* Missed a version change

* context menu fix

* Forgot to remove a log statement

* Added resized for redundancy and upgraded to spectron 13

* Don't need resized

* [MM-33542] Trigger finder cleanup on pressing close or Escape (#1502)

* [MM-33542] Clear the Finder selection when closing the finder

* Remove listener on close as well

* Run close() on escape as well

* [MM-33607] Remove old badge code, update unreads code (#1503)

* [MM-33607] Remove old badge code, update unreads code

* Fix 2 random lint errors

* [MM-33247] Have the app handle links to other teams as a deep link (#1498)

* [MM-33373] Trigger the smaller font for 99+ mentions (#1507)

* [MM-32805] Merge master, migrate LoadingScreen to BrowserView (#1504)

* [MM-467] Notification sounds (#1351)

* Custom sounds

* Trying new version

* Trying new version

* Some fixes

* Rollback version change

* Allow native sound

* Increase version

* Playing custom sounds :)

* Fix var name

* Fix

* Update src/browser/js/notification.js

Co-authored-by: Guillermo Vayá <guivaya@gmail.com>

* Update src/browser/js/notification.js

Co-authored-by: Guillermo Vayá <guivaya@gmail.com>

* Update src/browser/js/notification.js

Co-authored-by: Guillermo Vayá <guivaya@gmail.com>

* Several suggestions

* Update src/browser/js/notification.js

Co-authored-by: Guillermo Vayá <guivaya@gmail.com>

* Restore of version

Co-authored-by: Guillermo Vayá <guivaya@gmail.com>

* Clean caches on depcheck failure (#1369)

Co-authored-by: Mattermod <mattermod@users.noreply.github.com>

* [MM-28595] Open team links within the app (#1373)

* [MM-25789] - Update default settings for new installations (#1376)

* [MM-25789] - Update default settings for new installations

* Update src/main.js

Co-authored-by: Guillermo Vayá <guillermo.vaya@mattermost.com>

* Update src/main.js

Co-authored-by: Guillermo Vayá <guillermo.vaya@mattermost.com>

* Fix linter

Co-authored-by: Nevyana Angelova <nevyangelova@Nevyanas-MacBook-Pro-2.local>
Co-authored-by: Mattermod <mattermod@users.noreply.github.com>
Co-authored-by: Guillermo Vayá <guillermo.vaya@mattermost.com>

* add Russian language in the list available for spellcheck (#1375)

* [MM-28620] allow navigating links to admin_console (#1374)

* [MM-28620] allow navigating links to admin_console

* Fix when there is not a server associated

* [MM-27332] show window at autolaunch (#1379)

* Bump to version 4.7.0-develop

* Update NOTICE.txt (#1385)

* Update NOTICE.txt

* Update NOTICE.txt

* Update NOTICE.txt

* convert to markdown

* md linting

* Update NOTICE.md

* Revert "Update NOTICE.md"

This reverts commit 9381fca895c0677bcad1cf1c1071ca88afd6f486.

* Revert "md linting"

This reverts commit e7a68f120109d47b9849cf816d4fef79483ad22f.

* Revert "convert to markdown"

This reverts commit 1e7ed8a67c9c98cd0d0f3ff6cdc70782effb143d.

* add missing licenses to joi and jq

* Remove devDependencies

Co-authored-by: Guillermo Vaya <guivaya@gmail.com>

* [MM-9922] Hide tooltip for internal links (channels, timestamps, etc.) (#1386)

* Hide tooltip for internal links (channels, timestamps, etc.)

* Only hide tooltip for internal links on the *current* team

* feat(spellcheck): add Ukrainian language for spellcheck (#1382)

* [MM-29677] fix download complete notification not appearing (#1388)

* fix soundname not existing (#1390)

* [MM-29921] fix custom sound not playing when receiving a notification (#1396)

* [MM-29921] fix sound notification

* remove logs

* Update release-process.md (#1394)

* [MM-22013] - Allow users to specify default download locations (#1383)

* [MM-22013] - Allow users to specify default download locations

* PR comments

* Add proper config prop

* Update src/browser/components/SettingsPage.jsx

Co-authored-by: Guillermo Vayá <guillermo.vaya@mattermost.com>

* Remove string ref

* Fix styling

* Update styling

* Disable input

* Add variable for windows

* Prevent dialog from opening twice

Co-authored-by: Nevyana Angelova <nevyangelova@Nevyanas-MBP-2.fritz.box>
Co-authored-by: Nevyana Angelova <nevyangelova@Nevyanas-MacBook-Pro-2.local>
Co-authored-by: Guillermo Vayá <guillermo.vaya@mattermost.com>
Co-authored-by: Mattermod <mattermod@users.noreply.github.com>

* [MM-21835] Use URL instead of the url library (#1384)

Additionally, migrate all of the URL related helper functions
from `src/utils/utils.js` to the new `src/utils/url.js` file
and migrate tests.

Issue MM-21835
Fixes #1206

* Merge Powershell files together and remove AppVeyor related code

* Ensure nodejs deps are met before running script argument directly

* [MM-22810] Update loading screen with new design & animation (#1409)

* Update loading screen with new design & animation

* add prop back in

* adjust z-index for tests

* tweaks to pass tests

* address offline feedback

- shrink initial logo size
- introduce a slight delay before fading loading spinner out
- fix horizontal scrollbar showing on load screen

* add missing css variable

* no need to remove loading icon

* Apply suggestions from code review

Co-authored-by: Guillermo Vayá <guillermo.vaya@mattermost.com>

* Move LoadingScreen.jsx to file-only component

* Rename prop for better clarity

* Default prop to none and check when needed

* Update import paths

* Add ESDocs and remove unecessary conditional

* Forgot to remove the eslint override

Co-authored-by: Guillermo Vayá <guillermo.vaya@mattermost.com>

* [MM-22960] - Keep desktop app pinned to taskb bar when the app upgrades (#1397)

Co-authored-by: Nevyana Angelova <nevyangelova@Nevyanas-MacBook-Pro-2.local>

* Bump highlight.js from 9.18.1 to 9.18.5 (#1421)

Bumps [highlight.js](https://github.com/highlightjs/highlight.js) from 9.18.1 to 9.18.5.
- [Release notes](https://github.com/highlightjs/highlight.js/releases)
- [Changelog](https://github.com/highlightjs/highlight.js/blob/9.18.5/CHANGES.md)
- [Commits](https://github.com/highlightjs/highlight.js/compare/9.18.1...9.18.5)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump ini from 1.3.5 to 1.3.7 (#1427)

Bumps [ini](https://github.com/isaacs/ini) from 1.3.5 to 1.3.7.
- [Release notes](https://github.com/isaacs/ini/releases)
- [Commits](https://github.com/isaacs/ini/compare/v1.3.5...v1.3.7)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* fix missing key on apt-get (#1440)

see https://github.com/electron-userland/electron-builder/issues/5485#issuecomment-749244332

* [MM-31987] Allow camera use for jitsi (#1443)

* [MM-31987] allow camera use for jitsi

* update message for access

* Created codeql analysis (#1441)

Co-authored-by: Mattermod <mattermod@users.noreply.github.com>

* [MM-31626] bypass gitlab browser-check for oauth login (#1439)

* MM-31626 make User Agent configurable by user

* add info

* remove chrome from UA for gitlab.com

* remove previous solution

Co-authored-by: Mattermod <mattermod@users.noreply.github.com>

* Add Swedish sv-SE (already in simple-spellchecker) (#1483)

* Add Swedish sv-SE (already in simple-spellchecker)

* Remove spaces in empty lines

* Add some sv-SE test for spellchecker

Co-authored-by: Peter Johansson <peter.johansson@havochvatten.se>

* Add loading screen, fix reload

* WIP

* Migrate LoadingScreen to BrowserView

* Lint fixes

* Removed gitlab fix code, also returning null is bad apparently

* Fix reload logic

Co-authored-by: Rodrigo Villablanca <villa061004@gmail.com>
Co-authored-by: Guillermo Vayá <guivaya@gmail.com>
Co-authored-by: Juho Nurminen <juho.nurminen@mattermost.com>
Co-authored-by: Mattermod <mattermod@users.noreply.github.com>
Co-authored-by: Guillermo Vayá <guillermo.vaya@mattermost.com>
Co-authored-by: Nev Angelova <nevy.angelova@gmail.com>
Co-authored-by: Nevyana Angelova <nevyangelova@Nevyanas-MacBook-Pro-2.local>
Co-authored-by: Eugeny Fomin <github.com@jeka.ru>
Co-authored-by: Amy Blais <amy_blais@hotmail.com>
Co-authored-by: Nathan Bolender <nathan@nathanbolender.com>
Co-authored-by: Dmitriy Danilov <daniloff200@gmail.com>
Co-authored-by: Nevyana Angelova <nevyangelova@Nevyanas-MBP-2.fritz.box>
Co-authored-by: FalseHonesty <skipboman0@gmail.com>
Co-authored-by: William Gathoye <william@gathoye.be>
Co-authored-by: Dean Whillier <deanwhillier@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Rohitesh Gupta <srkg.gupta@gmail.com>
Co-authored-by: petermcj <petermcj@gmail.com>
Co-authored-by: Peter Johansson <peter.johansson@havochvatten.se>

* [MM-33668] Restore tests to browser-view branch (#1506)

* happy eslint

* wip

* wip

* remove aliases

* almost working tests

* green tests

* Revert "remove aliases"

This reverts commit 803d3695538197407b45e0d8d30dc429b259b7f3.

* add unit test, reconfigure package scripts, make test pass

* [MM-33542] Trigger finder cleanup on pressing close or Escape (#1502)

* [MM-33542] Clear the Finder selection when closing the finder

* Remove listener on close as well

* Run close() on escape as well

* [MM-33607] Remove old badge code, update unreads code (#1503)

* [MM-33607] Remove old badge code, update unreads code

* Fix 2 random lint errors

* fix script naming in circle

* fix check deps

* attempt to fix dependency-check download

* remove check-deps step

Co-authored-by: = <=>
Co-authored-by: Devin Binnie <52460000+devinbinnie@users.noreply.github.com>

* Cleanup of BrowserView migration, some bug fixes (#1509)

* 1st round of cleanup

* 2nd round of cleanup

* Set constant for reload-config

* Cleaned up some TODOs

* store daily build to S3 (#1508)

* store daily build to S3

* missing colon

* fix paths

* try to keep folders

* remove unneeded step

* change from arn to bucket name

* keep organization consistent

* fix indentation

* fix indentation x2

Co-authored-by: = <=>

* MM-33551 keep tray state between themes (#1511)

Co-authored-by: = <=>

* Set to version v4.7

Co-authored-by: Guillermo Vayá <guillermo.vaya@mattermost.com>
Co-authored-by: Amy Blais <amy_blais@hotmail.com>
Co-authored-by: Guillermo Vayá <guivaya@gmail.com>
Co-authored-by: Elisabeth Kulzer <elikul@elikul.de>
Co-authored-by: Rodrigo Villablanca <villa061004@gmail.com>
Co-authored-by: Juho Nurminen <juho.nurminen@mattermost.com>
Co-authored-by: Mattermod <mattermod@users.noreply.github.com>
Co-authored-by: Nev Angelova <nevy.angelova@gmail.com>
Co-authored-by: Nevyana Angelova <nevyangelova@Nevyanas-MacBook-Pro-2.local>
Co-authored-by: Eugeny Fomin <github.com@jeka.ru>
Co-authored-by: Nathan Bolender <nathan@nathanbolender.com>
Co-authored-by: Dmitriy Danilov <daniloff200@gmail.com>
Co-authored-by: Nevyana Angelova <nevyangelova@Nevyanas-MBP-2.fritz.box>
Co-authored-by: FalseHonesty <skipboman0@gmail.com>
Co-authored-by: William Gathoye <william@gathoye.be>
Co-authored-by: Dean Whillier <deanwhillier@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Rohitesh Gupta <srkg.gupta@gmail.com>
Co-authored-by: petermcj <petermcj@gmail.com>
Co-authored-by: Peter Johansson <peter.johansson@havochvatten.se>
This commit is contained in:
Devin Binnie
2021-03-18 10:51:53 -04:00
committed by GitHub
parent 9551d6628c
commit e76e0dc0a1
209 changed files with 17905 additions and 13921 deletions

View File

@@ -3,135 +3,144 @@
// See LICENSE.txt for license information.
import {EventEmitter} from 'events';
import WindowsRegistry from 'winreg';
import log from 'electron-log';
import WindowsRegistry from 'winreg-utf8';
const REGISTRY_HIVE_LIST = [WindowsRegistry.HKLM, WindowsRegistry.HKCU];
const BASE_REGISTRY_KEY_PATH = '\\Software\\Policies\\Mattermost';
export const REGISTRY_READ_EVENT = 'registry-read';
/**
* Handles loading config data from the Windows registry set manually or by GPO
*/
export default class RegistryConfig extends EventEmitter {
constructor() {
super();
this.initialized = false;
this.data = {
teams: [],
};
}
constructor() {
super();
this.initialized = false;
this.data = {
teams: [],
};
}
/**
/**
* Triggers loading data from Windows registry, supports async/await
*
* @emits {update} emitted once all data has been loaded from the registry
*/
async init() {
if (process.platform === 'win32') {
// extract DefaultServerList from the registry
try {
const servers = await this.getServersListFromRegistry();
if (servers.length) {
this.data.teams.push(...servers);
}
} catch (error) {
console.log('[RegistryConfig] Nothing retrieved for \'DefaultServerList\'', error);
}
async init() {
if (process.platform === 'win32') {
// extract DefaultServerList from the registry
try {
const servers = await this.getServersListFromRegistry();
if (servers.length) {
this.data.teams.push(...servers);
}
} catch (error) {
log.warn('[RegistryConfig] Nothing retrieved for \'DefaultServerList\'', error);
}
// extract EnableServerManagement from the registry
try {
const enableServerManagement = await this.getEnableServerManagementFromRegistry();
if (enableServerManagement !== null) {
this.data.enableServerManagement = enableServerManagement;
}
} catch (error) {
console.log('[RegistryConfig] Nothing retrieved for \'EnableServerManagement\'', error);
}
// extract EnableServerManagement from the registry
try {
const enableServerManagement = await this.getEnableServerManagementFromRegistry();
if (enableServerManagement !== null) {
this.data.enableServerManagement = enableServerManagement;
}
} catch (error) {
log.warn('[RegistryConfig] Nothing retrieved for \'EnableServerManagement\'', error);
}
// extract EnableAutoUpdater from the registry
try {
const enableAutoUpdater = await this.getEnableAutoUpdatorFromRegistry();
if (enableAutoUpdater !== null) {
this.data.enableAutoUpdater = enableAutoUpdater;
// extract EnableAutoUpdater from the registry
try {
const enableAutoUpdater = await this.getEnableAutoUpdatorFromRegistry();
if (enableAutoUpdater !== null) {
this.data.enableAutoUpdater = enableAutoUpdater;
}
} catch (error) {
log.warn('[RegistryConfig] Nothing retrieved for \'EnableAutoUpdater\'', error);
}
}
} catch (error) {
console.log('[RegistryConfig] Nothing retrieved for \'EnableAutoUpdater\'', error);
}
// this will happen wether we are on windows and load the info or not
this.initialized = true;
this.emit(REGISTRY_READ_EVENT, this.data);
}
this.initialized = true;
this.emit('update', this.data);
}
/**
/**
* Extracts a list of servers
*/
async getServersListFromRegistry() {
const defaultTeams = await this.getRegistryEntry(`${BASE_REGISTRY_KEY_PATH}\\DefaultServerList`);
return defaultTeams.flat(2).reduce((teams, team) => {
if (team) {
teams.push({
name: team.name,
url: team.value,
order: team.order,
});
}
return teams;
}, []);
}
async getServersListFromRegistry() {
const defaultServers = await this.getRegistryEntry(`${BASE_REGISTRY_KEY_PATH}\\DefaultServerList`);
return defaultServers.flat(2).reduce((servers, server, index) => {
if (server) {
servers.push({
name: server.name,
url: server.value,
order: server.order || index,
});
}
return servers;
}, []);
}
/**
/**
* Determines whether server management has been enabled, disabled or isn't configured
*/
async getEnableServerManagementFromRegistry() {
const entries = (await this.getRegistryEntry(BASE_REGISTRY_KEY_PATH, 'EnableServerManagement'));
const entry = entries.pop();
return entry ? entry === '0x1' : null;
}
async getEnableServerManagementFromRegistry() {
const entries = (await this.getRegistryEntry(BASE_REGISTRY_KEY_PATH, 'EnableServerManagement'));
const entry = entries.pop();
return entry ? entry === '0x1' : null;
}
/**
/**
* Determines whether the auto updated has been enabled, disabled or isn't configured
*/
async getEnableAutoUpdatorFromRegistry() {
const entries = (await this.getRegistryEntry(BASE_REGISTRY_KEY_PATH, 'EnableAutoUpdater'));
const entry = entries.pop();
return entry ? entry === '0x1' : null;
}
async getEnableAutoUpdatorFromRegistry() {
const entries = (await this.getRegistryEntry(BASE_REGISTRY_KEY_PATH, 'EnableAutoUpdater'));
const entry = entries.pop();
return entry ? entry === '0x1' : null;
}
/**
/**
* Initiates retrieval of a specific key in the Windows registry
*
* @param {string} key Path to the registry key to return
* @param {string} name Name of specific entry in the registry key to retrieve (optional)
*/
async getRegistryEntry(key, name) {
const results = [];
for (const hive of REGISTRY_HIVE_LIST) {
results.push(this.getRegistryEntryValues(new WindowsRegistry({hive, key}), name));
async getRegistryEntry(key, name) {
const results = [];
for (const hive of REGISTRY_HIVE_LIST) {
results.push(this.getRegistryEntryValues(hive, key, name));
}
const entryValues = await Promise.all(results);
return entryValues.filter((value) => value);
}
const entryValues = await Promise.all(results);
return entryValues.filter((value) => value);
}
/**
/**
* Handles actual retrieval of entries from a configured WindowsRegistry instance
*
* @param {WindowsRegistry} regKey A configured instance of the WindowsRegistry class
* @param {string} name Name of the specific entry to retrieve (optional)
*/
getRegistryEntryValues(regKey, name) {
return new Promise((resolve) => {
regKey.values((error, items) => {
if (error || !items || !items.length) {
resolve();
return;
}
if (name) { // looking for a single entry value
const registryItem = items.find((item) => item.name === name);
resolve(registryItem && registryItem.value ? registryItem.value : null);
} else { // looking for an entry list
resolve(items);
}
});
});
}
getRegistryEntryValues(hive, key, name) {
const registry = new WindowsRegistry({hive, key, utf8: true});
return new Promise((resolve, reject) => {
try {
registry.values((error, results) => {
if (error || !results || results.length === 0) {
resolve();
return;
}
if (name) { // looking for a single entry value
const registryItem = results.find((item) => item.name === name);
resolve(registryItem && registryItem.value ? registryItem.value : null);
} else { // looking for an entry list
resolve(results);
}
});
} catch (e) {
log.error(`There was an error accessing the registry for ${key}`);
reject(e);
}
});
}
}

View File

@@ -18,16 +18,16 @@
* @prop {[]} managedResources - Defines which paths are managed
*/
const buildConfig = {
defaultTeams: [/*
defaultTeams: [/*
{
name: 'example',
url: 'https://example.com'
}
*/],
helpLink: 'https://about.mattermost.com/default-desktop-app-documentation/',
enableServerManagement: true,
enableAutoUpdater: true,
managedResources: ['trusted'],
helpLink: 'https://about.mattermost.com/default-desktop-app-documentation/',
enableServerManagement: true,
enableAutoUpdater: true,
managedResources: ['trusted'],
};
export default buildConfig;

View File

@@ -7,23 +7,23 @@
* @param {number} version - Scheme version. (Not application version)
*/
const defaultPreferences = {
version: 2,
teams: [],
showTrayIcon: true,
trayIconTheme: 'light',
minimizeToTray: true,
notifications: {
flashWindow: 2,
bounceIcon: true,
bounceIconType: 'informational',
},
showUnreadBadge: true,
useSpellChecker: true,
enableHardwareAcceleration: true,
autostart: true,
spellCheckerLocale: 'en-US',
darkMode: false,
downloadLocation: `/Users/${process.env.USER || process.env.USERNAME}/Downloads`
version: 2,
teams: [],
showTrayIcon: true,
trayIconTheme: 'light',
minimizeToTray: true,
notifications: {
flashWindow: 2,
bounceIcon: true,
bounceIconType: 'informational',
},
showUnreadBadge: true,
useSpellChecker: true,
enableHardwareAcceleration: true,
autostart: true,
spellCheckerLocale: 'en-US',
darkMode: false,
downloadLocation: `/Users/${process.env.USER || process.env.USERNAME}/Downloads`,
};
export default defaultPreferences;

View File

@@ -1,397 +1,469 @@
// Copyright (c) 2015-2016 Yuya Ochiai
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import fs from 'fs';
import path from 'path';
import {EventEmitter} from 'events';
import {ipcMain, nativeTheme, app} from 'electron';
import log from 'electron-log';
import * as Validator from '../../main/Validator';
import {UPDATE_TEAMS, GET_CONFIGURATION, UPDATE_CONFIGURATION, GET_LOCAL_CONFIGURATION} from 'common/communication';
import defaultPreferences from './defaultPreferences';
import upgradeConfigData from './upgradePreferences';
import buildConfig from './buildConfig';
import RegistryConfig, {REGISTRY_READ_EVENT} from './RegistryConfig';
/**
* Handles loading and merging all sources of configuration as well as saving user provided config
*/
export default class Config extends EventEmitter {
constructor(configFilePath, registryConfigData = {teams: []}) {
super();
this.configFilePath = configFilePath;
this.registryConfigData = registryConfigData;
this.reload();
}
/**
* Reload all sources of config data
*
* @param {boolean} synchronize determines whether or not to emit a synchronize event once config has been reloaded
* @emits {update} emitted once all data has been loaded and merged
* @emits {synchronize} emitted when requested by a call to method; used to notify other config instances of changes
*/
reload(synchronize = false) {
this.defaultConfigData = this.loadDefaultConfigData();
this.buildConfigData = this.loadBuildConfigData();
this.localConfigData = this.loadLocalConfigFile();
this.localConfigData = this.checkForConfigUpdates(this.localConfigData);
this.regenerateCombinedConfigData();
this.emit('update', this.combinedData);
if (synchronize) {
this.emit('synchronize');
constructor(configFilePath) {
super();
this.configFilePath = configFilePath;
}
}
/**
* Used to save a single config property
*
* @param {string} key name of config property to be saved
* @param {*} data value to save for provided key
*/
set(key, data) {
if (key) {
this.localConfigData[key] = data;
this.regenerateCombinedConfigData();
this.saveLocalConfigData();
// separating constructor from init so main can setup event listeners
init = () => {
this.registryConfig = new RegistryConfig();
this.registryConfig.once(REGISTRY_READ_EVENT, this.loadRegistry);
this.registryConfig.init();
}
}
/**
* Used to save an array of config properties in one go
*
* @param {array} properties an array of config properties to save
*/
setMultiple(properties = []) {
if (properties.length) {
properties.forEach(({key, data}) => {
if (key) {
this.localConfigData[key] = data;
/**
* Gets the teams from registry into the config object and reload
*
* @param {object} registryData Team configuration from the registry and if teams can be managed by user
*/
loadRegistry = (registryData) => {
this.registryConfigData = registryData;
this.reload();
ipcMain.handle(GET_CONFIGURATION, this.handleGetConfiguration);
ipcMain.handle(GET_LOCAL_CONFIGURATION, this.handleGetLocalConfiguration);
ipcMain.handle(UPDATE_TEAMS, this.handleUpdateTeams);
ipcMain.on(UPDATE_CONFIGURATION, this.setMultiple);
if (process.platform === 'darwin' || process.platform === 'win32') {
nativeTheme.on('updated', this.handleUpdateTheme);
}
});
this.regenerateCombinedConfigData();
this.saveLocalConfigData();
}
}
setRegistryConfigData(registryConfigData = {teams: []}) {
this.registryConfigData = Object.assign({}, registryConfigData);
this.reload();
}
/**
* Reload all sources of config data
*
* @param {boolean} synchronize determines whether or not to emit a synchronize event once config has been reloaded
* @emits {update} emitted once all data has been loaded and merged
* @emits {synchronize} emitted when requested by a call to method; used to notify other config instances of changes
*/
reload = () => {
this.defaultConfigData = this.loadDefaultConfigData();
this.buildConfigData = this.loadBuildConfigData();
this.localConfigData = this.loadLocalConfigFile();
this.localConfigData = this.checkForConfigUpdates(this.localConfigData);
this.regenerateCombinedConfigData();
/**
* Used to replace the existing config data with new config data
*
* @param {object} configData a new, config data object to completely replace the existing config data
*/
replace(configData) {
const newConfigData = configData;
this.localConfigData = Object.assign({}, this.localConfigData, newConfigData);
this.regenerateCombinedConfigData();
this.saveLocalConfigData();
}
/**
* Used to save the current set of local config data to disk
*
* @emits {update} emitted once all data has been saved
* @emits {synchronize} emitted once all data has been saved; used to notify other config instances of changes
* @emits {error} emitted if saving local config data to file fails
*/
saveLocalConfigData() {
try {
this.writeFile(this.configFilePath, this.localConfigData, (error) => {
if (error) {
throw new Error(error);
}
this.emit('update', this.combinedData);
this.emit('synchronize');
});
} catch (error) {
this.emit('error', error);
}
}
// getters for accessing the various config data inputs
get data() {
return this.combinedData;
}
get localData() {
return this.localConfigData;
}
get defaultData() {
return this.defaultConfigData;
}
get buildData() {
return this.buildConfigData;
}
get registryData() {
return this.registryConfigData;
}
// convenience getters
get version() {
return this.combinedData.version;
}
get teams() {
return this.combinedData.teams;
}
get darkMode() {
return this.combinedData.darkMode;
}
get localTeams() {
return this.localConfigData.teams;
}
get predefinedTeams() {
return [...this.buildConfigData.defaultTeams, ...this.registryConfigData.teams];
}
get enableHardwareAcceleration() {
return this.combinedData.enableHardwareAcceleration;
}
get enableServerManagement() {
return this.combinedData.enableServerManagement;
}
get enableAutoUpdater() {
return this.combinedData.enableAutoUpdater;
}
get autostart() {
return this.combinedData.autostart;
}
get notifications() {
return this.combinedData.notifications;
}
get showUnreadBadge() {
return this.combinedData.showUnreadBadge;
}
get useSpellChecker() {
return this.combinedData.useSpellChecker;
}
get spellCheckerLocale() {
return this.combinedData.spellCheckerLocale;
}
get showTrayIcon() {
return this.combinedData.showTrayIcon;
}
get trayIconTheme() {
return this.combinedData.trayIconTheme;
}
get helpLink() {
return this.combinedData.helpLink;
}
// initialization/processing methods
/**
* Returns a copy of the app's default config data
*/
loadDefaultConfigData() {
return this.copy(defaultPreferences);
}
/**
* Returns a copy of the app's build config data
*/
loadBuildConfigData() {
return this.copy(buildConfig);
}
/**
* Loads and returns locally stored config data from the filesystem or returns app defaults if no file is found
*/
loadLocalConfigFile() {
let configData = {};
try {
configData = this.readFileSync(this.configFilePath);
// validate based on config file version
if (configData.version > 1) {
configData = Validator.validateV2ConfigData(configData);
} else {
switch (configData.version) {
case 1:
configData = Validator.validateV1ConfigData(configData);
break;
default:
configData = Validator.validateV0ConfigData(configData);
/**
* Used to save a single config property
*
* @param {string} key name of config property to be saved
* @param {*} data value to save for provided key
*/
set = (key, data) => {
if (key) {
this.localConfigData[key] = data;
this.regenerateCombinedConfigData();
this.saveLocalConfigData();
}
}
if (!configData) {
throw new Error('Provided configuration file does not validate, using defaults instead.');
}
} catch (e) {
console.log('Failed to load configuration file from the filesystem. Using defaults.');
configData = this.copy(this.defaultConfigData);
// add default team to teams if one exists and there arent currently any teams
if (!configData.teams.length && this.defaultConfigData.defaultTeam) {
configData.teams.push(this.defaultConfigData.defaultTeam);
}
delete configData.defaultTeam;
this.writeFileSync(this.configFilePath, configData);
}
return configData;
}
/**
* Determines if locally stored data needs to be updated and upgrades as needed
*
* @param {*} data locally stored data
*/
checkForConfigUpdates(data) {
let configData = data;
try {
if (configData.version !== this.defaultConfigData.version) {
configData = upgradeConfigData(configData);
this.writeFileSync(this.configFilePath, configData);
console.log(`Configuration updated to version ${this.defaultConfigData.version} successfully.`);
}
} catch (error) {
console.log(`Failed to update configuration to version ${this.defaultConfigData.version}.`);
}
return configData;
}
/**
* Properly combines all sources of data into a single, manageable set of all config data
*/
regenerateCombinedConfigData() {
// combine all config data in the correct order
this.combinedData = Object.assign({}, this.defaultConfigData, this.localConfigData, this.buildConfigData, this.registryConfigData);
// remove unecessary data pulled from default and build config
delete this.combinedData.defaultTeam;
delete this.combinedData.defaultTeams;
// IMPORTANT: properly combine teams from all sources
let combinedTeams = [];
// - start by adding default teams from buildConfig, if any
if (this.buildConfigData.defaultTeams && this.buildConfigData.defaultTeams.length) {
combinedTeams.push(...this.buildConfigData.defaultTeams);
}
// - add registry defined teams, if any
if (this.registryConfigData.teams && this.registryConfigData.teams.length) {
combinedTeams.push(...this.registryConfigData.teams);
/**
* Used to save an array of config properties in one go
*
* @param {array} properties an array of config properties to save
*/
setMultiple = (event, properties = []) => {
if (properties.length) {
properties.forEach(({key, data}) => {
if (key) {
this.localConfigData[key] = data;
}
});
this.regenerateCombinedConfigData();
this.saveLocalConfigData();
}
return this.localConfigData; //this is the only part that changes
}
// - add locally defined teams only if server management is enabled
if (this.enableServerManagement) {
combinedTeams.push(...this.localConfigData.teams);
setRegistryConfigData = (registryConfigData = {teams: []}) => {
this.registryConfigData = Object.assign({}, registryConfigData);
this.reload();
}
combinedTeams = this.filterOutDuplicateTeams(combinedTeams);
combinedTeams = this.sortUnorderedTeams(combinedTeams);
/**
* Used to replace the existing config data with new config data
*
* @param {object} configData a new, config data object to completely replace the existing config data
*/
replace = (configData) => {
const newConfigData = configData;
this.combinedData.teams = combinedTeams;
this.combinedData.localTeams = this.localConfigData.teams;
this.combinedData.buildTeams = this.buildConfigData.defaultTeams;
this.combinedData.registryTeams = this.registryConfigData.teams;
}
this.localConfigData = Object.assign({}, this.localConfigData, newConfigData);
/**
* Returns the provided list of teams with duplicates filtered out
*
* @param {array} teams array of teams to check for duplicates
*/
filterOutDuplicateTeams(teams) {
let newTeams = teams;
const uniqueURLs = new Set();
newTeams = newTeams.filter((team) => {
return uniqueURLs.has(team.url) ? false : uniqueURLs.add(team.url);
});
return newTeams;
}
/**
* Returns the provided array fo teams with existing teams filtered out
* @param {array} teams array of teams to check for already defined teams
*/
filterOutPredefinedTeams(teams) {
let newTeams = teams;
// filter out predefined teams
newTeams = newTeams.filter((newTeam) => {
return this.predefinedTeams.findIndex((existingTeam) => newTeam.url === existingTeam.url) === -1; // eslint-disable-line max-nested-callbacks
});
return newTeams;
}
/**
* Apply a default sort order to the team list, if no order is specified.
* @param {array} teams to sort
*/
sortUnorderedTeams(teams) {
// We want to preserve the array order of teams in the config, otherwise a lot of bugs will occur
const mappedTeams = teams.map((team, index) => ({team, originalOrder: index}));
// Make a best pass at interpreting sort order. If an order is not specified, assume it is 0.
//
const newTeams = mappedTeams.sort((x, y) => {
if (x.team.order == null) {
x.team.order = 0;
}
if (y.team.order == null) {
y.team.order = 0;
}
// once we ensured `order` exists, we can sort numerically
return x.team.order - y.team.order;
});
// Now re-number all items from 0 to (max), ensuring user's sort order is preserved. The
// new tabbed interface requires an item with order:0 in order to raise the first tab.
//
newTeams.forEach((mappedTeam, i) => {
mappedTeam.team.order = i;
});
return newTeams.sort((x, y) => x.originalOrder - y.originalOrder).map((mappedTeam) => mappedTeam.team);
}
// helper functions
readFileSync(filePath) {
return JSON.parse(fs.readFileSync(filePath, 'utf8'));
}
writeFile(filePath, configData, callback) {
if (configData.version !== this.defaultConfigData.version) {
throw new Error('version ' + configData.version + ' is not equal to ' + this.defaultConfigData.version);
}
const json = JSON.stringify(configData, null, ' ');
fs.writeFile(filePath, json, 'utf8', callback);
}
writeFileSync(filePath, config) {
if (config.version !== this.defaultConfigData.version) {
throw new Error('version ' + config.version + ' is not equal to ' + this.defaultConfigData.version);
this.regenerateCombinedConfigData();
this.saveLocalConfigData();
}
const dir = path.dirname(filePath);
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir);
/**
* Used to save the current set of local config data to disk
*
* @emits {update} emitted once all data has been saved
* @emits {synchronize} emitted once all data has been saved; used to notify other config instances of changes
* @emits {error} emitted if saving local config data to file fails
*/
saveLocalConfigData = () => {
try {
this.writeFile(this.configFilePath, this.localConfigData, (error) => {
if (error) {
throw new Error(error);
}
this.emit('update', this.combinedData);
this.emit('synchronize');
});
} catch (error) {
this.emit('error', error);
}
}
const json = JSON.stringify(config, null, ' ');
fs.writeFileSync(filePath, json, 'utf8');
}
// getters for accessing the various config data inputs
merge(base, target) {
return Object.assign({}, base, target);
}
get data() {
return this.combinedData;
}
get localData() {
return this.localConfigData;
}
get defaultData() {
return this.defaultConfigData;
}
get buildData() {
return this.buildConfigData;
}
get registryData() {
return this.registryConfigData;
}
copy(data) {
return Object.assign({}, data);
}
// convenience getters
get version() {
return this.combinedData.version;
}
get teams() {
return this.combinedData.teams;
}
get darkMode() {
return this.combinedData.darkMode;
}
get localTeams() {
return this.localConfigData.teams;
}
get predefinedTeams() {
return [...this.buildConfigData.defaultTeams, ...this.registryConfigData.teams];
}
get enableHardwareAcceleration() {
return this.combinedData.enableHardwareAcceleration;
}
get enableServerManagement() {
return this.combinedData.enableServerManagement;
}
get enableAutoUpdater() {
return this.combinedData.enableAutoUpdater;
}
get autostart() {
return this.combinedData.autostart;
}
get notifications() {
return this.combinedData.notifications;
}
get showUnreadBadge() {
return this.combinedData.showUnreadBadge;
}
get useSpellChecker() {
return this.combinedData.useSpellChecker;
}
get spellCheckerLocale() {
return this.combinedData.spellCheckerLocale;
}
get showTrayIcon() {
return this.combinedData.showTrayIcon;
}
get trayIconTheme() {
return this.combinedData.trayIconTheme;
}
get helpLink() {
return this.combinedData.helpLink;
}
// initialization/processing methods
/**
* Returns a copy of the app's default config data
*/
loadDefaultConfigData = () => {
return this.copy(defaultPreferences);
}
/**
* Returns a copy of the app's build config data
*/
loadBuildConfigData = () => {
return this.copy(buildConfig);
}
/**
* Loads and returns locally stored config data from the filesystem or returns app defaults if no file is found
*/
loadLocalConfigFile = () => {
let configData = {};
try {
configData = this.readFileSync(this.configFilePath);
// validate based on config file version
if (configData.version > 1) {
configData = Validator.validateV2ConfigData(configData);
} else {
switch (configData.version) {
case 1:
configData = Validator.validateV1ConfigData(configData);
break;
default:
configData = Validator.validateV0ConfigData(configData);
}
}
if (!configData) {
throw new Error('Provided configuration file does not validate, using defaults instead.');
}
} catch (e) {
log.warn('Failed to load configuration file from the filesystem. Using defaults.');
configData = this.copy(this.defaultConfigData);
// add default team to teams if one exists and there arent currently any teams
if (!configData.teams.length && this.defaultConfigData.defaultTeam) {
configData.teams.push(this.defaultConfigData.defaultTeam);
}
delete configData.defaultTeam;
this.writeFileSync(this.configFilePath, configData);
}
return configData;
}
/**
* Determines if locally stored data needs to be updated and upgrades as needed
*
* @param {*} data locally stored data
*/
checkForConfigUpdates = (data) => {
let configData = data;
try {
if (configData.version !== this.defaultConfigData.version) {
configData = upgradeConfigData(configData);
this.writeFileSync(this.configFilePath, configData);
log.info(`Configuration updated to version ${this.defaultConfigData.version} successfully.`);
}
} catch (error) {
log.error(`Failed to update configuration to version ${this.defaultConfigData.version}.`);
}
return configData;
}
/**
* Properly combines all sources of data into a single, manageable set of all config data
*/
regenerateCombinedConfigData = () => {
// combine all config data in the correct order
this.combinedData = Object.assign({}, this.defaultConfigData, this.localConfigData, this.buildConfigData, this.registryConfigData);
// remove unecessary data pulled from default and build config
delete this.combinedData.defaultTeam;
delete this.combinedData.defaultTeams;
// IMPORTANT: properly combine teams from all sources
let combinedTeams = [];
// - start by adding default teams from buildConfig, if any
if (this.buildConfigData.defaultTeams && this.buildConfigData.defaultTeams.length) {
combinedTeams.push(...this.buildConfigData.defaultTeams);
}
// - add registry defined teams, if any
if (this.registryConfigData.teams && this.registryConfigData.teams.length) {
combinedTeams.push(...this.registryConfigData.teams);
}
// - add locally defined teams only if server management is enabled
if (this.enableServerManagement) {
combinedTeams.push(...this.localConfigData.teams);
}
combinedTeams = this.filterOutDuplicateTeams(combinedTeams);
combinedTeams = this.sortUnorderedTeams(combinedTeams);
this.combinedData.teams = combinedTeams;
this.combinedData.localTeams = this.localConfigData.teams;
this.combinedData.buildTeams = this.buildConfigData.defaultTeams;
this.combinedData.registryTeams = this.registryConfigData.teams;
if (process.platform === 'darwin' || process.platform === 'win32') {
this.combinedData.darkMode = nativeTheme.shouldUseDarkColors;
}
this.combinedData.appName = app.name;
}
/**
* Returns the provided list of teams with duplicates filtered out
*
* @param {array} teams array of teams to check for duplicates
*/
filterOutDuplicateTeams = (teams) => {
let newTeams = teams;
const uniqueURLs = new Set();
newTeams = newTeams.filter((team) => {
return uniqueURLs.has(team.url) ? false : uniqueURLs.add(team.url);
});
return newTeams;
}
/**
* Returns the provided array fo teams with existing teams filtered out
* @param {array} teams array of teams to check for already defined teams
*/
filterOutPredefinedTeams = (teams) => {
let newTeams = teams;
// filter out predefined teams
newTeams = newTeams.filter((newTeam) => {
return this.predefinedTeams.findIndex((existingTeam) => newTeam.url === existingTeam.url) === -1; // eslint-disable-line max-nested-callbacks
});
return newTeams;
}
/**
* Apply a default sort order to the team list, if no order is specified.
* @param {array} teams to sort
*/
sortUnorderedTeams = (teams) => {
// We want to preserve the array order of teams in the config, otherwise a lot of bugs will occur
const mappedTeams = teams.map((team, index) => ({team, originalOrder: index}));
// Make a best pass at interpreting sort order. If an order is not specified, assume it is 0.
//
const newTeams = mappedTeams.sort((x, y) => {
if (x.team.order == null) {
x.team.order = 0;
}
if (y.team.order == null) {
y.team.order = 0;
}
// once we ensured `order` exists, we can sort numerically
return x.team.order - y.team.order;
});
// Now re-number all items from 0 to (max), ensuring user's sort order is preserved. The
// new tabbed interface requires an item with order:0 in order to raise the first tab.
//
newTeams.forEach((mappedTeam, i) => {
mappedTeam.team.order = i;
});
return newTeams.sort((x, y) => x.originalOrder - y.originalOrder).map((mappedTeam) => mappedTeam.team);
}
// helper functions
readFileSync = (filePath) => {
return JSON.parse(fs.readFileSync(filePath, 'utf8'));
}
writeFile = (filePath, configData, callback) => {
if (configData.version !== this.defaultConfigData.version) {
throw new Error('version ' + configData.version + ' is not equal to ' + this.defaultConfigData.version);
}
const json = JSON.stringify(configData, null, ' ');
fs.writeFile(filePath, json, 'utf8', callback);
}
writeFileSync = (filePath, config) => {
if (config.version !== this.defaultConfigData.version) {
throw new Error('version ' + config.version + ' is not equal to ' + this.defaultConfigData.version);
}
const dir = path.dirname(filePath);
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir);
}
const json = JSON.stringify(config, null, ' ');
fs.writeFileSync(filePath, json, 'utf8');
}
merge = (base, target) => {
return Object.assign({}, base, target);
}
copy = (data) => {
return Object.assign({}, data);
}
handleGetConfiguration = (event, option) => {
const config = {...this.combinedData};
if (option) {
return config[option];
}
return config;
}
handleGetLocalConfiguration = (event, option) => {
const config = {...this.localConfigData};
config.appName = app.name;
config.enableServerManagement = this.combinedData.enableServerManagement;
if (option) {
return config[option];
}
return config;
}
handleUpdateTeams = (event, newTeams) => {
this.set('teams', newTeams);
return this.combinedData.teams;
}
/**
* Detects changes in darkmode if it is windows or osx, updates the config and propagates the changes
* @emits 'darkModeChange'
*/
handleUpdateTheme = () => {
if (this.combinedData.darkMode !== nativeTheme.shouldUseDarkColors) {
this.combinedData.darkMode = nativeTheme.shouldUseDarkColors;
this.emit('darkModeChange', this.combinedData.darkMode);
}
}
/**
* Manually toggles dark mode for OSes that don't have a native dark mode setting
* @emits 'darkModeChange'
*/
toggleDarkModeManually = () => {
this.set('darkMode', !this.combinedData.darkMode);
this.emit('darkModeChange', this.combinedData.darkMode);
}
}

View File

@@ -4,26 +4,26 @@
import defaultPreferences from './defaultPreferences';
const pastDefaultPreferences = {
0: {
url: '',
},
1: {
version: 1,
teams: [],
showTrayIcon: false,
trayIconTheme: 'light',
minimizeToTray: false,
notifications: {
flashWindow: 0,
bounceIcon: false,
bounceIconType: 'informational',
0: {
url: '',
},
1: {
version: 1,
teams: [],
showTrayIcon: false,
trayIconTheme: 'light',
minimizeToTray: false,
notifications: {
flashWindow: 0,
bounceIcon: false,
bounceIconType: 'informational',
},
showUnreadBadge: true,
useSpellChecker: true,
enableHardwareAcceleration: true,
autostart: true,
spellCheckerLocale: 'en-US',
},
showUnreadBadge: true,
useSpellChecker: true,
enableHardwareAcceleration: true,
autostart: true,
spellCheckerLocale: 'en-US',
},
};
pastDefaultPreferences[`${defaultPreferences.version}`] = defaultPreferences;

View File

@@ -4,39 +4,39 @@
import pastDefaultPreferences from './pastDefaultPreferences';
function deepCopy(object) {
return JSON.parse(JSON.stringify(object));
return JSON.parse(JSON.stringify(object));
}
function upgradeV0toV1(configV0) {
const config = deepCopy(pastDefaultPreferences['1']);
if (config.version !== 1) {
throw new Error('pastDefaultPreferences[\'1\'].version is not equal to 1');
}
config.teams.push({
name: 'Primary team',
url: configV0.url,
});
return config;
const config = deepCopy(pastDefaultPreferences['1']);
if (config.version !== 1) {
throw new Error('pastDefaultPreferences[\'1\'].version is not equal to 1');
}
config.teams.push({
name: 'Primary team',
url: configV0.url,
});
return config;
}
function upgradeV1toV2(configV1) {
const config = deepCopy(configV1);
config.version = 2;
config.teams.forEach((value, index) => {
value.order = index;
});
config.darkMode = false;
return config;
const config = deepCopy(configV1);
config.version = 2;
config.teams.forEach((value, index) => {
value.order = index;
});
config.darkMode = false;
return config;
}
export default function upgradeToLatest(config) {
const configVersion = config.version ? config.version : 0;
switch (configVersion) {
case 1:
return upgradeToLatest(upgradeV1toV2(config));
case 0:
return upgradeToLatest(upgradeV0toV1(config));
default:
return config;
}
const configVersion = config.version ? config.version : 0;
switch (configVersion) {
case 1:
return upgradeToLatest(upgradeV1toV2(config));
case 0:
return upgradeToLatest(upgradeV0toV1(config));
default:
return config;
}
}