Work in progress, config re-write (#799)

This commit is contained in:
Alicia Sykes 2022-07-15 20:03:55 +01:00
parent e9ff44ac91
commit 6be38b9f58
6 changed files with 122 additions and 82 deletions

View File

@ -36,7 +36,7 @@ const HomeMixin = {
searchValue: '', searchValue: '',
}), }),
async mounted() { async mounted() {
await this.getConfigForRoute(); // await this.getConfigForRoute();
}, },
watch: { watch: {
async $route() { async $route() {
@ -44,15 +44,27 @@ const HomeMixin = {
this.setTheme(); this.setTheme();
}, },
}, },
async created() {
// console.log(this.$router.currentRoute.path);
const subPage = this.determineConfigFile();
await this.$store.dispatch(Keys.INITIALIZE_CONFIG, subPage);
},
methods: { methods: {
async getConfigForRoute() { /* Based on the current route, get which config to display, null will use default */
this.$store.commit(Keys.SET_CURRENT_SUB_PAGE, this.subPageInfo); determineConfigFile() {
if (this.subPageInfo && this.subPageInfo.confPath) { // Get config for sub-page const pagePath = this.$router.currentRoute.path;
await this.$store.dispatch(Keys.INITIALIZE_MULTI_PAGE_CONFIG, this.subPageInfo.confPath); const isSubPage = new RegExp((/(home|workspace|minimal)\/[a-zA-Z0-9-]+/g)).test(pagePath);
} else { // Otherwise, use main config const subPageName = isSubPage ? pagePath.split('/').pop() : null;
this.$store.commit(Keys.USE_MAIN_CONFIG); return subPageName;
}
}, },
// async getConfigForRoute() {
// this.$store.commit(Keys.SET_CURRENT_SUB_PAGE, this.subPageInfo);
// if (this.subPageInfo && this.subPageInfo.confPath) { // Get config for sub-page
// await this.$store.dispatch(Keys.INITIALIZE_MULTI_PAGE_CONFIG, this.subPageInfo.confPath);
// } else { // Otherwise, use main config
// this.$store.commit(Keys.USE_MAIN_CONFIG);
// }
// },
/* TEMPORARY: If on sub-page, check if custom theme is set and return it */ /* TEMPORARY: If on sub-page, check if custom theme is set and return it */
getSubPageTheme() { getSubPageTheme() {
if (!this.pageId || this.pageId === 'home') { if (!this.pageId || this.pageId === 'home') {

View File

@ -14,7 +14,7 @@ import Home from '@/views/Home.vue';
// Import helper functions, config data and defaults // Import helper functions, config data and defaults
import { isAuthEnabled, isLoggedIn, isGuestAccessEnabled } from '@/utils/Auth'; import { isAuthEnabled, isLoggedIn, isGuestAccessEnabled } from '@/utils/Auth';
import { makePageSlug, makePageName } from '@/utils/ConfigHelpers'; // import { makePageSlug, makePageName } from '@/utils/ConfigHelpers';
import { metaTagData, startingView, routePaths } from '@/utils/defaults'; import { metaTagData, startingView, routePaths } from '@/utils/defaults';
import ErrorHandler from '@/utils/ErrorHandler'; import ErrorHandler from '@/utils/ErrorHandler';
@ -27,7 +27,7 @@ if (!conf) {
// Assign top-level config fields, check not null // Assign top-level config fields, check not null
const config = conf || {}; const config = conf || {};
const pages = config.pages || []; // const pages = config.pages || [];
const pageInfo = config.pageInfo || {}; const pageInfo = config.pageInfo || {};
const appConfig = config.appConfig || {}; const appConfig = config.appConfig || {};
@ -64,54 +64,54 @@ const makeMetaTags = (defaultTitle) => ({
metaTags: metaTagData, metaTags: metaTagData,
}); });
const makeSubConfigPath = (rawPath) => { // const makeSubConfigPath = (rawPath) => {
if (!rawPath) return ''; // if (!rawPath) return '';
if (rawPath.startsWith('/') || rawPath.startsWith('http')) return rawPath; // if (rawPath.startsWith('/') || rawPath.startsWith('http')) return rawPath;
else return `/${rawPath}`; // else return `/${rawPath}`;
}; // };
/* For each additional config file, create routes for home, minimal and workspace views */ /* For each additional config file, create routes for home, minimal and workspace views */
const makeMultiPageRoutes = (userPages) => { // const makeMultiPageRoutes = (userPages) => {
// If no multi pages specified, or is not array, then return nothing // // If no multi pages specified, or is not array, then return nothing
if (!userPages || !Array.isArray(userPages)) return []; // if (!userPages || !Array.isArray(userPages)) return [];
const multiPageRoutes = []; // const multiPageRoutes = [];
// For each user page, create an additional route // // For each user page, create an additional route
userPages.forEach((page) => { // userPages.forEach((page) => {
if (!page.name || !page.path) { // Sumin not right, show warning // if (!page.name || !page.path) { // Sumin not right, show warning
ErrorHandler('Additional pages must have both a `name` and `path`'); // ErrorHandler('Additional pages must have both a `name` and `path`');
} // }
// Props to be passed to home mixin // // Props to be passed to home mixin
const subPageInfo = { // const subPageInfo = {
subPageInfo: { // subPageInfo: {
confPath: makeSubConfigPath(page.path), // confPath: makeSubConfigPath(page.path),
pageId: makePageName(page.name), // pageId: makePageName(page.name),
pageTitle: page.name, // pageTitle: page.name,
}, // },
}; // };
// Create route for default homepage // // Create route for default homepage
multiPageRoutes.push({ // multiPageRoutes.push({
path: makePageSlug(page.name, 'home'), // path: makePageSlug(page.name, 'home'),
name: `${subPageInfo.subPageInfo.pageId}-home`, // name: `${subPageInfo.subPageInfo.pageId}-home`,
component: Home, // component: Home,
props: subPageInfo, // props: subPageInfo,
}); // });
// Create route for the workspace view // // Create route for the workspace view
multiPageRoutes.push({ // multiPageRoutes.push({
path: makePageSlug(page.name, 'workspace'), // path: makePageSlug(page.name, 'workspace'),
name: `${subPageInfo.subPageInfo.pageId}-workspace`, // name: `${subPageInfo.subPageInfo.pageId}-workspace`,
component: () => import('./views/Workspace.vue'), // component: () => import('./views/Workspace.vue'),
props: subPageInfo, // props: subPageInfo,
}); // });
// Create route for the minimal view // // Create route for the minimal view
multiPageRoutes.push({ // multiPageRoutes.push({
path: makePageSlug(page.name, 'minimal'), // path: makePageSlug(page.name, 'minimal'),
name: `${subPageInfo.subPageInfo.pageId}-minimal`, // name: `${subPageInfo.subPageInfo.pageId}-minimal`,
component: () => import('./views/Minimal.vue'), // component: () => import('./views/Minimal.vue'),
props: subPageInfo, // props: subPageInfo,
}); // });
}); // });
return multiPageRoutes; // return multiPageRoutes;
}; // };
/* Routing mode, can be either 'hash', 'history' or 'abstract' */ /* Routing mode, can be either 'hash', 'history' or 'abstract' */
const mode = appConfig.routingMode || 'history'; const mode = appConfig.routingMode || 'history';
@ -120,7 +120,7 @@ const mode = appConfig.routingMode || 'history';
const router = new Router({ const router = new Router({
mode, mode,
routes: [ routes: [
...makeMultiPageRoutes(pages), // ...makeMultiPageRoutes(pages),
{ // The default view can be customized by the user { // The default view can be customized by the user
path: '/', path: '/',
name: `landing-page-${getStartingView()}`, name: `landing-page-${getStartingView()}`,

View File

@ -4,7 +4,7 @@ import Vuex from 'vuex';
import axios from 'axios'; import axios from 'axios';
import yaml from 'js-yaml'; import yaml from 'js-yaml';
import Keys from '@/utils/StoreMutations'; import Keys from '@/utils/StoreMutations';
import ConfigAccumulator from '@/utils/ConfigAccumalator'; // import ConfigAccumulator from '@/utils/ConfigAccumalator';
import { componentVisibility } from '@/utils/ConfigHelpers'; import { componentVisibility } from '@/utils/ConfigHelpers';
import { applyItemId } from '@/utils/SectionHelpers'; import { applyItemId } from '@/utils/SectionHelpers';
import filterUserSections from '@/utils/CheckSectionVisibility'; import filterUserSections from '@/utils/CheckSectionVisibility';
@ -16,8 +16,10 @@ Vue.use(Vuex);
const { const {
INITIALIZE_CONFIG, INITIALIZE_CONFIG,
INITIALIZE_MULTI_PAGE_CONFIG, INITIALIZE_ROOT_CONFIG,
// INITIALIZE_MULTI_PAGE_CONFIG,
SET_CONFIG, SET_CONFIG,
SET_ROOT_CONFIG,
SET_REMOTE_CONFIG, SET_REMOTE_CONFIG,
SET_CURRENT_SUB_PAGE, SET_CURRENT_SUB_PAGE,
SET_MODAL_OPEN, SET_MODAL_OPEN,
@ -46,7 +48,8 @@ const {
const store = new Vuex.Store({ const store = new Vuex.Store({
state: { state: {
config: {}, // The current config, rendered to the UI config: {}, // The current config, rendered to the UI
remoteConfig: {}, // The configuration stored on the server rootConfig: null, // The config from the main config file
// remoteConfig: {}, // The configuration stored on the server
editMode: false, // While true, the user can drag and edit items + sections editMode: false, // While true, the user can drag and edit items + sections
modalOpen: false, // KB shortcut functionality will be disabled when modal is open modalOpen: false, // KB shortcut functionality will be disabled when modal is open
currentConfigInfo: undefined, // For multi-page support, will store info about config file currentConfigInfo: undefined, // For multi-page support, will store info about config file
@ -68,7 +71,7 @@ const store = new Vuex.Store({
return filterUserSections(state.config.sections || []); return filterUserSections(state.config.sections || []);
}, },
pages(state) { pages(state) {
return state.remoteConfig.pages || []; return state.config.pages || [];
}, },
theme(state) { theme(state) {
let localTheme = null; let localTheme = null;
@ -145,6 +148,10 @@ const store = new Vuex.Store({
}, },
}, },
mutations: { mutations: {
[SET_ROOT_CONFIG](state, config) {
if (!config.appConfig) config.appConfig = {};
state.config = config;
},
[SET_CONFIG](state, config) { [SET_CONFIG](state, config) {
if (!config.appConfig) config.appConfig = {}; if (!config.appConfig) config.appConfig = {};
state.config = config; state.config = config;
@ -323,24 +330,43 @@ const store = new Vuex.Store({
}, },
actions: { actions: {
/* Called when app first loaded. Reads config and sets state */ /* Called when app first loaded. Reads config and sets state */
async [INITIALIZE_CONFIG]({ commit }) { // async [INITIALIZE_CONFIG]({ commit }) {
// Get the config file from the server and store it for use by the accumulator // // Get the config file from the server and store it for use by the accumulator
commit(SET_REMOTE_CONFIG, yaml.load((await axios.get('/conf.yml')).data)); // commit(SET_REMOTE_CONFIG, yaml.load((await axios.get('/conf.yml')).data));
const deepCopy = (json) => JSON.parse(JSON.stringify(json)); // const deepCopy = (json) => JSON.parse(JSON.stringify(json));
const config = deepCopy(new ConfigAccumulator().config()); // const config = deepCopy(new ConfigAccumulator().config());
commit(SET_CONFIG, config); // commit(SET_CONFIG, config);
// },
/* Fetches the root config file, only ever called by INITIALIZE_CONFIG */
async [INITIALIZE_ROOT_CONFIG]({ commit }) {
console.log('Initializing root config....');
commit(SET_ROOT_CONFIG, yaml.load((await axios.get('/conf.yml')).data));
}, },
/* Fetch config for a sub-page (sections and pageInfo only) */ /**
async [INITIALIZE_MULTI_PAGE_CONFIG]({ commit, state }, configPath) { * Fetches config and updates state
axios.get(configPath).then((response) => { * If not on sub-page, will trigger the fetch of main config, then use that
const subConfig = yaml.load(response.data); * If using sub-page config, then fetch that sub-config, then
const pageTheme = subConfig.appConfig?.theme; * override certain fields (appConfig, pages) and update config
subConfig.appConfig = state.config.appConfig; // Always use parent appConfig */
if (pageTheme) subConfig.appConfig.theme = pageTheme; // Apply page theme override async [INITIALIZE_CONFIG]({ commit, state }, subConfigPath) {
commit(SET_CONFIG, subConfig); const fetchPath = subConfigPath || '/conf.yml'; // The path to fetch config from
}).catch((err) => { if (!state.rootConfig) {
ErrorHandler(`Unable to load config from '${configPath}'`, err); await this.dispatch(Keys.INITIALIZE_ROOT_CONFIG);
}); }
console.log('rootConfig', state.rootConfig);
if (!subConfigPath) { // Use root config as config
commit(SET_CONFIG, state.rootConfig);
} else { // Fetch sub-config, and use as config
axios.get(fetchPath).then((response) => {
const configContent = yaml.load(response.data);
// Certain values must be inherited from root config
configContent.appConfig = state.rootConfig.appConfig;
configContent.pages = state.rootConfig.pages;
commit(SET_CONFIG, configContent);
}).catch((err) => {
ErrorHandler(`Unable to load config from '${fetchPath}'`, err);
});
}
}, },
}, },
modules: {}, modules: {},

View File

@ -20,7 +20,7 @@ import buildConf from '../../public/conf.yml';
export default class ConfigAccumulator { export default class ConfigAccumulator {
constructor() { constructor() {
this.conf = $store.state.remoteConfig; this.conf = $store.state.config;
} }
pages() { pages() {

View File

@ -1,8 +1,10 @@
// A list of mutation names // A list of mutation names
const KEY_NAMES = [ const KEY_NAMES = [
'INITIALIZE_CONFIG', 'INITIALIZE_CONFIG',
'INITIALIZE_ROOT_CONFIG',
'INITIALIZE_MULTI_PAGE_CONFIG', 'INITIALIZE_MULTI_PAGE_CONFIG',
'SET_CONFIG', 'SET_CONFIG',
'SET_ROOT_CONFIG',
'SET_REMOTE_CONFIG', 'SET_REMOTE_CONFIG',
'SET_CURRENT_SUB_PAGE', 'SET_CURRENT_SUB_PAGE',
'SET_MODAL_OPEN', 'SET_MODAL_OPEN',

View File

@ -28,9 +28,9 @@ module.exports = {
openingMethod: 'newtab', openingMethod: 'newtab',
/* The page paths for each route within the app for the router */ /* The page paths for each route within the app for the router */
routePaths: { routePaths: {
home: '/home', home: '/home/:config?/',
minimal: '/minimal', minimal: '/minimal/:config?/',
workspace: '/workspace', workspace: '/workspace/:config?/',
about: '/about', about: '/about',
login: '/login', login: '/login',
download: '/download', download: '/download',