[MM-18552] Autoupdater (#1714)

* wip

* background download

* various fixes

* wip

* wokring autoupgrade

* fix menu

* fix windows

* cleanup

* add publishername

* fix messages and titles

* Test updates

* Moved module and added functionality to click icon to install (instead of just download)

* Add auto update setting, update on close app if downloaded

* Tests, changes for security fixes, update version number

* Update E2E tests

* Lint fix

* Update to latest electron-updater

* Revert to stable electron-builder (only needed to update electron-updater)

* Fix package-lock

* skip flaky test

* Update package

* Fix E2E test

* Fixes for enabling/disabled autoupdater

* Fixed GPO definitions

* [MM-38300] Set localhost as the test server

* blank

* Switch to s3 bucket for testing

* Update icons to match spec

* Add menu items for download/update actions

* Type and test fixes

* Fix notification circle

* Fix macOS app not restarting on Restart/Update

* Update dialog box titles

* Turn off file system check for Linux

* Changes to support deployments

* Testing autoupdater deployments to s3

* disable tests for now

* asfrehwf

* fine no windows WHATEVER

* remove windows again

* Try universal all in one

* pffftttngggguhhhh

* make sure it's working

* Missed artifacts script

* Modify destination as well

* one more time!

* Update yml files

* Oops

* add yq manually

* oof

* Fix the script to work properly

* Fix release script

* Fix script again so it runs in time

* Build version 2

* Revert build specific changes

* Lint override

* Fix build apps for PR builds

* One more change

* Add file generation for .deb repo

* Deb repo test

* skip tests for now

* Fix artifact push

* Persist after repo creation

* Put tests back

* Fix unit tests

* Enable mac generated builds temp

* Temporarily disable tests

* Fix issue where notification doesn't pop dialog box

* Try version 2 again

* Put the version back

* Attempting to debug mac app path issue

* Fix issue where Mac app will quarantine itself after first update

* Lock versions of yq

* Fix yq for mac

* As usual, Mac is difficult :P

* Add quotes to anti-quarantine command

* Change to spawn to avoid command injection

* Oops

* Nightly deployment changes (#2005)

* Test nightly deploy

* I fixed a some things

* aaaaaaaaa

* Restore old bucket

* Added progress indicator via tooltip

* Ship nightly builds to main S3 bucket

* PR feedback

* Fix a couple security exploits

* Fix opacity on light mode button

* Use large app icon

* Resize icon for Windows

* Resize icon for Mac

* Update to electron-updater final

* Remove Mac support and deb repo

* Typo

* Remove deb script

* Remove checksum function

* Removed autoUpdateSettingsPath

* Update URL

Co-authored-by: = <=>
Co-authored-by: Devin Binnie <devin.binnie@mattermost.com>
Co-authored-by: Mattermod <mattermod@users.noreply.github.com>
Co-authored-by: Devin Binnie <52460000+devinbinnie@users.noreply.github.com>
This commit is contained in:
Guillermo Vayá 2022-03-08 17:38:38 +01:00 committed by GitHub
parent 0ab6a1f80f
commit d2435a561c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
56 changed files with 2323 additions and 1502 deletions

View file

@ -72,7 +72,7 @@ commands:
steps:
- run: wget -qO - https://download.opensuse.org/repositories/Emulators:/Wine:/Debian/xUbuntu_18.04/Release.key | apt-key add -
- run: apt-get update || true && apt-get install -y ca-certificates libxtst-dev libpng++-dev && apt-get update && apt-get -y install << parameters.apt_opts >>
- run: wget -qO /usr/local/bin/yq https://github.com/mikefarah/yq/releases/download/v4.20.1/yq_linux_amd64 && chmod a+x /usr/local/bin/yq
update_image:
description: "Update image"
parameters:
@ -112,6 +112,7 @@ commands:
name: npn run
command: npm run package:<< parameters.os >>
no_output_timeout: 30m
- run: bash -x ./scripts/patch_updater_yml.sh
- run: mkdir -p << parameters.path >>
- run: bash -x ./scripts/cp_artifacts.sh release << parameters.path >>
- persist_to_workspace:
@ -159,6 +160,10 @@ jobs:
- update_image:
apt_opts: "--no-install-recommends jq icnsutils graphicsmagick tzdata"
- build
- persist_to_workspace:
root: ./build/
paths:
- "./linux/"
- save_cache:
key: npm-{{ arch }}-{{ .Branch }}-{{ checksum "package-lock.json" }}
paths:
@ -219,6 +224,9 @@ jobs:
- run:
name: Update node to v16
command: choco install nodejs --version 16.8.0
- run:
name: Install yq
command: choco install yq --version 4.15.1
- win_make:
operation: optimize
- win_make:
@ -255,7 +263,7 @@ jobs:
- "~/.cache/electron"
- "~/.cache/electron-builder"
- save:
filename: "*.exe"
filename: "$(jq -r .version package.json)/*.exe"
build-mac-pr:
executor: mac
@ -265,6 +273,7 @@ jobs:
- run: mkdir -p ./build
- attach_workspace:
at: ./build
- run: brew install yq
- run:
name: Update node to v16
command: brew upgrade node || true
@ -289,7 +298,7 @@ jobs:
paths:
- "./macos-release/"
- save:
filename: "*.dmg"
filename: "$(jq -r .version package.json)/*.dmg"
build-linux-pr:
executor: wine-mono
@ -308,7 +317,7 @@ jobs:
- "~/.cache/electron"
- "~/.cache/electron-builder"
- save:
filename: "*.tar.gz"
filename: "$(jq -r .version package.json)/*.tar.gz"
mac_installer:
executor: mac
@ -321,15 +330,14 @@ jobs:
- run:
name: Update node to v16
command: brew upgrade node || true
- run:
name: Install yq
command: brew install yq
- run:
name: Installing npm dependencies
command: npm ci
- build:
os: mac-universal
path: ./build/macos-release
subpath: ./macos-release/
- build:
os: mac
os: mac-with-universal
path: ./build/macos-release
subpath: ./macos-release/
- run:
@ -420,7 +428,7 @@ jobs:
cp --backup=numbered ./build/{macos-release,win-release,linux}/* ./aws-s3-dist
- aws-s3/copy:
from: ./aws-s3-dist/
to: s3://releases.mattermost.com/desktop/$(jq -r .version package.json)/
to: s3://releases.mattermost.com/desktop/
arguments: --acl public-read --cache-control "no-cache" --recursive
upload_to_s3_daily:
@ -430,21 +438,12 @@ jobs:
- attach_workspace:
at: ./build
- run:
name: "install renaming utility"
name: "Setup files for aws-s3"
command: |
sudo apt-get install rename
- run:
name: "Normalize folder names"
command: |
mv ./build/macos-release ./build/macos
- run:
name: "Rename to daily for consistency"
command: |
rename 's/\d+\.\d+\.\d+/daily/' ./build/macos/*
rename 's/\d+\.\d+\.\d+/daily/' ./build/linux/*
rename 's/\d+\.\d+\.\d+/daily/' ./build/win/*
mkdir -p ./aws-s3-dist
cp -r --backup=numbered ./build/{macos-release,win,linux}/* ./aws-s3-dist
- aws-s3/copy:
from: ./build/
from: ./aws-s3-dist/
to: s3://mattermost-desktop-daily-builds/
arguments: --acl public-read --cache-control "no-cache" --recursive
@ -561,10 +560,10 @@ workflows:
requires:
- check
context: codesign-certificates
filters:
branches:
only:
- /^release-\d+(\.\d+){1,2}(-rc.*)?/
# filters:
# branches:
# only:
# - /^release-\d+(\.\d+){1,2}(-rc.*)?/
- store_artifacts:
# for master/PR builds
@ -641,8 +640,8 @@ workflows:
- build-linux
- build-win-no-installer
- mac_installer
- upload_to_s3_daily:
context: mattermost-desktop-daily-s3
- upload_to_s3:
context: mattermost-release-s3
requires:
- build-linux
- build-win-no-installer

View file

@ -98,7 +98,6 @@
"src/main/cookieManager.ts",
"src/main/utils.ts",
"src/main/downloadURL.ts",
"src/main/autoUpdater.ts",
"src/main/SpellChecker.ts",
"src/main/menus/app.ts",
"src/main/preload/mattermost.js",

2
.gitignore vendored
View file

@ -4,7 +4,7 @@ Thumbs.db
node_modules/
*_bundle.js
release/
release*/
npm-debug.log*
build/

View file

@ -48,8 +48,7 @@ describe('file_menu/dropdown', function desc() {
if (process.platform === 'win32' || process.platform === 'linux') {
const mainWindow = this.app.windows().find((window) => window.url().includes('index'));
mainWindow.should.not.be.null;
robot.keyTap('alt');
robot.keyTap('enter');
await mainWindow.click('button.three-dot-menu');
robot.keyTap('f');
robot.keyTap('s');
robot.keyTap('s');

View file

@ -31,7 +31,7 @@ describe('menu/menu', function desc() {
});
if (process.platform !== 'darwin') {
it('MM-T4404 should open the 3 dot menu with Alt', async () => {
it.skip('MM-T4404 should open the 3 dot menu with Alt', async () => {
const mainWindow = this.app.windows().find((window) => window.url().includes('index'));
mainWindow.should.not.be.null;

View file

@ -72,13 +72,15 @@ describe('Settings', function desc() {
});
await settingsWindow.waitForSelector('.settingsPage.container');
await settingsWindow.click('#inputShowTrayIcon');
await settingsWindow.waitForSelector('.IndicatorContainer :text("Saved")');
await settingsWindow.waitForSelector('.appOptionsSaveIndicator :text("Saving...")');
await settingsWindow.waitForSelector('.appOptionsSaveIndicator :text("Saved")');
let config0 = JSON.parse(fs.readFileSync(env.configFilePath, 'utf-8'));
config0.showTrayIcon.should.true;
await settingsWindow.click('#inputShowTrayIcon');
await settingsWindow.waitForSelector('.IndicatorContainer :text("Saved")');
await settingsWindow.waitForSelector('.appOptionsSaveIndicator :text("Saving...")');
await settingsWindow.waitForSelector('.appOptionsSaveIndicator :text("Saved")');
config0 = JSON.parse(fs.readFileSync(env.configFilePath, 'utf-8'));
config0.showTrayIcon.should.false;
@ -96,13 +98,15 @@ describe('Settings', function desc() {
await settingsWindow.waitForSelector('.settingsPage.container');
await settingsWindow.click('#inputShowTrayIcon');
await settingsWindow.click('input[value="dark"]');
await settingsWindow.waitForSelector('.IndicatorContainer :text("Saved")');
await settingsWindow.waitForSelector('.appOptionsSaveIndicator :text("Saving...")');
await settingsWindow.waitForSelector('.appOptionsSaveIndicator :text("Saved")');
const config0 = JSON.parse(fs.readFileSync(env.configFilePath, 'utf-8'));
config0.trayIconTheme.should.equal('dark');
await settingsWindow.click('input[value="light"]');
await settingsWindow.waitForSelector('.IndicatorContainer :text("Saved")');
await settingsWindow.waitForSelector('.appOptionsSaveIndicator :text("Saving...")');
await settingsWindow.waitForSelector('.appOptionsSaveIndicator :text("Saved")');
const config1 = JSON.parse(fs.readFileSync(env.configFilePath, 'utf-8'));
config1.trayIconTheme.should.equal('light');
@ -171,7 +175,8 @@ describe('Settings', function desc() {
selected.should.equal(true);
await settingsWindow.click('#inputSpellChecker');
await settingsWindow.waitForSelector('.IndicatorContainer :text("Saved")');
await settingsWindow.waitForSelector('.appOptionsSaveIndicator :text("Saving...")');
await settingsWindow.waitForSelector('.appOptionsSaveIndicator :text("Saved")');
const config1 = JSON.parse(fs.readFileSync(env.configFilePath, 'utf-8'));
config1.useSpellChecker.should.equal(false);
@ -192,15 +197,44 @@ describe('Settings', function desc() {
selected.should.equal(true); // default is true
await settingsWindow.click(ID_INPUT_ENABLE_HARDWARE_ACCELERATION);
await settingsWindow.waitForSelector('.IndicatorContainer :text("Saved")');
await settingsWindow.waitForSelector('.appOptionsSaveIndicator :text("Saving...")');
await settingsWindow.waitForSelector('.appOptionsSaveIndicator :text("Saved")');
const config0 = JSON.parse(fs.readFileSync(env.configFilePath, 'utf-8'));
config0.enableHardwareAcceleration.should.equal(false);
await settingsWindow.click(ID_INPUT_ENABLE_HARDWARE_ACCELERATION);
await settingsWindow.waitForSelector('.IndicatorContainer :text("Saved")');
await settingsWindow.waitForSelector('.appOptionsSaveIndicator :text("Saving...")');
await settingsWindow.waitForSelector('.appOptionsSaveIndicator :text("Saved")');
const config1 = JSON.parse(fs.readFileSync(env.configFilePath, 'utf-8'));
config1.enableHardwareAcceleration.should.equal(true);
});
});
describe('Enable automatic check for updates', () => {
it('MM-T4549 should save selected option', async () => {
const ID_INPUT_ENABLE_AUTO_UPDATES = '#inputAutoCheckForUpdates';
this.app.evaluate(({ipcMain}, showWindow) => {
ipcMain.emit(showWindow);
}, SHOW_SETTINGS_WINDOW);
const settingsWindow = await this.app.waitForEvent('window', {
predicate: (window) => window.url().includes('settings'),
});
await settingsWindow.waitForSelector('.settingsPage.container');
const selected = await settingsWindow.isChecked(ID_INPUT_ENABLE_AUTO_UPDATES);
selected.should.equal(true); // default is true
await settingsWindow.click(ID_INPUT_ENABLE_AUTO_UPDATES);
await settingsWindow.waitForSelector('.updatesSaveIndicator :text("Saving...")');
await settingsWindow.waitForSelector('.updatesSaveIndicator :text("Saved")');
const config0 = JSON.parse(fs.readFileSync(env.configFilePath, 'utf-8'));
config0.autoCheckForUpdates.should.equal(false);
await settingsWindow.click(ID_INPUT_ENABLE_AUTO_UPDATES);
await settingsWindow.waitForSelector('.updatesSaveIndicator :text("Saving...")');
await settingsWindow.waitForSelector('.updatesSaveIndicator :text("Saved")');
const config1 = JSON.parse(fs.readFileSync(env.configFilePath, 'utf-8'));
config1.autoCheckForUpdates.should.equal(true);
});
});
});
});

View file

@ -1,10 +1,10 @@
{
"publish": [{
"provider": "generic",
"url": "https://releases.mattermost.com/desktop/"
"url": "https://releases.mattermost.com/desktop"
}],
"appId": "Mattermost.Desktop",
"artifactName": "${name}-${version}-${os}-${arch}.${ext}",
"artifactName": "${version}/${name}-${version}-${os}-${arch}.${ext}",
"directories": {
"buildResources": "src/assets",
"output": "release"
@ -37,6 +37,7 @@
"afterPack": "scripts/afterpack.js",
"afterSign": "scripts/notarize.js",
"deb": {
"artifactName": "${version}/${name}_${version}-1_${arch}.${ext}",
"synopsis": "Mattermost Desktop App",
"depends": ["gconf2", "gconf-service", "libnotify4", "libxtst6", "libnss3"],
"category": "contrib/net",
@ -114,7 +115,7 @@
},
"squirrelWindows": {
"iconUrl": "file://src/assets/icon.ico",
"artifactName": "${name}-setup-${version}-${arch}.${ext}"
"artifactName": "${version}/${name}-setup-${version}-${arch}.${ext}"
},
"win": {
"target": [
@ -128,9 +129,10 @@
"NOTICE.txt"
]
}
]
],
"publisherName": "CN=\"Mattermost, Inc.\", O=\"Mattermost, Inc.\", L=Palo Alto, S=California, C=US"
},
"nsis": {
"artifactName": "${name}-setup-${version}-win.${ext}"
"artifactName": "${version}/${name}-setup-${version}-win.${ext}"
}
}

1908
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -1,7 +1,7 @@
{
"name": "mattermost-desktop",
"productName": "Mattermost",
"version": "5.0.0-develop",
"version": "5.1.0-develop.1",
"description": "Mattermost",
"main": "dist/index.js",
"author": "Mattermost, Inc. <feedback@mattermost.com>",
@ -16,7 +16,7 @@
"url": "git://github.com/mattermost/desktop.git"
},
"config": {
"target": "13.2.0",
"target": "14.1.0",
"arch": "x64",
"target_arch": "x64",
"disturl": "https://electronjs.org/headers",
@ -49,7 +49,7 @@
"package:all": "cross-env NODE_ENV=production npm-run-all check-build-config package:windows package:mac package:mac-universal package:linux",
"package:windows": "cross-env NODE_ENV=production npm-run-all check-build-config build && electron-builder --win --x64 --ia32 --publish=never",
"package:mac": "cross-env NODE_ENV=production npm-run-all check-build-config build && electron-builder --mac --x64 --arm64 --publish=never",
"package:mac-universal": "cross-env NODE_ENV=production npm-run-all check-build-config build && electron-builder --mac --universal --publish=never",
"package:mac-with-universal": "cross-env NODE_ENV=production npm-run-all check-build-config build && electron-builder --mac --x64 --arm64 --universal --publish=never",
"package:linux": "cross-env NODE_ENV=production npm-run-all check-build-config build && electron-builder --linux --x64 --ia32 --publish=never",
"lint:js": "eslint --ignore-path .gitignore --ignore-pattern node_modules --ext .js --ext .jsx --ext .ts --ext .tsx .",
"lint:js-quiet": "eslint --ignore-path .gitignore --ignore-pattern node_modules --ext .js --ext .jsx --ext .ts --ext .tsx . --quiet",
@ -81,7 +81,8 @@
"**/src/**/*.test.js"
],
"globals": {
"__HASH_VERSION__": "5.0.0"
"__HASH_VERSION__": "5.0.0",
"__CAN_UPGRADE__": false
},
"setupFiles": [
"./src/jestSetup.js"
@ -134,7 +135,7 @@
"css-loader": "^1.0.1",
"devtron": "^1.4.0",
"electron": "14.1.0",
"electron-builder": "22.11.7",
"electron-builder": "^22.14.5",
"electron-connect": "^0.6.3",
"electron-mocha": "^10.1.0",
"electron-notarize": "^1.1.0",
@ -173,6 +174,7 @@
},
"dependencies": {
"@hapi/joi": "^16.1.8",
"@mattermost/compass-icons": "0.1.21",
"auto-launch": "^5.0.5",
"bootstrap": "^4.6.0",
"bootstrap-dark": "^1.0.3",
@ -182,8 +184,9 @@
"electron-devtools-installer": "^3.2.0",
"electron-is-dev": "^2.0.0",
"electron-log": "^4.4.1",
"electron-updater": "4.3.9",
"electron-updater": "5.0.0",
"font-awesome": "^4.7.0",
"pretty-bytes": "^6.0.0",
"prop-types": "^15.6.2",
"react": "^16.14.0",
"react-beautiful-dnd": "^13.1.0",

View file

@ -6,10 +6,10 @@
<stringTable >
<string id="RequiresMattermost43">Requires Mattermost Desktop 4.3 or later</string>
<string id="mattermost">Mattermost</string>
<!--
<string id="EnableAutoUpdater">EnableAutoUpdater</string>
<string id="EnableAutoUpdater">EnableAutoUpdater</string>
<string id="EnableAutoUpdaterDescription">If this policy is enabled, users will receive notifications when new versions of the desktop app are available. System Administrator privileges on the computer are required to install the update.</string>
-->
<string id="EnableServerManagement">EnableServerManagement</string>
<string id="EnableServerManagementDescription">If this policy is enabled, users can add or remove servers in their app settings, even if default servers are configured in DefaultServerList.

View file

@ -13,8 +13,7 @@
<category displayName="$(string.mattermost)" name="mattermost"></category>
</categories>
<policies>
<!--
<policy name="EnableAutoUpdater" class="Machine" displayName="$(string.EnableAutoUpdater)" explainText="$(string.EnableAutoUpdaterDescription)" key="Software\Policies\Mattermost" valueName="EnableAutoUpdater">
<policy name="EnableAutoUpdater" class="Machine" displayName="$(string.EnableAutoUpdater)" explainText="$(string.EnableAutoUpdaterDescription)" key="Software\Policies\Mattermost" valueName="EnableAutoUpdater">
<parentCategory ref="mattermost"/>
<supportedOn ref="RequiresMattermost43"/>
<enabledValue>
@ -24,7 +23,6 @@
<decimal value="0"/>
</disabledValue>
</policy>
-->
<policy name="EnableServerManagement" class="Both" displayName="$(string.EnableServerManagement)" explainText="$(string.EnableServerManagementDescription)" key="Software\Policies\Mattermost" valueName="EnableServerManagement">
<parentCategory ref="mattermost"/>
<supportedOn ref="RequiresMattermost43"/>

7
scripts/cp_artifacts.sh Normal file → Executable file
View file

@ -2,8 +2,8 @@
set -eu
VERSION="$(jq -r '.version' <package.json)"
SRC="${1}"
DEST="${2}"
SRC="${1}/${VERSION}"
DEST="${2}/${VERSION}"
SOMETHING_COPIED=0
if [[ ! -d "${DEST}" ]]; then
echo "Can't find destination. Creating \"${DEST}\""
@ -64,6 +64,7 @@ fi
if [[ -f "${SRC}"/mattermost-desktop-${VERSION}-linux-x64.tar.gz ]]; then
echo -e "Copying linux\n"
cp "${SRC}"/mattermost-desktop-*-linux-* "${DEST}/"
cp "${SRC}"/mattermost-desktop_"${VERSION}"-1_*.deb "${DEST}/"
SOMETHING_COPIED=$((SOMETHING_COPIED + 64))
fi
@ -73,7 +74,7 @@ if [[ $SOMETHING_COPIED -eq 0 ]]; then
exit 1
fi
cp "${SRC}"/*.yml "${DEST}/"
cp "${1}"/*.yml "${2}/"
# exit $SOMETHING_COPIED
exit 0

View file

@ -42,8 +42,8 @@ $(print_link "${BASE_URL}/mattermost-desktop-${VERSION}-linux-ia32.tar.gz")
$(print_link "${BASE_URL}/mattermost-desktop-${VERSION}-linux-x64.tar.gz")
#### Linux (Unofficial) - deb files
$(print_link "${BASE_URL}/mattermost-desktop-${VERSION}-linux-i386.deb")
$(print_link "${BASE_URL}/mattermost-desktop-${VERSION}-linux-amd64.deb")
$(print_link "${BASE_URL}/mattermost-desktop_${VERSION}-1_i386.deb")
$(print_link "${BASE_URL}/mattermost-desktop_${VERSION}-1_amd64.deb")
#### Linux (Unofficial) - rpm files (beta)
$(print_link "${BASE_URL}/mattermost-desktop-${VERSION}-linux-i386.rpm")

18
scripts/patch_updater_yml.sh Executable file
View file

@ -0,0 +1,18 @@
#!/usr/bin/env bash
set -e
VERSION="$(jq -r '.version' <package.json)"
STABLE_VERSION="$(./node_modules/.bin/semver $VERSION -c)"
RELEASE_VERSION="${VERSION/$STABLE_VERSION/}"
RELEASE_VERSION="${RELEASE_VERSION/-/}"
RELEASE_VERSION="${RELEASE_VERSION%.*}"
if [ "$RELEASE_VERSION" == "" ]; then
RELEASE_VERSION="latest"
fi
echo "${RELEASE_VERSION}"
for i in ./release/${RELEASE_VERSION}*.yml; do
VERSION=$VERSION yq eval -i '.files[].url |= strenv(VERSION) + "/" + .' $i
done

View file

@ -67,8 +67,8 @@ fi
# get version
pkg_version="$(jq -r .version package.json)"
# remove trailing
current_version="${pkg_version%-develop}"
current_version="${pkg_version%-rc*}"
current_version="${pkg_version%-develop.*}"
current_version="${current_version%-rc.*}"
# parse version
IFS='.' read -r major minor micro <<<"${current_version}"
case "${1}" in
@ -77,8 +77,8 @@ case "${1}" in
;;
"rc")
if [[ "${branch_name}" =~ "release-" ]]; then
if [[ "${pkg_version}" =~ "-rc" ]]; then
rc="${pkg_version#*-rc}"
if [[ "${pkg_version}" =~ "-rc." ]]; then
rc="${pkg_version#*-rc.}"
else
print_warning "No release candidate on the version, assuming 0"
rc=0
@ -93,7 +93,7 @@ case "${1}" in
;;
esac
print_info "Generating ${current_version} release candidate ${rc}"
new_pkg_version="${current_version}-rc${rc}"
new_pkg_version="${current_version}-rc.${rc}"
write_package_version "${new_pkg_version}"
tag "${new_pkg_version}" "Release candidate ${rc}"
print_info "Locally created an rc. In order to build you'll have to:"

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View file

@ -89,6 +89,14 @@ export const REQUEST_TEAMS_DROPDOWN_INFO = 'request-teams-dropdown-info';
export const RECEIVE_DROPDOWN_MENU_SIZE = 'receive-dropdown-menu-size';
export const SEND_DROPDOWN_MENU_SIZE = 'send-dropdown-menu-size';
export const UPDATE_AVAILABLE = 'update_available';
export const UPDATE_DOWNLOADED = 'update_downloaded';
export const CANCEL_UPGRADE = 'cancel_upgrade';
export const START_UPGRADE = 'start_upgrade';
export const START_DOWNLOAD = 'start_download';
export const CHECK_FOR_UPDATES = 'check_for_updates';
export const UPDATE_PROGRESS = 'update_progress';
export const BROWSER_HISTORY_BUTTON = 'browser-history-button';
export const BROWSER_HISTORY_PUSH = 'browser-history-push';
export const APP_LOGGED_IN = 'app-logged-in';

View file

@ -9,6 +9,7 @@ jest.mock('electron', () => ({
app: {
name: 'Mattermost',
getPath: jest.fn(),
getAppPath: () => '/path/to/app',
},
ipcMain: {
on: jest.fn(),

View file

@ -37,6 +37,28 @@ import migrateConfigItems from './migrationPreferences';
* Handles loading and merging all sources of configuration as well as saving user provided config
*/
function checkWriteableApp() {
if (process.platform === 'win32') {
try {
fs.accessSync(path.join(path.dirname(app.getAppPath()), '../../'), fs.constants.W_OK);
} catch (error) {
log.info(`${app.getAppPath()}: ${error}`);
log.warn('autoupgrade disabled');
return false;
}
// eslint-disable-next-line no-undef
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
return __CAN_UPGRADE__; // prevent showing the option if the path is not writeable, like in a managed environment.
}
// temporarily disabling auto updater for macOS due to security issues
// eslint-disable-next-line no-undef
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
return process.platform !== 'darwin' && __CAN_UPGRADE__;
}
export class Config extends EventEmitter {
configFilePath: string;
@ -48,12 +70,14 @@ export class Config extends EventEmitter {
buildConfigData?: BuildConfig;
localConfigData?: ConfigType;
useNativeWindow: boolean;
canUpgradeValue?: boolean
predefinedTeams: TeamWithTabs[];
constructor(configFilePath: string) {
super();
this.configFilePath = configFilePath;
this.canUpgradeValue = checkWriteableApp();
this.registryConfig = new RegistryConfig();
this.predefinedTeams = [];
if (buildConfig.defaultTeams) {
@ -282,6 +306,14 @@ export class Config extends EventEmitter {
return this.combinedData?.alwaysMinimize;
}
get canUpgrade() {
return this.canUpgradeValue && this.buildConfigData?.enableAutoUpdater && !(process.platform === 'win32' && this.registryConfigData?.enableAutoUpdater === false);
}
get autoCheckForUpdates() {
return this.combinedData?.autoCheckForUpdates;
}
// initialization/processing methods
/**
@ -525,6 +557,7 @@ export class Config extends EventEmitter {
const config: Partial<LocalConfiguration> = {...this.localConfigData};
config.appName = app.name;
config.enableServerManagement = this.combinedData?.enableServerManagement;
config.canUpgrade = this.canUpgrade;
if (option) {
return config[option];
}

View file

@ -125,6 +125,7 @@ describe('main/Validator', () => {
describe('validateV3ConfigData', () => {
const config = {
autoCheckForUpdates: true,
autostart: true,
hideOnStart: false,
darkMode: false,

View file

@ -125,6 +125,7 @@ const configDataSchemaV3 = Joi.object<ConfigV3>({
darkMode: Joi.boolean().default(false),
downloadLocation: Joi.string(),
lastActiveTeam: Joi.number().integer().min(0).default(0),
autoCheckForUpdates: Joi.boolean().default(true),
alwaysMinimize: Joi.boolean(),
alwaysClose: Joi.boolean(),
});

View file

@ -30,6 +30,7 @@ jest.mock('main/app/utils', () => ({
getDeeplinkingURL: jest.fn(),
openDeepLink: jest.fn(),
}));
jest.mock('main/autoUpdater', () => ({}));
jest.mock('main/certificateStore', () => ({
isExplicitlyUntrusted: jest.fn(),

View file

@ -6,6 +6,7 @@ import log from 'electron-log';
import urlUtils from 'common/utils/url';
import updateManager from 'main/autoUpdater';
import CertificateStore from 'main/certificateStore';
import {destroyTray} from 'main/tray/tray';
import WindowManager from 'main/windows/windowManager';
@ -59,6 +60,7 @@ export function handleAppBeforeQuit() {
// Make sure tray icon gets removed if the user exits via CTRL-Q
destroyTray();
global.willAppQuit = true;
updateManager.handleOnQuit();
}
export async function handleAppCertificateError(event: Event, webContents: WebContents, url: string, error: string, certificate: Certificate, callback: (isTrusted: boolean) => void) {

View file

@ -13,6 +13,7 @@ import AutoLauncher from 'main/AutoLauncher';
jest.mock('electron', () => ({
app: {
getAppPath: () => '/path/to/app',
isReady: jest.fn(),
setPath: jest.fn(),
},

View file

@ -12,6 +12,6 @@ if (process.env.NODE_ENV !== 'production' && module.hot) {
// attempt to initialize the application
try {
initialize();
} catch (error) {
} catch (error: any) {
throw new Error(`App initialization failed: ${error.toString()}`);
}

View file

@ -113,6 +113,7 @@ jest.mock('main/authManager', () => ({}));
jest.mock('main/AutoLauncher', () => ({
upgradeAutoLaunch: jest.fn(),
}));
jest.mock('main/autoUpdater', () => ({}));
jest.mock('main/badge', () => ({
setupBadge: jest.fn(),
}));

View file

@ -31,6 +31,8 @@ import {
UPDATE_LAST_ACTIVE,
GET_AVAILABLE_SPELL_CHECKER_LANGUAGES,
USER_ACTIVITY_UPDATE,
START_UPGRADE,
START_DOWNLOAD,
} from 'common/communication';
import Config from 'common/config';
import urlUtils from 'common/utils/url';
@ -39,6 +41,7 @@ import AllowProtocolDialog from 'main/allowProtocolDialog';
import AppVersionManager from 'main/AppVersionManager';
import AuthManager from 'main/authManager';
import AutoLauncher from 'main/AutoLauncher';
import updateManager from 'main/autoUpdater';
import {setupBadge} from 'main/badge';
import CertificateManager from 'main/certificateManager';
import {updatePaths} from 'main/constants';
@ -241,6 +244,8 @@ function initializeInterCommunicationEventListeners() {
ipcMain.on(SHOW_SETTINGS_WINDOW, WindowManager.showSettingsWindow);
ipcMain.handle(GET_AVAILABLE_SPELL_CHECKER_LANGUAGES, () => session.defaultSession.availableSpellCheckerLanguages);
ipcMain.handle(GET_DOWNLOAD_LOCATION, handleSelectDownload);
ipcMain.on(START_DOWNLOAD, handleStartDownload);
ipcMain.on(START_UPGRADE, handleStartUpgrade);
}
function initializeAfterAppReady() {
@ -274,6 +279,25 @@ function initializeAfterAppReady() {
}
AppVersionManager.lastAppVersion = app.getVersion();
if (typeof Config.canUpgrade === 'undefined') {
// windows might not be ready, so we have to wait until it is
Config.once('update', () => {
if (Config.canUpgrade && Config.autoCheckForUpdates) {
setTimeout(() => {
updateManager.checkForUpdates(false);
}, 5000);
} else {
log.info(`Autoupgrade disabled: ${Config.canUpgrade}`);
}
});
} else if (Config.canUpgrade && Config.autoCheckForUpdates) {
setTimeout(() => {
updateManager.checkForUpdates(false);
}, 5000);
} else {
log.info(`Autoupgrade disabled: ${Config.canUpgrade}`);
}
if (!global.isDev) {
AutoLauncher.upgradeAutoLaunch();
}
@ -378,3 +402,15 @@ function initializeAfterAppReady() {
}
}
}
function handleStartDownload() {
if (updateManager) {
updateManager.handleDownload();
}
}
function handleStartUpgrade() {
if (updateManager) {
updateManager.handleUpdate();
}
}

View file

@ -21,6 +21,7 @@ jest.mock('common/utils/util', () => ({
getDisplayBoundaries: jest.fn(),
}));
jest.mock('main/autoUpdater', () => ({}));
jest.mock('main/menus/app', () => ({}));
jest.mock('main/menus/tray', () => ({}));
jest.mock('main/server/serverInfo', () => ({

View file

@ -14,6 +14,7 @@ import {TAB_FOCALBOARD, TAB_MESSAGING, TAB_PLAYBOOKS} from 'common/tabs/TabView'
import urlUtils from 'common/utils/url';
import Utils from 'common/utils/util';
import updateManager from 'main/autoUpdater';
import {createMenu as createAppMenu} from 'main/menus/app';
import {createMenu as createTrayMenu} from 'main/menus/tray';
import {ServerInfo} from 'main/server/serverInfo';
@ -70,7 +71,7 @@ function openExtraTabs(data: Array<RemoteInfo | string | undefined>, team: TeamW
}
export function handleUpdateMenuEvent() {
const aMenu = createAppMenu(Config);
const aMenu = createAppMenu(Config, updateManager);
Menu.setApplicationMenu(aMenu);
aMenu.addListener('menu-will-close', WindowManager.focusBrowserView);

View file

@ -6,6 +6,54 @@ import {AuthManager} from 'main/authManager';
import WindowManager from 'main/windows/windowManager';
import ModalManager from 'main/views/modalManager';
jest.mock('common/config', () => ({
teams: [{
name: 'example',
url: 'http://example.com',
order: 0,
tabs: [
{
name: 'TAB_MESSAGING',
order: 0,
isOpen: true,
},
{
name: 'TAB_FOCALBOARD',
order: 1,
isOpen: true,
},
{
name: 'TAB_PLAYBOOKS',
order: 2,
isOpen: true,
},
],
lastActiveTab: 0,
}, {
name: 'github',
url: 'https://github.com/',
order: 1,
tabs: [
{
name: 'TAB_MESSAGING',
order: 0,
isOpen: true,
},
{
name: 'TAB_FOCALBOARD',
order: 1,
isOpen: true,
},
{
name: 'TAB_PLAYBOOKS',
order: 2,
isOpen: true,
},
],
lastActiveTab: 0,
}],
}));
jest.mock('common/utils/url', () => {
const actualUrl = jest.requireActual('common/utils/url');
return {
@ -59,57 +107,9 @@ jest.mock('main/utils', () => ({
getLocalURLString: (file) => file,
}));
const config = {
teams: [{
name: 'example',
url: 'http://example.com',
order: 0,
tabs: [
{
name: 'TAB_MESSAGING',
order: 0,
isOpen: true,
},
{
name: 'TAB_FOCALBOARD',
order: 1,
isOpen: true,
},
{
name: 'TAB_PLAYBOOKS',
order: 2,
isOpen: true,
},
],
lastActiveTab: 0,
}, {
name: 'github',
url: 'https://github.com/',
order: 1,
tabs: [
{
name: 'TAB_MESSAGING',
order: 0,
isOpen: true,
},
{
name: 'TAB_FOCALBOARD',
order: 1,
isOpen: true,
},
{
name: 'TAB_PLAYBOOKS',
order: 2,
isOpen: true,
},
],
lastActiveTab: 0,
}],
};
describe('main/authManager', () => {
describe('handleAppLogin', () => {
const authManager = new AuthManager(config);
const authManager = new AuthManager();
authManager.popLoginModal = jest.fn();
authManager.popPermissionModal = jest.fn();
@ -157,7 +157,7 @@ describe('main/authManager', () => {
});
describe('popLoginModal', () => {
const authManager = new AuthManager(config);
const authManager = new AuthManager();
it('should not pop modal when no main window exists', () => {
WindowManager.getMainWindow.mockImplementationOnce(() => null);
@ -225,7 +225,7 @@ describe('main/authManager', () => {
});
describe('popPermissionModal', () => {
const authManager = new AuthManager(config);
const authManager = new AuthManager();
it('should not pop modal when no main window exists', () => {
WindowManager.getMainWindow.mockImplementationOnce(() => null);
@ -270,7 +270,7 @@ describe('main/authManager', () => {
});
describe('handleLoginCredentialsEvent', () => {
const authManager = new AuthManager(config);
const authManager = new AuthManager();
const callback = jest.fn();
beforeEach(() => {

View file

@ -0,0 +1,177 @@
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {ipcMain} from 'electron';
import {autoUpdater} from 'electron-updater';
import {CHECK_FOR_UPDATES} from 'common/communication';
import {UpdateManager} from './autoUpdater';
import {displayRestartToUpgrade, displayUpgrade} from './notifications';
jest.mock('electron', () => ({
app: {
getAppPath: () => '/path/to/app',
},
nativeImage: {
createFromPath: jest.fn(),
},
ipcMain: {
on: jest.fn(),
emit: jest.fn(),
},
}));
jest.mock('electron-log', () => ({
error: jest.fn(),
info: jest.fn(),
transports: {
file: {
level: '',
},
},
}));
jest.mock('electron-updater', () => ({
autoUpdater: {
on: jest.fn(),
once: jest.fn(),
removeListener: jest.fn(),
quitAndInstall: jest.fn(),
downloadUpdate: jest.fn(),
checkForUpdates: jest.fn(),
},
}));
jest.mock('common/config', () => ({
canUpgrade: true,
}));
jest.mock('main/notifications', () => ({
displayUpgrade: jest.fn(),
displayRestartToUpgrade: jest.fn(),
}));
jest.mock('main/windows/windowManager', () => ({
sendToRenderer: jest.fn(),
}));
describe('main/autoUpdater', () => {
describe('constructor', () => {
afterEach(() => {
jest.resetAllMocks();
});
it('should notify user on update-available', () => {
let cb;
autoUpdater.on.mockImplementation((event, callback) => {
if (event === 'update-available') {
cb = callback;
}
});
const updateManager = new UpdateManager();
updateManager.notify = jest.fn();
cb({version: '5.1.0'});
expect(updateManager.versionAvailable).toBe('5.1.0');
expect(updateManager.notify).toHaveBeenCalled();
});
it('should notify user on update-downloaded', () => {
let cb;
autoUpdater.on.mockImplementation((event, callback) => {
if (event === 'update-downloaded') {
cb = callback;
}
});
const updateManager = new UpdateManager();
updateManager.notifyDownloaded = jest.fn();
cb({version: '5.1.0'});
expect(updateManager.versionDownloaded).toBe('5.1.0');
expect(updateManager.notifyDownloaded).toHaveBeenCalled();
});
it('should check for updates when emitted', () => {
let cb;
ipcMain.on.mockImplementation((event, callback) => {
if (event === CHECK_FOR_UPDATES) {
cb = callback;
}
});
const updateManager = new UpdateManager();
updateManager.checkForUpdates = jest.fn();
cb();
expect(updateManager.checkForUpdates).toHaveBeenCalledWith(true);
});
});
describe('notify', () => {
beforeEach(() => {
jest.useFakeTimers();
});
afterEach(() => {
jest.runAllTimers();
});
it('should add a new timeout', () => {
const updateManager = new UpdateManager();
updateManager.notify();
updateManager.notify = jest.fn();
jest.runAllTimers();
expect(updateManager.notify).toBeCalled();
});
it('should display upgrade notification', () => {
const updateManager = new UpdateManager();
updateManager.versionAvailable = '5.1.0';
updateManager.notify();
updateManager.notify = jest.fn();
expect(displayUpgrade).toHaveBeenCalledWith('5.1.0', expect.any(Function));
});
it('should display downloaded upgrade notification', () => {
const updateManager = new UpdateManager();
updateManager.versionDownloaded = '5.1.0';
updateManager.notify();
updateManager.notify = jest.fn();
expect(displayRestartToUpgrade).toHaveBeenCalledWith('5.1.0', expect.any(Function));
});
});
describe('checkForUpdates', () => {
beforeEach(() => {
autoUpdater.checkForUpdates.mockReturnValue(Promise.resolve());
jest.useFakeTimers();
});
afterEach(() => {
jest.resetAllMocks();
});
it('should show dialog if update is not available', () => {
autoUpdater.once.mockImplementation((event, callback) => {
if (event === 'update-not-available') {
callback();
}
});
const updateManager = new UpdateManager();
updateManager.displayNoUpgrade = jest.fn();
updateManager.checkForUpdates(true);
updateManager.checkForUpdates = jest.fn();
expect(updateManager.displayNoUpgrade).toHaveBeenCalled();
});
it('should check again at the next interval', () => {
const updateManager = new UpdateManager();
updateManager.checkForUpdates();
updateManager.checkForUpdates = jest.fn();
jest.runAllTimers();
expect(updateManager.checkForUpdates).toBeCalled();
});
});
});

182
src/main/autoUpdater.ts Normal file
View file

@ -0,0 +1,182 @@
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import path from 'path';
import {dialog, ipcMain, app, nativeImage} from 'electron';
import log from 'electron-log';
import {autoUpdater, ProgressInfo, UpdateInfo} from 'electron-updater';
import {displayUpgrade, displayRestartToUpgrade} from 'main/notifications';
import {CANCEL_UPGRADE, UPDATE_AVAILABLE, UPDATE_DOWNLOADED, CHECK_FOR_UPDATES, UPDATE_SHORTCUT_MENU, UPDATE_PROGRESS} from 'common/communication';
import Config from 'common/config';
import WindowManager from './windows/windowManager';
const NEXT_NOTIFY = 86400000; // 24 hours
const NEXT_CHECK = 3600000; // 1 hour
log.transports.file.level = 'info';
autoUpdater.logger = log;
autoUpdater.autoDownload = false;
autoUpdater.disableWebInstaller = true;
const assetsDir = path.resolve(app.getAppPath(), 'assets');
const appIconURL = path.resolve(assetsDir, 'appicon_with_spacing_32.png');
const appIcon = nativeImage.createFromPath(appIconURL);
/** to test this during development
* add the following to electron-builder.json in the publish entry
{
"provider": "generic",
"url": "http://localhost:8000"
},
* create a packaged build, copy that to a directory B (I usually do a third C copy to be able to go back without packaging again)
* upgrade the package.json version
* package a second copy of the app
* on release dir setup an http server (using `python -m SimpleHTTPServer` should match the above entry)
* start the app from directory B
* if the app upgraded and you want to repeat, simply copy C into B if you did the C step, if not, package again.
* yeah, it is a time consuming process :( improve this doc if you find a way to go faster.
**/
export class UpdateManager {
lastNotification?: NodeJS.Timeout;
lastCheck?: NodeJS.Timeout;
versionAvailable?: string;
versionDownloaded?: string;
constructor() {
autoUpdater.on('error', (err: Error) => {
log.error(`[Mattermost] There was an error while trying to update: ${err}`);
});
autoUpdater.on('update-available', (info: UpdateInfo) => {
autoUpdater.removeListener('update-not-available', this.displayNoUpgrade);
this.versionAvailable = info.version;
ipcMain.emit(UPDATE_SHORTCUT_MENU);
log.info(`[Mattermost] available version ${info.version}`);
this.notify();
});
autoUpdater.on('update-downloaded', (info: UpdateInfo) => {
this.versionDownloaded = info.version;
ipcMain.emit(UPDATE_SHORTCUT_MENU);
log.info(`[Mattermost] downloaded version ${info.version}`);
this.notifyDownloaded();
});
autoUpdater.on('download-progress', (progress: ProgressInfo) => {
WindowManager.sendToRenderer(UPDATE_PROGRESS, progress.total, progress.delta, progress.transferred, progress.percent, progress.bytesPerSecond);
});
ipcMain.on(CANCEL_UPGRADE, () => {
log.info('[Mattermost] User Canceled upgrade');
});
ipcMain.on(CHECK_FOR_UPDATES, () => {
this.checkForUpdates(true);
});
}
notify = (): void => {
if (this.lastNotification) {
clearTimeout(this.lastNotification);
}
this.lastNotification = setTimeout(this.notify, NEXT_NOTIFY);
if (this.versionDownloaded) {
this.notifyDownloaded();
} else if (this.versionAvailable) {
this.notifyUpgrade();
}
}
notifyUpgrade = (): void => {
WindowManager.sendToRenderer(UPDATE_AVAILABLE, this.versionAvailable);
displayUpgrade(this.versionAvailable || 'unknown', this.handleDownload);
}
notifyDownloaded = (): void => {
WindowManager.sendToRenderer(UPDATE_DOWNLOADED, this.versionDownloaded);
displayRestartToUpgrade(this.versionDownloaded || 'unknown', this.handleUpdate);
}
handleDownload = (): void => {
if (this.lastCheck) {
clearTimeout(this.lastCheck);
}
dialog.showMessageBox({
title: 'Mattermost',
message: 'New desktop version available',
detail: 'A new version of the Mattermost Desktop app is available for you to download and install now.',
icon: appIcon,
buttons: ['Download', 'Remind me Later'],
type: 'info',
defaultId: 0,
cancelId: 1,
}).then(({response}) => {
if (response === 0) {
autoUpdater.downloadUpdate();
}
});
}
handleOnQuit = (): void => {
if (this.versionDownloaded) {
autoUpdater.quitAndInstall(true, false);
}
}
handleUpdate = (): void => {
dialog.showMessageBox({
title: 'Mattermost',
message: 'A new version is ready to install',
detail: 'A new version of the Mattermost Desktop app is ready to install.',
icon: appIcon,
buttons: ['Restart and Update', 'Remind me Later'],
type: 'info',
defaultId: 0,
cancelId: 1,
}).then(({response}) => {
if (response === 0) {
autoUpdater.quitAndInstall();
}
});
}
displayNoUpgrade = (): void => {
const version = app.getVersion();
dialog.showMessageBox({
title: 'Mattermost',
icon: appIcon,
message: 'You\'re up to date',
type: 'info',
buttons: ['OK'],
detail: `You are using the latest version of the Mattermost Desktop App (version ${version}). You'll be notified when a new version is available to install.`,
});
}
checkForUpdates = (manually: boolean): void => {
if (!Config.canUpgrade) {
log.info('auto updates are disabled');
return;
}
if (this.lastCheck) {
clearTimeout(this.lastCheck);
}
if (!this.lastNotification || manually) {
if (manually) {
autoUpdater.once('update-not-available', this.displayNoUpgrade);
}
autoUpdater.checkForUpdates().catch((reason) => {
log.error(`[Mattermost] Failed to check for updates: ${reason}`);
});
this.lastCheck = setTimeout(() => this.checkForUpdates(false), NEXT_CHECK);
}
}
}
const updateManager = new UpdateManager();
export default updateManager;

View file

@ -10,8 +10,9 @@ import {Config} from 'common/config';
import {TabType, getTabDisplayName} from 'common/tabs/TabView';
import WindowManager from 'main/windows/windowManager';
import {UpdateManager} from 'main/autoUpdater';
export function createTemplate(config: Config) {
export function createTemplate(config: Config, updateManager: UpdateManager) {
const separatorItem: MenuItemConstructorOptions = {
type: 'separator',
};
@ -260,6 +261,30 @@ export function createTemplate(config: Config) {
};
template.push(windowMenu);
const submenu = [];
if (updateManager && config.canUpgrade) {
if (updateManager.versionDownloaded) {
submenu.push({
label: 'Restart and Update',
click() {
updateManager.handleUpdate();
},
});
} else if (updateManager.versionAvailable) {
submenu.push({
label: 'Download Update',
click() {
updateManager.handleDownload();
},
});
} else {
submenu.push({
label: 'Check for Updates',
click() {
updateManager.checkForUpdates(true);
},
});
}
}
if (config.data?.helpLink) {
submenu.push({
label: 'Learn More...',
@ -286,7 +311,7 @@ export function createTemplate(config: Config) {
return template;
}
export function createMenu(config: Config) {
// Electron is enforcing certain variables that it doesn't need
return Menu.buildFromTemplate(createTemplate(config) as Array<MenuItemConstructorOptions | MenuItem>);
export function createMenu(config: Config, updateManager: UpdateManager) {
// TODO: Electron is enforcing certain variables that it doesn't need
return Menu.buildFromTemplate(createTemplate(config, updateManager) as Array<MenuItemConstructorOptions | MenuItem>);
}

View file

@ -0,0 +1,46 @@
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import path from 'path';
import {app, Notification} from 'electron';
const assetsDir = path.resolve(app.getAppPath(), 'assets');
const appIconURL = path.resolve(assetsDir, 'appicon_48.png');
const defaultOptions = {
title: 'New desktop version available',
body: 'A new version is available for you to download now.',
silent: false,
icon: appIconURL,
urgency: 'normal' as Notification['urgency'],
};
export class NewVersionNotification extends Notification {
constructor() {
const options = {...defaultOptions};
if (process.platform === 'win32') {
options.icon = appIconURL;
} else if (process.platform === 'darwin') {
// Notification Center shows app's icon, so there were two icons on the notification.
Reflect.deleteProperty(options, 'icon');
}
super(options);
}
}
export class UpgradeNotification extends Notification {
constructor() {
const options = {...defaultOptions};
options.title = 'Click to restart and install update';
options.body = 'A new desktop version is ready to install now.';
if (process.platform === 'win32') {
options.icon = appIconURL;
} else if (process.platform === 'darwin') {
// Notification Center shows app's icon, so there were two icons on the notification.
Reflect.deleteProperty(options, 'icon');
}
super(options);
}
}

View file

@ -13,6 +13,7 @@ import WindowManager from '../windows/windowManager';
import {Mention} from './Mention';
import {DownloadNotification} from './Download';
import {NewVersionNotification, UpgradeNotification} from './Upgrade';
export const currentNotifications = new Map();
@ -76,3 +77,27 @@ export function displayDownloadCompleted(fileName: string, path: string, serverN
});
download.show();
}
let upgrade: NewVersionNotification;
export function displayUpgrade(version: string, handleUpgrade: () => void): void {
if (upgrade) {
upgrade.close();
}
upgrade = new NewVersionNotification();
upgrade.on('click', () => {
log.info(`User clicked to upgrade to ${version}`);
handleUpgrade();
});
upgrade.show();
}
let restartToUpgrade;
export function displayRestartToUpgrade(version: string, handleUpgrade: () => void): void {
restartToUpgrade = new UpgradeNotification();
restartToUpgrade.on('click', () => {
log.info(`User requested perform the upgrade now to ${version}`);
handleUpgrade();
});
restartToUpgrade.show();
}

View file

@ -378,7 +378,7 @@ export class MattermostView extends EventEmitter {
findUnreadState = (favicon: string | null) => {
try {
this.view.webContents.send(IS_UNREAD, favicon, this.tab.name);
} catch (err) {
} catch (err: any) {
log.error(`There was an error trying to request the unread state: ${err}`);
log.error(err.stack);
}

View file

@ -15,6 +15,9 @@ import {MattermostView} from './MattermostView';
import {ViewManager} from './viewManager';
jest.mock('electron', () => ({
app: {
getAppPath: () => '/path/to/app',
},
dialog: {
showErrorBox: jest.fn(),
},

View file

@ -156,6 +156,7 @@ describe('main/windows/windowManager', () => {
it('should create the main window and add listeners', () => {
const window = {
on: jest.fn(),
once: jest.fn(),
};
createMainWindow.mockReturnValue(window);
windowManager.showMainWindow();
@ -166,6 +167,7 @@ describe('main/windows/windowManager', () => {
it('should open deep link when provided', () => {
const window = {
on: jest.fn(),
once: jest.fn(),
};
createMainWindow.mockReturnValue(window);
windowManager.showMainWindow('mattermost://server-1.com/subpath');

View file

@ -24,6 +24,7 @@ import {
BROWSER_HISTORY_BUTTON,
} from 'common/communication';
import urlUtils from 'common/utils/url';
import {SECOND} from 'common/utils/constants';
import Config from 'common/config';
import {getTabViewName, TAB_MESSAGING} from 'common/tabs/TabView';
@ -43,12 +44,14 @@ export class WindowManager {
assetsDir: string;
mainWindow?: BrowserWindow;
mainWindowReady: boolean;
settingsWindow?: BrowserWindow;
viewManager?: ViewManager;
teamDropdown?: TeamDropdownView;
currentServerName?: string;
constructor() {
this.mainWindowReady = false;
this.assetsDir = path.resolve(app.getAppPath(), 'assets');
ipcMain.on(HISTORY, this.handleHistory);
@ -94,6 +97,7 @@ export class WindowManager {
this.mainWindow.show();
}
} else {
this.mainWindowReady = false;
this.mainWindow = createMainWindow({
linuxAppIcon: path.join(this.assetsDir, 'linux', 'app_icon.png'),
});
@ -104,10 +108,15 @@ export class WindowManager {
return;
}
this.mainWindow.once('ready-to-show', () => {
this.mainWindowReady = true;
});
// window handlers
this.mainWindow.on('closed', () => {
log.warn('main window closed');
delete this.mainWindow;
this.mainWindowReady = false;
});
this.mainWindow.on('unresponsive', () => {
CriticalErrorHandler.setMainWindow(this.mainWindow!);
@ -189,16 +198,34 @@ export class WindowManager {
ipcMain.emit(RESIZE_MODAL, null, bounds);
}
sendToRenderer = (channel: string, ...args: any[]) => {
if (!this.mainWindow) {
// max retries allows the message to get to the renderer even if it is sent while the app is starting up.
sendToRendererWithRetry = (maxRetries: number, channel: string, ...args: any[]) => {
if (!this.mainWindow || !this.mainWindowReady) {
this.showMainWindow();
if (maxRetries > 0) {
log.info(`Can't send ${channel}, will retry`);
setTimeout(() => {
this.sendToRendererWithRetry(maxRetries - 1, channel, ...args);
}, SECOND);
} else {
log.error(`Unable to send the message to the main window for message type ${channel}`);
}
return;
}
this.mainWindow!.webContents.send(channel, ...args);
if (this.settingsWindow && this.settingsWindow.isVisible()) {
this.settingsWindow.webContents.send(channel, ...args);
try {
this.settingsWindow.webContents.send(channel, ...args);
} catch (e) {
log.error(`There was an error while trying to communicate with the renderer: ${e}`);
}
}
}
sendToRenderer = (channel: string, ...args: any[]) => {
this.sendToRendererWithRetry(3, channel, ...args);
}
sendToAll = (channel: string, ...args: any[]) => {
this.sendToRenderer(channel, ...args);
if (this.settingsWindow) {

View file

@ -1,466 +0,0 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg">
<metadata>Copyright (C) 2021 by original authors @ fontello.com</metadata>
<defs>
<font id="compass-icons" horiz-adv-x="1000" >
<font-face font-family="compass-icons" font-weight="400" font-stretch="normal" units-per-em="1000" ascent="850" descent="-150" />
<missing-glyph horiz-adv-x="1000" />
<glyph glyph-name="mattermost" unicode="&#xe800;" d="M745 687l4-88c72-79 100-192 65-297-54-157-229-240-393-185-163 55-253 228-199 385 36 106 127 178 232 197l57 68c-178 4-345-106-405-283-74-218 43-455 261-529s454 43 528 262c60 177-6 366-150 470z m-102-261l-3 124-3 71-1 62c0 0 0 29-1 36 0 2-1 3-1 4l0 0-1 1c-1 2-3 3-5 4-2 1-5 1-7 0l0 0-1-1c-1 0-2-1-3-2-5-5-23-28-23-28l-38-48-46-55-77-97c0 0-36-44-28-99 8-54 49-81 80-92 32-10 80-14 120 25 39 38 38 95 38 95z" horiz-adv-x="1000" />
<glyph glyph-name="archive-outline" unicode="&#xe801;" d="M833-25h-666v458h83v-375h500v375h83v-458m-708 750h750v-250h-750v250m271-333h208c12 0 21-9 21-21v-63h-250v63c0 12 9 21 21 21m-188 250v-84h584v84h-584z" horiz-adv-x="1000" />
<glyph glyph-name="beach-umbrella-outline" unicode="&#xe802;" d="M329 521c75 75 179 108 275 100-25-33-46-75-50-117-54-4-104-29-141-66-38-38-63-88-71-142-42-8-84-25-117-50-8 100 29 200 104 275m-58 62c-146-145-167-370-58-533 0 42 16 88 50 121 45 46 108 58 166 46-16 54-4 121 46 166 46 46 108 59 167 46-17 54 0 121 46 167 33 33 75 50 116 50-166 100-387 83-533-63l0 0z m587-533l-58-58-296 296 59 58 295-296z" horiz-adv-x="1000" />
<glyph glyph-name="exclamation-thick" unicode="&#xe803;" d="M417 725h166l-41-458h-84l-41 458m166-667c0-46-37-83-83-83s-83 37-83 83 37 84 83 84 83-38 83-84z" horiz-adv-x="1000" />
<glyph glyph-name="gfycat" unicode="&#xe804;" d="M300 83h-58c-17 0-29 5-42 17-12 13-17 25-17 42s5 29 17 41c13 13 25 17 42 17h54c17 0 29 4 42 17 12 12 16 25 16 37v117c0 17-4 29-16 42-13 8-25 16-38 16-17 0-29-4-42-16-12-13-16-25-16-42 0-13 4-25 12-38l0 0c9-12 13-25 13-37 0-17-4-29-17-42s-25-16-42-16c-25 0-45 16-62 50-17 29-21 54-21 83 0 46 17 87 50 121 38 33 75 50 121 50s87-17 121-50 50-75 50-121v-117c0-46-17-87-50-121-34-33-71-50-117-50z m617 271c0-12-4-25-17-37-8-9-21-17-37-17h-71v-50c0-12-4-25-17-37-8-9-21-17-37-17-13 0-25 4-38 17-8 8-17 20-17 37v208c0 42 17 80 46 113 29 29 67 46 109 46h20c13 0 25-4 38-17 17-12 21-25 21-37s-4-25-17-38c-8-8-21-17-37-17h-21c-13 0-25-4-38-16-8-9-16-21-16-38v-54h70c13 0 25-4 38-17 17-4 21-16 21-29z m-279-104c0-12-5-25-17-37-8-9-21-17-38-17-12 0-25 4-37 17-8 8-17 20-17 37v171c0 12 4 25 17 37 8 9 21 17 37 17 13 0 25-4 38-17 8-8 17-20 17-37v-171z m-542 229c-8 34-13 63-13 63 0 8 5 16 13 12 0 0 8 0 17-4 12 0 25-4 37-8 25-4 46-13 46-13s-25-16-46-37c-21-25-33-59-33-59s-13 17-21 46z m408 0c9 29 13 63 13 63 0 8-4 12-13 12 0 0-29-4-54-12-21-4-46-13-46-13s25-16 46-37c21-25 33-59 33-59s13 17 21 46z m134 84c0-13-5-25-17-38-8-8-21-17-38-17-12 0-25 5-37 17-8 8-17 21-17 38 0 12 4 25 17 37 8 8 21 17 37 17 13 0 25-4 38-17s17-21 17-37z" horiz-adv-x="1000" />
<glyph glyph-name="globe" unicode="&#xe805;" d="M500 767c-229 0-417-188-417-417s188-417 417-417 417 188 417 417-188 417-417 417z m333-438c-12-16-70-50-166-66 0 29 0 58 0 87 0 21 0 38 0 54 50 9 100 21 137 38 4 4 13 4 17 8 8-29 12-67 12-100 0-8 0-12 0-21l0 0z m-395-162c20 0 41-4 62-4s42 0 63 4c-21-84-46-134-63-146-17 12-46 62-62 146z m62 79c-29 0-54 0-79 4 0 29-4 63-4 100 0 17 0 29 0 46 29-4 54-4 83-4s54 0 83 4c0-17 0-29 0-46 0-37-4-71-4-100-25-4-50-4-79-4z m75 233c-25-4-50-4-75-4s-50 0-75 4c17 117 54 188 75 204 21-16 58-87 75-204z m208 46c-29-12-70-29-125-37-8 66-25 129-45 175 70-25 129-71 170-138z m-566 0c41 63 100 113 175 138-21-46-38-105-50-175-54 12-96 25-125 37l0 0z m-34-75c5-4 9-4 17-8 38-17 83-29 138-38-5-16-5-33-5-54 0-29 0-58 5-87-96 16-155 50-167 66l0 0c0 9 0 13 0 21-4 33 0 71 12 100z m13-233c42-17 96-34 154-42 8-54 25-100 42-137-88 29-159 95-196 179z m608 0c-37-84-108-150-196-179 17 37 34 83 42 137 58 8 113 21 154 42l0 0z" horiz-adv-x="1000" />
<glyph glyph-name="iframe-list-outline" unicode="&#xe806;" d="M833 725h-666c-46 0-84-37-84-83v-584c0-45 38-83 84-83h666c46 0 84 38 84 83v584c0 46-38 83-84 83m0-667h-666v500h666v-500z m-416 292v83h333v-83h-333m-167 83h83v-83h-83v83m167-250v84h333v-84h-333m-167 84h83v-84h-83v84" horiz-adv-x="1000" />
<glyph glyph-name="oauth" unicode="&#xe807;" d="M500 17c-183 0-333 150-333 333s150 333 333 333 333-150 333-333-150-333-333-333m0 750c-229 0-417-188-417-417s188-417 417-417 417 188 417 417-188 417-417 417z m0-125c-162 0-292-129-292-292s130-292 292-292 292 130 292 292-129 292-292 292z m117-459c-4 0-9 0-13 0-16 0-33 13-37 25l-21 59h-96l-17-59c-4-12-20-25-37-25-4 0-8 0-13 0-20 5-33 30-25 50l80 255c8 16 20 29 37 29h42c4 0 8 0 12 0 9-4 17-9 21-13 4-4 4-8 4-12l84-254c8-25 0-46-21-55z m-325 167c0 71 37 138 96 175-5-4-5-12-9-17l-75-233c-8 25-12 50-12 75z m208-208c-12 0-25 0-37 4 12 12 25 29 29 46l4 12h4l4-16c4-17 17-34 29-46-8 0-20 0-33 0z m192 133l-79 233c0 9-5 13-9 17 63-33 104-100 104-175 0-25-4-50-16-75z" horiz-adv-x="1000" />
<glyph glyph-name="power-plug-outline" unicode="&#xe808;" d="M759 343l117 118c17 16 17 43 0 59-16 16-42 16-59 0l-117-118-148 148 118 117c16 17 16 43 0 59-16 17-43 17-59 0l-118-117-118 117c-16 17-42 17-58 0l-1 0c-16-16-16-43 0-59l30-29-133-133c-112-112-121-288-26-410-1-1-2-1-3-2l-88-88c-17-17-17-43 0-60s42-16 59 0l88 89c1 1 1 2 2 3 122-95 298-86 410 26l133 133 29-30c16-16 43-16 59 0l0 1c17 16 17 42 0 58l-117 118z m-163-221c-89-89-234-89-324 0s-89 235 0 324l133 133 324-324-133-133z" horiz-adv-x="1000" />
<glyph glyph-name="robot-happy" unicode="&#xe809;" d="M833 404h30c29 0 54-25 54-54v-112c0-30-25-55-54-55h-30v221z m-695 0h29v-221h-29c-30 0-55 25-55 55v112c0 29 25 54 55 54z m475-108c29 0 54 25 54 54s-25 54-54 54-55-25-55-54 21-54 55-54z m-225 0c29 0 54 25 54 54s-21 54-54 54-55-25-55-54 25-54 55-54z m-55-75c0-4 0-8 0-8 0-63 75-113 167-113s167 50 167 113c0 4 0 8 0 8-42-21-100-38-167-38s-125 13-167 38z m113 350v58c0 29 25 54 54 54s54-25 54-54v-54h113c62 0 112-50 112-112v-334c0-62-50-112-112-112h-334c-62 0-112 50-112 112v334c0 62 50 112 112 112h113v-4z" horiz-adv-x="1000" />
<glyph glyph-name="server-outline" unicode="&#xe80a;" d="M792 725h-584c-45 0-83-37-83-83v-125-292-125c0-46 38-83 83-83h584c46 0 83 37 83 83v125 292 125c0 46-37 83-83 83z m-584-292h584v-125h-584v125z m584-333h-584v125h584v-125z m-584 417v125h584v-125h-584z m250 41h-166v42h166v-42z m167 0h-83v42h83v-42z m-167-208h-166v42h166v-42z m167 0h-83v42h83v-42z m-167-208h-166v41h166v-41z m167 0h-83v41h83v-41z" horiz-adv-x="1000" />
<glyph glyph-name="slash-forward-box-outline" unicode="&#xe80b;" d="M792 725h-584c-45 0-83-37-83-83v-584c0-45 38-83 83-83h584c46 0 83 38 83 83v584c0 46-37 83-83 83z m0-667h-584v584h584v-584z m-125 500h-100l-234-416h100l234 416z" horiz-adv-x="1000" />
<glyph glyph-name="webhook-incoming" unicode="&#xe80c;" d="M638 388l-59 108c13 12 17 29 21 46 0 41-33 79-75 83-42 0-83-33-83-75s33-79 79-83h8l54-104c13 12 34 16 55 25z m-234 104c-29 66 0 141 63 171 66 29 141-5 166-71 17-38 13-79-4-113l50-29c29 50 34 113 9 171-42 96-155 146-250 104s-142-154-100-250c8-25 29-50 45-67l-95-158c-17 4-34 0-50-8-38-21-55-67-34-109 21-37 71-54 109-33 37 21 54 67 33 104 0 4-4 4-4 9l129 208-13 8c-25 13-45 34-54 63z m59-292h-55v-42c-4-20-8-41-25-58-41-58-120-75-179-33s-71 121-29 179c25 33 58 54 100 58v59c-58-5-112-30-150-84-58-87-42-208 46-266 87-63 204-42 267 45 12 21 20 42 25 63-5 12-5 25-5 42 0 12 0 25 5 37z m204 4v84l-125-125 125-125v83h166v83h-166z" horiz-adv-x="1000" />
<glyph glyph-name="webhook-outgoing" unicode="&#xe80d;" d="M638 388l-59 108c13 12 17 29 21 46 0 41-33 79-75 83-42 0-83-33-83-75s33-79 79-83h8l54-104c13 12 34 16 55 25z m-234 104c-29 66 0 141 63 171 66 29 141-5 166-71 17-38 13-79-4-113l50-29c29 50 34 113 9 171-42 96-155 146-250 104s-142-154-100-250c8-25 29-50 45-67l-95-158c-17 4-34 0-50-8-38-21-55-67-34-109 21-37 71-54 109-33 37 21 54 67 33 104 0 4-4 4-4 9l129 208-13 8c-25 13-45 34-54 63z m59-292h-55v-42c-4-20-8-41-25-58-41-58-120-75-179-33s-71 121-29 179c25 33 58 54 100 58v59c-58-5-112-30-150-84-58-87-42-208 46-266 87-63 204-42 267 45 12 21 20 42 25 63-5 12-5 25-5 42 0 12 0 25 5 37z m245 4v84l125-125-125-125v83h-166v83h166z" horiz-adv-x="1000" />
<glyph glyph-name="image-area-outline" unicode="&#xe80e;" d="M833 100h-666v500h666m0 83h-666c-47 0-84-37-84-83v-500c0-46 38-83 84-83h666c46 0 84 37 84 83v500c0 46-38 83-84 83m-625-500l146 188 104-125 146 187 188-250" horiz-adv-x="1000" />
<glyph glyph-name="emoticon-plus-outline" unicode="&#xe80f;" d="M604 350c34 0 63 29 63 63s-29 62-63 62-62-29-62-62 29-63 62-63m-250 0c34 0 63 29 63 63s-29 62-63 62-62-29-62-62 29-63 62-63m436 4c1-8 2-17 2-25 0-172-140-312-313-312s-312 140-312 312 140 313 312 313c8 0 17-1 25-2 4 29 14 57 27 81-17 2-34 4-52 4-218 0-396-177-396-396s178-396 396-396 396 178 396 396c0 18-2 35-4 52-24-13-52-23-81-27z m-82 413h84v-125h125v-84h-125v-125h-84v125h-125v84h125v125z m-442-521c33-85 116-146 213-146s180 61 214 146h-427z" horiz-adv-x="1000" />
<glyph glyph-name="mark-as-unread" unicode="&#xe810;" d="M125 642v-84h750v84h-750z m750-209v-166h-83l-84 83 84 83h83z m-750-41v-84h500v84h-500m0-250v-84h750v84h-750z" horiz-adv-x="1000" />
<glyph glyph-name="arrow-back-ios" unicode="&#xe811;" d="M771 688l-75 75-413-413 413-413 75 76-338 337 338 338z m-21 4l-75 75-425-417 425-417 75 75-350 342 350 342z" horiz-adv-x="1000" />
<glyph glyph-name="arrow-forward-ios" unicode="&#xe812;" d="M245 678l328-328-328-328 88-89 417 417-417 417z" horiz-adv-x="1000" />
<glyph glyph-name="brand-zoom" unicode="&#xe813;" d="M500 767c-229 0-417-188-417-417s188-417 417-417 417 188 417 417-188 417-417 417z m113-504c0-21 0-30-5-38s-8-12-16-17c-9-4-17-4-38-4h-166c-50 0-75 0-92 9-17 8-29 20-38 37-8 21-8 42-8 92v96c0 20 0 29 4 33 4 8 9 12 17 17 8 4 17 4 33 4h171c50 0 75 0 92-9 16-8 29-20 37-37 9-21 9-42 9-92v-91z m141-13c0-17 0-21 0-25-4-8-12-12-25-12-4 0-8 4-21 16l-50 38c-8 8-12 8-12 12-4 9-8 17-13 25 0 4 0 9 0 21v50c0 8 0 17 0 21 0 8 5 17 13 25 4 4 8 8 12 12l50 38c13 8 17 12 21 17 9 4 21-5 25-13 0-4 0-12 0-25v-200z" horiz-adv-x="1000" />
<glyph glyph-name="menu-variant" unicode="&#xe814;" d="M125 642h750v-84h-750v84z m0-250h542v-84h-542v84z m0-250h750v-84h-750v84z" horiz-adv-x="1000" />
<glyph glyph-name="message-check" unicode="&#xe815;" d="M833 767h-666c-46 0-84-38-84-84v-750l167 167h583c46 0 84 37 84 83v500c0 47-38 84-84 84z m-145-250l-230-229-145 145 58 59 87-87 171 170 59-58z" horiz-adv-x="1000" />
<glyph glyph-name="airplane-variant" unicode="&#xe816;" d="M804 654c-17 17-48 19-67 0-14-14-29-30-46-47l-3-3c-18-18-37-37-55-55l-16-16-312 63-39-39 292-83-233-233-83 21-42-41 124-47 46-124 42 42-21 83 233 233 83-292 39 39-63 312 120 120c7 7 12 19 12 34 1 15-4 26-11 33z m-126 59c54 53 138 47 185 0 25-26 36-61 36-93-1-32-12-67-37-92l-88-88 57-286c3-17-2-34-15-47l-87-87c-28-28-76-16-87 22l-59 207-99-99 13-55c5-18 0-36-13-49l-89-89c-27-27-72-17-85 19l-51 133-133 51c-36 13-46 58-19 85l89 89c13 13 31 18 49 13l55-13 99 99-207 59c-38 11-50 59-22 87l87 87c13 13 30 18 47 15l286-57c13 13 26 26 38 39l4 3c16 17 32 33 46 47z" horiz-adv-x="1000" />
<glyph glyph-name="food-apple" unicode="&#xe817;" d="M779 767c-83 0-158-13-221-50-29-17-50-38-66-67-4 4-9 8-13 13-33 33-75 62-112 79-21 8-46-4-50-25-9-21 4-46 25-50 25-9 54-29 79-54 12-13 21-25 25-34-71 9-142 4-200-29-83-42-129-129-121-246 13-125 58-216 125-279 71-63 158-92 250-92 167 0 350 121 375 371 13 117-37 204-112 250 41 46 66 104 70 159 0 29-25 54-54 54z m-37-84c-9-29-29-62-59-87-33-29-79-50-141-42 8 50 29 75 58 96 38 17 83 29 142 33z m-242-208c71-12 138-4 188 21 58-17 112-79 104-183-21-209-167-296-292-296-75 0-142 25-192 71-50 45-87 120-100 225-8 87 25 137 75 162 50 25 125 29 205 0 4 0 8 0 8-4 0 4 4 4 4 4z" horiz-adv-x="1000" />
<glyph glyph-name="leaf-outline" unicode="&#xe818;" d="M242 71c116-96 308-109 433 17 63 62 117 175 150 287 38 113 63 229 67 304 4 46-42 67-75 50-34-16-79-29-129-37-25-4-55-9-80-17l0 0c-29-4-54-8-83-17-117-16-242-50-325-133-117-117-96-275-21-387-4-13-12-25-16-38-13-29-21-50-25-67-5-8-9-16-13-25-8-21 8-46 29-50 21-8 46 9 50 29l0 0 0 0c0 0 0 5 0 5 0 4 4 8 4 16 5 17 13 38 25 63 5 0 9 0 9 0z m504 333c-38-108-83-204-129-254-100-100-254-83-338 0 17 29 38 63 63 92 46 58 121 112 187 154 34 21 59 37 79 50 9 4 17 8 25 12 5 0 5 5 9 5l0 0 0 0 0 0c21 8 29 33 16 54-8 21-33 29-54 16-12-4-25-12-37-20-21-13-50-30-84-50-66-42-150-105-204-171-21-25-37-50-54-71-42 79-37 175 29 246 63 62 167 91 279 116 30 5 55 13 84 17l0 0c29 4 54 8 83 17 33 8 67 16 100 25-4-71-25-154-54-238z" horiz-adv-x="1000" />
<glyph glyph-name="basketball" unicode="&#xe819;" d="M915 318c1 10 2 21 2 32 0 7-1 13-1 20l0 0c-11 220-193 397-416 397-230 0-417-187-417-417 0-223 177-405 397-416l0 0c7 0 13-1 20-1 11 0 22 1 33 2 203 16 366 179 382 383z m-432-308c-72 4-138 29-192 71l212 212 73-73c-49-58-82-131-93-210z m146 156l83-82c-43-35-95-59-151-69 10 56 34 108 68 151z m60 59c42 32 92 55 146 64-10-54-32-104-65-146l-81 82z m151 142c-77-11-147-42-205-88l-73 73 207 207c42-54 68-120 71-192z m-547 253c49 38 107 62 171 69-7-64-31-122-69-171l-102 102z m247 68c64-7 122-32 170-70l-207-207-54 53c51 63 83 140 91 224z m-306-126l103-103c-49-40-110-66-176-73 7 66 33 127 73 176z m-72-252c86 8 166 42 229 95l53-53-212-212c-38 48-63 106-70 170z" horiz-adv-x="1000" />
<glyph glyph-name="emoticon-custom-outline" unicode="&#xe81a;" d="M875 608c0 5 0 9 0 13 0 4 0 12 0 17l38 29c0 0 0 4 0 4l-30 50c0 0-4 4-4 0l-41-17c-9 4-17 13-25 13l-9 46c0 0 0 4-4 4h-54c0 0-4 0-4-4l-9-46c-8-4-16-9-25-13l-41 17c0 0-4 0-4 0l-30-50c0 0 0-4 0-4l34-34c0-4 0-12 0-16 0-4 0-9 0-13l-38-29c0 0 0-4 0-4l29-50c0 0 5-4 5 0l41 17c9-5 17-9 25-13l9-46c0 0 0-4 4-4h54c0 0 4 0 4 4l8 46c9 4 17 8 25 13l42-17c0 0 4 0 4 0l29 50c0 0 0 4 0 4l-33 33z m-104-29c-25 0-42 17-42 42 0 25 17 42 42 42 21 0 42-17 42-42 0-25-17-42-42-42z m-213-208c-12 12-16 29-16 46 0 16 4 29 16 41 17 9 30 17 46 17 17 0 34-8 46-21 13-12 21-25 21-41 0-17-8-34-21-46-12-13-25-21-46-21-16 4-29 12-46 25z m-204-21c-16 0-33 8-46 21-8 12-16 25-16 42 0 16 4 29 16 41 17 13 30 21 46 21 17 0 34-8 46-21 13-12 21-25 21-41 0-17-8-34-21-46-12-9-29-17-46-17z m517 29c4-21 4-41 4-50 0-71-17-137-54-200-33-58-83-108-142-142-62-37-129-54-200-54-71 0-137 17-200 54-58 34-108 84-141 142-38 63-55 129-55 200 0 71 17 138 55 200 33 59 83 109 141 142 63 37 129 54 200 54 13 0 29 0 50-4-12-25-25-54-25-79-12 0-21 0-25 0-58 0-108-13-158-42-46-29-83-67-113-112-29-50-41-100-41-159s12-108 41-158c30-46 67-83 113-113 50-29 100-41 158-41 59 0 109 12 159 41 45 30 83 67 112 113 29 50 42 100 42 158 0 4 0 13 0 25 25 4 54 13 79 25z m-604-133h425c-17-42-46-79-84-104-37-25-83-42-129-42-50 0-91 13-129 42-37 25-67 62-83 104z" horiz-adv-x="1000" />
<glyph glyph-name="message-check-outline" unicode="&#xe81b;" d="M833 767h-666c-46 0-84-38-84-84v-750l167 167h583c47 0 84 37 84 83v500c0 46-37 84-84 84m0-584h-583l-83-83v583h666m-145-166l-230-229-145 145 58 59 87-87 171 170 59-58z" horiz-adv-x="1000" />
<glyph glyph-name="image-broken-outline" unicode="&#xe81c;" d="M571 338c-16 16-42 16-59 0l-95-96-96 96c-16 16-42 16-59 0l-137-137v-143c0-46 37-83 83-83h584c46 0 83 37 83 83v332c0 23-27 34-43 18l-165-166-96 96z m221-89v-191h-584v108l84 83 95-95c17-16 43-16 59 0l96 95 95-95c8-8 19-12 30-12 10 0 21 4 29 12l96 95z m0 476h-584c-46 0-83-37-83-83v-233c0 0 0 0 0 0l0-58c0-22 27-33 42-18l125 125 95-96c17-16 43-16 59 0l96 96 95-96c8-8 19-12 30-12 10 0 21 4 29 12l179 179v101c0 46-37 83-83 83z m0-149l-125-125-96 95c-16 16-42 16-59 0l-95-95-96 95c-16 16-42 16-59 0l-54-54v150h584v-66z" horiz-adv-x="1000" />
<glyph glyph-name="format-header" unicode="&#xe81d;" d="M292 683h83v-250h250v250h83v-583h-83v250h-250v-250h-83v583" horiz-adv-x="1000" />
<glyph glyph-name="circle-multiple-outline-lock" unicode="&#xe81e;" d="M917 183v63c0 80-66 146-146 146s-146-66-146-146v-63c-23 0-42-18-42-41v-209c0-23 19-41 42-41h292c23 0 41 18 41 41v209c0 23-18 41-41 41z m-229 63c0 46 37 83 83 83s83-37 83-83v-63h-166v63z m-224 390c39 30 88 47 140 47 123 0 222-96 229-217 30-8 58-23 82-42 1 10 2 20 2 30 0 173-140 313-313 313-103 0-195-50-252-128 15 2 29 3 44 3 23 0 46-2 68-6z m36-594c-31-16-67-25-104-25-127 0-229 102-229 229s102 229 229 229c22 0 43-3 63-9 51-14 94-46 124-89 16 23 37 43 60 59-13 16-26 32-42 45-55 48-126 77-205 77-173 0-313-140-313-312s140-313 313-313c36 0 71 7 104 18v91z m-86 285c-13 19-24 41-30 64-29-2-56-13-78-30 11-36 29-70 52-99 36-47 86-83 144-103 4 30 18 56 39 75-3 1-5 1-8 2-49 16-91 48-119 91z" horiz-adv-x="1000" />
<glyph glyph-name="server-variant" unicode="&#xe81f;" d="M333 558v42h-83v-42h83z m0-416h-83v-42h83v42z m292 458v-42h-208v42h208z m0-458h-208v-42h208v42z m292 541c0 46-38 84-84 84h-666c-46 0-84-38-84-84v-208c0-46 38-83 84-83h666c46 0 84 37 84 83v208z m-84 0v-208h-666v208h666z m84-458v-208c0-46-38-84-84-84h-666c-46 0-84 38-84 84v208c0 46 38 83 84 83h666c46 0 84-37 84-83z m-84 0h-666v-208h666v208z" horiz-adv-x="1000" />
<glyph glyph-name="server-variant-plus" unicode="&#xe820;" d="M708 163h-125v-84h125v-125h84v125h125v84h-125v125h-84v-125z m-458-63v42h83v-42h-83z m167 42h83v-42h-83v42z m-167 458h83v-42h-83v42z m167 0h208v-42h-208v42z m166-667h-416c-46 0-84 38-84 84v208c0 46 38 83 84 83h416c-25-25-45-50-62-83h-354v-208h358c13-34 33-59 58-84z m-416 459h666c46 0 84 37 84 83v208c0 46-38 84-84 84h-666c-46 0-84-38-84-84v-208c0-46 38-83 84-83z m0 291h666v-208h-666v208z" horiz-adv-x="1000" />
<glyph glyph-name="search-list" unicode="&#xe821;" d="M125 558v84h750v-84h-750z m225-416h-225v-84h271c-21 25-33 55-46 84z m21 250h-246v-84h217c4 30 12 59 29 84z m529-342l-67 67c63 87 55 212-25 291-87 88-233 88-325 0s-87-233 0-325c80-79 205-87 292-25l71-71c17-16 42-16 58 0 17 17 17 42-4 63z m-358 92c-59 58-59 150 0 204 58 58 150 58 204 0 58-58 58-150 0-204s-146-54-204 0z" horiz-adv-x="1000" />
<glyph glyph-name="brand-gitlab" unicode="&#xe822;" d="M914 285l-44 136c0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0l-88 272c-5 14-18 23-33 23-16 0-29-9-33-24l-84-257h-264l-84 257c-4 15-17 24-32 24 0 0-1 0-1 0-15 0-28-9-33-24l-88-271 0 0c0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0l-44-136c-7-21 0-43 18-56l385-280c0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1-1 2-1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0-1 0-1 1-1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0-1 0 0 0 0 0 0 1 0 1 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 2 0 3 0 0 0 0 0 0 0l0 0c0 0 0 0 0 0h0c0 0 0 0 0 0 1 0 2 0 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 1 0 2 0 0 0 0 0 0 0 0 1 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 1 0 1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 1 2 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0l385 280c18 13 25 35 18 56z m-165 382l75-232h-151l76 232z m62-271l-31-40-227-291 108 331 150 0 0 0z m-330-437l0 0c0 0 0 0 0 0 0 0 0 0 0 0z m-34 106l-258 331 0 0h151l107-331z m-196 602l76-232h-151l75 232z m-124-406c-4 2-5 7-4 11l33 102 243-311-272 198z m361-311c0 0 0 0 0 0 0 0 0 0 0 0-1 0-1 0-1 0 0 1 0 1-1 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 2-1 2-1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0z m12 79l-63 194-56 173h238l-119-367z m13-79c0 0 0 0 0 0 0 0-1 0-1 0 0 0 0 0 0 0 0 0 0 0 0-1 0 1 0 1 0 1 0 0 0 0 0 0 0 0 1 1 2 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0-1 0-1-1z m360 311l-272-198 243 311 33-101c1-5 0-10-4-12z" horiz-adv-x="1000" />
<glyph glyph-name="brand-google" unicode="&#xe823;" d="M668 539c-43 41-100 64-160 63-108 0-201-74-234-172-17-52-17-108 0-160h0c34-98 126-172 234-172 57 0 105 15 142 40v0c44 29 74 75 83 127h-225v160h393c5-28 7-56 7-84 0-127-45-234-124-307l0 0c-69-64-163-101-276-101-157 0-301 89-372 230-59 118-59 256 0 374 71 141 215 230 372 230 104 1 204-38 279-109l-119-119z" horiz-adv-x="1000" />
<glyph glyph-name="brand-office-365" unicode="&#xe824;" d="M125 100v500l500 146 250-63v-645l-271-84-437 146 458-62v604l-333-84v-395l-167-63z" horiz-adv-x="1000" />
<glyph glyph-name="brand-one-login" unicode="&#xe825;" d="M500-67c-230 0-417 187-417 417s187 417 417 417 417-187 417-417-187-417-417-417z m-104 542v-83h62v-209h105v209 83h-167z" horiz-adv-x="1000" />
<glyph glyph-name="application-cog" unicode="&#xe826;" d="M904 75v42l46 33c4 4 8 8 4 13l-41 70c0 5-9 5-13 5l-50-21c-12 8-25 16-37 21l-9 54c0 4-4 8-8 8h-83c-9 0-13-4-13-8l-8-54c-13-9-21-13-34-21l-50 21c-4 0-8 0-12-5l-42-70c0-5 0-9 4-13l46-33v-42l-46-33c-4-4-8-9-4-13l42-71c4-4 8-4 12-4l50 21c9-8 21-17 34-21l8-54c4-4 8-8 13-8h83c4 0 8 4 8 8l9 54c12 8 20 13 33 21l50-17c4 0 8 0 12 4l42 71c4 5 4 9 0 9l-46 33m-154-37c-33 0-62 29-62 62s29 63 62 63 63-30 63-63-30-62-63-62m-280-21h-262c-46 0-83 37-83 83v500c0 46 38 83 83 83h584c46 0 83-37 83-83v-237c-26 12-54 21-83 25v129h-584v-417h250c0-29 5-57 12-83z" horiz-adv-x="1000" />
<glyph glyph-name="key-variant-circle" unicode="&#xe827;" d="M500 767c230 0 417-187 417-417s-187-417-417-417-417 187-417 417 187 417 417 417z m125-293c9-9 13-20 13-32s-4-23-13-32c-9-9-20-13-32-13s-23 4-32 13c-9 9-13 20-13 32s4 23 13 32c9 9 20 13 32 13s23-4 32-13z m65 65c-27 27-60 40-98 40-37 0-69-13-96-40-21-22-34-47-39-76-4-28 0-55 14-80l-200-199 63-63 65 65 66-65 63 63-65 65 71 71c25-13 52-18 80-14 30 5 55 18 76 40 27 27 40 59 39 96 1 37-12 69-39 97z" horiz-adv-x="1000" />
<glyph glyph-name="car-outline" unicode="&#xe899;" d="M788 600c-9 25-34 42-59 42h-458c-29 0-50-17-58-42l-88-250v-333c0-21 21-42 42-42h41c25 0 42 21 42 42v41h500v-41c0-21 21-42 42-42h41c21 0 42 21 42 42v333l-87 250m-505-42h430l45-125h-516l41 125m509-416h-584v208h584v-208m-479 166c33 0 62-29 62-62m313 62c33 0 62-29 62-62-96-63-125-33-125 0z" horiz-adv-x="1000" />
<glyph glyph-name="jumbo-attachment-text" unicode="&#xe900;" d="M750 767h-335c-17 0-33-7-44-18l-186-183 0 0c-11-12-18-28-18-45v-504c0-46 37-84 83-84h500c46 0 83 38 83 84v666c0 46-37 84-83 84z m-375-73v-156h-159l159 156z m417-677c0-23-19-42-42-42h-500c-23 0-42 19-42 42v479h167c23 0 42 19 42 42v187h333c23 0 42-19 42-42v-666z m-146 375h-292c-11 0-21-10-21-21s10-21 21-21h292c11 0 21 9 21 21s-10 21-21 21z m0-84h-292c-11 0-21-9-21-20s10-21 21-21h292c11 0 21 9 21 21s-10 20-21 20z m0-83h-292c-11 0-21-9-21-21s10-21 21-21h292c11 0 21 10 21 21s-10 21-21 21z m-83-83h-209c-11 0-21-10-21-21s10-21 21-21h209c11 0 20 9 20 21s-9 21-20 21z" horiz-adv-x="1000" />
<glyph glyph-name="jumbo-attachment-word" unicode="&#xe901;" d="M750 767h-335c-17 0-33-7-44-18l-186-183 0 0c-11-12-18-28-18-45v-504c0-46 37-84 83-84h500c46 0 83 38 83 84v666c0 46-37 84-83 84z m-375-73v-156h-159l159 156z m417-677c0-23-19-42-42-42h-500c-23 0-42 19-42 42v479h167c23 0 42 19 42 42v187h333c23 0 42-19 42-42v-666z m-208 197c-1-6-3-14-5-22l-2-11c-2-10-3-19-4-27l-1-6c-1 7-2 16-4 25l-1 8c-2 11-4 20-6 26l0 3-36 140h-50l-35-140c-3-8-5-18-7-32l-1-3c-2-12-3-21-4-27-2 19-6 40-12 66l-31 136h-52l63-250h59l34 132c1 4 2 10 4 17l3 17c1 8 3 14 3 19l1 5c0-4 1-10 3-20l3-12c2-12 4-20 5-25l34-133h59l63 250h-52l-31-136z" horiz-adv-x="1000" />
<glyph glyph-name="jumbo-attachment-excel" unicode="&#xe902;" d="M750 767h-335c-17 0-33-7-44-18l-186-183 0 0c-11-12-18-28-18-45v-504c0-46 37-84 83-84h500c46 0 83 38 83 84v666c0 46-37 84-83 84z m-375-73v-156h-159l159 156z m417-677c0-23-19-42-42-42h-500c-23 0-42 19-42 42v479h167c23 0 42 19 42 42v187h333c23 0 42-19 42-42v-666z m-173 354h-61l-57-90-58 90h-62l83-121-89-129h61l62 94 62-94h65l-90 126 84 124z" horiz-adv-x="1000" />
<glyph glyph-name="jumbo-attachment-powerpoint" unicode="&#xe903;" d="M750 767h-335c-17 0-33-7-44-18l-186-183 0 0c-11-12-18-28-18-45v-504c0-46 37-84 83-84h500c46 0 83 38 83 84v666c0 46-37 84-83 84z m-375-73v-156h-159l159 156z m417-677c0-23-19-42-42-42h-500c-23 0-42 19-42 42v479h167c23 0 42 19 42 42v187h333c23 0 42-19 42-42v-666z m-277 354h-77v-250h51v89h22c30 0 53 7 69 21 16 14 24 35 24 62 0 26-7 45-23 58-15 13-37 20-66 20z m26-108c-8-7-20-10-35-10h-17v74h23c14 0 24-3 31-8 6-6 10-16 10-28 0-12-4-22-12-28z" horiz-adv-x="1000" />
<glyph glyph-name="jumbo-attachment-pdf" unicode="&#xe904;" d="M750 767h-335c-17 0-33-7-44-18l-186-183 0 0c-11-12-18-28-18-45v-504c0-46 37-84 83-84h500c46 0 83 38 83 84v666c0 46-37 84-83 84z m-375-73v-156h-159l159 156z m417-677c0-23-19-42-42-42h-500c-23 0-42 19-42 42v479h167c23 0 42 19 42 42v187h333c23 0 42-19 42-42v-666z m-147 246c-18 12-48 15-84 10-10 7-20 16-30 26-2 1-4 3-6 6 13 47 16 86 1 108-8 13-21 20-36 20h-1c-19 0-36-12-44-31-12-29-6-71 17-108-4-10-7-18-10-25l-4-9c-6-16-10-24-15-34-68-34-101-60-100-89 2-15 12-29 32-34 6-2 12-3 17-3 38 0 67 30 95 83 10 5 22 10 35 16 11 5 24 9 37 12 36-23 70-33 93-24 15 7 25 21 25 38 0 16-8 30-22 38z m-213-87c-19-30-38-45-57-40l-2 1-1 0-5 2 3 5c5 8 24 21 53 37l3 2 16 9-10-16z m46 212c2 7 6 10 11 10h0c4 0 6-1 8-4 6-10 5-36-3-70l-3-13-6 12c-11 25-14 50-7 65z m53-146c-12-3-23-7-33-11-8-4-13-6-17-8l-2-1-11-5 5 12c2 4 4 8 6 13l2 4 3 8c3 6 5 12 7 18l2 6 3 7 5-6c2-2 4-4 5-5 7-7 14-13 21-19l6-4 7-6-9-3z m101-20l-2-2c-6-4-23 0-44 10l-2 1-16 8 18 1c18 1 33-1 40-6 4-2 5-5 6-9v-1l0-2z" horiz-adv-x="1000" />
<glyph glyph-name="jumbo-attachment-image" unicode="&#xe905;" d="M750 767h-335c-17 0-33-7-44-18l-186-183 0 0c-11-12-18-28-18-45v-504c0-46 37-84 83-84h500c46 0 83 38 83 84v666c0 46-37 84-83 84z m-375-73v-156h-159l159 156z m417-677c0-23-19-42-42-42h-500c-23 0-42 19-42 42v479h167c23 0 42 19 42 42v187h333c23 0 42-19 42-42v-666z m-396 250c34 0 62 28 62 62s-28 63-62 63-63-28-63-63 28-62 63-62z m0 83c11 0 21-9 21-21s-10-21-21-21-21 10-21 21 9 21 21 21z m186-39c-4 8-12 13-21 14-9 0-18-3-23-11l-66-87-27 19c-12 8-28 5-36-6l-86-119c-6-8-7-19-3-28 5-8 14-14 24-14h314c9 0 18 5 22 13s6 17 1 25l-99 194z m-208-190l60 82 29-20c10-7 24-5 31 4l62 83 77-149-259 0 0 0z" horiz-adv-x="1000" />
<glyph glyph-name="jumbo-attachment-video" unicode="&#xe906;" d="M750 767h-335c-17 0-33-7-44-18l-186-183 0 0c-11-12-18-28-18-45v-504c0-46 37-84 83-84h500c46 0 83 38 83 84v666c0 46-37 84-83 84z m-375-73v-156h-159l159 156z m417-677c0-23-19-42-42-42h-500c-23 0-42 19-42 42v479h167c23 0 42 19 42 42v187h333c23 0 42-19 42-42v-666z m-146 231l-233 117c-8 4-18 4-26-1-7-5-12-13-12-22v-234c0-9 5-17 12-22 5-2 9-4 14-4 4 0 8 1 12 3l233 117c9 4 14 13 14 23s-5 19-14 23z m-229-114v182l182-91-182-91z" horiz-adv-x="1000" />
<glyph glyph-name="jumbo-attachment-audio" unicode="&#xe907;" d="M750 767h-335c-17 0-33-7-44-18l-186-183 0 0c-11-12-18-28-18-45v-504c0-46 37-84 83-84h500c46 0 83 38 83 84v666c0 46-37 84-83 84z m-375-73v-156h-159l159 156z m417-677c0-23-19-42-42-42h-500c-23 0-42 19-42 42v479h167c23 0 42 19 42 42v187h333c23 0 42-19 42-42v-666z m-276 356l-76-65h-85l-22-1v-143l1-22h106l66-56 11-9 25 12v259l-1 14-25 11z m-16-228l-44 38h-81v84h81l44 38v-160z m140 177c-7 5-16 2-20-5-4-7-2-17 4-22 24-16 39-44 39-74 0-30-15-58-39-75-6-4-8-14-4-21 4-7 13-10 20-5 32 22 52 60 52 101 0 41-20 79-52 101z m-34-51c-7 4-16 1-19-6-4-7-2-16 4-21l1 0c8-5 13-14 13-23 0-9-4-17-11-22l-2-1c-7-4-9-13-5-21 3-8 12-10 19-6 17 10 28 29 28 50 0 21-11 40-28 50z" horiz-adv-x="1000" />
<glyph glyph-name="jumbo-attachment-generic" unicode="&#xe908;" d="M750 767h-335c-17 0-33-7-44-18l-186-183 0 0c-11-12-18-28-18-45v-504c0-46 37-84 83-84h500c46 0 83 38 83 84v666c0 46-37 84-83 84z m-375-73v-156h-159l159 156z m417-677c0-23-19-42-42-42h-500c-23 0-42 19-42 42v479h167c23 0 42 19 42 42v187h333c23 0 42-19 42-42v-666z m-162 251c-4 4-11 4-15 0l-123-124c-9-8-19-14-31-17-12-3-24-3-35 0-12 3-22 9-31 17s-14 19-17 31c-4 12-4 23 0 35 3 12 8 22 17 31l139 139c5 5 11 9 18 10l0 0c7 2 14 2 21 0 7-1 13-5 18-10s8-11 10-18l0 0c2-7 2-14 0-21l0 0c-2-7-5-12-10-18l-126-126c-2-2-5-3-9-3-3 0-5 1-8 3-2 3-4 6-4 9 0 3 2 6 4 8l110 110c4 5 4 11 0 15l-15 15c-4 4-10 4-14 0l-110-110c-7-7-12-15-14-24l0-1c-3-9-3-18 0-27l0 0c2-9 7-17 14-24 6-7 15-12 24-14 9-2 18-2 27 0l0 0c10 2 18 7 25 14l125 126c11 10 18 23 22 37 3 14 3 28 0 42-4 14-11 26-22 37s-22 17-36 21c-14 3-28 3-42 0-14-4-27-11-37-21l-139-140c-14-14-24-30-29-49-5-19-5-38 0-57 5-19 15-35 29-49 14-14 30-24 49-29 19-5 38-5 57 0 18 5 35 15 49 29l123 123c5 4 5 11 0 15l-14 15z" horiz-adv-x="1000" />
<glyph glyph-name="jumbo-attachment-patch" unicode="&#xe909;" d="M750 767h-335c-17 0-33-7-44-18l-186-183 0 0c-11-12-18-28-18-45v-504c0-46 37-84 83-84h500c46 0 83 38 83 84v666c0 46-37 84-83 84z m-375-73v-156h-159l159 156z m417-677c0-23-19-42-42-42h-500c-23 0-42 19-42 42v479h167c23 0 42 19 42 42v187h333c23 0 42-19 42-42v-666z m-200 408c-16 16-43 16-59 0l-206-206c-16-17-16-43 0-59l88-89c17-16 43-16 59 0l206 206c17 17 17 43 0 59l-88 89z m-107-122c8 8 22 8 30 0s8-21 0-29-22-8-30 0-8 21 0 29z m-37-37c9 9 22 9 30 0s8-21 0-29-21-8-30 0-8 21 0 29z m-3-165l-89 88 59 59 89-88-59-59z m77 92c-8-8-21-8-29 0s-9 21 0 29 21 8 29 0 8-21 0-29z m37 37c-8-9-21-9-30 0s-8 21 0 29 22 8 30 0c8-8 8-21 0-29z m33 18l-88 88 59 59 88-88-59-59z" horiz-adv-x="1000" />
<glyph glyph-name="jumbo-attachment-zip" unicode="&#xe90a;" d="M750 767h-335c-17 0-33-7-44-18l-186-183 0 0c-11-12-18-28-18-45v-504c0-46 37-84 83-84h500c46 0 83 38 83 84v666c0 46-37 84-83 84z m-375-73v-156h-159l159 156z m417-677c0-23-19-42-42-42h-83v4c0 9-8 17-17 17h-29c-9 0-17-8-17-17v-4h-354c-23 0-42 19-42 42v479h167c23 0 42 19 42 42v187h333c23 0 42-19 42-42v-666z m-146 583h-83c-12 0-21-9-21-21v-104c0-23 18-42 41-42h42c23 0 42 19 42 42v104c0 12-10 21-21 21z m-21-73c0-6-5-10-10-10h-21c-6 0-11 4-11 10v26c0 3 3 5 6 5h31c3 0 5-2 5-5v-26z m25-114h-29c-9 0-17-8-17-17v-8c0-10 8-17 17-17h29c9 0 17 7 17 17v8c0 9-8 17-17 17z m-92-84h30c9 0 16 8 16 17v8c0 9-7 17-16 17h-30c-9 0-16-8-16-17v-8c0-9 7-17 16-17z m92 0h-29c-9 0-17-7-17-16v-9c0-9 8-16 17-16h29c9 0 17 7 17 16v9c0 9-8 16-17 16z m-92-83h30c9 0 16 7 16 17v8c0 9-7 17-16 17h-30c-9 0-16-8-16-17v-8c0-10 7-17 16-17z m92 0h-29c-9 0-17-8-17-17v-8c0-9 8-17 17-17h29c9 0 17 8 17 17v8c0 9-8 17-17 17z m-92-83h30c9 0 16 7 16 16v9c0 9-7 16-16 16h-30c-9 0-16-7-16-16v-9c0-9 7-16 16-16z m92 0h-29c-9 0-17-8-17-17v-8c0-10 8-17 17-17h29c9 0 17 7 17 17v8c0 9-8 17-17 17z m-92-84h30c9 0 16 8 16 17v8c0 9-7 17-16 17h-30c-9 0-16-8-16-17v-8c0-9 7-17 16-17z m92 0h-29c-9 0-17-7-17-16v-9c0-9 8-16 17-16h29c9 0 17 7 17 16v9c0 9-8 16-17 16z m-62-41h-30c-9 0-16-8-16-17v-8c0-10 7-17 16-17h30c9 0 16 7 16 17v8c0 9-7 17-16 17z" horiz-adv-x="1000" />
<glyph glyph-name="jumbo-attachment-code" unicode="&#xe90b;" d="M750 767h-335c-17 0-33-7-44-18l-186-183 0 0c-11-12-18-28-18-45v-504c0-46 37-84 83-84h500c46 0 83 38 83 84v666c0 46-37 84-83 84z m-375-73v-156h-159l159 156z m417-677c0-23-19-42-42-42h-500c-23 0-42 19-42 42v479h167c23 0 42 19 42 42v187h333c23 0 42-19 42-42v-666z m-203 310c-4 3-10 3-14-1l-15-16c-2-2-3-5-3-7 0-3 1-6 3-7l57-50-57-50c-2-1-3-4-3-7 0-2 1-5 3-7l15-16c2-2 5-3 7-3 3 0 5 0 7 2l80 74c2 2 3 4 3 7s-1 5-3 7l-80 74z m-146-138c0 3-1 5-3 7l-57 50 57 50c2 1 3 4 3 6 0 3-1 6-2 8l-16 16c-4 4-10 4-14 1l-80-74c-2-2-3-4-3-7s1-5 3-7l80-74c2-2 4-2 7-2 2 0 5 1 7 3l16 16c2 2 2 5 2 7z m118 196c-2 3-4 4-6 5l-23 7c-5 1-10-2-12-7l-81-276c-1-3-1-5 0-8 2-2 4-4 6-4l23-7h0c1 0 2 0 3 0 4 0 8 3 9 7l81 276c1 3 1 5 0 7z" horiz-adv-x="1000" />
<glyph glyph-name="jumbo-attachment-image-broken" unicode="&#xe90c;" d="M704 262c-4 4-9 6-15 6 0 0 0 0 0 0-6 0-11-2-15-6l-113-113-111 111c-8 8-22 8-30 0l-108-109-110 110c-6 6-15 7-22 4-8-3-13-11-13-19v-33-51-145c0-46 37-84 83-84h500c46 0 83 38 83 84v104c0 5-2 11-6 14l-123 127z m88-245c0-23-19-42-42-42h-500c-23 0-42 19-42 42v179l89-89c8-8 21-8 29 0l109 109 111-111c8-8 22-8 30 0l113 112 103-105v-95z m-42 750h-335c-17 0-33-7-44-18l-186-183c-11-12-18-28-18-45v-108c0-6 2-11 6-15l124-124c8-8 21-8 29 0l109 109 111-112c4-4 10-6 15-6s11 2 15 6l113 113 109-111c6-6 15-8 22-5 8 3 13 11 13 20v29 366c0 46-37 84-83 84z m-375-73v-156h-159l159 156z m417-355l-88 89c-4 4-9 7-15 7 0 0 0 0 0 0-6 0-11-3-15-7l-113-113-111 112c-8 8-22 8-30 0l-108-109-104 103v40 35h167c23 0 42 19 42 42v187h333c23 0 42-19 42-42v-344z" horiz-adv-x="1000" />
<glyph glyph-name="account-multiple-outline" unicode="&#xf00f;" d="M679 175l-104 63c42 58 67 137 67 216 0 138-92 229-225 229s-225-91-225-229c0-79 25-158 66-216l-104-63c-41-21-71-67-71-112 0-71 59-130 125-130h417c71 0 125 59 125 130 0 45-29 91-71 112z m-404 279c0 100 63 146 142 146s141-46 141-146c0-62-20-129-58-175-21-29-50-46-87-46-38 0-63 17-88 46-29 46-50 113-50 175z m350-437h-417c-25 0-41 21-41 46 0 4 0 8 0 12 4 8 8 17 12 21 4 0 9 4 13 4l129 79c29-16 58-25 96-25s66 9 96 25l129-79c16-8 25-21 25-42s-21-41-42-41z m163 287c12 50 20 100 20 150 0 17 0 129-79 229-33 42-104 84-146 84-29 0-54-4-75-13 55-16 105-46 142-83 42-46 67-104 75-171 0-17 4-29 4-46 0-66-12-129-37-187l33-21c21-13 42-29 58-46 21-25 38-50 46-83 4-21 9-38 9-59 0-12 0-25-5-37 42 12 71 46 84 87 4 13 4 21 4 34-4 50-42 125-133 162z" horiz-adv-x="1000" />
<glyph glyph-name="airplane" unicode="&#xf01d;" d="M875 183v84l-333 208v229a63 63 0 0 1-63 63 63 63 0 0 1-62-63v-229l-334-208v-84l334 105v-230l-84-62v-63l146 42 146-42v63l-83 62v230l333-105z" horiz-adv-x="1000" />
<glyph glyph-name="alert-outline" unicode="&#xf02a;" d="M902 159l-292 542c-22 41-64 66-110 66s-88-25-110-66l-292-542c-21-39-20-85 3-123 23-38 63-61 108-61h583c44 0 84 23 107 61 23 38 24 84 3 123z m-110-101h-584c-31 0-51 34-36 62l291 541c8 15 23 22 37 22s29-7 37-22l291-541c15-28-5-62-36-62z m-271 250h-42l-21 250h84l-21-250z m21-125c0-23-19-41-42-41s-42 18-42 41 19 42 42 42c23 0 42-19 42-42z" horiz-adv-x="1000" />
<glyph glyph-name="arrow-down" unicode="&#xf045;" d="M458 683h84v-500l229 230 59-60-330-330-330 330 59 60 229-230v500z" horiz-adv-x="1000" />
<glyph glyph-name="arrow-left" unicode="&#xf04d;" d="M833 392v-84h-500l230-229-60-59-330 330 330 330 60-59-230-229h500z" horiz-adv-x="1000" />
<glyph glyph-name="arrow-up" unicode="&#xf05d;" d="M542 17h-84v500l-229-229-59 59 330 330 330-330-59-59-229 229v-500z" horiz-adv-x="1000" />
<glyph glyph-name="at" unicode="&#xf065;" d="M500 225c34 0 63 13 88 37 25 26 37 54 37 88 0 34-12 63-37 88-25 25-54 37-88 37-34 0-62-12-88-37-24-25-37-54-37-88 0-34 13-62 37-88 26-24 54-37 88-37m0 542c115 0 213-42 294-123 81-81 123-179 123-294v-60c0-42-15-77-42-107-29-28-62-41-104-41-50 0-91 21-123 62-41-41-90-62-148-62-57 0-106 21-147 61-40 41-61 90-61 147 0 57 21 106 61 148 41 40 90 60 147 60 58 0 106-20 148-60 40-42 60-91 60-148v-60c0-17 7-32 20-45 12-13 27-20 43-20 17 0 32 7 44 20 13 13 18 28 18 45v60c0 91-32 170-98 235-65 66-144 98-235 98-91 0-170-32-235-98-66-65-98-144-98-235 0-91 32-170 98-235 65-66 144-98 235-98h208v-84h-208c-115 0-212 42-294 123-81 82-123 179-123 294 0 115 42 213 123 294 82 81 179 123 294 123z" horiz-adv-x="1000" />
<glyph glyph-name="flask-outline" unicode="&#xf096;" d="M208 58a42 42 0 0 1 42-41h500a42 42 0 0 1 42 41c0 9-3 17-8 24l-242 420v181h-84v-181l-242-420c-5-7-8-15-8-24m42-125a125 125 0 0 0-125 125c0 25 8 49 21 68l229 399v75a42 42 0 0 0-42 42v41a83 83 0 0 0 84 84h166a83 83 0 0 0 84-84v-41a42 42 0 0 0-42-42v-75l229-399c14-19 21-43 21-68a125 125 0 0 0-125-125h-500m292 250l56 56 80-139h-356l111 192 109-109m-21 167a21 21 0 0 0 21-21 21 21 0 0 0-21-21 21 21 0 0 0-21 21 21 21 0 0 0 21 21z" horiz-adv-x="1000" />
<glyph glyph-name="bell-outline" unicode="&#xf09c;" d="M667 142h-375v271c0 104 83 187 187 187 104 0 188-83 188-187m83-230v230c0 127-89 235-208 263v28a63 63 0 0 1-63 63 63 63 0 0 1-62-63v-28c-120-28-209-136-209-263v-230l-83-83v-42h708v42m-354-167a83 83 0 0 1 84 84h-167a83 83 0 0 1 83-84z" horiz-adv-x="1000" />
<glyph glyph-name="cellphone" unicode="&#xf11c;" d="M708 58h-416v584h416m0 166h-416c-47 0-84-37-84-83v-750a83 83 0 0 1 84-83h416a83 83 0 0 1 84 83v750c0 46-38 83-84 83z" horiz-adv-x="1000" />
<glyph glyph-name="chart-bar" unicode="&#xf128;" d="M917-25h-834v750h84v-667h83v375h167v-375h83v542h167v-542h83v209h167v-292z" horiz-adv-x="1000" />
<glyph glyph-name="chart-line" unicode="&#xf12a;" d="M667 359l176 306 72-42-217-377-272 156-198-344h689v-83h-834v750h84v-606l229 398 271-158z" horiz-adv-x="1000" />
<glyph glyph-name="check" unicode="&#xf12c;" d="M875 558l-500-500-229 230 59 58 170-170 441 441 59-59z" horiz-adv-x="1000" />
<glyph glyph-name="checkbox-blank-outline" unicode="&#xf131;" d="M792 725h-584c-46 0-83-37-83-83v-584a83 83 0 0 1 83-83h584a83 83 0 0 1 83 83v584c0 46-37 83-83 83m0-83v-584h-584v584h584z" horiz-adv-x="1000" />
<glyph glyph-name="checkbox-marked" unicode="&#xf132;" d="M417 142l-209 208 59 59 150-149 316 316 59-59m0 208h-584c-46 0-83-37-83-83v-584a83 83 0 0 1 83-83h584a83 83 0 0 1 83 83v584c0 46-37 83-83 83z" horiz-adv-x="1000" />
<glyph glyph-name="chevron-down" unicode="&#xf140;" d="M309 493l191-192 191 192 59-60-250-250-250 250 59 60z" horiz-adv-x="1000" />
<glyph glyph-name="chevron-left" unicode="&#xf141;" d="M642 159l-191 191 191 191-59 59-250-250 250-250 59 59z" horiz-adv-x="1000" />
<glyph glyph-name="chevron-right" unicode="&#xf142;" d="M358 159l191 191-191 191 59 59 250-250-250-250-59 59z" horiz-adv-x="1000" />
<glyph glyph-name="clock-outline" unicode="&#xf150;" d="M500 17c183 0 333 150 333 333s-150 333-333 333-333-150-333-333 150-333 333-333m0 750c229 0 417-188 417-417s-188-417-417-417-417 188-417 417 188 417 417 417m147-623l-189 189v225h84v-191l164-164-59-59z" horiz-adv-x="1000" />
<glyph glyph-name="close" unicode="&#xf156;" d="M792 583l-59 59-233-233-233 233-59-59 233-233-233-233 59-59 233 233 233-233 59 59-233 233 233 233z" horiz-adv-x="1000" />
<glyph glyph-name="close-circle-outline" unicode="&#xf15a;" d="M500 17c-184 0-333 149-333 333 0 184 149 333 333 333 184 0 333-149 333-333 0-184-149-333-333-333m0 750c-230 0-417-187-417-417 0-230 187-417 417-417 230 0 417 187 417 417 0 230-187 417-417 417m108-250l-108-108-108 108-59-59 108-108-108-108 59-59 108 108 108-108 59 59-108 108 108 108-59 59z" horiz-adv-x="1000" />
<glyph glyph-name="code-brackets" unicode="&#xf16a;" d="M625 683v-83h125v-500h-125v-83h208v666m-666 0v-666h208v83h-125v500h125v83h-208z" horiz-adv-x="1000" />
<glyph glyph-name="code-tags" unicode="&#xf174;" d="M608 158l192 192-192 192 59 58 250-250-250-250-59 58m-216 0l-192 192 192 192-59 58-250-250 250-250 59 58z" horiz-adv-x="1000" />
<glyph glyph-name="console" unicode="&#xf18d;" d="M833 58v500h-666v-500h666m0 667a83 83 0 0 0 84-83v-584a83 83 0 0 0-84-83h-666a83 83 0 0 0-84 83v584c0 46 38 83 84 83h666m-291-583v83h208v-83h-208m-143 166l-167 167h118l138-137c16-17 16-43 0-60l-137-136h-118l166 166z" horiz-adv-x="1000" />
<glyph glyph-name="dots-horizontal" unicode="&#xf1d8;" d="M667 350a83 83 0 0 0 83 83 83 83 0 0 0 83-83 83 83 0 0 0-83-83 83 83 0 0 0-83 83m-250 0a83 83 0 0 0 83 83 83 83 0 0 0 83-83 83 83 0 0 0-83-83 83 83 0 0 0-83 83m-250 0a83 83 0 0 0 83 83 83 83 0 0 0 83-83 83 83 0 0 0-83-83 83 83 0 0 0-83 83z" horiz-adv-x="1000" />
<glyph glyph-name="dots-vertical" unicode="&#xf1d9;" d="M500 183a83 83 0 0 0 83-83 83 83 0 0 0-83-83 83 83 0 0 0-83 83 83 83 0 0 0 83 83m0 250a83 83 0 0 0 83-83 83 83 0 0 0-83-83 83 83 0 0 0-83 83 83 83 0 0 0 83 83m0 250a83 83 0 0 0 83-83 83 83 0 0 0-83-83 83 83 0 0 0-83 83 83 83 0 0 0 83 83z" horiz-adv-x="1000" />
<glyph glyph-name="email-outline" unicode="&#xf1f0;" d="M917 600c0 46-38 83-84 83h-666c-46 0-84-37-84-83v-500c0-46 38-83 84-83h666c46 0 84 37 84 83v500m-84 0l-333-208-333 208h666m0-500h-666v417l333-209 333 209v-417z" horiz-adv-x="1000" />
<glyph glyph-name="emoticon-outline" unicode="&#xf1f2;" d="M500 121c97 0 179 61 213 146h-426c33-85 116-146 213-146m-146 271a63 63 0 0 1 63 62 63 63 0 0 1-63 63 63 63 0 0 1-62-63 63 63 0 0 1 62-62m292 0a63 63 0 0 1 62 62 63 63 0 0 1-62 63 63 63 0 0 1-63-63 63 63 0 0 1 63-62m-146-375a333 333 0 0 0-333 333 333 333 0 0 0 333 333 333 333 0 0 0 333-333 333 333 0 0 0-333-333m0 750c-230 0-417-188-417-417a417 417 0 0 1 417-417 417 417 0 0 1 417 417 417 417 0 0 1-417 417z" horiz-adv-x="1000" />
<glyph glyph-name="emoticon-happy-outline" unicode="&#xf1f5;" d="M833 350a333 333 0 0 1-333 333 333 333 0 0 1-333-333 333 333 0 0 1 333-333 333 333 0 0 1 333 333m84 0a417 417 0 0 0-417-417 417 417 0 0 0-417 417 417 417 0 0 0 417 417 417 417 0 0 0 417-417m-500 104c0-33-29-62-63-62-33 0-62 29-62 62 0 34 29 63 62 63 34 0 63-29 63-63m291 0c0-33-29-62-62-62-33 0-63 29-63 62 0 34 30 63 63 63 33 0 62-29 62-63m-208-322c-73 0-137 31-175 76l60 59c18-30 63-52 115-52 52 0 97 22 115 52l60-59c-38-45-102-76-175-76z" horiz-adv-x="1000" />
<glyph glyph-name="filter-variant" unicode="&#xf236;" d="M250 308h500v84h-500m-125 208v-83h750v83m-458-500h166v83h-166v-83z" horiz-adv-x="1000" />
<glyph glyph-name="fire" unicode="&#xf238;" d="M492 600c4-4 8-12 12-17 17-25 46-54 88-91 33-29 58-54 71-71 20-25 37-50 50-75 12-29 16-67 16-100 0-42-8-79-29-113-21-37-50-62-83-83-38-25-75-33-117-33s-79 8-112 29c-38 21-63 50-84 83s-29 71-29 113c0 37 8 71 25 104 0 0 0 4 4 4v-58c0-42 17-79 42-104 29-30 67-42 104-42s79 17 104 42c29 29 42 66 42 104 0 25-8 50-21 75-4 12-12 29-29 54-25 42-38 67-46 79-8 29-12 54-12 83 4 9 4 13 4 17m8 167h-4c-13 0-21-9-29-17-34-54-54-104-59-154-4-42 5-79 17-121 8-21 25-54 50-92 13-20 21-37 25-45 8-13 13-25 13-38 0-17-5-33-17-46-13-12-29-16-46-16s-33 4-46 16c-12 13-16 29-16 46v171c0 17-9 25-21 33-13 4-17 4-25 4s-13 0-21-4c-42-29-75-66-96-112-25-46-37-96-37-146 0-58 12-108 41-154s67-88 113-113 100-42 158-42 108 13 158 42 88 67 113 113c29 46 42 100 42 154 0 46-9 92-25 133-13 34-34 63-63 96-17 17-42 46-75 75-37 33-62 63-75 79-21 34-33 63-33 96 0 13-4 21-13 29-12 9-21 13-29 13l0 0z" horiz-adv-x="1000" />
<glyph glyph-name="flag" unicode="&#xf23b;" d="M600 600l-17 83h-375v-708h84v292h233l17-84h291v417h-233z" horiz-adv-x="1000" />
<glyph glyph-name="flag-outline" unicode="&#xf23d;" d="M517 600l16-83h217v-250h-142l-16 83h-300v250h225m66 83h-375v-708h84v292h233l17-84h291v417h-233" horiz-adv-x="1000" />
<glyph glyph-name="format-bold" unicode="&#xf264;" d="M650 400c40 28 69 74 69 117 0 94-73 166-167 166h-260v-583h293c87 0 155 71 155 158 0 63-36 117-90 142z m-233 179h125c34 0 62-28 62-62s-28-63-62-63h-125v125z m146-375h-146v125h146c34 0 62-28 62-62s-28-63-62-63z" horiz-adv-x="1000" />
<glyph glyph-name="format-clear" unicode="&#xf265;" d="M136 642l-53-53 291-291-103-240h125l65 153 236-236 53 53-602 602-12 12z m114 0v-8l118-117h100l-30-70 87-88 67 158h241v125h-583z" horiz-adv-x="1000" />
<glyph glyph-name="format-header-1" unicode="&#xf26b;" d="M125 683h83v-250h167v250h83v-583h-83v250h-167v-250h-83v583m458-583v83h84v404l-104-60v96l104 60h83v-500h83v-83h-250z" horiz-adv-x="1000" />
<glyph glyph-name="format-header-2" unicode="&#xf26c;" d="M125 683h83v-250h167v250h83v-583h-83v250h-167v-250h-83v583m750-583h-250a83 83 0 0 0-83 83c0 22 8 42 22 57l203 218c16 15 25 36 25 59a83 83 0 0 1-84 83 83 83 0 0 1-83-83h-83a167 167 0 0 0 166 166 167 167 0 0 0 167-166c0-46-19-88-49-118l-201-216h250v-83z" horiz-adv-x="1000" />
<glyph glyph-name="format-header-3" unicode="&#xf26d;" d="M125 683h83v-250h167v250h83v-583h-83v250h-167v-250h-83v583m500 0h167a83 83 0 0 0 83-83v-417a83 83 0 0 0-83-83h-167a83 83 0 0 0-83 83v42h83v-42h167v167h-167v83h167v167h-167v-42h-83v42a83 83 0 0 0 83 83z" horiz-adv-x="1000" />
<glyph glyph-name="format-header-4" unicode="&#xf26e;" d="M125 683h83v-250h167v250h83v-583h-83v250h-167v-250h-83v583m625-583v208h-208v84l208 291h83v-291h42v-84h-42v-208h-83m0 292v149l-106-149h106z" horiz-adv-x="1000" />
<glyph glyph-name="format-header-5" unicode="&#xf26f;" d="M125 683h83v-250h167v250h83v-583h-83v250h-167v-250h-83v583m500 0h208v-83h-208v-167h83a167 167 0 0 0 167-166 167 167 0 0 0-167-167h-83a83 83 0 0 0-83 83v42h83v-42h83a83 83 0 0 1 84 84 83 83 0 0 1-84 83h-83a83 83 0 0 0-83 83v167a83 83 0 0 0 83 83z" horiz-adv-x="1000" />
<glyph glyph-name="format-header-6" unicode="&#xf270;" d="M125 683h83v-250h167v250h83v-583h-83v250h-167v-250h-83v583m500 0h167a83 83 0 0 0 83-83v-42h-83v42h-167v-167h167a83 83 0 0 0 83-83v-167a83 83 0 0 0-83-83h-167a83 83 0 0 0-83 83v417a83 83 0 0 0 83 83m0-333v-167h167v167h-167z" horiz-adv-x="1000" />
<glyph glyph-name="format-italic" unicode="&#xf277;" d="M417 683v-125h92l-143-333h-116v-125h333v125h-92l143 333h116v125z" horiz-adv-x="1000" />
<glyph glyph-name="format-list-bulleted" unicode="&#xf279;" d="M292 642h583v-84h-583v84m0-334v84h583v-84h-583m-125 355a63 63 0 0 0 62-63 63 63 0 0 0-62-62 63 63 0 0 0-63 62 63 63 0 0 0 63 63m0-250a63 63 0 0 0 62-63 63 63 0 0 0-62-62 63 63 0 0 0-63 62 63 63 0 0 0 63 63m125-355v84h583v-84h-583m-125 105a63 63 0 0 0 62-63 63 63 0 0 0-62-62 63 63 0 0 0-63 62 63 63 0 0 0 63 63z" horiz-adv-x="1000" />
<glyph glyph-name="format-list-numbered" unicode="&#xf27b;" d="M292 308v84h583v-84h-583m0-250v84h583v-84h-583m0 500v84h583v-84h-583m-167-41v125h-42v41h84v-166h-42m-42-375v41h125v-166h-125v41h84v21h-42v42h42v21h-84m94 291a31 31 0 0 0 31-31c0-8-3-16-8-22l-70-72h78v-41h-125v38l84 87h-84v41h94z" horiz-adv-x="1000" />
<glyph glyph-name="format-strikethrough-variant" unicode="&#xf281;" d="M285 555c0 113 109 170 225 170 68 0 125-20 163-53 32-27 60-72 60-135h-125c0 13-2 24-6 35-12 36-50 53-94 53-78 0-98-42-98-70 0-20 11-37 31-51 16-10 32-20 59-29h-192c-9 14-23 37-23 80z m590-205v83h-750v-83h401c48-19 82-31 82-82 0-42-34-70-95-70-65 0-123 23-123 105h-123c0-23 3-47 10-66 33-95 137-137 236-137 95 0 221 37 221 168 0 13-1 49-20 81h161v1z" horiz-adv-x="1000" />
<glyph glyph-name="github-circle" unicode="&#xf2a4;" d="M500 767a417 417 0 0 1-417-417c0-184 120-340 285-396 21-3 28 10 28 21 0 10 0 36 0 70-116-25-140 56-140 56-19 49-46 62-46 62-38 25 3 25 3 25 41-3 63-43 63-43 37-64 98-45 122-35 3 27 14 45 26 56-93 10-190 46-190 205 0 46 16 83 43 113-4 10-19 54 4 110 0 0 35 11 115-43 33 9 69 14 104 14 35 0 71-5 104-14 80 54 115 43 115 43 23-56 8-100 4-110 27-30 43-67 43-113 0-159-98-194-191-205 15-13 29-38 29-77 0-56 0-101 0-114 0-11 7-25 28-21 166 56 285 212 285 396a417 417 0 0 1-417 417z" horiz-adv-x="1000" />
<glyph glyph-name="heart-outline" unicode="&#xf2d5;" d="M504 77l-4-4-5 4c-197 180-328 298-328 419 0 83 62 146 146 146 64 0 126-42 148-99h78c22 57 84 99 149 99 83 0 145-63 145-146 0-121-130-239-329-419m184 648c-73 0-143-34-188-87-45 53-115 87-187 87-129 0-230-100-230-229 0-157 142-286 357-481l60-55 60 55c215 195 357 324 357 481 0 129-101 229-229 229z" horiz-adv-x="1000" />
<glyph glyph-name="help" unicode="&#xf2d6;" d="M417 58h125v-125h-125v125m83 709c223-9 320-234 188-403-35-42-91-69-118-104-28-35-28-77-28-118h-125c0 69 0 128 28 170 27 41 83 66 118 93 100 94 75 226-63 237a125 125 0 0 1-125-125h-125a250 250 0 0 0 250 250z" horiz-adv-x="1000" />
<glyph glyph-name="information-outline" unicode="&#xf2fd;" d="M458 475h84v83h-84m42-541c-184 0-333 149-333 333 0 184 149 333 333 333 184 0 333-149 333-333 0-184-149-333-333-333m0 750a417 417 0 0 1-417-417 417 417 0 0 1 417-417 417 417 0 0 1 417 417 417 417 0 0 1-417 417m-42-625h84v250h-84v-250z" horiz-adv-x="1000" />
<glyph glyph-name="laptop" unicode="&#xf322;" d="M167 600h666v-417h-666m666-83a83 83 0 0 1 84 83v417c0 46-38 83-84 83h-666c-47 0-84-37-84-83v-417a83 83 0 0 1 84-83h-167v-83h1000v83h-167z" horiz-adv-x="1000" />
<glyph glyph-name="leaf" unicode="&#xf32a;" d="M708 517c-375-84-462-341-549-556l79-28 40 96c20-7 40-12 55-12 459 0 584 708 584 708-42-83-334-94-542-135-208-42-292-219-292-302 0-84 73-157 73-157 136 386 552 386 552 386z" horiz-adv-x="1000" />
<glyph glyph-name="lightbulb-outline" unicode="&#xf336;" d="M500 767a292 292 0 0 0 292-292c0-99-50-186-125-239v-94a42 42 0 0 0-42-42h-250a42 42 0 0 0-42 42v94c-75 53-125 140-125 239a292 292 0 0 0 292 292m-125-792v42h250v-42a42 42 0 0 0-42-42h-166a42 42 0 0 0-42 42m125 708a208 208 0 0 1-208-208c0-85 51-159 125-191v-101h166v101c74 32 125 106 125 191a208 208 0 0 1-208 208z" horiz-adv-x="1000" />
<glyph glyph-name="link-variant" unicode="&#xf339;" d="M441 291c17-16 17-43 0-59-16-16-43-16-59 0-81 81-81 213 0 295v0l148 147c81 81 213 81 294 0 81-81 81-213 0-294l-62-62c1 34-5 68-17 100l20 20c49 49 49 128 0 177-49 49-128 49-177 0l-147-147c-49-49-49-128 0-177m118 177c16 16 43 16 59 0 81-81 81-213 0-295v0l-148-147c-81-81-213-81-294 0-81 81-81 213 0 294l62 63c0-35 5-69 17-102l-20-19c-49-49-49-128 0-177 49-49 128-49 177 0l147 147c49 49 49 128 0 177-17 16-17 43 0 59z" horiz-adv-x="1000" />
<glyph glyph-name="link-variant-off" unicode="&#xf33a;" d="M83 630l54 53 696-696-53-54-201 202-109-109c-81-81-213-81-294 0-81 81-81 213 0 294l62 63c0-35 5-69 17-102l-20-19c-49-49-49-128 0-177 49-49 128-49 177 0l109 108-68 67c0-10-4-20-12-28-16-16-43-16-59 0-44 44-64 103-60 160l-239 238m447 44c81 81 213 81 294 0 81-81 81-213 0-294l-62-62c1 34-5 68-17 100l20 20c49 49 49 128 0 177-49 49-128 49-177 0l-138-139-59 59 139 139m29-206c16 16 43 16 59 0 57-57 74-139 51-211l-74 74c-2 28-14 56-36 78-17 16-17 43 0 59z" horiz-adv-x="1000" />
<glyph glyph-name="lock" unicode="&#xf33e;" d="M750 475c46 0 83-37 83-83v-375c0-46-37-84-83-84h-500c-46 0-83 38-83 84v375c0 46 37 83 83 83h42v83c0 117 91 209 208 209s208-92 208-209v-83h42m-250 208c-71 0-125-54-125-125v-83h250v83c0 71-54 125-125 125z" horiz-adv-x="1000" />
<glyph glyph-name="lock-outline" unicode="&#xf341;" d="M750 17v375h-500v-375h500m0 458c46 0 83-37 83-83v-375c0-46-37-84-83-84h-500c-46 0-83 38-83 84v375c0 46 37 83 83 83h42v83c0 117 91 209 208 209s208-92 208-209v-83h42m-250 208c-71 0-125-54-125-125v-83h250v83c0 71-54 125-125 125z" horiz-adv-x="1000" />
<glyph glyph-name="magnify" unicode="&#xf349;" d="M843 66l-158 157c41 52 65 118 65 190 0 172-140 312-312 312s-313-140-313-312 140-313 313-313c71 0 136 24 189 64l157-156c16-16 42-16 59 0 15 16 15 41 0 58z m-635 347c0 126 103 229 230 229s229-103 229-229-103-230-229-230-230 103-230 230z" horiz-adv-x="1000" />
<glyph glyph-name="menu" unicode="&#xf35c;" d="M125 600h750v-83h-750v83m0-208h750v-84h-750v84m0-209h750v-83h-750v83z" horiz-adv-x="1000" />
<glyph glyph-name="menu-down" unicode="&#xf35d;" d="M292 433l208-208 208 208h-416z" horiz-adv-x="1000" />
<glyph glyph-name="minus-box" unicode="&#xf375;" d="M708 308h-416v84h416m84 333h-584c-46 0-83-37-83-83v-584a83 83 0 0 1 83-83h584a83 83 0 0 1 83 83v584c0 46-37 83-83 83z" horiz-adv-x="1000" />
<glyph glyph-name="minus-circle" unicode="&#xf376;" d="M708 308h-416v84h416m-208 375c-229 0-417-188-417-417s188-417 417-417 417 188 417 417-188 417-417 417z" horiz-adv-x="1000" />
<glyph glyph-name="paperclip" unicode="&#xf3e2;" d="M688 558v-395c0-92-75-167-167-167s-167 75-167 167v437c0 58 47 104 104 104s105-46 105-104v-396c0-23-19-41-42-41s-42 18-42 41v354h-62v-354c0-57 46-104 104-104s104 47 104 104v396c0 92-75 167-167 167s-166-75-166-167v-437c0-127 102-230 229-230s229 103 229 230v395h-62z" horiz-adv-x="1000" />
<glyph glyph-name="pin" unicode="&#xf403;" d="M904 442l-41 41-271 271 0 0c-17 17-42 17-59 0l0 0c-16-16-16-41 0-58l13-13-183-183c-71 8-142 0-209-29-16-4-25-17-29-29 0-13 4-29 13-38l179-179-171-167-42-104 104 42 167 167 175-180c8-8 25-12 38-12 12 4 25 12 29 25 25 67 37 137 29 208l187 192 13-13c17-16 42-16 58 0 17 17 17 42 0 59z" horiz-adv-x="1000" />
<glyph glyph-name="plus" unicode="&#xf415;" d="M792 308h-250v-250h-84v250h-250v84h250v250h84v-250h250v-84z" horiz-adv-x="1000" />
<glyph glyph-name="plus-box" unicode="&#xf416;" d="M708 308h-166v-166h-84v166h-166v84h166v166h84v-166h166m84 333h-584c-46 0-83-37-83-83v-584a83 83 0 0 1 83-83h584a83 83 0 0 1 83 83v584c0 46-37 83-83 83z" horiz-adv-x="1000" />
<glyph glyph-name="refresh" unicode="&#xf450;" d="M735 585c-60 61-143 98-235 98a333 333 0 0 1-333-333 333 333 0 0 1 333-333c155 0 285 106 322 250h-87c-34-97-126-167-235-167a250 250 0 0 0-250 250 250 250 0 0 0 250 250c69 0 131-29 176-74l-134-134h291v291l-98-98z" horiz-adv-x="1000" />
<glyph glyph-name="send" unicode="&#xf48a;" d="M83-25l875 375-875 375v-292l625-83-625-83v-292z" horiz-adv-x="1000" />
<glyph glyph-name="shield-outline" unicode="&#xf499;" d="M875 392c0-232-160-448-375-500-215 52-375 268-375 500v250l375 166 375-166v-250m-375-417c156 42 292 228 292 408v205l-292 130-292-130v-205c0-180 136-366 292-408z" horiz-adv-x="1000" />
<glyph glyph-name="sitemap" unicode="&#xf4aa;" d="M833 175v133c0 46-37 84-83 84h-208v133c50 17 83 63 83 117 0 71-54 125-125 125s-125-54-125-125c0-54 33-100 83-117v-133h-208c-46 0-83-38-83-84v-133c-50-17-84-62-84-117 0-71 55-125 125-125s125 54 125 125c0 55-33 100-83 117v133h208v-133c-50-17-83-62-83-117 0-71 54-125 125-125s125 54 125 125c0 55-33 100-83 117v133h208v-133c-50-17-83-62-83-117 0-71 54-125 125-125s125 54 125 125c0 55-34 100-84 117z" horiz-adv-x="1000" />
<glyph glyph-name="soccer" unicode="&#xf4b8;" d="M500 767a417 417 0 0 1-417-417 417 417 0 0 1 417-417 417 417 0 0 1 417 417 417 417 0 0 1-417 417m0-42c73 0 142-22 199-59l-11-24h-146l-42 0-72 35 15 43c19 3 37 5 57 5m-103-16l-14-43-107-53-52-10c47 50 106 87 173 106m145-109h125l112-150-52-107-110-25-137 160 62 122m-285-27l35-140-51-127-107-37c-6 26-9 53-9 81 0 79 25 152 66 212l66 11m600-107c12-36 18-76 18-116 0-60-15-116-40-167h-43l-35 140 62 125 38 18m-524-33h125l117-136-75-114-132-32-96 129 61 153m167-291l125-84-36-71c-29-7-59-12-89-12-73 0-140 21-198 57l48 72 150 38m292 0h21c-42-63-105-112-175-139l29 55 125 84z" horiz-adv-x="1000" />
<glyph glyph-name="source-pull" unicode="&#xf4c2;" d="M250 725a125 125 0 0 0 125-125c0-55-35-101-83-118v-264c48-17 83-63 83-118a125 125 0 0 0-125-125 125 125 0 0 0-125 125c0 55 35 101 83 118v264c-48 17-83 63-83 118a125 125 0 0 0 125 125m0-83a42 42 0 0 1-42-42 42 42 0 0 1 42-42 42 42 0 0 1 42 42 42 42 0 0 1-42 42m0-500a42 42 0 0 1-42-42 42 42 0 0 1 42-42 42 42 0 0 1 42 42 42 42 0 0 1-42 42m625-42a125 125 0 0 0-125-125 125 125 0 0 0-125 125c0 55 35 101 83 118v340h-83v-135l-177 177 177 177v-135h83a83 83 0 0 0 84-84v-340c48-17 83-63 83-118m-125 42a42 42 0 0 1-42-42 42 42 0 0 1 42-42 42 42 0 0 1 42 42 42 42 0 0 1-42 42z" horiz-adv-x="1000" />
<glyph glyph-name="star" unicode="&#xf4ce;" d="M500 116l232-140c17-10 38 5 33 24l-61 264 205 178c15 13 7 37-13 39l-270 23-105 249c-8 18-34 18-41 0l-106-249-270-23c-20-2-28-26-13-39l205-178-61-264c-5-19 16-34 33-24l232 140z" horiz-adv-x="1000" />
<glyph glyph-name="star-outline" unicode="&#xf4d2;" d="M500 615l59-139 17-40 44-4 151-13-115-100-33-28 10-43 34-147-129 78-38 22-38-22-129-79 34 148 10 43-33 28-115 100 151 13 44 4 17 40 59 139m0 152c-8 0-17-5-20-14l-106-249-270-23c-20-2-28-26-13-39l205-178-61-264c-4-15 8-27 21-27 4 0 8 1 12 3l232 140 232-140c4-2 8-3 12-3 13 0 25 12 21 27l-61 264 205 178c15 13 7 37-13 39l-270 23-105 249c-4 9-13 14-21 14l0 0z" horiz-adv-x="1000" />
<glyph glyph-name="sync" unicode="&#xf4e6;" d="M500 100a250 250 0 0 0-250 250c0 42 10 82 29 117l-61 61c-32-52-51-113-51-178a333 333 0 0 1 333-333v-125l167 166-167 167m0 458v125l-167-166 167-167v125a250 250 0 0 0 250-250c0-42-10-82-29-117l61-60c32 51 51 112 51 177a333 333 0 0 1-333 333z" horiz-adv-x="1000" />
<glyph glyph-name="alert-circle-outline" unicode="&#xf5d6;" d="M500 767c-229 0-417-188-417-417s188-417 417-417 417 188 417 417-188 417-417 417m0-750c-183 0-333 150-333 333s150 333 333 333 333-150 333-333-150-333-333-333z m21 291h-42l-21 250h84l-21-250z m21-125c0-23-19-41-42-41s-42 18-42 41 19 42 42 42 42-19 42-42z" horiz-adv-x="1000" />
<glyph glyph-name="check-circle" unicode="&#xf5e0;" d="M500 767c-230 0-417-187-417-417s187-417 417-417 417 187 417 417-187 417-417 417z m-73-612l0 0-59 58-118 118 59 59 118-118 265 266 59-59-324-324z" horiz-adv-x="1000" />
<glyph glyph-name="email-variant" unicode="&#xf5f0;" d="M500 308l-417 260v32c0 46 37 83 84 83h666a83 83 0 0 0 84-83v-31l-417-261m417-208a83 83 0 0 0-84-83h-666c-47 0-84 37-84 83v370l84-52v-318h666v318l84 52v-370z" horiz-adv-x="1000" />
<glyph glyph-name="food-fork-drink" unicode="&#xf5f2;" d="M125 725a42 42 0 0 1-42-42v-166l0-63c0-70 43-130 105-155v-261a63 63 0 0 1 62-63 63 63 0 0 1 63 63v261c61 25 104 85 104 155v63l0 166a42 42 0 0 1-42 42 42 42 0 0 1-42-42v-166a21 21 0 0 0-20-21 21 21 0 0 0-21 21v166a42 42 0 0 1-42 42 42 42 0 0 1-42-42v-166a21 21 0 0 0-20-21 21 21 0 0 0-21 21v166a42 42 0 0 1-42 42m703 0c-5 0-10-4-15-7l-146-87v-156h-167v-83h42l41-417h250l42 417h42v83h-167v111l104 62c21 12 26 35 14 56-8 15-24 23-40 21z" horiz-adv-x="1000" />
<glyph glyph-name="arrow-collapse" unicode="&#xf615;" d="M813 721l-188-187v149h-83v-291h291v83h-149l187 188-58 58m-646-413v-83h149l-187-187 59-59 187 187v-149h83v291h-291z" horiz-adv-x="1000" />
<glyph glyph-name="arrow-expand" unicode="&#xf616;" d="M417-25v83h-150l188 188-59 59-188-188v150h-83v-292h292m187 420l188 188v-150h83v292h-292v-83h150l-188-188 59-59z" horiz-adv-x="1000" />
<glyph glyph-name="source-branch" unicode="&#xf62c;" d="M542 267c-140 0-186-57-201-94 44-19 76-63 76-115a125 125 0 0 0-125-125 125 125 0 0 0-125 125c0 55 34 101 83 118v348c-49 17-83 63-83 118a125 125 0 0 0 125 125 125 125 0 0 0 125-125c0-55-35-101-84-118v-221c37 27 90 47 167 47 111 0 148 56 160 93-45 19-77 63-77 115a125 125 0 0 0 125 125 125 125 0 0 0 125-125c0-55-36-104-87-119-11-59-51-172-204-172m-250-167a42 42 0 0 1-42-42 42 42 0 0 1 42-41 42 42 0 0 1 41 41 42 42 0 0 1-41 42m0 583a42 42 0 0 1-42-41 42 42 0 0 1 42-42 42 42 0 0 1 41 42 42 42 0 0 1-41 41m416-83a42 42 0 0 1-41-42 42 42 0 0 1 41-41 42 42 0 0 1 42 41 42 42 0 0 1-42 42z" horiz-adv-x="1000" />
<glyph glyph-name="tune" unicode="&#xf62e;" d="M125 142v-84h250v84h-250m0 500v-84h417v84h-417m417-667v83h333v84h-333v83h-84v-250h84m-250 500v-83h-167v-84h167v-83h83v250h-83m583-167v84h-417v-84h417m-250 167h83v83h167v84h-167v83h-83v-250z" horiz-adv-x="1000" />
<glyph glyph-name="webhook" unicode="&#xf62f;" d="M436 58c-61-86-180-108-266-48-85 60-105 180-45 267 36 52 92 80 149 83l2-60c-38-3-74-22-98-57-42-60-29-140 28-181 58-40 138-24 180 35 13 19 20 39 23 60v42l233 2 3 4c22 39 70 52 107 30 38-21 51-70 28-108-22-38-70-51-107-29-18 9-30 25-35 42l-170-1c-4-28-15-55-32-81m303 298c106-13 181-108 168-211-13-105-109-178-214-165-63 7-114 43-143 92l51 30c21-32 55-55 97-61 73-8 137 41 146 111 9 69-43 133-115 142-22 2-44-1-64-8l-35-18-107 199h-10c-44 1-78 38-77 81 2 43 39 77 83 75 44-2 78-38 77-81-1-18-8-35-19-48l79-146c26 8 54 11 83 8m-395 113c-42 98 2 210 99 251 96 41 208-5 250-103 24-57 19-120-9-170l-51 30c17 34 20 75 3 114-28 67-103 99-168 72-65-28-94-105-66-171 12-28 31-49 55-63l16-9-128-208c2-2 3-4 5-8 20-38 6-86-32-106-38-20-86-5-107 34-21 38-6 86 32 107 16 9 34 11 51 7l96 157c-19 18-36 40-46 66z" horiz-adv-x="1000" />
<glyph glyph-name="eye-outline" unicode="&#xf6cf;" d="M500 475a125 125 0 0 0 125-125 125 125 0 0 0-125-125 125 125 0 0 0-125 125 125 125 0 0 0 125 125m0 188c208 0 386-130 458-313-72-183-250-312-458-312-208 0-386 129-458 312 72 183 250 313 458 313m-367-313c68-140 210-229 367-229 157 0 299 89 368 229-69 140-211 229-368 229-157 0-299-89-367-229z" horiz-adv-x="1000" />
<glyph glyph-name="cancel" unicode="&#xf739;" d="M500 767a417 417 0 0 0 417-417 417 417 0 0 0-417-417 417 417 0 0 0-417 417 417 417 0 0 0 417 417m0-84a333 333 0 0 1-333-333c0-77 26-148 70-205l468 468c-57 44-128 70-205 70m0-666a333 333 0 0 1 333 333c0 77-26 148-70 205l-468-468c57-44 128-70 205-70z" horiz-adv-x="1000" />
<glyph glyph-name="format-quote-open" unicode="&#xf756;" d="M417 558l-84-166h125v-250h-250v250l84 166h125m333 0l-83-166h125v-250h-250v250l83 166h125z" horiz-adv-x="1000" />
<glyph glyph-name="square" unicode="&#xf763;" d="M750 683h-500c-46 0-83-37-83-83v-500c0-46 37-83 83-83h500c46 0 83 37 83 83v500c0 46-37 83-83 83z" horiz-adv-x="1000" />
<glyph glyph-name="circle-outline" unicode="&#xf765;" d="M500 17a333 333 0 0 0-333 333 333 333 0 0 0 333 333 333 333 0 0 0 333-333 333 333 0 0 0-333-333m0 750a417 417 0 0 1-417-417 417 417 0 0 1 417-417 417 417 0 0 1 417 417 417 417 0 0 1-417 417z" horiz-adv-x="1000" />
<glyph glyph-name="account-plus-outline" unicode="&#xf800;" d="M210 58c-24 0-43 20-43 44 0 5 0 9 2 13 2 8 7 16 13 21 3 3 7 5 11 7l129 77c28-17 59-26 95-26s67 9 95 26l14-9c13 26 30 48 50 68l-1 0c44 58 68 138 68 217 0 137-91 229-226 229s-226-92-226-229c0-79 24-159 67-217l-105-63c-42-21-70-65-70-114 0-70 57-127 127-127h324c-15 25-25 53-30 83h-294z m207 584c79 0 143-45 143-146 0-62-21-130-57-174-23-27-52-45-86-45-11 0-22 2-32 5-5 2-10 4-15 7-9 5-18 11-26 19-5 4-9 9-14 14-3 4-6 8-9 12-6 9-12 20-18 31-8 17-15 35-19 54-4 13-6 26-8 39-1 12-2 25-2 38 0 101 64 146 143 146z m291-375h84v-125h125v-84h-125v-125h-84v125h-125v84h125v125" horiz-adv-x="1000" />
<glyph glyph-name="forum-outline" unicode="&#xf821;" d="M708 267c25 0 42 16 42 41v417c0 25-17 42-42 42h-583c-25 0-42-17-42-42v-625l167 167h458z m-541 33v383h500v-333h-450l-50-50z m708 300h-42v-467l-50 50h-533v-41c0-4 0-4 0-9 4-16 21-33 42-33h458l167-167v625c0 25-17 42-42 42z" horiz-adv-x="1000" />
<glyph glyph-name="settings-outline" unicode="&#xf8ba;" d="M810 309c1 14 3 27 3 41 0 14-2 28-3 41l88 69c7 6 10 17 5 26l-84 144c-4 7-11 11-18 11-3 0-5-1-7-1l-104-42c-22 17-45 30-70 41l-16 110c-1 10-10 18-21 18h-166c-11 0-19-8-21-18l-16-110c-25-11-48-25-70-41l-104 42c-2 0-5 1-7 1-7 0-14-4-18-11l-83-144c-6-9-3-20 5-26l87-69c-1-13-2-27-2-41 0-14 1-27 2-41l-87-69c-8-6-10-17-5-26l83-144c4-7 11-11 18-11 3 0 5 1 7 1l104 42c22-17 45-30 70-41l16-110c2-10 10-18 21-18h166c11 0 20 8 21 18l16 110c25 11 48 25 70 41l104-42c2 0 5-1 7-1 7 0 14 4 18 11l84 144c5 9 2 20-5 26l-88 69z m-83 71c2-12 2-21 2-30 0-9-1-18-2-30l-6-47 37-30 45-35-29-50-53 21-43 18-38-29c-17-13-35-23-52-30l-44-18-6-47-9-56h-58l-8 56-7 47-44 18c-18 7-34 17-51 30l-38 29-44-18-53-21-29 50 45 35 37 29-6 47c-1 13-2 23-2 31s1 18 2 30l6 48-37 29-45 35 29 50 53-21 43-18 38 29c18 13 35 23 52 30l44 18 7 47 8 56h58l8-56 6-47 45-18c17-7 34-17 51-29l38-30 44 18 53 22 29-51-45-35-37-29 6-48z m-227 137c-92 0-167-75-167-167s75-167 167-167 167 75 167 167-75 167-167 167z m0-250c-46 0-83 37-83 83s37 83 83 83 83-37 83-83-37-83-83-83z" horiz-adv-x="1000" />
<glyph glyph-name="hammer" unicode="&#xf8e9;" d="M83 32l477 476-30 30 59 59-89 91c50 50 129 50 178 0l150-150-59-59h118l30-30-148-149-30 29v120l-61-59-30 30-476-477-89 89z" horiz-adv-x="1000" />
<glyph glyph-name="pin-outline" unicode="&#xf930;" d="M904 442l-41 41-271 271c0 0 0 1 0 1-16 16-43 16-59-1 0 0 0 0 0 0-16-16-16-43 0-59l13-12-185-183c-71 8-143-1-209-28-13-5-23-16-26-30-3-14 2-28 12-38l177-177-169-169-42-104 104 42 169 169 177-178c10-10 25-14 39-11 14 3 25 14 30 27 27 66 36 138 27 209l183 183 12-12c17-17 43-17 59 0 17 16 17 42 0 59z m-330-187c-11-11-15-27-11-41 10-39 10-79 0-118l-317 318c39 10 79 10 117 0 15-5 31-1 42 10l199 200 169-169-199-200z" horiz-adv-x="1000" />
<glyph glyph-name="clock" unicode="&#xf953;" d="M500 767c-229 0-417-188-417-417s188-417 417-417 417 188 417 417-188 417-417 417m147-623l-189 189v225h84v-191l164-164-59-59z" horiz-adv-x="1000" />
<glyph glyph-name="image-outline" unicode="&#xf975;" d="M792 58h-584v584h584m0 83h-584a83 83 0 0 1-83-83v-584a83 83 0 0 1 83-83h584a83 83 0 0 1 83 83v584a83 83 0 0 1-83 83m-210-387l-115-148-82 99-114-147h458l-147 196z" horiz-adv-x="1000" />
<glyph glyph-name="email-plus-outline" unicode="&#xf9eb;" d="M792 225v-125h-125v-83h125v-125h83v125h125v83h-125v125h-83m-209-125h-458v417l333-209 334 209v-209h83v292c0 46-37 83-83 83h-667c-46 0-83-37-83-83v-500c0-46 37-83 83-83h458v83m209 500l-334-208-333 208h667z" horiz-adv-x="1000" />
<glyph glyph-name="file-document-outline" unicode="&#xf9ed;" d="M250 767a83 83 0 0 1-83-84v-666a83 83 0 0 1 83-84h500a83 83 0 0 1 83 84v500l-250 250h-333m0-84h292v-208h208v-458h-500v666m83-333v-83h334v83h-334m0-167v-83h209v83h-209z" horiz-adv-x="1000" />
<glyph glyph-name="layers-outline" unicode="&#xf9fd;" d="M500 78l307 239 68-53-375-292-375 292 68 52 307-238m0 105l-375 292 375 292 375-292-375-292m0 478l-239-186 239-186 239 186-239 186z" horiz-adv-x="1000" />
<glyph glyph-name="bell-off-outline" unicode="&#xfa90;" d="M921-44l-821 822-54-53 197-197c-23-42-35-89-35-136v-250l-83-84v-41h630l113-114 53 53m-629 144v292c0 25 4 50 14 73l365-365h-379m125-125h166a83 83 0 0 0-83-83 83 83 0 0 0-83 83m-72 663c23 14 47 25 72 33 0 4 0 8 0 12a83 83 0 0 0 83 84 83 83 0 0 0 83-84c0-4 0-8 0-12 124-36 209-150 209-279v-200l-84 83v117a208 208 0 0 1-208 208c-32 0-65-8-93-23l-62 61z" horiz-adv-x="1000" />
<glyph glyph-name="chevron-down-circle-outline" unicode="&#xfb0c;" d="M917 350a417 417 0 0 0-417-417 417 417 0 0 0-417 417 417 417 0 0 0 417 417 417 417 0 0 0 417-417m-84 0a333 333 0 0 1-333 333 333 333 0 0 1-333-333 333 333 0 0 1 333-333 333 333 0 0 1 333 333m-583 83l250-250 250 250-58 59-192-192-192 192-58-59z" horiz-adv-x="1000" />
<glyph glyph-name="format-letter-case" unicode="&#xfb19;" d="M836 100c-3 7-6 19-8 37-28-29-62-44-101-44-34 0-63 10-85 30-22 19-34 44-34 75 0 36 14 65 42 85 28 20 67 30 118 30h58v27c0 20-6 37-18 49-13 12-32 18-56 18-22 0-39-5-54-15-15-11-22-23-22-37h-61c0 18 7 35 19 51 12 17 30 30 51 39 21 9 44 15 70 15 41 0 73-10 96-30 23-21 35-49 36-85v-162c0-33 4-59 12-78v-5h-63m-100 47c19 0 37 4 54 13 16 9 29 20 36 35v65h-47c-74 0-111-20-111-59 0-18 7-30 20-40 12-9 28-14 48-14m-508 132h169l-84 226-85-226m49 321h71l197-500h-81l-40 107h-223l-40-107h-81l197 500z" horiz-adv-x="1000" />
<glyph glyph-name="download-outline" unicode="&#xfb6b;" d="M792 100h-584v-83h584v83z m-334 667h84v-425l187 187 59-58-288-288-287 288 58 58 187-187v425z" horiz-adv-x="1000" />
<glyph glyph-name="video-outline" unicode="&#xfbb8;" d="M750 517v83c0 46-37 83-83 83h-500c-46 0-84-37-84-83v-500c0-46 38-83 84-83h500c46 0 83 37 83 83v83l106-53c28-14 61 7 61 37v366c0 31-33 51-61 37l-106-53z m83-282l-83 42-53 26c-14 7-30-3-30-18v-60-125h-500v500h500v-125-59c0-16 16-26 30-19l53 27 83 41v-230z" horiz-adv-x="1000" />
<glyph glyph-name="pencil-outline" unicode="&#xfc92;" d="M586 475l39-39-378-378h-39v39l378 378m150 250c-11 0-21-4-29-12l-77-76 157-157 76 77c16 16 16 43 0 58l-98 98c-8 8-18 12-29 12m-150-133l-461-461v-156h156l461 461-156 156z" horiz-adv-x="1000" />
<glyph glyph-name="camera-outline" unicode="&#xfd39;" d="M833 683h-132l-76 84h-250l-76-84h-132a83 83 0 0 1-84-83v-500a83 83 0 0 1 84-83h666a83 83 0 0 1 84 83v500a83 83 0 0 1-84 83m0-583h-666v500h168l77 83h176l77-83h168v-500m-333 458a208 208 0 0 1-208-208 208 208 0 0 1 208-208 208 208 0 0 1 208 208 208 208 0 0 1-208 208m0-333a125 125 0 0 0-125 125 125 125 0 0 0 125 125 125 125 0 0 0 125-125 125 125 0 0 0-125-125z" horiz-adv-x="1000" />
<glyph glyph-name="file-video-outline" unicode="&#xfe10;" d="M583 767l250-250v-500a83 83 0 0 0-83-84h-500a83 83 0 0 0-83 84v666a83 83 0 0 0 83 84h333m167-750v458h-208v208h-292v-666h500m-83 83l-104 71v-71h-230v208h230v-70l104 70v-208z" horiz-adv-x="1000" />
<glyph glyph-name="palette-outline" unicode="&#xfe6c;" d="M500-67a417 417 0 0 0-417 417 417 417 0 0 0 417 417c229 0 417-167 417-375a250 250 0 0 0-250-250h-75c-13 0-21-9-21-21 0-4 4-8 4-13 17-20 25-45 25-70 4-59-42-105-100-105m0 750a333 333 0 0 1-333-333 333 333 0 0 1 333-333c13 0 21 8 21 21 0 8-4 12-4 16-17 21-25 42-25 67 0 58 46 104 104 104h71a167 167 0 0 1 166 167c0 162-150 291-333 291m-229-250c33 0 62-29 62-62 0-33-29-63-62-63-33 0-63 30-63 63 0 33 30 62 63 62m125 167c33 0 62-29 62-62 0-34-29-63-62-63-33 0-63 29-63 63 0 33 30 62 63 62m208 0c34 0 63-29 63-62 0-34-29-63-63-63-33 0-62 29-62 63 0 33 29 62 62 62m125-167c34 0 63-29 63-62 0-33-29-63-63-63-33 0-62 30-62 63 0 33 29 62 62 62z" horiz-adv-x="1000" />
<glyph glyph-name="file-music-outline" unicode="&#xfe7c;" d="M583 767l250-250v-500c0-46-37-84-83-84h-500c-46 0-83 38-83 84v666c0 46 37 84 83 84h333m167-750v458h-208v208h-292v-666h500m-208 41l-125 125h-84v125h84l125 125v-375z" horiz-adv-x="1000" />
<glyph glyph-name="file-pdf-outline" unicode="&#xfe7d;" d="M583 767l250-250v-500a83 83 0 0 0-83-84h-500a83 83 0 0 0-83 84v666a83 83 0 0 0 83 84h333m167-750v458h-208v208h-292v-666h500m-295 320c-10 32-32 135 26 136 59 2 20-130 20-130 17-62 84-106 84-106 21 6 140 20 123-42-18-62-145-4-145-4-82-6-143-27-143-27-47-88-102-126-124-89-28 46 89 105 89 105 60 98 69 155 70 157m27-35c-17-54-50-112-50-112 36 14 113 30 113 30-47 42-62 82-63 82m131-90c0 0 73-27 75-17 2 12-56 22-75 17m-236-62c-32-13-63-66-55-66 7-1 38 25 55 66m105 231c0 2 18 70 0 72-12 1 0-70 0-72z" horiz-adv-x="1000" />
<glyph glyph-name="file-image-outline" unicode="&#xfecd;" d="M583 767l250-250v-500a83 83 0 0 0-83-84h-500a83 83 0 0 0-83 84v666a83 83 0 0 0 83 84h333m167-750v458h-208v208h-292v-666h500m-42 291v-250h-416l208 209 83-84m-166 230a63 63 0 0 0-63-63 63 63 0 0 0-62 63 63 63 0 0 0 62 62 63 63 0 0 0 63-62z" horiz-adv-x="1000" />
<glyph glyph-name="reply-outline" unicode="&#xff3d;" d="M354 513l0 0v-84l79-4c113-4 205-50 280-137-88 29-180 33-280 33h-83v-83-30l-154 155 158 150m75 170c-4 0-12 0-21-4l-320-300c-5-4-5-8-5-16 0-5 0-9 5-13l320-308c5-4 13-4 17-4 4 4 8 8 8 20v184c196 0 346-21 450-213 5-4 9-8 13-8h4c8 4 13 12 8 21 5 12-12 125-87 241-92 146-225 225-388 234v154c5 8 0 12-4 12l0 0z" horiz-adv-x="1000" />
<glyph glyph-name="draw" unicode="&#xff66;" d="M406-19c74 29 58 110 21 161-37 52-89 88-140 122-37 24-71 53-98 86-11 14-35 39-11 44 25 5 67-19 89-28 38-16 75-34 110-56l42 71c-65 43-148 81-226 92-44 7-90-3-105-50-14-42 7-83 32-116 57-76 145-113 212-179 14-13 31-30 39-49 9-18 7-19-13-19-51 0-116 40-158 67l-42-71c64-39 170-101 248-75m462 650c10 9 10 24 0 33l-54 54c-9 9-24 9-32 0l-43-42 87-87m-368-194v-87h87l256 257-86 86-257-256z" horiz-adv-x="1000" />
<glyph glyph-name="account-outline" unicode="&#xf0013;" d="M800 188l-133 79c8 12 21 25 29 41 33 59 54 134 54 209 0 150-100 250-250 250s-250-100-250-250c0-75 21-150 54-213 9-16 17-29 29-41l-133-80c-46-16-75-66-75-116 0-75 58-134 133-134h484c75 0 133 59 133 134 0 50-29 100-75 121z m-467 329c0 116 75 166 167 166s167-50 167-166c0-75-25-159-75-209-25-25-54-41-92-41s-67 16-92 41c-50 50-75 134-75 209z m409-500h-484c-29 0-50 21-50 50 0 21 13 37 30 46l162 95c33-16 67-25 100-25s67 9 96 25l162-95c17-9 30-25 30-46 4-29-17-50-46-50z" horiz-adv-x="1000" />
<glyph glyph-name="arrow-expand-all" unicode="&#xf004c;" d="M396 305l59-59-188-188h150v-83h-292v292h83v-150l188 188m59 149l-59-59-188 188v-150h-83v292h292v-83h-150l188-188m149-149l188-188v150h83v-292h-292v83h150l-188 188 59 59m-59 149l188 188h-150v83h292v-292h-83v150l-188-188-59 59z" horiz-adv-x="1000" />
<glyph glyph-name="file-code-outline" unicode="&#xf004d;" d="M583 767h-333c-46 0-83-38-83-84v-666c0-47 37-84 83-84h500c46 0 83 37 83 84v500l-250 250m167-750h-500v666h292v-208h208v-458m-352 181l87-87-54-53-139 140 139 140 54-53-87-87m310 0l-139-140-53 53 87 87-87 87 53 53 139-140z" horiz-adv-x="1000" />
<glyph glyph-name="file-excel-outline" unicode="&#xf004f;" d="M583 767h-333c-46 0-83-38-83-84v-666c0-47 37-84 83-84h500c46 0 83 37 83 84v500l-250 250m167-750h-500v666h292v-208h208v-458m-212 229l120-188h-75l-83 142-83-142h-75l121 188-121 187h75l83-141 83 141h75l-120-187z" horiz-adv-x="1000" />
<glyph glyph-name="arrow-right" unicode="&#xf0054;" d="M167 392v-84h500l-229-229 59-59 330 330-330 330-59-59 229-229h-500z" horiz-adv-x="1000" />
<glyph glyph-name="file-powerpoint-outline" unicode="&#xf0057;" d="M583 767h-333c-46 0-83-38-83-84v-666c0-47 37-84 83-84h500c46 0 83 37 83 84v500l-250 250m167-750h-500v666h292v-208h208v-458m-117 383c-20 21-45 33-100 33h-158v-375h67v138h91c55 0 75 8 100 29 25 21 34 50 34 88 0 37-9 62-34 87m-54-133c-12-13-25-21-50-21h-87v133h83c25 0 42-8 54-21 13-12 17-25 17-45s-4-34-17-46z" horiz-adv-x="1000" />
<glyph glyph-name="file-word-outline" unicode="&#xf0060;" d="M583 767h-333c-46 0-83-38-83-84v-666c0-47 37-84 83-84h500c46 0 83 37 83 84v500l-250 250m167-750h-500v666h292v-208h208v-458m-27 416l-88-375h-58l-75 283-75-283h-58l-92 375h63l58-283 75 283h54l75-283 58 283h63z" horiz-adv-x="1000" />
<glyph glyph-name="bookmark" unicode="&#xf00c0;" d="M708 725h-416a83 83 0 0 1-84-83v-667l292 125 292-125v667c0 46-38 83-84 83z" horiz-adv-x="1000" />
<glyph glyph-name="bookmark-outline" unicode="&#xf00c3;" d="M708 100l-208 91-208-91v542h416m0 83h-416c-46 0-84-37-84-83v-667l292 125 292-125v667c0 46-38 83-84 83z" horiz-adv-x="1000" />
<glyph glyph-name="dock-left" unicode="&#xf00d5;" d="M833 683h-666a83 83 0 0 1-84-83v-500a83 83 0 0 1 84-83h666a83 83 0 0 1 84 83v500a83 83 0 0 1-84 83m0-583h-458v500h458z" horiz-adv-x="1000" />
<glyph glyph-name="chevron-up" unicode="&#xf0143;" d="M309 208l191 191 191-191 59 59-250 250-250-250 59-59z" horiz-adv-x="1000" />
<glyph glyph-name="close-circle" unicode="&#xf0159;" d="M500 767c230 0 417-187 417-417 0-230-187-417-417-417-230 0-417 187-417 417 0 230 187 417 417 417m150-209l-150-149-150 149-58-58 149-150-149-150 58-58 150 149 150-149 58 58-149 150 149 150-58 58z" horiz-adv-x="1000" />
<glyph glyph-name="content-copy" unicode="&#xf018f;" d="M792-25h-459v583h459m0 84h-459a83 83 0 0 1-83-84v-583a83 83 0 0 1 83-83h459a83 83 0 0 1 83 83v583a83 83 0 0 1-83 84m-125 166h-500a83 83 0 0 1-84-83v-583h84v583h500v83z" horiz-adv-x="1000" />
<glyph glyph-name="send-outline" unicode="&#xf0190;" d="M167 599l312-134-312 41 0 93m312-364l-312-134v93l312 41m-396 490l0-292 625-83-625-83 0-292 875 375-875 375z" horiz-adv-x="1000" />
<glyph glyph-name="credit-card-outline" unicode="&#xf019b;" d="M833 517h-666v83h666m0-500h-666v250h666m0 333h-666c-47 0-84-37-84-83v-500a83 83 0 0 1 84-83h666a83 83 0 0 1 84 83v500c0 46-38 83-84 83z" horiz-adv-x="1000" />
<glyph glyph-name="drag-vertical" unicode="&#xf01dd;" d="M375 725h83v-83h-83v83m167 0h83v-83h-83v83m-167-167h83v-83h-83v83m167 0h83v-83h-83v83m-167-166h83v-84h-83v84m167 0h83v-84h-83v84m-167-167h83v-83h-83v83m167 0h83v-83h-83v83m-167-167h83v-83h-83v83m167 0h83v-83h-83v83z" horiz-adv-x="1000" />
<glyph glyph-name="view-grid-outline" unicode="&#xf0204;" d="M125 392h333v333h-333m83-83h167v-167h-167m334-500h333v333h-333m83-83h167v-167h-167m-500-83h333v333h-333m83-83h167v-167h-167m334 667v-333h333v333m-83-250h-167v167h167z" horiz-adv-x="1000" />
<glyph glyph-name="exit-to-app" unicode="&#xf0206;" d="M792 725h-584c-46 0-83-37-83-83v-167h83v167h584v-584h-584v167h-83v-167c0-46 37-83 83-83h584c46 0 83 37 83 83v584c0 46-37 83-83 83m-372-524l59-59 209 208-209 208-59-58 108-108h-403v-84h403l-108-107z" horiz-adv-x="1000" />
<glyph glyph-name="file-outline" unicode="&#xf0224;" d="M583 767h-333a83 83 0 0 1-83-84v-666a83 83 0 0 1 83-84h500a83 83 0 0 1 83 84v500l-250 250m167-750h-500v666h292v-208h208v-458z" horiz-adv-x="1000" />
<glyph glyph-name="folder-outline" unicode="&#xf0256;" d="M833 100h-666v417h666m0 83h-333l-83 83h-250c-47 0-84-37-84-83v-500a83 83 0 0 1 84-83h666a83 83 0 0 1 84 83v417c0 46-38 83-84 83z" horiz-adv-x="1000" />
<glyph glyph-name="archive-arrow-up-outline" unicode="&#xf0287;" d="M833-25h-666v458h83v-375h500v375h83v-458m-708 750h750v-250h-750v250m83-83v-84h584v84m-354-500v125h-105l167 166 167-166h-104v-125" horiz-adv-x="1000" />
<glyph glyph-name="glasses" unicode="&#xf02aa;" d="M125 433c-10 0-19-3-25-10-5-6-8-15-7-25l21-125c4-27 28-48 53-48h125c26 0 56 23 62 49l44 133c2 6 1 13-2 18-5 5-12 8-21 8h-250m167-291h-125c-68 0-127 52-135 119l-21 124c-5 36 5 69 27 93 22 25 53 39 87 39h250c35 0 66-15 86-40 4-7 9-13 12-21 18 4 36 4 54 0 3 8 7 14 12 21 20 25 51 40 86 40h250c34 0 65-14 87-39 21-24 31-57 27-91l-21-128c-8-65-68-117-135-117h-125c-65 0-128 49-144 112l-37 113c-16 12-38 12-54 0l-38-116c-15-60-78-109-143-109m333 291c-9 0-16-3-21-8-3-5-4-12-2-21l42-127c8-29 38-52 64-52h125c25 0 50 21 52 46l22 128c1 9-2 18-7 24-6 7-15 10-25 10h-250z" horiz-adv-x="1000" />
<glyph glyph-name="key-variant" unicode="&#xf030b;" d="M727 575c16-17 25-36 25-58s-9-41-25-57c-17-17-36-25-58-25s-41 8-58 25c-16 16-24 35-24 57s8 41 24 58c17 16 36 25 58 25s41-9 58-25z m118 118c-49 49-109 74-179 74-66 0-123-25-173-74-38-39-62-84-71-137-8-51 1-100 24-146l-363-361 116-116 118 118 118-118 116 116-118 117 129 129c46-24 94-32 146-24 53 9 99 32 137 71 50 49 73 108 72 175 1 68-22 126-72 176z" horiz-adv-x="1000" />
<glyph glyph-name="magnify-minus" unicode="&#xf034a;" d="M375 767a292 292 0 0 0 292-292c0-65-21-125-58-175l33-33h25l250-250-84-84-250 250v25l-33 33c-50-37-110-58-175-58a292 292 0 0 0-292 292 292 292 0 0 0 292 292m-167-250v-84h334v84h-334z" horiz-adv-x="1000" />
<glyph glyph-name="magnify-plus" unicode="&#xf034b;" d="M375 767a292 292 0 0 0 292-292c0-65-21-125-58-175l33-33h25l250-250-84-84-250 250v25l-33 33c-50-37-110-58-175-58a292 292 0 0 0-292 292 292 292 0 0 0 292 292m-42-125v-125h-125v-84h125v-125h84v125h125v84h-125v125h-84z" horiz-adv-x="1000" />
<glyph glyph-name="menu-left" unicode="&#xf035e;" d="M583 558l-208-208 208-208v416z" horiz-adv-x="1000" />
<glyph glyph-name="menu-right" unicode="&#xf035f;" d="M417 142l208 208-208 208v-416z" horiz-adv-x="1000" />
<glyph glyph-name="menu-up" unicode="&#xf0360;" d="M292 225l208 208 208-208h-416z" horiz-adv-x="1000" />
<glyph glyph-name="message-text-outline" unicode="&#xf036a;" d="M833 767a83 83 0 0 0 84-84v-500a83 83 0 0 0-84-83h-583l-167-167v750c0 47 38 84 84 84h666m-666-84v-548l48 48h618v500h-666m83-125h500v-83h-500v83m0-166h375v-84h-375v84z" horiz-adv-x="1000" />
<glyph glyph-name="minus" unicode="&#xf0374;" d="M792 308h-584v84h584v-84z" horiz-adv-x="1000" />
<glyph glyph-name="minus-circle-outline" unicode="&#xf0377;" d="M500 17c-184 0-333 149-333 333 0 184 149 333 333 333 184 0 333-149 333-333 0-184-149-333-333-333m0 750a417 417 0 0 1-417-417 417 417 0 0 1 417-417 417 417 0 0 1 417 417 417 417 0 0 1-417 417m-208-459h416v84h-416" horiz-adv-x="1000" />
<glyph glyph-name="open-in-new" unicode="&#xf03cc;" d="M583 725v-83h150l-410-410 59-59 410 410v-150h83v292m-83-667h-584v584h292v83h-292c-46 0-83-37-83-83v-584a83 83 0 0 1 83-83h584a83 83 0 0 1 83 83v292h-83v-292z" horiz-adv-x="1000" />
<glyph glyph-name="pause" unicode="&#xf03e4;" d="M583 58h167v584h-167m-333-584h167v584h-167v-584z" horiz-adv-x="1000" />
<glyph glyph-name="play" unicode="&#xf040a;" d="M333 636v-583l459 291-459 292z" horiz-adv-x="1000" />
<glyph glyph-name="radiobox-blank" unicode="&#xf043d;" d="M500 17a333 333 0 0 0-333 333 333 333 0 0 0 333 333 333 333 0 0 0 333-333 333 333 0 0 0-333-333m0 750a417 417 0 0 1-417-417 417 417 0 0 1 417-417 417 417 0 0 1 417 417 417 417 0 0 1-417 417z" horiz-adv-x="1000" />
<glyph glyph-name="radiobox-marked" unicode="&#xf043e;" d="M500 17a333 333 0 0 0-333 333 333 333 0 0 0 333 333 333 333 0 0 0 333-333 333 333 0 0 0-333-333m0 750a417 417 0 0 1-417-417 417 417 0 0 1 417-417 417 417 0 0 1 417 417 417 417 0 0 1-417 417m0-209a208 208 0 0 1-208-208 208 208 0 0 1 208-208 208 208 0 0 1 208 208 208 208 0 0 1-208 208z" horiz-adv-x="1000" />
<glyph glyph-name="sort-alphabetical-ascending" unicode="&#xf05bd;" d="M792 142h125l-167-167-167 167h125v583h84m-334-417v-83l-138-167h138v-83h-250v83l139 167h-139v83m167 417h-83c-46 0-84-37-84-83v-250h84v83h83v-83h83v250c0 46-37 83-83 83m0-167h-83v84h83z" horiz-adv-x="1000" />
<glyph glyph-name="playlist-check" unicode="&#xf05c7;" d="M583 433h-500v-83h500v83m0 167h-500v-83h500v83m-500-417h334v84h-334v-84m813 188l62-63-291-291-188 187 63 63 125-125 229 229z" horiz-adv-x="1000" />
<glyph glyph-name="check-circle-outline" unicode="&#xf05e1;" d="M500 767c-229 0-417-188-417-417s188-417 417-417 417 188 417 417-188 417-417 417m0-750c-184 0-333 149-333 333s149 333 333 333 333-149 333-333-149-333-333-333m191 517l-274-274-108 107-59-59 167-166 333 333-59 59z" horiz-adv-x="1000" />
<glyph glyph-name="help-circle-outline" unicode="&#xf0625;" d="M458 100h84v83h-84v-83m42 667a417 417 0 0 1-417-417 417 417 0 0 1 417-417 417 417 0 0 1 417 417 417 417 0 0 1-417 417m0-750c-184 0-333 149-333 333 0 184 149 333 333 333 184 0 333-149 333-333 0-184-149-333-333-333m0 583a167 167 0 0 1-167-167h84a83 83 0 0 0 83 84 83 83 0 0 0 83-84c0-83-125-73-125-208h84c0 94 125 104 125 208a167 167 0 0 1-167 167z" horiz-adv-x="1000" />
<glyph glyph-name="circle-multiple-outline" unicode="&#xf0695;" d="M604 142c173 0 313 140 313 312 0 173-140 313-313 313-103 0-195-50-252-128 15 2 29 3 44 3 23 0 46-2 68-6 39 30 88 47 140 47 127 0 229-102 229-229 0-126-102-229-229-229-22 0-43 3-63 9-2 1-5 1-8 2-49 16-91 48-119 91-13 19-24 41-30 64-29-2-56-13-78-30 11-36 29-70 52-99 38-49 91-87 153-106 29-9 61-14 93-14z m0-84c15 0 29 1 44 3-57-78-149-128-252-128-173 0-313 140-313 313 0 172 140 312 313 312 79 0 150-29 205-77l0 0c43-37 76-86 93-142-22-17-48-28-78-30-21 76-81 136-157 157v0c-20 6-41 9-63 9-127 0-229-103-229-229 0-127 102-229 229-229 53 0 101 17 140 47 22-4 45-6 68-6z" horiz-adv-x="1000" />
<glyph glyph-name="update" unicode="&#xf06b0;" d="M875 428h-282l114 118c-114 112-298 117-412 4-114-113-114-295 0-408 114-113 298-113 412 0 56 56 85 121 85 204h83c0-83-37-190-110-262-146-145-384-145-530 0-146 144-147 379-1 524 146 145 381 145 527 0l114 117v-297m-354 89v-177l146-87-30-50-179 105v209h63z" horiz-adv-x="1000" />
<glyph glyph-name="eye-off-outline" unicode="&#xf06d1;" d="M83 630l54 53 696-696-53-54-128 129c-48-16-99-24-152-24-208 0-386 129-458 312 28 73 74 138 133 189l-92 91m417-155a125 125 0 0 0 125-125c0-15-2-29-7-42l-160 160c13 5 27 7 42 7m0 188c208 0 386-130 458-313-34-87-92-162-166-216l-59 59c56 40 103 93 135 157-69 140-211 229-368 229-45 0-90-7-132-21l-64 64c60 26 126 41 196 41m-367-313c68-140 210-229 367-229 29 0 57 3 83 9l-95 95c-59 6-107 54-113 113l-142 142c-41-35-75-79-100-130z" horiz-adv-x="1000" />
<glyph glyph-name="infinity" unicode="&#xf06e4;" d="M775 574c124 0 225-99 225-224 0-123-101-224-225-224-60 0-117 24-159 66l-116 102-118-104c-40-41-97-64-157-64-124 0-225 101-225 224 0 123 101 224 225 224 60 0 117-23 159-66l116-102 118 104c40 41 97 64 157 64m-450-324l113 100-111 98c-29 28-64 43-102 43-78 0-142-63-142-141 0-78 64-141 142-141 38 0 73 15 100 41m350 200l-112-100 110-98c29-28 65-43 102-43 78 0 142 63 142 141 0 78-64 141-142 141-38 0-73-15-100-41z" horiz-adv-x="1000" />
<glyph glyph-name="plus-box-outline" unicode="&#xf0704;" d="M792 58v584h-584v-584h584m0 667a83 83 0 0 0 83-83v-584a83 83 0 0 0-83-83h-584a83 83 0 0 0-83 83v584c0 46 38 83 83 83h584m-334-167h84v-166h166v-84h-166v-166h-84v166h-166v84h166v166z" horiz-adv-x="1000" />
<glyph glyph-name="arrow-right-bold-outline" unicode="&#xf09c2;" d="M458 183h-333v334h333v250l417-417-417-417v250m84 375v-125h-334v-166h334v-125l208 208-208 208z" horiz-adv-x="1000" />
<glyph glyph-name="trash-can-outline" unicode="&#xf0a7a;" d="M375 725v-42h-208v-83h41v-542a83 83 0 0 1 84-83h416a83 83 0 0 1 84 83v542h41v83h-208v42h-250m-83-125h416v-542h-416v542m83-83v-375h83v375h-83m167 0v-375h83v375h-83z" horiz-adv-x="1000" />
<glyph glyph-name="account-minus-outline" unicode="&#xf0aec;" d="M210 58c-24 0-43 20-43 44 0 5 0 9 2 13 2 8 7 16 13 21 3 3 7 5 11 7l129 77c28-17 59-26 95-26s67 9 95 26l14-9c13 26 30 48 50 68l-1 0c44 58 68 138 68 217 0 137-91 229-226 229s-226-92-226-229c0-79 24-159 67-217l-105-63c-42-21-70-65-70-114 0-70 57-127 127-127h324c-15 25-25 53-30 83h-294z m207 584c79 0 143-45 143-146 0-62-21-130-57-174-23-27-52-45-86-45-11 0-22 2-32 5-5 2-10 4-15 7-9 5-18 11-26 19-5 4-9 9-14 14-3 4-6 8-9 12-6 9-12 20-18 31-8 17-15 35-19 54-4 13-6 26-8 39-1 12-2 25-2 38 0 101 64 146 143 146z m500-500v-84h-334v84h334z" horiz-adv-x="1000" />
<glyph glyph-name="calendar-outline" unicode="&#xf0b67;" d="M792 725h-42v83h-83v-83h-334v83h-83v-83h-42c-46 0-83-37-83-83v-584c0-45 37-83 83-83h584c46 0 83 38 83 83v584c0 46-37 83-83 83z m0-667h-584v417h584v-417z m0 500h-584v84h584v-84z m-500-166h208v-209h-208z" horiz-adv-x="1000" />
<glyph glyph-name="export-variant" unicode="&#xf0b93;" d="M500 808l-167-166h125v-375h84v375h125m83-750h-500c-46 0-83 37-83 83v500a83 83 0 0 0 83 83h125v-83h-125v-500h500v500h-125v83h125a83 83 0 0 0 83-83v-500a83 83 0 0 0-83-83z" horiz-adv-x="1000" />
<glyph glyph-name="folder-plus-outline" unicode="&#xf0b9d;" d="M500 350h83v83h84v-83h83v-83h-83v-84h-84v84h-83v83m417 167v-417c0-46-37-83-84-83h-666c-47 0-84 37-84 83v500c0 46 37 83 84 83h250l83-83h333c47 0 84-37 84-83m-84 0h-666v-417h666v417z" horiz-adv-x="1000" />
<glyph glyph-name="home-variant-outline" unicode="&#xf0ba7;" d="M750 58v375l-250 188-250-188v-375h500z m-583-41v437c0 13 6 26 16 34l292 218c15 11 35 11 50 0l292-218c10-8 16-21 16-34v-437c0-23-18-42-41-42h-584c-23 0-41 19-41 42z m385 250h-104c-17 0-31-14-31-32v-177h166v177c0 18-14 32-31 32z" horiz-adv-x="1000" />
<glyph glyph-name="calendar-check-outline" unicode="&#xf0c44;" d="M792 683h-42v84h-83v-84h-334v84h-83v-84h-42a83 83 0 0 1-83-83v-583a83 83 0 0 1 83-84h584a83 83 0 0 1 83 84v583a83 83 0 0 1-83 83m0-666h-584v416h584v-416m-584 500v83h584v-83h-584m232-436l248 247-45 44-203-203-88 88-44-44 132-132z" horiz-adv-x="1000" />
<glyph glyph-name="hand-right" unicode="&#xf0e47;" d="M875 576v-504a139 139 0 0 0-139-139h-253c-38 0-73 15-99 42l-273 277c0 0 44 43 45 43 8 7 17 10 28 10 7 0 14-2 21-5 1-1 149-86 149-86v414a52 52 0 0 0 52 52 52 52 0 0 0 52-52v-243h35v330a52 52 0 0 0 52 52c29 0 52-24 52-52v-330h35v295c0 29 23 52 52 52a52 52 0 0 0 52-52v-295h35v191a52 52 0 0 0 52 52 52 52 0 0 0 52-52z" horiz-adv-x="1000" />
<glyph glyph-name="notebook-outline" unicode="&#xf0ebf;" d="M708 683v-250l-83 84-83-84v250h-167v-666h417v666h-84m-583-125v84h83v41c0 47 38 84 84 84h500c43 0 83-40 83-84v-666c0-44-40-84-83-84h-500c-44 0-84 40-84 84v41h-83v84h83v166h-83v84h83v166h-83m83 84v-84h84v84h-84m0-584h84v84h-84v-84m0 250h84v84h-84v-84z" horiz-adv-x="1000" />
<glyph glyph-name="shield-alert-outline" unicode="&#xf0ecd;" d="M875 392c0-232-160-448-375-500-215 52-375 268-375 500v250l375 166 375-166v-250m-375-417c156 42 292 228 292 408v205l-292 130-292-130v-205c0-180 136-366 292-408m-42 583h84v-250h-84v250m0-333h84v-83h-84v83z" horiz-adv-x="1000" />
<glyph glyph-name="slash-forward" unicode="&#xf0fdf;" d="M292-25l329 750h87l-329-750h-87z" horiz-adv-x="1000" />
<glyph glyph-name="file-multiple-outline" unicode="&#xf1032;" d="M667 850h-334c-45 0-83-37-83-83v-667c0-46 38-83 83-83h500c46 0 84 37 84 83v500l-250 250m166-750h-500v667h292v-209h208v-458m-666 583v-750h666v-83h-666c-46 0-84 37-84 83v750h84z" horiz-adv-x="1000" />
<glyph glyph-name="message-plus-outline" unicode="&#xf10bb;" d="M833 767h-666c-46 0-84-38-84-84v-750l167 167h583c46 0 84 38 84 83v500c0 46-38 84-84 84m0-584h-583l-83-83v583h666m-166-208v-83h-125v-125h-84v125h-125v83h125v125h84v-125h125z" horiz-adv-x="1000" />
<glyph glyph-name="message-minus-outline" unicode="&#xf116f;" d="M833 767h-666c-46 0-84-38-84-84v-750l167 167h583c47 0 84 37 84 83v500c0 46-37 84-84 84m0-584h-583l-83-83v583h666m-500-208v-83h334v83h-334z" horiz-adv-x="1000" />
<glyph glyph-name="crown-outline" unicode="&#xf11d0;" d="M500 517l125-217 125 113-29-146h-442l-29 146 125-113 125 217m0 166l-146-250-229 209 83-459h584l83 459-229-209-146 250m292-583h-584v-42c0-25 17-41 42-41h500c25 0 42 16 42 41v42z" horiz-adv-x="1000" />
<glyph glyph-name="folder-move-outline" unicode="&#xf1246;" d="M833 100h-666v417h666v-417m-333 500l-83 83h-250c-46 0-84-37-84-83v-500c0-46 38-83 84-83h666c47 0 84 37 84 83v417c0 46-37 83-84 83h-333m-42-333v83h167v125l167-167-167-166v125h-167z" horiz-adv-x="1000" />
</font>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 84 KiB

View file

@ -2,11 +2,13 @@
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import classNames from 'classnames';
import React, {Fragment} from 'react';
import {Container, Row} from 'react-bootstrap';
import {DropResult} from 'react-beautiful-dnd';
import DotsVerticalIcon from 'mdi-react/DotsVerticalIcon';
import {IpcRendererEvent} from 'electron/renderer';
import prettyBytes from 'pretty-bytes';
import {TeamWithTabs} from 'types/config';
@ -36,6 +38,11 @@ import {
CLOSE_TEAMS_DROPDOWN,
OPEN_TEAMS_DROPDOWN,
SWITCH_TAB,
UPDATE_AVAILABLE,
UPDATE_DOWNLOADED,
UPDATE_PROGRESS,
START_UPGRADE,
START_DOWNLOAD,
CLOSE_TAB,
} from 'common/communication';
@ -50,6 +57,7 @@ import TabBar from './TabBar';
import ExtraBar from './ExtraBar';
import ErrorView from './ErrorView';
import TeamDropdownButton from './TeamDropdownButton';
import '../css/components/UpgradeButton.scss';
enum Status {
LOADING = 1,
@ -59,6 +67,13 @@ enum Status {
NOSERVERS = -2,
}
enum UpgradeStatus {
NONE = 0,
AVAILABLE = 1,
DOWNLOADING = 2,
DOWNLOADED = 3,
}
type Props = {
teams: TeamWithTabs[];
lastActiveTeam?: number;
@ -82,6 +97,14 @@ type State = {
fullScreen?: boolean;
showExtraBar?: boolean;
isMenuOpen: boolean;
upgradeStatus: UpgradeStatus;
upgradeProgress?: {
total: number;
delta: number;
transferred: number;
percent: number;
bytesPerSecond: number;
};
};
type TabViewStatus = {
@ -119,6 +142,7 @@ export default class MainPage extends React.PureComponent<Props, State> {
tabViewStatus: new Map(this.props.teams.map((team) => team.tabs.map((tab) => getTabViewName(team.name, tab.name))).flat().map((tabViewName) => [tabViewName, {status: Status.LOADING}])),
darkMode: this.props.darkMode,
isMenuOpen: false,
upgradeStatus: UpgradeStatus.NONE,
};
}
@ -221,6 +245,27 @@ export default class MainPage extends React.PureComponent<Props, State> {
this.setState({isMenuOpen: true});
});
window.ipcRenderer.on(UPDATE_AVAILABLE, () => {
this.setState({upgradeStatus: UpgradeStatus.AVAILABLE});
});
window.ipcRenderer.on(UPDATE_DOWNLOADED, () => {
this.setState({upgradeStatus: UpgradeStatus.DOWNLOADED});
});
window.ipcRenderer.on(UPDATE_PROGRESS, (event, total, delta, transferred, percent, bytesPerSecond) => {
this.setState({
upgradeStatus: UpgradeStatus.DOWNLOADING,
upgradeProgress: {
total,
delta,
transferred,
percent,
bytesPerSecond,
},
});
});
if (window.process.platform !== 'darwin') {
window.ipcRenderer.on(FOCUS_THREE_DOT_MENU, () => {
if (this.threeDotMenu.current) {
@ -334,16 +379,11 @@ export default class MainPage extends React.PureComponent<Props, State> {
/>
);
let topBarClassName = 'topBar';
if (window.process.platform === 'darwin') {
topBarClassName += ' macOS';
}
if (this.state.darkMode) {
topBarClassName += ' darkMode';
}
if (this.state.fullScreen) {
topBarClassName += ' fullScreen';
}
const topBarClassName = classNames('topBar', {
macOS: window.process.platform === 'darwin',
darkMode: this.state.darkMode,
fullScreen: this.state.fullScreen,
});
let maxButton;
if (this.state.maximized || this.state.fullScreen) {
@ -366,11 +406,46 @@ export default class MainPage extends React.PureComponent<Props, State> {
);
}
let overlayGradient;
if (window.process.platform !== 'darwin') {
overlayGradient = (
<span className='overlay-gradient'/>
);
let upgradeTooltip;
switch (this.state.upgradeStatus) {
case UpgradeStatus.AVAILABLE:
upgradeTooltip = 'Update available';
break;
case UpgradeStatus.DOWNLOADED:
upgradeTooltip = 'Update ready to install';
break;
case UpgradeStatus.DOWNLOADING:
upgradeTooltip = `Downloading update. ${String(this.state.upgradeProgress?.percent).split('.')[0]}% of ${prettyBytes(this.state.upgradeProgress?.total || 0)} @ ${prettyBytes(this.state.upgradeProgress?.bytesPerSecond || 0)}/s`;
break;
}
let upgradeIcon;
if (this.state.upgradeStatus !== UpgradeStatus.NONE) {
upgradeIcon = (
<span className={classNames('upgrade-btns', {darkMode: this.state.darkMode})}>
<div
className={classNames('button upgrade-button', {
rotate: this.state.upgradeStatus === UpgradeStatus.DOWNLOADING,
})}
title={upgradeTooltip}
onClick={() => {
if (this.state.upgradeStatus === UpgradeStatus.DOWNLOADING) {
return;
}
window.ipcRenderer.send(this.state.upgradeStatus === UpgradeStatus.DOWNLOADED ? START_UPGRADE : START_DOWNLOAD);
}}
>
<i
className={classNames({
'icon-arrow-down-bold-circle-outline': this.state.upgradeStatus === UpgradeStatus.AVAILABLE,
'icon-sync': this.state.upgradeStatus === UpgradeStatus.DOWNLOADING,
'icon-arrow-up-bold-circle-outline': this.state.upgradeStatus === UpgradeStatus.DOWNLOADED,
})}
/>
{(this.state.upgradeStatus !== UpgradeStatus.DOWNLOADING) && <div className={'circle'}/>}
</div>
</span>);
}
let titleBarButtons;
@ -435,7 +510,7 @@ export default class MainPage extends React.PureComponent<Props, State> {
darkMode={this.state.darkMode}
/>
{tabsRow}
{overlayGradient}
{upgradeIcon}
{titleBarButtons}
</div>
</Row>

View file

@ -24,14 +24,15 @@ import {
GET_DOWNLOAD_LOCATION,
RELOAD_CONFIGURATION,
GET_AVAILABLE_SPELL_CHECKER_LANGUAGES,
CHECK_FOR_UPDATES,
} from 'common/communication';
import AutoSaveIndicator, {SavingState} from './AutoSaveIndicator';
const CONFIG_TYPE_SERVERS = 'servers';
const CONFIG_TYPE_UPDATES = 'updates';
const CONFIG_TYPE_APP_OPTIONS = 'appOptions';
type ConfigType = typeof CONFIG_TYPE_SERVERS | typeof CONFIG_TYPE_APP_OPTIONS;
type ConfigType = typeof CONFIG_TYPE_UPDATES | typeof CONFIG_TYPE_APP_OPTIONS;
type State = DeepPartial<CombinedConfig> & {
ready: boolean;
@ -40,11 +41,12 @@ type State = DeepPartial<CombinedConfig> & {
userOpenedDownloadDialog: boolean;
allowSaveSpellCheckerURL: boolean;
availableLanguages: Array<{label: string; value: string}>;
canUpgrade?: boolean;
}
type SavingStateItems = {
appOptions: SavingState;
servers: SavingState;
updates: SavingState;
};
type SaveQueueItem = {
@ -66,6 +68,7 @@ export default class SettingsPage extends React.PureComponent<Record<string, nev
useSpellCheckerRef: React.RefObject<HTMLInputElement>;
spellCheckerURLRef: React.RefObject<HTMLInputElement>;
enableHardwareAccelerationRef: React.RefObject<HTMLInputElement>;
autoCheckForUpdatesRef: React.RefObject<HTMLInputElement>;
saveQueue: SaveQueueItem[];
@ -77,7 +80,7 @@ export default class SettingsPage extends React.PureComponent<Record<string, nev
ready: false,
savingState: {
appOptions: SavingState.SAVING_STATE_DONE,
servers: SavingState.SAVING_STATE_DONE,
updates: SavingState.SAVING_STATE_DONE,
},
userOpenedDownloadDialog: false,
allowSaveSpellCheckerURL: false,
@ -97,6 +100,7 @@ export default class SettingsPage extends React.PureComponent<Record<string, nev
this.useSpellCheckerRef = React.createRef();
this.enableHardwareAccelerationRef = React.createRef();
this.spellCheckerURLRef = React.createRef();
this.autoCheckForUpdatesRef = React.createRef();
this.saveQueue = [];
this.selectedSpellCheckerLocales = [];
@ -125,7 +129,7 @@ export default class SettingsPage extends React.PureComponent<Record<string, nev
const newState = Object.assign({} as State, configData);
newState.savingState = currentState.savingState || {
appOptions: SavingState.SAVING_STATE_DONE,
servers: SavingState.SAVING_STATE_DONE,
updates: SavingState.SAVING_STATE_DONE,
};
this.selectedSpellCheckerLocales = configData.spellCheckerLocales?.map((language: string) => ({label: localeTranslations[language] || language, value: language})) || [];
return newState;
@ -147,7 +151,7 @@ export default class SettingsPage extends React.PureComponent<Record<string, nev
updateSaveState = () => {
let queuedUpdateCounts = {
[CONFIG_TYPE_SERVERS]: 0,
[CONFIG_TYPE_UPDATES]: 0,
[CONFIG_TYPE_APP_OPTIONS]: 0,
};
@ -284,6 +288,21 @@ export default class SettingsPage extends React.PureComponent<Record<string, nev
});
}
handleChangeAutoCheckForUpdates = () => {
window.timers.setImmediate(this.saveSetting, CONFIG_TYPE_UPDATES, {key: 'autoCheckForUpdates', data: this.autoCheckForUpdatesRef.current?.checked});
this.setState({
autoCheckForUpdates: this.autoCheckForUpdatesRef.current?.checked,
}, () => {
if (this.state.autoCheckForUpdates) {
this.checkForUpdates();
}
});
}
checkForUpdates = () => {
window.ipcRenderer.send(CHECK_FOR_UPDATES);
}
handleChangeSpellCheckerLocales = (value: OptionsType<{label: string; value: string}>, actionMeta: ActionMeta<{label: string; value: string}>) => {
switch (actionMeta.action) {
case 'select-option':
@ -407,6 +426,12 @@ export default class SettingsPage extends React.PureComponent<Record<string, nev
container: {
paddingBottom: '40px',
},
checkForUpdatesButton: {
marginBottom: '4px',
marginLeft: '16px',
marginTop: '8px',
},
};
const options = [];
@ -757,7 +782,7 @@ export default class SettingsPage extends React.PureComponent<Record<string, nev
<Row>
<Col md={12}>
<h2 style={settingsPage.sectionHeading}>{'App Options'}</h2>
<div className='IndicatorContainer'>
<div className='IndicatorContainer appOptionsSaveIndicator'>
<AutoSaveIndicator
id='appOptionsSaveIndicator'
savingState={this.state.savingState.appOptions}
@ -774,9 +799,60 @@ export default class SettingsPage extends React.PureComponent<Record<string, nev
);
}
let updateRow = null;
if (this.state.canUpgrade) {
updateRow = (
<>
<Row>
<Col md={12}>
<h2 style={settingsPage.sectionHeading}>{'Updates'}</h2>
<div className='IndicatorContainer updatesSaveIndicator'>
<AutoSaveIndicator
id='updatesSaveIndicator'
savingState={this.state.savingState.updates}
errorMessage={'Can\'t save your changes. Please try again.'}
/>
</div>
<FormGroup
key='inputAutoCheckForUpdates'
>
<FormCheck>
<FormCheck.Input
type='checkbox'
key='inputAutoCheckForUpdates'
id='inputAutoCheckForUpdates'
ref={this.autoCheckForUpdatesRef}
checked={this.state.autoCheckForUpdates}
onChange={this.handleChangeAutoCheckForUpdates}
/>
{'Automatically check for updates'}
<FormText>
{'If enabled, updates to the Desktop App will download automatically and you will be notified when ready to install.'}
</FormText>
</FormCheck>
<Button
style={settingsPage.checkForUpdatesButton}
id='checkForUpdatesNow'
onClick={this.checkForUpdates}
>
<span>{'Check for Updates Now'}</span>
</Button>
</FormGroup>
</Col>
</Row>
<hr/>
</>
);
}
let waitForIpc;
if (this.state.ready) {
waitForIpc = optionsRow;
waitForIpc = (
<>
{updateRow}
{optionsRow}
</>
);
} else {
waitForIpc = (<p>{'Loading configuration...'}</p>);
}

View file

@ -7,7 +7,6 @@ import React, {useEffect} from 'react';
import {CLOSE_TEAMS_DROPDOWN, OPEN_TEAMS_DROPDOWN} from 'common/communication';
import '../css/components/TeamDropdownButton.scss';
import '../css/compass-icons.css';
type Props = {
isDisabled?: boolean;

View file

@ -1,285 +0,0 @@
@charset "UTF-8";
@font-face {
font-family: 'compass-icons';
src: url('../assets/fonts/compass-icons/compass-icons.eot?81398164');
src: url('../assets/fonts/compass-icons/compass-icons.eot?81398164#iefix') format('embedded-opentype'),
url('../assets/fonts/compass-icons/compass-icons.woff2?81398164') format('woff2'),
url('../assets/fonts/compass-icons/compass-icons.woff?81398164') format('woff'),
url('../assets/fonts/compass-icons/compass-icons.ttf?81398164') format('truetype'),
url('../assets/fonts/compass-icons/compass-icons.svg?81398164#compass-icons') format('svg');
font-weight: normal;
font-style: normal;
}
/* Chrome hack: SVG is rendered more smooth in Windozze. 100% magic, uncomment if you need it. */
/* Note, that will break hinting! In other OS-es font will be not as sharp as it could be */
/*
@media screen and (-webkit-min-device-pixel-ratio:0) {
@font-face {
font-family: 'compass-icons';
src: url('../font/compass-icons.svg?81398164#compass-icons') format('svg');
}
}
*/
[class^="icon-"]:before, [class*=" icon-"]:before {
font-family: "compass-icons";
font-style: normal;
font-weight: normal;
speak: never;
display: inline-block;
text-decoration: inherit;
width: 1em;
margin-right: .2em;
text-align: center;
/* opacity: .8; */
/* For safety - reset parent styles, that can break glyph codes*/
font-variant: normal;
text-transform: none;
/* fix buttons height, for twitter bootstrap */
line-height: 1em;
/* Animation center compensation - margins should be symmetric */
/* remove if not needed */
margin-left: .2em;
/* you can be more comfortable with increased icons size */
/* font-size: 120%; */
/* Font smoothing. That was taken from TWBS */
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
/* Uncomment for 3D effect */
/* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */
}
.icon-mattermost:before { content: '\e800'; } /* '' */
.icon-archive-outline:before { content: '\e801'; } /* '' */
.icon-beach-umbrella-outline:before { content: '\e802'; } /* '' */
.icon-exclamation-thick:before { content: '\e803'; } /* '' */
.icon-gfycat:before { content: '\e804'; } /* '' */
.icon-globe:before { content: '\e805'; } /* '' */
.icon-iframe-list-outline:before { content: '\e806'; } /* '' */
.icon-oauth:before { content: '\e807'; } /* '' */
.icon-power-plug-outline:before { content: '\e808'; } /* '' */
.icon-robot-happy:before { content: '\e809'; } /* '' */
.icon-server-outline:before { content: '\e80a'; } /* '' */
.icon-slash-forward-box-outline:before { content: '\e80b'; } /* '' */
.icon-webhook-incoming:before { content: '\e80c'; } /* '' */
.icon-webhook-outgoing:before { content: '\e80d'; } /* '' */
.icon-image-area-outline:before { content: '\e80e'; } /* '' */
.icon-emoticon-plus-outline:before { content: '\e80f'; } /* '' */
.icon-mark-as-unread:before { content: '\e810'; } /* '' */
.icon-arrow-back-ios:before { content: '\e811'; } /* '' */
.icon-arrow-forward-ios:before { content: '\e812'; } /* '' */
.icon-brand-zoom:before { content: '\e813'; } /* '' */
.icon-menu-variant:before { content: '\e814'; } /* '' */
.icon-message-check:before { content: '\e815'; } /* '' */
.icon-airplane-variant:before { content: '\e816'; } /* '' */
.icon-food-apple:before { content: '\e817'; } /* '' */
.icon-leaf-outline:before { content: '\e818'; } /* '' */
.icon-basketball:before { content: '\e819'; } /* '' */
.icon-emoticon-custom-outline:before { content: '\e81a'; } /* '' */
.icon-message-check-outline:before { content: '\e81b'; } /* '' */
.icon-image-broken-outline:before { content: '\e81c'; } /* '' */
.icon-format-header:before { content: '\e81d'; } /* '' */
.icon-circle-multiple-outline-lock:before { content: '\e81e'; } /* '' */
.icon-server-variant:before { content: '\e81f'; } /* '' */
.icon-server-variant-plus:before { content: '\e820'; } /* '' */
.icon-search-list:before { content: '\e821'; } /* '' */
.icon-brand-gitlab:before { content: '\e822'; } /* '' */
.icon-brand-google:before { content: '\e823'; } /* '' */
.icon-brand-office-365:before { content: '\e824'; } /* '' */
.icon-brand-one-login:before { content: '\e825'; } /* '' */
.icon-application-cog:before { content: '\e826'; } /* '' */
.icon-key-variant-circle:before { content: '\e827'; } /* '' */
.icon-car-outline:before { content: '\e899'; } /* '' */
.icon-jumbo-attachment-text:before { content: '\e900'; } /* '' */
.icon-jumbo-attachment-word:before { content: '\e901'; } /* '' */
.icon-jumbo-attachment-excel:before { content: '\e902'; } /* '' */
.icon-jumbo-attachment-powerpoint:before { content: '\e903'; } /* '' */
.icon-jumbo-attachment-pdf:before { content: '\e904'; } /* '' */
.icon-jumbo-attachment-image:before { content: '\e905'; } /* '' */
.icon-jumbo-attachment-video:before { content: '\e906'; } /* '' */
.icon-jumbo-attachment-audio:before { content: '\e907'; } /* '' */
.icon-jumbo-attachment-generic:before { content: '\e908'; } /* '' */
.icon-jumbo-attachment-patch:before { content: '\e909'; } /* '' */
.icon-jumbo-attachment-zip:before { content: '\e90a'; } /* '' */
.icon-jumbo-attachment-code:before { content: '\e90b'; } /* '' */
.icon-jumbo-attachment-image-broken:before { content: '\e90c'; } /* '' */
.icon-account-multiple-outline:before { content: '\f00f'; } /* '' */
.icon-airplane:before { content: '\f01d'; } /* '' */
.icon-alert-outline:before { content: '\f02a'; } /* '' */
.icon-arrow-down:before { content: '\f045'; } /* '' */
.icon-arrow-left:before { content: '\f04d'; } /* '' */
.icon-arrow-up:before { content: '\f05d'; } /* '' */
.icon-at:before { content: '\f065'; } /* '' */
.icon-flask-outline:before { content: '\f096'; } /* '' */
.icon-bell-outline:before { content: '\f09c'; } /* '' */
.icon-cellphone:before { content: '\f11c'; } /* '' */
.icon-chart-bar:before { content: '\f128'; } /* '' */
.icon-chart-line:before { content: '\f12a'; } /* '' */
.icon-check:before { content: '\f12c'; } /* '' */
.icon-checkbox-blank-outline:before { content: '\f131'; } /* '' */
.icon-checkbox-marked:before { content: '\f132'; } /* '' */
.icon-chevron-down:before { content: '\f140'; } /* '' */
.icon-chevron-left:before { content: '\f141'; } /* '' */
.icon-chevron-right:before { content: '\f142'; } /* '' */
.icon-clock-outline:before { content: '\f150'; } /* '' */
.icon-close:before { content: '\f156'; } /* '' */
.icon-close-circle-outline:before { content: '\f15a'; } /* '' */
.icon-code-brackets:before { content: '\f16a'; } /* '' */
.icon-code-tags:before { content: '\f174'; } /* '' */
.icon-console:before { content: '\f18d'; } /* '' */
.icon-dots-horizontal:before { content: '\f1d8'; } /* '' */
.icon-dots-vertical:before { content: '\f1d9'; } /* '' */
.icon-email-outline:before { content: '\f1f0'; } /* '' */
.icon-emoticon-outline:before { content: '\f1f2'; } /* '' */
.icon-emoticon-happy-outline:before { content: '\f1f5'; } /* '' */
.icon-filter-variant:before { content: '\f236'; } /* '' */
.icon-fire:before { content: '\f238'; } /* '' */
.icon-flag:before { content: '\f23b'; } /* '' */
.icon-flag-outline:before { content: '\f23d'; } /* '' */
.icon-format-bold:before { content: '\f264'; } /* '' */
.icon-format-clear:before { content: '\f265'; } /* '' */
.icon-format-header-1:before { content: '\f26b'; } /* '' */
.icon-format-header-2:before { content: '\f26c'; } /* '' */
.icon-format-header-3:before { content: '\f26d'; } /* '' */
.icon-format-header-4:before { content: '\f26e'; } /* '' */
.icon-format-header-5:before { content: '\f26f'; } /* '' */
.icon-format-header-6:before { content: '\f270'; } /* '' */
.icon-format-italic:before { content: '\f277'; } /* '' */
.icon-format-list-bulleted:before { content: '\f279'; } /* '' */
.icon-format-list-numbered:before { content: '\f27b'; } /* '' */
.icon-format-strikethrough-variant:before { content: '\f281'; } /* '' */
.icon-github-circle:before { content: '\f2a4'; } /* '' */
.icon-heart-outline:before { content: '\f2d5'; } /* '' */
.icon-help:before { content: '\f2d6'; } /* '' */
.icon-information-outline:before { content: '\f2fd'; } /* '' */
.icon-laptop:before { content: '\f322'; } /* '' */
.icon-leaf:before { content: '\f32a'; } /* '' */
.icon-lightbulb-outline:before { content: '\f336'; } /* '' */
.icon-link-variant:before { content: '\f339'; } /* '' */
.icon-link-variant-off:before { content: '\f33a'; } /* '' */
.icon-lock:before { content: '\f33e'; } /* '' */
.icon-lock-outline:before { content: '\f341'; } /* '' */
.icon-magnify:before { content: '\f349'; } /* '' */
.icon-menu:before { content: '\f35c'; } /* '' */
.icon-menu-down:before { content: '\f35d'; } /* '' */
.icon-minus-box:before { content: '\f375'; } /* '' */
.icon-minus-circle:before { content: '\f376'; } /* '' */
.icon-paperclip:before { content: '\f3e2'; } /* '' */
.icon-pin:before { content: '\f403'; } /* '' */
.icon-plus:before { content: '\f415'; } /* '' */
.icon-plus-box:before { content: '\f416'; } /* '' */
.icon-refresh:before { content: '\f450'; } /* '' */
.icon-send:before { content: '\f48a'; } /* '' */
.icon-shield-outline:before { content: '\f499'; } /* '' */
.icon-sitemap:before { content: '\f4aa'; } /* '' */
.icon-soccer:before { content: '\f4b8'; } /* '' */
.icon-source-pull:before { content: '\f4c2'; } /* '' */
.icon-star:before { content: '\f4ce'; } /* '' */
.icon-star-outline:before { content: '\f4d2'; } /* '' */
.icon-sync:before { content: '\f4e6'; } /* '' */
.icon-alert-circle-outline:before { content: '\f5d6'; } /* '' */
.icon-check-circle:before { content: '\f5e0'; } /* '' */
.icon-email-variant:before { content: '\f5f0'; } /* '' */
.icon-food-fork-drink:before { content: '\f5f2'; } /* '' */
.icon-arrow-collapse:before { content: '\f615'; } /* '' */
.icon-arrow-expand:before { content: '\f616'; } /* '' */
.icon-source-branch:before { content: '\f62c'; } /* '' */
.icon-tune:before { content: '\f62e'; } /* '' */
.icon-webhook:before { content: '\f62f'; } /* '' */
.icon-eye-outline:before { content: '\f6cf'; } /* '' */
.icon-cancel:before { content: '\f739'; } /* '' */
.icon-format-quote-open:before { content: '\f756'; } /* '' */
.icon-square:before { content: '\f763'; } /* '' */
.icon-circle-outline:before { content: '\f765'; } /* '' */
.icon-account-plus-outline:before { content: '\f800'; } /* '' */
.icon-forum-outline:before { content: '\f821'; } /* '' */
.icon-settings-outline:before { content: '\f8ba'; } /* '' */
.icon-hammer:before { content: '\f8e9'; } /* '' */
.icon-pin-outline:before { content: '\f930'; } /* '擄' */
.icon-clock:before { content: '\f953'; } /* '肋' */
.icon-image-outline:before { content: '\f975'; } /* '掠' */
.icon-email-plus-outline:before { content: '\f9eb'; } /* '匿' */
.icon-file-document-outline:before { content: '\f9ed'; } /* '吝' */
.icon-layers-outline:before { content: '\f9fd'; } /* '什' */
.icon-bell-off-outline:before { content: '\fa90'; } /* '敖' */
.icon-chevron-down-circle-outline:before { content: '\fb0c'; } /* '﬌' */
.icon-format-letter-case:before { content: '\fb19'; } /* '﬙' */
.icon-download-outline:before { content: '\fb6b'; } /* 'ﭫ' */
.icon-video-outline:before { content: '\fbb8'; } /* '﮸' */
.icon-pencil-outline:before { content: '\fc92'; } /* 'ﲒ' */
.icon-camera-outline:before { content: '\fd39'; } /* 'ﴹ' */
.icon-file-video-outline:before { content: '\fe10'; } /* '︐' */
.icon-palette-outline:before { content: '\fe6c'; } /* '﹬' */
.icon-file-music-outline:before { content: '\fe7c'; } /* 'ﹼ' */
.icon-file-pdf-outline:before { content: '\fe7d'; } /* 'ﹽ' */
.icon-file-image-outline:before { content: '\fecd'; } /* 'ﻍ' */
.icon-reply-outline:before { content: '\ff3d'; } /* '' */
.icon-draw:before { content: '\ff66'; } /* 'ヲ' */
.icon-account-outline:before { content: '󰀓'; } /* '\f0013' */
.icon-arrow-expand-all:before { content: '󰁌'; } /* '\f004c' */
.icon-file-code-outline:before { content: '󰁍'; } /* '\f004d' */
.icon-file-excel-outline:before { content: '󰁏'; } /* '\f004f' */
.icon-arrow-right:before { content: '󰁔'; } /* '\f0054' */
.icon-file-powerpoint-outline:before { content: '󰁗'; } /* '\f0057' */
.icon-file-word-outline:before { content: '󰁠'; } /* '\f0060' */
.icon-bookmark:before { content: '󰃀'; } /* '\f00c0' */
.icon-bookmark-outline:before { content: '󰃃'; } /* '\f00c3' */
.icon-dock-left:before { content: '󰃕'; } /* '\f00d5' */
.icon-chevron-up:before { content: '󰅃'; } /* '\f0143' */
.icon-close-circle:before { content: '󰅙'; } /* '\f0159' */
.icon-content-copy:before { content: '󰆏'; } /* '\f018f' */
.icon-send-outline:before { content: '󰆐'; } /* '\f0190' */
.icon-credit-card-outline:before { content: '󰆛'; } /* '\f019b' */
.icon-drag-vertical:before { content: '󰇝'; } /* '\f01dd' */
.icon-view-grid-outline:before { content: '󰈄'; } /* '\f0204' */
.icon-exit-to-app:before { content: '󰈆'; } /* '\f0206' */
.icon-file-outline:before { content: '󰈤'; } /* '\f0224' */
.icon-folder-outline:before { content: '󰉖'; } /* '\f0256' */
.icon-archive-arrow-up-outline:before { content: '󰊇'; } /* '\f0287' */
.icon-glasses:before { content: '󰊪'; } /* '\f02aa' */
.icon-key-variant:before { content: '󰌋'; } /* '\f030b' */
.icon-magnify-minus:before { content: '󰍊'; } /* '\f034a' */
.icon-magnify-plus:before { content: '󰍋'; } /* '\f034b' */
.icon-menu-left:before { content: '󰍞'; } /* '\f035e' */
.icon-menu-right:before { content: '󰍟'; } /* '\f035f' */
.icon-menu-up:before { content: '󰍠'; } /* '\f0360' */
.icon-message-text-outline:before { content: '󰍪'; } /* '\f036a' */
.icon-minus:before { content: '󰍴'; } /* '\f0374' */
.icon-minus-circle-outline:before { content: '󰍷'; } /* '\f0377' */
.icon-open-in-new:before { content: '󰏌'; } /* '\f03cc' */
.icon-pause:before { content: '󰏤'; } /* '\f03e4' */
.icon-play:before { content: '󰐊'; } /* '\f040a' */
.icon-radiobox-blank:before { content: '󰐽'; } /* '\f043d' */
.icon-radiobox-marked:before { content: '󰐾'; } /* '\f043e' */
.icon-sort-alphabetical-ascending:before { content: '󰖽'; } /* '\f05bd' */
.icon-playlist-check:before { content: '󰗇'; } /* '\f05c7' */
.icon-check-circle-outline:before { content: '󰗡'; } /* '\f05e1' */
.icon-help-circle-outline:before { content: '󰘥'; } /* '\f0625' */
.icon-circle-multiple-outline:before { content: '󰚕'; } /* '\f0695' */
.icon-update:before { content: '󰚰'; } /* '\f06b0' */
.icon-eye-off-outline:before { content: '󰛑'; } /* '\f06d1' */
.icon-infinity:before { content: '󰛤'; } /* '\f06e4' */
.icon-plus-box-outline:before { content: '󰜄'; } /* '\f0704' */
.icon-arrow-right-bold-outline:before { content: '󰧂'; } /* '\f09c2' */
.icon-trash-can-outline:before { content: '󰩺'; } /* '\f0a7a' */
.icon-account-minus-outline:before { content: '󰫬'; } /* '\f0aec' */
.icon-calendar-outline:before { content: '󰭧'; } /* '\f0b67' */
.icon-export-variant:before { content: '󰮓'; } /* '\f0b93' */
.icon-folder-plus-outline:before { content: '󰮝'; } /* '\f0b9d' */
.icon-home-variant-outline:before { content: '󰮧'; } /* '\f0ba7' */
.icon-calendar-check-outline:before { content: '󰱄'; } /* '\f0c44' */
.icon-hand-right:before { content: '󰹇'; } /* '\f0e47' */
.icon-notebook-outline:before { content: '󰺿'; } /* '\f0ebf' */
.icon-shield-alert-outline:before { content: '󰻍'; } /* '\f0ecd' */
.icon-slash-forward:before { content: '󰿟'; } /* '\f0fdf' */
.icon-file-multiple-outline:before { content: '󱀲'; } /* '\f1032' */
.icon-message-plus-outline:before { content: '󱂻'; } /* '\f10bb' */
.icon-message-minus-outline:before { content: '󱅯'; } /* '\f116f' */
.icon-crown-outline:before { content: '󱇐'; } /* '\f11d0' */
.icon-folder-move-outline:before { content: '󱉆'; } /* '\f1246' */

View file

@ -0,0 +1,65 @@
.upgrade-btns {
width: 32px;
height: 32px;
font-size: 18px;
line-height: 18px;
border-radius: 4px;
margin-top: 4px;
margin-right: 4px;
text-align: center;
color: rgba(63, 67, 80, 0.56);
&:hover {
background-color: rgba(63, 67, 80, 0.08);
}
}
.upgrade-button {
margin: 7px;
height: 18px;
cursor: pointer;
> i::before {
margin: 0;
}
}
.rotate {
animation: rotation 2s infinite linear;
> i::before {
transform: scaleX(-1);
}
}
@keyframes rotation {
from {
transform: rotate(0deg);
}
to {
transform: rotate(359deg);
}
}
.circle {
background: #F74343;
border-radius: 100px;
width: 12px;
height: 12px;
position: relative;
top: -22px;
right: -10px;
border: 2px solid #efefef;
}
.upgrade-btns.darkMode {
color: rgba(221, 221, 221, 0.56);
&:hover {
background-color: rgba(175, 188, 192, 0.08);
}
.circle {
border-color: #2e2e2e;
}
}

View file

@ -1,4 +1,5 @@
@import url("fonts.css");
@import '~@mattermost/compass-icons/css/compass-icons.css';
body {
margin: 0;

View file

@ -1,7 +1,7 @@
@import url("components/index.css");
@import url("fonts.css");
@import '~font-awesome/css/font-awesome.css';
@import '~@mattermost/compass-icons/css/compass-icons.css';
html {
height: 100%;
@ -119,8 +119,8 @@ body {
.topBar .title-bar-btns {
position: relative;
line-height: 36px;
height: 36px;
line-height: 40px;
height: 40px;
z-index: 9;
color: rgba(61,60,64,0.7);
-webkit-app-region: no-drag;

View file

@ -22,7 +22,6 @@ import {getTabViewName} from 'common/tabs/TabView';
import {TAB_BAR_HEIGHT, THREE_DOT_MENU_WIDTH_MAC} from 'common/utils/constants';
import './css/dropdown.scss';
import './css/compass-icons.css';
type State = {
teams?: TeamWithTabs[];

View file

@ -98,7 +98,7 @@ class Root extends React.PureComponent<Record<string, never>, State> {
try {
const configRequest = await window.ipcRenderer.invoke(GET_CONFIGURATION);
return configRequest;
} catch (err) {
} catch (err: any) {
console.log(`there was an error with the config: ${err}`);
if (exitOnError) {
window.ipcRenderer.send(QUIT, `unable to load configuration: ${err}`, err.stack);

View file

@ -40,6 +40,8 @@ export type ConfigV3 = {
downloadLocation: string;
spellCheckerURL?: string;
lastActiveTeam?: number;
autoCheckForUpdates?: boolean;
alwaysMinimize?: boolean;
alwaysClose?: boolean;
}
@ -119,6 +121,7 @@ export type CombinedConfig = ConfigV3 & BuildConfig & {
export type LocalConfiguration = Config & {
appName: string;
enableServerManagement: boolean;
canUpgrade: boolean;
}
export type MigrationInfo = {

View file

@ -18,6 +18,7 @@ const isRelease = process.env.CIRCLE_BRANCH && process.env.CIRCLE_BRANCH.startsW
const codeDefinitions = {
__HASH_VERSION__: !isRelease && JSON.stringify(VERSION),
__CAN_UPGRADE__: JSON.stringify(true), // we should set this to false when working on a store version. Hardcoding for now.
};
codeDefinitions['process.env.NODE_ENV'] = JSON.stringify(process.env.NODE_ENV);