Migrate app to TypeScript (#1637)
* Initial setup and migrated src/common * WIP * WIP * WIP * Main module basically finished * Renderer process migrated * Added CI step and some fixes * Fixed remainder of issues and added proper ESLint config * Fixed a couple issues * Progress! * Some more fixes * Fixed a test * Fix build step * PR feedback
This commit is contained in:
@@ -6,6 +6,8 @@ import {EventEmitter} from 'events';
|
||||
import log from 'electron-log';
|
||||
import WindowsRegistry from 'winreg-utf8';
|
||||
|
||||
import {RegistryConfig as RegistryConfigType, Team} from 'types/config';
|
||||
|
||||
const REGISTRY_HIVE_LIST = [WindowsRegistry.HKLM, WindowsRegistry.HKCU];
|
||||
const BASE_REGISTRY_KEY_PATH = '\\Software\\Policies\\Mattermost';
|
||||
export const REGISTRY_READ_EVENT = 'registry-read';
|
||||
@@ -14,6 +16,9 @@ export const REGISTRY_READ_EVENT = 'registry-read';
|
||||
* Handles loading config data from the Windows registry set manually or by GPO
|
||||
*/
|
||||
export default class RegistryConfig extends EventEmitter {
|
||||
initialized: boolean;
|
||||
data: Partial<RegistryConfigType>;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.initialized = false;
|
||||
@@ -33,7 +38,7 @@ export default class RegistryConfig extends EventEmitter {
|
||||
try {
|
||||
const servers = await this.getServersListFromRegistry();
|
||||
if (servers.length) {
|
||||
this.data.teams.push(...servers);
|
||||
this.data.teams!.push(...servers);
|
||||
}
|
||||
} catch (error) {
|
||||
log.warn('[RegistryConfig] Nothing retrieved for \'DefaultServerList\'', error);
|
||||
@@ -70,12 +75,12 @@ export default class RegistryConfig extends EventEmitter {
|
||||
*/
|
||||
async getServersListFromRegistry() {
|
||||
const defaultServers = await this.getRegistryEntry(`${BASE_REGISTRY_KEY_PATH}\\DefaultServerList`);
|
||||
return defaultServers.flat(2).reduce((servers, server, index) => {
|
||||
return defaultServers.flat(2).reduce((servers: Team[], server, index) => {
|
||||
if (server) {
|
||||
servers.push({
|
||||
name: server.name,
|
||||
url: server.value,
|
||||
order: server.order || index,
|
||||
name: (server as WindowsRegistry.RegistryItem).name,
|
||||
url: (server as WindowsRegistry.RegistryItem).value,
|
||||
order: index,
|
||||
});
|
||||
}
|
||||
return servers;
|
||||
@@ -106,7 +111,7 @@ export default class RegistryConfig extends EventEmitter {
|
||||
* @param {string} key Path to the registry key to return
|
||||
* @param {string} name Name of specific entry in the registry key to retrieve (optional)
|
||||
*/
|
||||
async getRegistryEntry(key, name) {
|
||||
async getRegistryEntry(key: string, name?: string) {
|
||||
const results = [];
|
||||
for (const hive of REGISTRY_HIVE_LIST) {
|
||||
results.push(this.getRegistryEntryValues(hive, key, name));
|
||||
@@ -121,18 +126,18 @@ export default class RegistryConfig extends EventEmitter {
|
||||
* @param {WindowsRegistry} regKey A configured instance of the WindowsRegistry class
|
||||
* @param {string} name Name of the specific entry to retrieve (optional)
|
||||
*/
|
||||
getRegistryEntryValues(hive, key, name) {
|
||||
getRegistryEntryValues(hive: string, key: string, name?: string) {
|
||||
const registry = new WindowsRegistry({hive, key, utf8: true});
|
||||
return new Promise((resolve, reject) => {
|
||||
return new Promise<string | WindowsRegistry.RegistryItem[] | undefined>((resolve, reject) => {
|
||||
try {
|
||||
registry.values((error, results) => {
|
||||
registry.values((error: Error, results: WindowsRegistry.RegistryItem[]) => {
|
||||
if (error || !results || results.length === 0) {
|
||||
resolve();
|
||||
resolve(undefined);
|
||||
return;
|
||||
}
|
||||
if (name) { // looking for a single entry value
|
||||
const registryItem = results.find((item) => item.name === name);
|
||||
resolve(registryItem && registryItem.value ? registryItem.value : null);
|
||||
resolve(registryItem && registryItem.value ? registryItem.value : undefined);
|
||||
} else { // looking for an entry list
|
||||
resolve(results);
|
||||
}
|
@@ -2,6 +2,8 @@
|
||||
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {BuildConfig} from 'types/config';
|
||||
|
||||
// For detailed guides, please refer to https://docs.mattermost.com/deployment/desktop-app-deployment.html
|
||||
|
||||
/**
|
||||
@@ -17,7 +19,7 @@
|
||||
* when "enableServerManagement is set to false
|
||||
* @prop {[]} managedResources - Defines which paths are managed
|
||||
*/
|
||||
const buildConfig = {
|
||||
const buildConfig: BuildConfig = {
|
||||
defaultTeams: [/*
|
||||
{
|
||||
name: 'example',
|
@@ -7,7 +7,9 @@
|
||||
* @param {number} version - Scheme version. (Not application version)
|
||||
*/
|
||||
|
||||
const getDefaultDownloadLocation = () => {
|
||||
import {ConfigV2} from 'types/config';
|
||||
|
||||
export const getDefaultDownloadLocation = () => {
|
||||
switch (process.platform) {
|
||||
case 'darwin':
|
||||
return `/Users/${process.env.USER || process.env.USERNAME}/Downloads`;
|
||||
@@ -18,7 +20,7 @@ const getDefaultDownloadLocation = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const defaultPreferences = {
|
||||
const defaultPreferences: ConfigV2 = {
|
||||
version: 2,
|
||||
teams: [],
|
||||
showTrayIcon: true,
|
@@ -9,11 +9,21 @@ import {EventEmitter} from 'events';
|
||||
import {ipcMain, nativeTheme, app} from 'electron';
|
||||
import log from 'electron-log';
|
||||
|
||||
import * as Validator from '../../main/Validator';
|
||||
import {
|
||||
AnyConfig,
|
||||
BuildConfig,
|
||||
CombinedConfig,
|
||||
Config as ConfigType,
|
||||
LocalConfiguration,
|
||||
RegistryConfig as RegistryConfigType,
|
||||
Team,
|
||||
} from 'types/config';
|
||||
|
||||
import {UPDATE_TEAMS, GET_CONFIGURATION, UPDATE_CONFIGURATION, GET_LOCAL_CONFIGURATION} from 'common/communication';
|
||||
|
||||
import defaultPreferences from './defaultPreferences';
|
||||
import * as Validator from '../../main/Validator';
|
||||
|
||||
import defaultPreferences, {getDefaultDownloadLocation} from './defaultPreferences';
|
||||
import upgradeConfigData from './upgradePreferences';
|
||||
import buildConfig from './buildConfig';
|
||||
import RegistryConfig, {REGISTRY_READ_EVENT} from './RegistryConfig';
|
||||
@@ -21,14 +31,25 @@ import RegistryConfig, {REGISTRY_READ_EVENT} from './RegistryConfig';
|
||||
/**
|
||||
* Handles loading and merging all sources of configuration as well as saving user provided config
|
||||
*/
|
||||
|
||||
export default class Config extends EventEmitter {
|
||||
constructor(configFilePath) {
|
||||
configFilePath: string;
|
||||
|
||||
registryConfig?: RegistryConfig;
|
||||
|
||||
combinedData?: CombinedConfig;
|
||||
registryConfigData?: Partial<RegistryConfigType>;
|
||||
defaultConfigData?: ConfigType;
|
||||
buildConfigData?: BuildConfig;
|
||||
localConfigData?: ConfigType;
|
||||
|
||||
constructor(configFilePath: string) {
|
||||
super();
|
||||
this.configFilePath = configFilePath;
|
||||
}
|
||||
|
||||
// separating constructor from init so main can setup event listeners
|
||||
init = () => {
|
||||
init = (): void => {
|
||||
this.registryConfig = new RegistryConfig();
|
||||
this.registryConfig.once(REGISTRY_READ_EVENT, this.loadRegistry);
|
||||
this.registryConfig.init();
|
||||
@@ -40,7 +61,7 @@ export default class Config extends EventEmitter {
|
||||
* @param {object} registryData Team configuration from the registry and if teams can be managed by user
|
||||
*/
|
||||
|
||||
loadRegistry = (registryData) => {
|
||||
loadRegistry = (registryData: Partial<RegistryConfigType>): void => {
|
||||
this.registryConfigData = registryData;
|
||||
this.reload();
|
||||
ipcMain.handle(GET_CONFIGURATION, this.handleGetConfiguration);
|
||||
@@ -59,11 +80,11 @@ export default class Config extends EventEmitter {
|
||||
* @emits {update} emitted once all data has been loaded and merged
|
||||
* @emits {synchronize} emitted when requested by a call to method; used to notify other config instances of changes
|
||||
*/
|
||||
reload = () => {
|
||||
reload = (): void => {
|
||||
this.defaultConfigData = this.loadDefaultConfigData();
|
||||
this.buildConfigData = this.loadBuildConfigData();
|
||||
this.localConfigData = this.loadLocalConfigFile();
|
||||
this.localConfigData = this.checkForConfigUpdates(this.localConfigData);
|
||||
const loadedConfig = this.loadLocalConfigFile();
|
||||
this.localConfigData = this.checkForConfigUpdates(loadedConfig);
|
||||
this.regenerateCombinedConfigData();
|
||||
|
||||
this.emit('update', this.combinedData);
|
||||
@@ -76,9 +97,9 @@ export default class Config extends EventEmitter {
|
||||
* @param {string} key name of config property to be saved
|
||||
* @param {*} data value to save for provided key
|
||||
*/
|
||||
set = (key, data) => {
|
||||
if (key) {
|
||||
this.localConfigData[key] = data;
|
||||
set = (key: keyof ConfigType, data: ConfigType[keyof ConfigType]): void => {
|
||||
if (key && this.localConfigData) {
|
||||
this.localConfigData = Object.assign({}, this.localConfigData, {[key]: data});
|
||||
this.regenerateCombinedConfigData();
|
||||
this.saveLocalConfigData();
|
||||
}
|
||||
@@ -89,13 +110,9 @@ export default class Config extends EventEmitter {
|
||||
*
|
||||
* @param {array} properties an array of config properties to save
|
||||
*/
|
||||
setMultiple = (event, properties = []) => {
|
||||
setMultiple = (event: Electron.IpcMainEvent, properties: Array<{key: keyof ConfigType; data: ConfigType[keyof ConfigType]}> = []): Partial<ConfigType> | undefined => {
|
||||
if (properties.length) {
|
||||
properties.forEach(({key, data}) => {
|
||||
if (key) {
|
||||
this.localConfigData[key] = data;
|
||||
}
|
||||
});
|
||||
this.localConfigData = Object.assign({}, this.localConfigData, ...properties.map(({key, data}) => ({[key]: data})));
|
||||
this.regenerateCombinedConfigData();
|
||||
this.saveLocalConfigData();
|
||||
}
|
||||
@@ -103,7 +120,7 @@ export default class Config extends EventEmitter {
|
||||
return this.localConfigData; //this is the only part that changes
|
||||
}
|
||||
|
||||
setRegistryConfigData = (registryConfigData = {teams: []}) => {
|
||||
setRegistryConfigData = (registryConfigData = {teams: []}): void => {
|
||||
this.registryConfigData = Object.assign({}, registryConfigData);
|
||||
this.reload();
|
||||
}
|
||||
@@ -113,7 +130,7 @@ export default class Config extends EventEmitter {
|
||||
*
|
||||
* @param {object} configData a new, config data object to completely replace the existing config data
|
||||
*/
|
||||
replace = (configData) => {
|
||||
replace = (configData: ConfigType) => {
|
||||
const newConfigData = configData;
|
||||
|
||||
this.localConfigData = Object.assign({}, this.localConfigData, newConfigData);
|
||||
@@ -129,11 +146,15 @@ export default class Config extends EventEmitter {
|
||||
* @emits {synchronize} emitted once all data has been saved; used to notify other config instances of changes
|
||||
* @emits {error} emitted if saving local config data to file fails
|
||||
*/
|
||||
saveLocalConfigData = () => {
|
||||
saveLocalConfigData = (): void => {
|
||||
if (!this.localConfigData) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
this.writeFile(this.configFilePath, this.localConfigData, (error) => {
|
||||
this.writeFile(this.configFilePath, this.localConfigData, (error: NodeJS.ErrnoException | null) => {
|
||||
if (error) {
|
||||
throw new Error(error);
|
||||
throw new Error(error.message);
|
||||
}
|
||||
this.emit('update', this.combinedData);
|
||||
this.emit('synchronize');
|
||||
@@ -149,13 +170,13 @@ export default class Config extends EventEmitter {
|
||||
return this.combinedData;
|
||||
}
|
||||
get localData() {
|
||||
return this.localConfigData;
|
||||
return this.localConfigData ?? defaultPreferences;
|
||||
}
|
||||
get defaultData() {
|
||||
return this.defaultConfigData;
|
||||
return this.defaultConfigData ?? defaultPreferences;
|
||||
}
|
||||
get buildData() {
|
||||
return this.buildConfigData;
|
||||
return this.buildConfigData ?? buildConfig;
|
||||
}
|
||||
get registryData() {
|
||||
return this.registryConfigData;
|
||||
@@ -164,52 +185,55 @@ export default class Config extends EventEmitter {
|
||||
// convenience getters
|
||||
|
||||
get version() {
|
||||
return this.combinedData.version;
|
||||
return this.combinedData?.version ?? defaultPreferences.version;
|
||||
}
|
||||
get teams() {
|
||||
return this.combinedData.teams;
|
||||
return this.combinedData?.teams ?? defaultPreferences.teams;
|
||||
}
|
||||
get darkMode() {
|
||||
return this.combinedData.darkMode;
|
||||
return this.combinedData?.darkMode ?? defaultPreferences.darkMode;
|
||||
}
|
||||
get localTeams() {
|
||||
return this.localConfigData.teams;
|
||||
return this.localConfigData?.teams ?? defaultPreferences.version;
|
||||
}
|
||||
get predefinedTeams() {
|
||||
return [...this.buildConfigData.defaultTeams, ...this.registryConfigData.teams];
|
||||
return [...this.buildConfigData?.defaultTeams ?? [], ...this.registryConfigData?.teams ?? []];
|
||||
}
|
||||
get enableHardwareAcceleration() {
|
||||
return this.combinedData.enableHardwareAcceleration;
|
||||
return this.combinedData?.enableHardwareAcceleration ?? defaultPreferences.enableHardwareAcceleration;
|
||||
}
|
||||
get enableServerManagement() {
|
||||
return this.combinedData.enableServerManagement;
|
||||
return this.combinedData?.enableServerManagement ?? buildConfig.enableServerManagement;
|
||||
}
|
||||
get enableAutoUpdater() {
|
||||
return this.combinedData.enableAutoUpdater;
|
||||
return this.combinedData?.enableAutoUpdater ?? buildConfig.enableAutoUpdater;
|
||||
}
|
||||
get autostart() {
|
||||
return this.combinedData.autostart;
|
||||
return this.combinedData?.autostart ?? defaultPreferences.autostart;
|
||||
}
|
||||
get notifications() {
|
||||
return this.combinedData.notifications;
|
||||
return this.combinedData?.notifications ?? defaultPreferences.notifications;
|
||||
}
|
||||
get showUnreadBadge() {
|
||||
return this.combinedData.showUnreadBadge;
|
||||
return this.combinedData?.showUnreadBadge ?? defaultPreferences.showUnreadBadge;
|
||||
}
|
||||
get useSpellChecker() {
|
||||
return this.combinedData.useSpellChecker;
|
||||
return this.combinedData?.useSpellChecker ?? defaultPreferences.useSpellChecker;
|
||||
}
|
||||
get spellCheckerLocale() {
|
||||
return this.combinedData.spellCheckerLocale;
|
||||
return this.combinedData?.spellCheckerLocale ?? defaultPreferences.spellCheckerLocale;
|
||||
}
|
||||
get showTrayIcon() {
|
||||
return this.combinedData.showTrayIcon;
|
||||
return this.combinedData?.showTrayIcon ?? defaultPreferences.showTrayIcon;
|
||||
}
|
||||
get trayIconTheme() {
|
||||
return this.combinedData.trayIconTheme;
|
||||
return this.combinedData?.trayIconTheme ?? defaultPreferences.trayIconTheme;
|
||||
}
|
||||
get downloadLocation() {
|
||||
return this.combinedData?.downloadLocation ?? getDefaultDownloadLocation();
|
||||
}
|
||||
get helpLink() {
|
||||
return this.combinedData.helpLink;
|
||||
return this.combinedData?.helpLink;
|
||||
}
|
||||
|
||||
// initialization/processing methods
|
||||
@@ -231,22 +255,21 @@ export default class Config extends EventEmitter {
|
||||
/**
|
||||
* Loads and returns locally stored config data from the filesystem or returns app defaults if no file is found
|
||||
*/
|
||||
loadLocalConfigFile = () => {
|
||||
let configData = {};
|
||||
loadLocalConfigFile = (): AnyConfig => {
|
||||
let configData: AnyConfig;
|
||||
try {
|
||||
configData = this.readFileSync(this.configFilePath);
|
||||
|
||||
// validate based on config file version
|
||||
if (configData.version > 1) {
|
||||
configData = Validator.validateV2ConfigData(configData);
|
||||
} else {
|
||||
switch (configData.version) {
|
||||
case 1:
|
||||
configData = Validator.validateV1ConfigData(configData);
|
||||
break;
|
||||
default:
|
||||
configData = Validator.validateV0ConfigData(configData);
|
||||
}
|
||||
switch (configData.version) {
|
||||
case 2:
|
||||
configData = Validator.validateV2ConfigData(configData)!;
|
||||
break;
|
||||
case 1:
|
||||
configData = Validator.validateV1ConfigData(configData)!;
|
||||
break;
|
||||
default:
|
||||
configData = Validator.validateV0ConfigData(configData)!;
|
||||
}
|
||||
if (!configData) {
|
||||
throw new Error('Provided configuration file does not validate, using defaults instead.');
|
||||
@@ -255,12 +278,6 @@ export default class Config extends EventEmitter {
|
||||
log.warn('Failed to load configuration file from the filesystem. Using defaults.');
|
||||
configData = this.copy(this.defaultConfigData);
|
||||
|
||||
// add default team to teams if one exists and there arent currently any teams
|
||||
if (!configData.teams.length && this.defaultConfigData.defaultTeam) {
|
||||
configData.teams.push(this.defaultConfigData.defaultTeam);
|
||||
}
|
||||
delete configData.defaultTeam;
|
||||
|
||||
this.writeFileSync(this.configFilePath, configData);
|
||||
}
|
||||
return configData;
|
||||
@@ -271,18 +288,21 @@ export default class Config extends EventEmitter {
|
||||
*
|
||||
* @param {*} data locally stored data
|
||||
*/
|
||||
checkForConfigUpdates = (data) => {
|
||||
checkForConfigUpdates = (data: AnyConfig) => {
|
||||
let configData = data;
|
||||
try {
|
||||
if (configData.version !== this.defaultConfigData.version) {
|
||||
configData = upgradeConfigData(configData);
|
||||
this.writeFileSync(this.configFilePath, configData);
|
||||
log.info(`Configuration updated to version ${this.defaultConfigData.version} successfully.`);
|
||||
if (this.defaultConfigData) {
|
||||
try {
|
||||
if (configData.version !== this.defaultConfigData.version) {
|
||||
configData = upgradeConfigData(configData);
|
||||
this.writeFileSync(this.configFilePath, configData);
|
||||
log.info(`Configuration updated to version ${this.defaultConfigData.version} successfully.`);
|
||||
}
|
||||
} catch (error) {
|
||||
log.error(`Failed to update configuration to version ${this.defaultConfigData.version}.`);
|
||||
}
|
||||
} catch (error) {
|
||||
log.error(`Failed to update configuration to version ${this.defaultConfigData.version}.`);
|
||||
}
|
||||
return configData;
|
||||
|
||||
return configData as ConfigType;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -293,38 +313,37 @@ export default class Config extends EventEmitter {
|
||||
this.combinedData = Object.assign({}, this.defaultConfigData, this.localConfigData, this.buildConfigData, this.registryConfigData);
|
||||
|
||||
// remove unecessary data pulled from default and build config
|
||||
delete this.combinedData.defaultTeam;
|
||||
delete this.combinedData.defaultTeams;
|
||||
delete this.combinedData!.defaultTeams;
|
||||
|
||||
// IMPORTANT: properly combine teams from all sources
|
||||
let combinedTeams = [];
|
||||
|
||||
// - start by adding default teams from buildConfig, if any
|
||||
if (this.buildConfigData.defaultTeams && this.buildConfigData.defaultTeams.length) {
|
||||
if (this.buildConfigData?.defaultTeams?.length) {
|
||||
combinedTeams.push(...this.buildConfigData.defaultTeams);
|
||||
}
|
||||
|
||||
// - add registry defined teams, if any
|
||||
if (this.registryConfigData.teams && this.registryConfigData.teams.length) {
|
||||
if (this.registryConfigData?.teams?.length) {
|
||||
combinedTeams.push(...this.registryConfigData.teams);
|
||||
}
|
||||
|
||||
// - add locally defined teams only if server management is enabled
|
||||
if (this.enableServerManagement) {
|
||||
combinedTeams.push(...this.localConfigData.teams);
|
||||
if (this.localConfigData && this.enableServerManagement) {
|
||||
combinedTeams.push(...this.localConfigData.teams || []);
|
||||
}
|
||||
|
||||
combinedTeams = this.filterOutDuplicateTeams(combinedTeams);
|
||||
combinedTeams = this.sortUnorderedTeams(combinedTeams);
|
||||
|
||||
this.combinedData.teams = combinedTeams;
|
||||
this.combinedData.localTeams = this.localConfigData.teams;
|
||||
this.combinedData.buildTeams = this.buildConfigData.defaultTeams;
|
||||
this.combinedData.registryTeams = this.registryConfigData.teams;
|
||||
if (process.platform === 'darwin' || process.platform === 'win32') {
|
||||
this.combinedData.darkMode = nativeTheme.shouldUseDarkColors;
|
||||
if (this.combinedData) {
|
||||
this.combinedData.teams = combinedTeams;
|
||||
this.combinedData.registryTeams = this.registryConfigData?.teams || [];
|
||||
if (process.platform === 'darwin' || process.platform === 'win32') {
|
||||
this.combinedData.darkMode = nativeTheme.shouldUseDarkColors;
|
||||
}
|
||||
this.combinedData.appName = app.name;
|
||||
}
|
||||
this.combinedData.appName = app.name;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -332,7 +351,7 @@ export default class Config extends EventEmitter {
|
||||
*
|
||||
* @param {array} teams array of teams to check for duplicates
|
||||
*/
|
||||
filterOutDuplicateTeams = (teams) => {
|
||||
filterOutDuplicateTeams = (teams: Team[]) => {
|
||||
let newTeams = teams;
|
||||
const uniqueURLs = new Set();
|
||||
newTeams = newTeams.filter((team) => {
|
||||
@@ -345,7 +364,7 @@ export default class Config extends EventEmitter {
|
||||
* Returns the provided array fo teams with existing teams filtered out
|
||||
* @param {array} teams array of teams to check for already defined teams
|
||||
*/
|
||||
filterOutPredefinedTeams = (teams) => {
|
||||
filterOutPredefinedTeams = (teams: Team[]) => {
|
||||
let newTeams = teams;
|
||||
|
||||
// filter out predefined teams
|
||||
@@ -360,17 +379,17 @@ export default class Config extends EventEmitter {
|
||||
* Apply a default sort order to the team list, if no order is specified.
|
||||
* @param {array} teams to sort
|
||||
*/
|
||||
sortUnorderedTeams = (teams) => {
|
||||
sortUnorderedTeams = (teams: Team[]) => {
|
||||
// We want to preserve the array order of teams in the config, otherwise a lot of bugs will occur
|
||||
const mappedTeams = teams.map((team, index) => ({team, originalOrder: index}));
|
||||
|
||||
// Make a best pass at interpreting sort order. If an order is not specified, assume it is 0.
|
||||
//
|
||||
const newTeams = mappedTeams.sort((x, y) => {
|
||||
if (x.team.order == null) {
|
||||
if (!x.team.order) {
|
||||
x.team.order = 0;
|
||||
}
|
||||
if (y.team.order == null) {
|
||||
if (!y.team.order) {
|
||||
y.team.order = 0;
|
||||
}
|
||||
|
||||
@@ -390,11 +409,15 @@ export default class Config extends EventEmitter {
|
||||
|
||||
// helper functions
|
||||
|
||||
readFileSync = (filePath) => {
|
||||
readFileSync = (filePath: string) => {
|
||||
return JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
||||
}
|
||||
|
||||
writeFile = (filePath, configData, callback) => {
|
||||
writeFile = (filePath: string, configData: Partial<ConfigType>, callback: fs.NoParamCallback) => {
|
||||
if (!this.defaultConfigData) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (configData.version !== this.defaultConfigData.version) {
|
||||
throw new Error('version ' + configData.version + ' is not equal to ' + this.defaultConfigData.version);
|
||||
}
|
||||
@@ -402,7 +425,11 @@ export default class Config extends EventEmitter {
|
||||
fs.writeFile(filePath, json, 'utf8', callback);
|
||||
}
|
||||
|
||||
writeFileSync = (filePath, config) => {
|
||||
writeFileSync = (filePath: string, config: Partial<ConfigType>) => {
|
||||
if (!this.defaultConfigData) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (config.version !== this.defaultConfigData.version) {
|
||||
throw new Error('version ' + config.version + ' is not equal to ' + this.defaultConfigData.version);
|
||||
}
|
||||
@@ -416,15 +443,15 @@ export default class Config extends EventEmitter {
|
||||
fs.writeFileSync(filePath, json, 'utf8');
|
||||
}
|
||||
|
||||
merge = (base, target) => {
|
||||
merge = <T, T2>(base: T, target: T2) => {
|
||||
return Object.assign({}, base, target);
|
||||
}
|
||||
|
||||
copy = (data) => {
|
||||
copy = <T>(data: T) => {
|
||||
return Object.assign({}, data);
|
||||
}
|
||||
|
||||
handleGetConfiguration = (event, option) => {
|
||||
handleGetConfiguration = (event: Electron.IpcMainInvokeEvent, option: keyof CombinedConfig) => {
|
||||
const config = {...this.combinedData};
|
||||
if (option) {
|
||||
return config[option];
|
||||
@@ -432,19 +459,19 @@ export default class Config extends EventEmitter {
|
||||
return config;
|
||||
}
|
||||
|
||||
handleGetLocalConfiguration = (event, option) => {
|
||||
const config = {...this.localConfigData};
|
||||
handleGetLocalConfiguration = (event: Electron.IpcMainInvokeEvent, option: keyof ConfigType) => {
|
||||
const config: Partial<LocalConfiguration> = {...this.localConfigData};
|
||||
config.appName = app.name;
|
||||
config.enableServerManagement = this.combinedData.enableServerManagement;
|
||||
config.enableServerManagement = this.combinedData?.enableServerManagement;
|
||||
if (option) {
|
||||
return config[option];
|
||||
}
|
||||
return config;
|
||||
}
|
||||
|
||||
handleUpdateTeams = (event, newTeams) => {
|
||||
handleUpdateTeams = (event: Electron.IpcMainInvokeEvent, newTeams: Team[]) => {
|
||||
this.set('teams', newTeams);
|
||||
return this.combinedData.teams;
|
||||
return this.combinedData!.teams;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -452,7 +479,7 @@ export default class Config extends EventEmitter {
|
||||
* @emits 'darkModeChange'
|
||||
*/
|
||||
handleUpdateTheme = () => {
|
||||
if (this.combinedData.darkMode !== nativeTheme.shouldUseDarkColors) {
|
||||
if (this.combinedData && this.combinedData.darkMode !== nativeTheme.shouldUseDarkColors) {
|
||||
this.combinedData.darkMode = nativeTheme.shouldUseDarkColors;
|
||||
this.emit('darkModeChange', this.combinedData.darkMode);
|
||||
}
|
||||
@@ -463,6 +490,10 @@ export default class Config extends EventEmitter {
|
||||
* @emits 'darkModeChange'
|
||||
*/
|
||||
toggleDarkModeManually = () => {
|
||||
if (!this.combinedData) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.set('darkMode', !this.combinedData.darkMode);
|
||||
this.emit('darkModeChange', this.combinedData.darkMode);
|
||||
}
|
@@ -1,12 +1,14 @@
|
||||
// Copyright (c) 2015-2016 Yuya Ochiai
|
||||
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
import {ConfigV0, ConfigV1} from 'types/config';
|
||||
|
||||
import defaultPreferences from './defaultPreferences';
|
||||
|
||||
const pastDefaultPreferences = {
|
||||
0: {
|
||||
url: '',
|
||||
},
|
||||
} as ConfigV0,
|
||||
1: {
|
||||
version: 1,
|
||||
teams: [],
|
||||
@@ -23,9 +25,8 @@ const pastDefaultPreferences = {
|
||||
enableHardwareAcceleration: true,
|
||||
autostart: true,
|
||||
spellCheckerLocale: 'en-US',
|
||||
},
|
||||
} as ConfigV1,
|
||||
2: defaultPreferences,
|
||||
};
|
||||
|
||||
pastDefaultPreferences[`${defaultPreferences.version}`] = defaultPreferences;
|
||||
|
||||
export default pastDefaultPreferences;
|
@@ -1,42 +0,0 @@
|
||||
// Copyright (c) 2015-2016 Yuya Ochiai
|
||||
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
import pastDefaultPreferences from './pastDefaultPreferences';
|
||||
|
||||
function deepCopy(object) {
|
||||
return JSON.parse(JSON.stringify(object));
|
||||
}
|
||||
|
||||
function upgradeV0toV1(configV0) {
|
||||
const config = deepCopy(pastDefaultPreferences['1']);
|
||||
if (config.version !== 1) {
|
||||
throw new Error('pastDefaultPreferences[\'1\'].version is not equal to 1');
|
||||
}
|
||||
config.teams.push({
|
||||
name: 'Primary team',
|
||||
url: configV0.url,
|
||||
});
|
||||
return config;
|
||||
}
|
||||
|
||||
function upgradeV1toV2(configV1) {
|
||||
const config = deepCopy(configV1);
|
||||
config.version = 2;
|
||||
config.teams.forEach((value, index) => {
|
||||
value.order = index;
|
||||
});
|
||||
config.darkMode = false;
|
||||
return config;
|
||||
}
|
||||
|
||||
export default function upgradeToLatest(config) {
|
||||
const configVersion = config.version ? config.version : 0;
|
||||
switch (configVersion) {
|
||||
case 1:
|
||||
return upgradeToLatest(upgradeV1toV2(config));
|
||||
case 0:
|
||||
return upgradeToLatest(upgradeV0toV1(config));
|
||||
default:
|
||||
return config;
|
||||
}
|
||||
}
|
42
src/common/config/upgradePreferences.ts
Normal file
42
src/common/config/upgradePreferences.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
// Copyright (c) 2015-2016 Yuya Ochiai
|
||||
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
import {ConfigV2, ConfigV1, ConfigV0, AnyConfig} from 'types/config';
|
||||
|
||||
import pastDefaultPreferences from './pastDefaultPreferences';
|
||||
|
||||
function deepCopy<T>(object: T): T {
|
||||
return JSON.parse(JSON.stringify(object));
|
||||
}
|
||||
|
||||
function upgradeV0toV1(configV0: ConfigV0) {
|
||||
const config = deepCopy(pastDefaultPreferences[1]);
|
||||
config.teams.push({
|
||||
name: 'Primary team',
|
||||
url: configV0.url,
|
||||
});
|
||||
return config;
|
||||
}
|
||||
|
||||
function upgradeV1toV2(configV1: ConfigV1) {
|
||||
const config: ConfigV2 = Object.assign({}, deepCopy<ConfigV2>(pastDefaultPreferences[2]), configV1);
|
||||
config.version = 2;
|
||||
config.teams = configV1.teams.map((value, index) => {
|
||||
return {
|
||||
...value,
|
||||
order: index,
|
||||
};
|
||||
});
|
||||
return config;
|
||||
}
|
||||
|
||||
export default function upgradeToLatest(config: AnyConfig): ConfigV2 {
|
||||
switch (config.version) {
|
||||
case 2:
|
||||
return config as ConfigV2;
|
||||
case 1:
|
||||
return upgradeToLatest(upgradeV1toV2(config as ConfigV1));
|
||||
default:
|
||||
return upgradeToLatest(upgradeV0toV1(config as ConfigV0));
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user