From 0a56db539726014626795926954317d54f29c023 Mon Sep 17 00:00:00 2001 From: Alicia Sykes Date: Sat, 13 Apr 2024 12:17:40 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=94=A5=20Local=20saving=20for=20multi-pag?= =?UTF-8?q?e=20full=20working?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.vue | 2 +- .../Configuration/CloudBackupRestore.vue | 23 +++++++++--- src/mixins/ConfigSaving.js | 37 ++++++++++++++++--- src/store.js | 28 +++++++++++++- src/utils/defaults.js | 3 +- 5 files changed, 78 insertions(+), 15 deletions(-) diff --git a/src/App.vue b/src/App.vue index 56e49cb9..4cfd5d5d 100644 --- a/src/App.vue +++ b/src/App.vue @@ -64,7 +64,7 @@ export default { return this.$store.getters.pageInfo; }, sections() { - return this.$store.getters.pageInfo; + return this.$store.getters.sections; }, visibleComponents() { return this.$store.getters.visibleComponents; diff --git a/src/components/Configuration/CloudBackupRestore.vue b/src/components/Configuration/CloudBackupRestore.vue index f8d75a65..9126dc48 100644 --- a/src/components/Configuration/CloudBackupRestore.vue +++ b/src/components/Configuration/CloudBackupRestore.vue @@ -155,12 +155,23 @@ export default { }, /* When restored data is revieved, then save to local storage, and apply it in state */ applyRestoredData(config, backupId) { - // Store restored data in local storage - localStorage.setItem(localStorageKeys.CONF_SECTIONS, JSON.stringify(config.sections)); - localStorage.setItem(localStorageKeys.APP_CONFIG, JSON.stringify(config.appConfig)); - localStorage.setItem(localStorageKeys.PAGE_INFO, JSON.stringify(config.pageInfo)); - if (config.appConfig.theme) { - localStorage.setItem(localStorageKeys.THEME, config.appConfig.theme); + const isSubPage = !!this.$store.state.currentConfigInfo.confId; + if (isSubPage) { // Apply to sub-page only + const subConfigId = this.$store.state.currentConfigInfo.confId; + const sectionStorageKey = `${localStorageKeys.CONF_SECTIONS}-${subConfigId}`; + const pageInfoStorageKey = `${localStorageKeys.PAGE_INFO}-${subConfigId}`; + const themeStoreKey = `${localStorageKeys.THEME}-${subConfigId}`; + localStorage.setItem(sectionStorageKey, JSON.stringify(config.sections)); + localStorage.setItem(pageInfoStorageKey, JSON.stringify(config.pageInfo)); + localStorage.setItem(themeStoreKey, config.appConfig.theme); + } else { // Apply to main config + localStorage.setItem(localStorageKeys.CONF_SECTIONS, JSON.stringify(config.sections)); + localStorage.setItem(localStorageKeys.APP_CONFIG, JSON.stringify(config.appConfig)); + localStorage.setItem(localStorageKeys.PAGE_INFO, JSON.stringify(config.pageInfo)); + localStorage.setItem(localStorageKeys.CONF_PAGES, JSON.stringify(config.pages || [])); + if (config.appConfig.theme) { + localStorage.setItem(localStorageKeys.THEME, config.appConfig.theme); + } } // Save hashed token in local storage this.setBackupIdLocally(backupId, this.restorePassword); diff --git a/src/mixins/ConfigSaving.js b/src/mixins/ConfigSaving.js index 9357038d..caa269ef 100644 --- a/src/mixins/ConfigSaving.js +++ b/src/mixins/ConfigSaving.js @@ -23,9 +23,15 @@ export default { // 1. Get the config, and strip appConfig if is sub-page const isSubPag = !!this.$store.state.currentConfigInfo.confId; const jsonConfig = config; - if (isSubPag) delete jsonConfig.appConfig; jsonConfig.sections = jsonConfig.sections.map(({ filteredItems, ...section }) => section); - + // If a sub-config, then remove appConfig, and check path isn't an external URL + if (isSubPag) { + delete jsonConfig.appConfig; + if (this.$store.state.currentConfigInfo.confPath.includes('http')) { + ErrorHandler('Cannot save to an external URL'); + return; + } + } // 2. Convert JSON into YAML const yamlOptions = {}; const strjsonConfig = JSON.stringify(jsonConfig); @@ -67,20 +73,39 @@ export default { ErrorHandler('Unable to save changes locally, this feature has been disabled'); return; } - localStorage.setItem(localStorageKeys.CONF_SECTIONS, JSON.stringify(config.sections)); - localStorage.setItem(localStorageKeys.PAGE_INFO, JSON.stringify(config.pageInfo)); - localStorage.setItem(localStorageKeys.APP_CONFIG, JSON.stringify(config.appConfig)); + + const isSubPag = !!this.$store.state.currentConfigInfo.confId; + if (isSubPag) { // Save for sub-page only + const configId = this.$store.state.currentConfigInfo.confId; + const localStorageKeySections = `${localStorageKeys.CONF_SECTIONS}-${configId}`; + const localStorageKeyPageInfo = `${localStorageKeys.PAGE_INFO}-${configId}`; + localStorage.setItem(localStorageKeySections, JSON.stringify(config.sections)); + localStorage.setItem(localStorageKeyPageInfo, JSON.stringify(config.pageInfo)); + } else { // Or save to main config + localStorage.setItem(localStorageKeys.CONF_SECTIONS, JSON.stringify(config.sections)); + localStorage.setItem(localStorageKeys.PAGE_INFO, JSON.stringify(config.pageInfo)); + localStorage.setItem(localStorageKeys.APP_CONFIG, JSON.stringify(config.appConfig)); + } + if (config.appConfig.theme) { localStorage.setItem(localStorageKeys.THEME, config.appConfig.theme); } - InfoHandler('Config has succesfully been saved in browser storage', 'Config Update'); + InfoHandler('Config has successfully been saved in browser storage', 'Config Update'); this.showToast(this.$t('config-editor.success-msg-local'), true); this.$store.commit(StoreKeys.SET_EDIT_MODE, false); }, carefullyClearLocalStorage() { + // Delete the main keys localStorage.removeItem(localStorageKeys.PAGE_INFO); localStorage.removeItem(localStorageKeys.APP_CONFIG); localStorage.removeItem(localStorageKeys.CONF_SECTIONS); + // Then, if we've got any sub-pages, delete those too + (this.$store.getters.pages || []).forEach((page) => { + const localStorageKeySections = `${localStorageKeys.CONF_SECTIONS}-${page.id}`; + const localStorageKeyPageInfo = `${localStorageKeys.PAGE_INFO}-${page.id}`; + localStorage.removeItem(localStorageKeySections); + localStorage.removeItem(localStorageKeyPageInfo); + }); }, }, }; diff --git a/src/store.js b/src/store.js index c137ceaa..6d034900 100644 --- a/src/store.js +++ b/src/store.js @@ -337,6 +337,20 @@ const store = new Vuex.Store({ if (!subConfigId) { // Use root config as config commit(SET_CONFIG, rootConfig); commit(SET_CURRENT_CONFIG_INFO, {}); + + let localSections = []; + const localSectionsRaw = localStorage[localStorageKeys.CONF_SECTIONS]; + if (localSectionsRaw) { + try { + const json = JSON.parse(localSectionsRaw); + if (json.length >= 1) localSections = json; + } catch (e) { + ErrorHandler('Malformed section data in local storage'); + } + } + if (localSections.length > 0) { + rootConfig.sections = localSections; + } return rootConfig; } else { // Find and format path to fetch sub-config from @@ -350,15 +364,27 @@ const store = new Vuex.Store({ } axios.get(subConfigPath).then((response) => { + // Parse the YAML const configContent = yaml.load(response.data) || {}; // Certain values must be inherited from root config const theme = configContent?.appConfig?.theme || rootConfig.appConfig?.theme || 'default'; configContent.appConfig = rootConfig.appConfig; configContent.pages = rootConfig.pages; configContent.appConfig.theme = theme; + + // Load local sections if they exist + const localSectionsRaw = localStorage[`${localStorageKeys.CONF_SECTIONS}-${subConfigId}`]; + if (localSectionsRaw) { + try { + const json = JSON.parse(localSectionsRaw); + if (json.length >= 1) configContent.sections = json; + } catch (e) { + ErrorHandler('Malformed section data in local storage for sub-config'); + } + } + // Set the config commit(SET_CONFIG, configContent); commit(SET_CURRENT_CONFIG_INFO, { confPath: subConfigPath, confId: subConfigId }); - return configContent; }).catch((err) => { ErrorHandler(`Unable to load config from '${subConfigPath}'`, err); }); diff --git a/src/utils/defaults.js b/src/utils/defaults.js index 4a2576ba..cf32f360 100644 --- a/src/utils/defaults.js +++ b/src/utils/defaults.js @@ -124,6 +124,7 @@ module.exports = { PRIMARY_THEME: 'primaryTheme', CUSTOM_COLORS: 'customColors', CONF_SECTIONS: 'confSections', + CONF_PAGES: 'confPages', CONF_WIDGETS: 'confSections', PAGE_INFO: 'pageInfo', APP_CONFIG: 'appConfig', @@ -188,7 +189,7 @@ module.exports = { // delay: { show: 380, hide: 0 }, }, /* Server location of the Backup & Sync cloud function */ - backupEndpoint: 'https://dashy-sync-service.as93.net', + backupEndpoint: 'https://sync-service.dashy.to', /* Available services for fetching favicon icon for user apps */ faviconApiEndpoints: { allesedv: 'https://f1.allesedv.com/128/$URL',