diff --git a/src/utils/ConfigAccumalator.js b/src/utils/ConfigAccumalator.js index 0e04c2b6..5c0848a9 100644 --- a/src/utils/ConfigAccumalator.js +++ b/src/utils/ConfigAccumalator.js @@ -4,72 +4,109 @@ * object is structurally sound, to avoid any error if the user is missing something * The main config object is made up of three parts: appConfig, pageInfo and sections */ -import Defaults, { localStorageKeys } from '@/utils/defaults'; +import { + localStorageKeys, + appConfig as defaultAppConfig, + layout as defaultLayout, + iconSize as defaultIconSize, + pageInfo as defaultPageInfo, +} from '@/utils/defaults'; +import ErrorHandler from '@/utils/ErrorHandler'; import conf from '../../public/conf.yml'; -/** - * Returns the appConfig section, as JSON - */ -export const appConfig = (() => { - const appConfigFile = conf.appConfig || {}; - let usersAppConfig = Defaults.appConfig; - if (localStorage[localStorageKeys.APP_CONFIG]) { - usersAppConfig = JSON.parse(localStorage[localStorageKeys.APP_CONFIG]); - } else if (appConfigFile !== {}) { - usersAppConfig = appConfigFile; - } - usersAppConfig.layout = localStorage[localStorageKeys.LAYOUT_ORIENTATION] - || appConfigFile.layout || Defaults.layout; - usersAppConfig.iconSize = localStorage[localStorageKeys.ICON_SIZE] - || appConfigFile.iconSize || Defaults.iconSize; - return usersAppConfig; -})(); - -/** - * Returns the pageInfo section, as JSON - */ -export const pageInfo = (() => { - const defaults = Defaults.pageInfo; - let localPageInfo; - try { - localPageInfo = JSON.parse(localStorage[localStorageKeys.PAGE_INFO]); - } catch (e) { - localPageInfo = {}; - } - const pi = conf.pageInfo || defaults; // The page info object to return - pi.title = localPageInfo.title || conf.pageInfo.title || defaults.title; - pi.description = localPageInfo.description || conf.pageInfo.description || defaults.description; - pi.navLinks = localPageInfo.navLinks || conf.pageInfo.navLinks || defaults.navLinks; - pi.footerText = localPageInfo.footerText || conf.pageInfo.footerText || defaults.footerText; - return pi; -})(); - -/** - * Returns the sections section, as an array of JSON objects - */ -export const sections = (() => { - // If the user has stored sections in local storage, return those - const localSections = localStorage[localStorageKeys.CONF_SECTIONS]; - if (localSections) { - try { - const json = JSON.parse(localSections); - if (json.length >= 1) return json; - } catch (e) { - // The data in local storage has been malformed, will return conf.sections instead +export default class ConfigAccumulator { + constructor(filePath) { + if (filePath) { // Custom config path passed in + this.loadAdditionalConfig(filePath); + } else { // We are using the default config + this.conf = conf; } } - // If the function hasn't yet returned, then return the config file sections - return conf.sections; -})(); + + /** + * If we're loading the config for any page other than the default (conf.yml) + * then this function handles the importing and checking of additional configs. + * This feature is only used when the user has multiple pages and config files. + */ + loadAdditionalConfig(filePath) { + try { + // eslint-disable-next-line global-require, import/no-dynamic-require + const importedConf = require(`../../public/configs/${filePath}`); + // Ensure user isn't trying to import anything funky + if (typeof importedConf === 'object') { + this.conf = importedConf; + } else { + this.conf = conf; + } + } catch (e) { // Unable to read input config, fallback to the main conf.yml file + this.conf = conf; + ErrorHandler(`Unable to read this pages config file using ${filePath}`, e); + } + } + + /* App Config */ + appConfig() { + const appConfigFile = this.conf.appConfig || {}; + let usersAppConfig = defaultAppConfig; + if (localStorage[localStorageKeys.APP_CONFIG]) { + usersAppConfig = JSON.parse(localStorage[localStorageKeys.APP_CONFIG]); + } else if (appConfigFile !== {}) { + usersAppConfig = appConfigFile; + } + usersAppConfig.layout = localStorage[localStorageKeys.LAYOUT_ORIENTATION] + || appConfigFile.layout || defaultLayout; + usersAppConfig.iconSize = localStorage[localStorageKeys.ICON_SIZE] + || appConfigFile.iconSize || defaultIconSize; + return usersAppConfig; + } + + /* Page Info */ + pageInfo() { + const defaults = defaultPageInfo; + let localPageInfo; + try { + localPageInfo = JSON.parse(localStorage[localStorageKeys.PAGE_INFO]); + } catch (e) { + localPageInfo = {}; + } + const pi = this.conf.pageInfo || defaults; // The page info object to return + pi.title = localPageInfo.title || conf.pageInfo.title || defaults.title; + pi.description = localPageInfo.description || conf.pageInfo.description || defaults.description; + pi.navLinks = localPageInfo.navLinks || conf.pageInfo.navLinks || defaults.navLinks; + pi.footerText = localPageInfo.footerText || conf.pageInfo.footerText || defaults.footerText; + return pi; + } + + /* Sections */ + sections() { + // If the user has stored sections in local storage, return those + const localSections = localStorage[localStorageKeys.CONF_SECTIONS]; + if (localSections) { + try { + const json = JSON.parse(localSections); + if (json.length >= 1) return json; + } catch (e) { + // The data in local storage has been malformed, will return conf.sections instead + } + } + // If the function hasn't yet returned, then return the config file sections + return this.conf.sections; + } + + /* Complete config */ + config() { + return { + appConfig: this.appConfig(), + pageInfo: this.pageInfo(), + sections: this.sections(), + }; + } +} /** * Returns the complete configuration, as JSON */ export const config = (() => { - const result = { - appConfig, - pageInfo, - sections, - }; - return result; + const Accumulator = new ConfigAccumulator(); + return Accumulator.config(); })(); diff --git a/src/utils/defaults.js b/src/utils/defaults.js index 7e39e47a..859c5de1 100644 --- a/src/utils/defaults.js +++ b/src/utils/defaults.js @@ -1,3 +1,15 @@ +/** + * If the user has multiple dashboards within Dashy, + * then the Local storage keys need to be appended with an ID for each page + * This function just checks if we're not on the default homepage, + * and then appends the ID from the URL to the key + */ +const appendRouteId = (key) => { + const UrlParts = document.URL.split('/'); + const currentRoute = UrlParts[UrlParts.length - 1]; + return currentRoute !== '' ? `${currentRoute}_${key}` : key; +}; + module.exports = { pageInfo: { title: 'Dashy', @@ -48,17 +60,17 @@ module.exports = { }, localStorageKeys: { HIDE_WELCOME_BANNER: 'hideWelcomeHelpers', - LAYOUT_ORIENTATION: 'layoutOrientation', - COLLAPSE_STATE: 'collapseState', - ICON_SIZE: 'iconSize', - THEME: 'theme', - CONF_SECTIONS: 'confSections', - PAGE_INFO: 'pageInfo', - APP_CONFIG: 'appConfig', - BACKUP_ID: 'backupId', - BACKUP_HASH: 'backupHash', - HIDE_SETTINGS: 'hideSettings', - USERNAME: 'username', + LAYOUT_ORIENTATION: appendRouteId('layoutOrientation'), + COLLAPSE_STATE: appendRouteId('collapseState'), + ICON_SIZE: appendRouteId('iconSize'), + THEME: appendRouteId('theme'), + CONF_SECTIONS: appendRouteId('confSections'), + PAGE_INFO: appendRouteId('pageInfo'), + APP_CONFIG: appendRouteId('appConfig'), + BACKUP_ID: appendRouteId('backupId'), + BACKUP_HASH: appendRouteId('backupHash'), + HIDE_SETTINGS: appendRouteId('hideSettings'), + USERNAME: appendRouteId('username'), }, cookieKeys: { AUTH_TOKEN: 'authenticationToken',