-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
* [GH-314] Export native app user settings on change This switches from exporting the native app user settings on window close to exporting on settings change. This way the settings export remains independent of native application life-cycle events. This is a stop-gap towards enabling settings export on the native Linux app. The latter does not have an easy way to catch window close events. Relates to: #314 * Disable no-shadow rule to prevent false-positive * Verify allowed localStorage keys * Fix import order/spacing * Treat JSON parsing errors as failed import * Read known keys from the correct type 🤦 * Extend logging with imported keys and always include _current_ user settings * Fixing eslint Co-authored-by: Hossein <[email protected]> Co-authored-by: Jesús Espino <[email protected]>
- Loading branch information
1 parent
f983a59
commit b6d32da
Showing
8 changed files
with
145 additions
and
74 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,53 +1,135 @@ | ||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. | ||
// See LICENSE.txt for license information. | ||
|
||
import {notifySettingsChanged} from './nativeApp' | ||
import {Utils} from './utils' | ||
|
||
// eslint-disable-next-line no-shadow | ||
enum UserSettingKey { | ||
Language = 'language', | ||
Theme = 'theme', | ||
LastBoardId = 'lastBoardId', | ||
LastViewId = 'lastViewId', | ||
EmojiMartSkin = 'emoji-mart.skin', | ||
EmojiMartLast = 'emoji-mart.last', | ||
EmojiMartFrequently = 'emoji-mart.frequently', | ||
RandomIcons = 'randomIcons' | ||
} | ||
|
||
export class UserSettings { | ||
static get(key: UserSettingKey): string | null { | ||
return localStorage.getItem(key) | ||
} | ||
|
||
static set(key: UserSettingKey, value: string | null) { | ||
if (!Object.values(UserSettingKey).includes(key)) { | ||
return | ||
} | ||
if (value === null) { | ||
localStorage.removeItem(key) | ||
} else { | ||
localStorage.setItem(key, value) | ||
} | ||
notifySettingsChanged(key) | ||
} | ||
|
||
static get language(): string | null { | ||
return UserSettings.get(UserSettingKey.Language) | ||
} | ||
|
||
static set language(newValue: string | null) { | ||
UserSettings.set(UserSettingKey.Language, newValue) | ||
} | ||
|
||
static get theme(): string | null { | ||
return UserSettings.get(UserSettingKey.Theme) | ||
} | ||
|
||
static set theme(newValue: string | null) { | ||
UserSettings.set(UserSettingKey.Theme, newValue) | ||
} | ||
|
||
static get lastBoardId(): string | null { | ||
return UserSettings.get(UserSettingKey.LastBoardId) | ||
} | ||
|
||
static set lastBoardId(newValue: string | null) { | ||
UserSettings.set(UserSettingKey.LastBoardId, newValue) | ||
} | ||
|
||
static get lastViewId(): string | null { | ||
return UserSettings.get(UserSettingKey.LastViewId) | ||
} | ||
|
||
static set lastViewId(newValue: string | null) { | ||
UserSettings.set(UserSettingKey.LastViewId, newValue) | ||
} | ||
|
||
static get prefillRandomIcons(): boolean { | ||
return localStorage.getItem('randomIcons') !== 'false' | ||
return UserSettings.get(UserSettingKey.RandomIcons) !== 'false' | ||
} | ||
|
||
static set prefillRandomIcons(newValue: boolean) { | ||
localStorage.setItem('randomIcons', JSON.stringify(newValue)) | ||
UserSettings.set(UserSettingKey.RandomIcons, JSON.stringify(newValue)) | ||
} | ||
|
||
static getEmojiMartSetting(key: string): any { | ||
const prefixed = `emoji-mart.${key}` | ||
Utils.assert((Object as any).values(UserSettingKey).includes(prefixed)) | ||
const json = UserSettings.get(prefixed as UserSettingKey) | ||
return json ? JSON.parse(json) : null | ||
} | ||
} | ||
|
||
const keys = ['language', 'theme', 'lastBoardId', 'lastViewId', 'emoji-mart.last', 'emoji-mart.frequently', 'randomIcons'] | ||
static setEmojiMartSetting(key: string, value: any) { | ||
const prefixed = `emoji-mart.${key}` | ||
Utils.assert((Object as any).values(UserSettingKey).includes(prefixed)) | ||
UserSettings.set(prefixed as UserSettingKey, JSON.stringify(value)) | ||
} | ||
} | ||
|
||
export function exportUserSettingsBlob(): string { | ||
return window.btoa(exportUserSettings()) | ||
} | ||
|
||
function exportUserSettings(): string { | ||
const keys = Object.values(UserSettingKey) | ||
const settings = Object.fromEntries(keys.map((key) => [key, localStorage.getItem(key)])) | ||
settings.timestamp = `${Date.now()}` | ||
return JSON.stringify(settings) | ||
} | ||
|
||
export function importUserSettingsBlob(blob: string): boolean { | ||
export function importUserSettingsBlob(blob: string): string[] { | ||
return importUserSettings(window.atob(blob)) | ||
} | ||
|
||
function importUserSettings(json: string): boolean { | ||
function importUserSettings(json: string): string[] { | ||
const settings = parseUserSettings(json) | ||
if (!settings) { | ||
return [] | ||
} | ||
const timestamp = settings.timestamp | ||
const lastTimestamp = localStorage.getItem('timestamp') | ||
if (!timestamp || (lastTimestamp && Number(timestamp) <= Number(lastTimestamp))) { | ||
return false | ||
return [] | ||
} | ||
const importedKeys = [] | ||
for (const [key, value] of Object.entries(settings)) { | ||
if (value) { | ||
localStorage.setItem(key, value as string) | ||
} else { | ||
localStorage.removeItem(key) | ||
if (Object.values(UserSettingKey).includes(key as UserSettingKey)) { | ||
if (value) { | ||
localStorage.setItem(key, value as string) | ||
} else { | ||
localStorage.removeItem(key) | ||
} | ||
importedKeys.push(key) | ||
} | ||
} | ||
return true | ||
return importedKeys | ||
} | ||
|
||
function parseUserSettings(json: string): any { | ||
try { | ||
return JSON.parse(json) | ||
} catch (e) { | ||
return {} | ||
return undefined | ||
} | ||
} |