mirror of https://github.com/Lissy93/dashy.git
🔀 Merge pull request #271 from Lissy93/ARCH/implement-vuex-state
[ARCH] Implement VueX State Management
This commit is contained in:
commit
7f555ee142
|
@ -1,5 +1,8 @@
|
||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## ⚡️ 1.8.6 - Implementation of VueX [PR: #271](https://github.com/Lissy93/dashy/pull/271)
|
||||||
|
- New state management pattern, which should lead to a more organized code base long term, and will also make building out the new UI editor significantly easier to do in a clean and reliable way
|
||||||
|
|
||||||
## 💄 1.8.5 - Lots of Requested UI Improvements [PR #261](https://github.com/Lissy93/dashy/pull/261)
|
## 💄 1.8.5 - Lots of Requested UI Improvements [PR #261](https://github.com/Lissy93/dashy/pull/261)
|
||||||
- Adds an option for landing URL in workspace, Re: #255
|
- Adds an option for landing URL in workspace, Re: #255
|
||||||
- Switches to a new API for generative icons, Re: #163
|
- Switches to a new API for generative icons, Re: #163
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# Config file for pull-request-badge. See: https://pullrequestbadge.com/
|
# Config file for pull-request-badge. See: https://pullrequestbadge.com/ by @stefanbuck
|
||||||
# Enables badges to be inserted into the PR description, based on certain conditions
|
# Dynamically inserts status badges into PR description, based on certain conditions
|
||||||
|
|
||||||
# Checks if the required sections are missing
|
# Checks if the required sections are missing
|
||||||
- label: "⚠️Missing"
|
- label: "⚠️Missing"
|
||||||
|
@ -23,21 +23,43 @@
|
||||||
color: "#f25265"
|
color: "#f25265"
|
||||||
when: "$labels.length == 0"
|
when: "$labels.length == 0"
|
||||||
|
|
||||||
# Show note when in draft mode
|
# Show note when task list has unfinished items
|
||||||
|
- label: "⚠️Notice"
|
||||||
|
message: "Unchecked Tasks"
|
||||||
|
when: "$payload.pull_request.body.includes('- [ ] ')"
|
||||||
|
color: "#f25265"
|
||||||
|
|
||||||
|
# Show badge indicating PR status
|
||||||
- label: "Status"
|
- label: "Status"
|
||||||
message: "Draft"
|
message: "✏️ Draft"
|
||||||
when: "$isDraft"
|
when: "$isDraft"
|
||||||
color: "#ffa933"
|
color: "#ffa933"
|
||||||
|
- label: "Status"
|
||||||
|
message: "🧱 Work in Progress"
|
||||||
|
when: "$payload.pull_request.title.includes('WIP')"
|
||||||
|
color: "#29e3f4"
|
||||||
|
- label: "Status"
|
||||||
|
message: "✅ Ready"
|
||||||
|
color: "#3ef963"
|
||||||
|
when: "$labels.includes('🔀 Ready for Merge')"
|
||||||
|
|
||||||
# Add size label based on very large or tiny PRs
|
# Add size label based on very large or tiny PRs
|
||||||
|
- label: "PR Size"
|
||||||
|
message: "Extra Large"
|
||||||
|
color: "#f9833e"
|
||||||
|
when: "$additions > 1000"
|
||||||
- label: "PR Size"
|
- label: "PR Size"
|
||||||
message: "Large"
|
message: "Large"
|
||||||
color: "#f79c47"
|
color: "#f4b546"
|
||||||
when: "$additions > 600"
|
when: "$additions > 500 && $additions < 1000"
|
||||||
|
- label: "PR Size"
|
||||||
|
message: "Medium"
|
||||||
|
color: "#f3ff59"
|
||||||
|
when: "$additions > 10 && $additions < 500"
|
||||||
- label: "PR Size"
|
- label: "PR Size"
|
||||||
message: "Quick"
|
message: "Quick"
|
||||||
color: "#3eef8b"
|
color: "#3eef8b"
|
||||||
when: "$additions < 5"
|
when: "$additions < 10"
|
||||||
|
|
||||||
# Show PR number, to destination and from destination
|
# Show PR number, to destination and from destination
|
||||||
- label: "#$prNumber"
|
- label: "#$prNumber"
|
||||||
|
@ -57,7 +79,7 @@
|
||||||
when: "$payload.pull_request.author_association !== 'OWNER'"
|
when: "$payload.pull_request.author_association !== 'OWNER'"
|
||||||
url: "https://github.com/$payload.pull_request.user.login"
|
url: "https://github.com/$payload.pull_request.user.login"
|
||||||
|
|
||||||
# Show a badge indicating the PR category
|
# Show a badge indicating the PR category, based on tag
|
||||||
- label: "Type"
|
- label: "Type"
|
||||||
message: "✨ Feature"
|
message: "✨ Feature"
|
||||||
color: "#39b0fd"
|
color: "#39b0fd"
|
||||||
|
@ -90,3 +112,34 @@
|
||||||
message: "🌟 Showcase Addition"
|
message: "🌟 Showcase Addition"
|
||||||
color: "#39b0fd"
|
color: "#39b0fd"
|
||||||
when: "$labels.includes('💯 Showcase')"
|
when: "$labels.includes('💯 Showcase')"
|
||||||
|
- label: "Type"
|
||||||
|
message: "🏗️ Architecture"
|
||||||
|
color: "#39b0fd"
|
||||||
|
when: "$labels.includes('🏗️ Architectural Changes')"
|
||||||
|
- label: "Type"
|
||||||
|
message: "🤖 Auto Submission"
|
||||||
|
color: "#39b0fd"
|
||||||
|
when: "$labels.includes('🤖 Auto')"
|
||||||
|
- label: "Type"
|
||||||
|
message: "🌐 Language Update"
|
||||||
|
color: "#39b0fd"
|
||||||
|
when: "$labels.includes('🌐 Language')"
|
||||||
|
|
||||||
|
# Show warning, when certain tags are applied
|
||||||
|
- label: "Warning"
|
||||||
|
message: "⛔ Do Not Merge"
|
||||||
|
color: "#f25265"
|
||||||
|
when: "$labels.includes('⛔ Don't Merge')"
|
||||||
|
- label: "Warning"
|
||||||
|
message: "🚫 Merge Conflicts"
|
||||||
|
color: "#f25265"
|
||||||
|
when: "$labels.includes('🚫 Merge Conflicts')"
|
||||||
|
- label: "Warning"
|
||||||
|
message: "🕸️ Inactive"
|
||||||
|
color: "#f25265"
|
||||||
|
when: "$labels.includes('🕸️ Inactive')"
|
||||||
|
- label: "Warning"
|
||||||
|
message: "💀 Spam"
|
||||||
|
color: "#f25265"
|
||||||
|
when: "$labels.includes('💀 Spam')"
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
# PR labels and the branch patterns they should be auto-assigned to
|
# PR labels and the branch patterns they should be auto-assigned to
|
||||||
|
✨ New Feature: ['FEATURE/*', 'FEAT/*']
|
||||||
🦋 Bug Fix: ['FIX/*', 'HOT-FIX/*', 'BUG-FIX/*']
|
|
||||||
✨ New Feature: ['FEATURE/*']
|
|
||||||
🚚 Refactor: ['IMPROVMENTS/*', 'REFACTOR/*']
|
🚚 Refactor: ['IMPROVMENTS/*', 'REFACTOR/*']
|
||||||
💯 Showcase: ['SHOWCASE/*']
|
🦋 Bug Fix: ['FIX/*', 'HOT-FIX/*', 'BUG-FIX/*']
|
||||||
💄 Stylistic Changes: ['STYLES/*', 'THEME/*']
|
💯 Showcase: ['SHOWCASE/*', 'SHOWCASE_SUBMISSION/*']
|
||||||
🛠️ Build Changes: ['ARCH/*', 'ARCHITECTURE/*', 'DOCKER/*', 'BUILD/*']
|
💄 Stylistic Changes: ['STYLES/*', 'THEME/*', 'UI/*']
|
||||||
|
🏗️ Architectural Changes: ['ARCH/*', 'ARCHITECTURE/*']
|
||||||
|
🛠️ Build Changes: ['DOCKER/*', 'BUILD/*', 'CI/*', 'ACTIONS/*']
|
||||||
|
🌐 Language: ['LANG/*', 'INTERNATIONALIZATION/*', 'I18N/*', 'TEXT-UPDATE/*']
|
||||||
🤖 Auto: ['AUTO/*', 'BOT/*', 'snyk-upgrade-*', 'snyk-fix-*']
|
🤖 Auto: ['AUTO/*', 'BOT/*', 'snyk-upgrade-*', 'snyk-fix-*']
|
||||||
⛔ Don't Merge: ['WEBSITE/*', 'EXPERIMENT/*', 'DEPLOY/*', 'deploy_*', 'gh-pages', 'dev-demo']
|
⛔ Don't Merge: ['WEBSITE/*', 'EXPERIMENT/*', 'DEPLOY/*', 'deploy_*', 'gh-pages', 'dev-demo']
|
|
@ -4,7 +4,7 @@ on:
|
||||||
repository_dispatch:
|
repository_dispatch:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
schedule:
|
schedule:
|
||||||
- cron: '0 1 * * 0' # At 01:00 on Sunday.
|
- cron: '0 1 1 * *' # Run monthly
|
||||||
jobs:
|
jobs:
|
||||||
link-checker:
|
link-checker:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
@ -14,7 +14,7 @@ jobs:
|
||||||
- name: Check for Broken Links
|
- name: Check for Broken Links
|
||||||
uses: lycheeverse/lychee-action@v1.0.8
|
uses: lycheeverse/lychee-action@v1.0.8
|
||||||
with:
|
with:
|
||||||
args: --verbose --no-progress **/*.md **/*.html
|
args: --verbose -a 200,302,304,429 --no-progress **/*.md **/*.html
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{secrets.BOT_GITHUB_TOKEN}}
|
GITHUB_TOKEN: ${{secrets.BOT_GITHUB_TOKEN}}
|
||||||
LYCHEE_OUT: .github/broken-link-report.md
|
LYCHEE_OUT: .github/broken-link-report.md
|
||||||
|
|
|
@ -19,7 +19,7 @@ jobs:
|
||||||
|
|
||||||
add-awaiting-author:
|
add-awaiting-author:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
if: ${{ github.event.comment.author_association != 'COLLABORATOR' && github.event.comment.author_association != 'OWNER' }}
|
if: ${{ !github.event.issue.pull_request && github.event.comment.author_association != 'COLLABORATOR' && github.event.comment.author_association != 'OWNER' }}
|
||||||
steps:
|
steps:
|
||||||
- name: Add Awaiting Author labels when Updated
|
- name: Add Awaiting Author labels when Updated
|
||||||
uses: actions-cool/issues-helper@v2
|
uses: actions-cool/issues-helper@v2
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "Dashy",
|
"name": "Dashy",
|
||||||
"version": "1.8.5",
|
"version": "1.8.6",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"main": "server",
|
"main": "server",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
@ -39,7 +39,8 @@
|
||||||
"vue-router": "^3.0.3",
|
"vue-router": "^3.0.3",
|
||||||
"vue-select": "^3.12.1",
|
"vue-select": "^3.12.1",
|
||||||
"vue-swatches": "^2.1.1",
|
"vue-swatches": "^2.1.1",
|
||||||
"vue-toasted": "^1.1.28"
|
"vue-toasted": "^1.1.28",
|
||||||
|
"vuex": "^3.6.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@architect/sandbox": "^3.7.4",
|
"@architect/sandbox": "^3.7.4",
|
||||||
|
|
34
src/App.vue
34
src/App.vue
|
@ -11,10 +11,9 @@
|
||||||
import Header from '@/components/PageStrcture/Header.vue';
|
import Header from '@/components/PageStrcture/Header.vue';
|
||||||
import Footer from '@/components/PageStrcture/Footer.vue';
|
import Footer from '@/components/PageStrcture/Footer.vue';
|
||||||
import LoadingScreen from '@/components/PageStrcture/LoadingScreen.vue';
|
import LoadingScreen from '@/components/PageStrcture/LoadingScreen.vue';
|
||||||
import { componentVisibility } from '@/utils/ConfigHelpers';
|
|
||||||
import ConfigAccumulator from '@/utils/ConfigAccumalator';
|
|
||||||
import { welcomeMsg } from '@/utils/CoolConsole';
|
import { welcomeMsg } from '@/utils/CoolConsole';
|
||||||
import ErrorHandler from '@/utils/ErrorHandler';
|
import ErrorHandler from '@/utils/ErrorHandler';
|
||||||
|
import Keys from '@/utils/StoreMutations';
|
||||||
import {
|
import {
|
||||||
localStorageKeys,
|
localStorageKeys,
|
||||||
splashScreenTime,
|
splashScreenTime,
|
||||||
|
@ -22,10 +21,6 @@ import {
|
||||||
language as defaultLanguage,
|
language as defaultLanguage,
|
||||||
} from '@/utils/defaults';
|
} from '@/utils/defaults';
|
||||||
|
|
||||||
const Accumulator = new ConfigAccumulator();
|
|
||||||
const config = Accumulator.config();
|
|
||||||
const visibleComponents = componentVisibility(config.appConfig) || defaultVisibleComponents;
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'app',
|
name: 'app',
|
||||||
components: {
|
components: {
|
||||||
|
@ -33,17 +28,9 @@ export default {
|
||||||
Footer,
|
Footer,
|
||||||
LoadingScreen,
|
LoadingScreen,
|
||||||
},
|
},
|
||||||
provide: {
|
|
||||||
config,
|
|
||||||
visibleComponents,
|
|
||||||
},
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
isLoading: true, // Set to false after mount complete
|
isLoading: true, // Set to false after mount complete
|
||||||
showFooter: visibleComponents.footer,
|
|
||||||
appConfig: Accumulator.appConfig(),
|
|
||||||
pageInfo: Accumulator.pageInfo(),
|
|
||||||
visibleComponents,
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
@ -55,6 +42,24 @@ export default {
|
||||||
shouldShowSplash() {
|
shouldShowSplash() {
|
||||||
return (this.visibleComponents || defaultVisibleComponents).splashScreen;
|
return (this.visibleComponents || defaultVisibleComponents).splashScreen;
|
||||||
},
|
},
|
||||||
|
config() {
|
||||||
|
return this.$store.state.config;
|
||||||
|
},
|
||||||
|
appConfig() {
|
||||||
|
return this.$store.getters.appConfig;
|
||||||
|
},
|
||||||
|
pageInfo() {
|
||||||
|
return this.$store.getters.pageInfo;
|
||||||
|
},
|
||||||
|
sections() {
|
||||||
|
return this.$store.getters.pageInfo;
|
||||||
|
},
|
||||||
|
visibleComponents() {
|
||||||
|
return this.$store.getters.visibleComponents;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.$store.dispatch('initializeConfig');
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
/* Injects the users custom CSS as a style tag */
|
/* Injects the users custom CSS as a style tag */
|
||||||
|
@ -103,6 +108,7 @@ export default {
|
||||||
/* Fetch or detect users language, then apply it */
|
/* Fetch or detect users language, then apply it */
|
||||||
applyLanguage() {
|
applyLanguage() {
|
||||||
const language = this.getLanguage();
|
const language = this.getLanguage();
|
||||||
|
this.$store.commit(Keys.SET_LANGUAGE, language);
|
||||||
this.$i18n.locale = language;
|
this.$i18n.locale = language;
|
||||||
document.getElementsByTagName('html')[0].setAttribute('lang', language);
|
document.getElementsByTagName('html')[0].setAttribute('lang', language);
|
||||||
},
|
},
|
||||||
|
|
|
@ -36,7 +36,11 @@ import ErrorHandler from '@/utils/ErrorHandler';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'AppInfoModal',
|
name: 'AppInfoModal',
|
||||||
inject: ['config'],
|
computed: {
|
||||||
|
appConfig() {
|
||||||
|
return this.$store.getters.appConfig;
|
||||||
|
},
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
appVersion: process.env.VUE_APP_VERSION, // Current version, from package.json
|
appVersion: process.env.VUE_APP_VERSION, // Current version, from package.json
|
||||||
|
@ -50,8 +54,7 @@ export default {
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
const appConfig = this.config.appConfig || {};
|
if (!this.appVersion || (this.appConfig && this.appConfig.disableUpdateChecks)) {
|
||||||
if (!this.appVersion || (appConfig && appConfig.disableUpdateChecks)) {
|
|
||||||
// Either current version isn't found, or user disabled checks
|
// Either current version isn't found, or user disabled checks
|
||||||
this.checksEnabled = false;
|
this.checksEnabled = false;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -55,7 +55,11 @@ import { modalNames, serviceEndpoints } from '@/utils/defaults';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'RebuildApp',
|
name: 'RebuildApp',
|
||||||
inject: ['config'],
|
computed: {
|
||||||
|
appConfig() {
|
||||||
|
return this.$store.getters.appConfig;
|
||||||
|
},
|
||||||
|
},
|
||||||
components: {
|
components: {
|
||||||
Button,
|
Button,
|
||||||
RebuildIcon,
|
RebuildIcon,
|
||||||
|
@ -112,12 +116,8 @@ export default {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
if (this.config) {
|
if (this.appConfig.allowConfigEdit === false) {
|
||||||
if (this.config.appConfig) {
|
this.allowRebuild = false;
|
||||||
if (this.config.appConfig.allowConfigEdit === false) {
|
|
||||||
this.allowRebuild = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<transition name="slide">
|
<transition name="slide">
|
||||||
<div class="context-menu" v-if="show && menuEnabled"
|
<div class="context-menu" v-if="show && !isMenuDisabled()"
|
||||||
:style="posX && posY ? `top:${posY}px;left:${posX}px;` : ''">
|
:style="posX && posY ? `top:${posY}px;left:${posX}px;` : ''">
|
||||||
<ul>
|
<ul>
|
||||||
<li @click="launch('sametab')">
|
<li @click="launch('sametab')">
|
||||||
|
@ -33,7 +33,6 @@ import WorkspaceOpenIcon from '@/assets/interface-icons/open-workspace.svg';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'ContextMenu',
|
name: 'ContextMenu',
|
||||||
inject: ['config'],
|
|
||||||
components: {
|
components: {
|
||||||
SameTabOpenIcon,
|
SameTabOpenIcon,
|
||||||
NewTabOpenIcon,
|
NewTabOpenIcon,
|
||||||
|
@ -45,10 +44,10 @@ export default {
|
||||||
posY: Number, // The Y coordinate for positioning
|
posY: Number, // The Y coordinate for positioning
|
||||||
show: Boolean, // Should show or hide the menu
|
show: Boolean, // Should show or hide the menu
|
||||||
},
|
},
|
||||||
data() {
|
computed: {
|
||||||
return {
|
appConfig() {
|
||||||
menuEnabled: !this.isMenuDisabled(), // Specifies if the context menu should be used
|
return this.$store.getters.appConfig;
|
||||||
};
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
/* Called on item click, emits an event up to Item */
|
/* Called on item click, emits an event up to Item */
|
||||||
|
@ -58,10 +57,7 @@ export default {
|
||||||
},
|
},
|
||||||
/* Checks if the user as disabled context menu in config */
|
/* Checks if the user as disabled context menu in config */
|
||||||
isMenuDisabled() {
|
isMenuDisabled() {
|
||||||
if (this.config && this.config.appConfig) {
|
return !!this.appConfig.disableContextMenu;
|
||||||
return !!this.config.appConfig.disableContextMenu;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -9,6 +9,8 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import Keys from '@/utils/StoreMutations';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'IframeModal',
|
name: 'IframeModal',
|
||||||
props: {
|
props: {
|
||||||
|
@ -21,13 +23,13 @@ export default {
|
||||||
show(url) {
|
show(url) {
|
||||||
this.url = url;
|
this.url = url;
|
||||||
this.$modal.show(this.name);
|
this.$modal.show(this.name);
|
||||||
this.$emit('modalChanged', true);
|
this.$store.commit(Keys.SET_MODAL_OPEN, true);
|
||||||
},
|
},
|
||||||
hide() {
|
hide() {
|
||||||
this.$modal.hide(this.name);
|
this.$modal.hide(this.name);
|
||||||
},
|
},
|
||||||
modalClosed() {
|
modalClosed() {
|
||||||
this.$emit('modalChanged', false);
|
this.$store.commit(Keys.SET_MODAL_OPEN, false);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -53,7 +53,6 @@ import { localStorageKeys, serviceEndpoints } from '@/utils/defaults';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Item',
|
name: 'Item',
|
||||||
inject: ['config'],
|
|
||||||
props: {
|
props: {
|
||||||
id: String, // The unique ID of a tile (e.g. 001)
|
id: String, // The unique ID of a tile (e.g. 001)
|
||||||
title: String, // The main text of tile, required
|
title: String, // The main text of tile, required
|
||||||
|
@ -77,6 +76,11 @@ export default {
|
||||||
statusCheckInterval: Number,
|
statusCheckInterval: Number,
|
||||||
statusCheckAllowInsecure: Boolean,
|
statusCheckAllowInsecure: Boolean,
|
||||||
},
|
},
|
||||||
|
computed: {
|
||||||
|
appConfig() {
|
||||||
|
return this.$store.getters.appConfig;
|
||||||
|
},
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
contextMenuOpen: false,
|
contextMenuOpen: false,
|
||||||
|
@ -110,7 +114,7 @@ export default {
|
||||||
this.$emit('itemClicked');
|
this.$emit('itemClicked');
|
||||||
}
|
}
|
||||||
// Update the most/ last used ledger, for smart-sorting
|
// Update the most/ last used ledger, for smart-sorting
|
||||||
if (!this.config.appConfig.disableSmartSort) {
|
if (!this.appConfig.disableSmartSort) {
|
||||||
this.incrementMostUsedCount(this.id);
|
this.incrementMostUsedCount(this.id);
|
||||||
this.incrementLastUsedCount(this.id);
|
this.incrementLastUsedCount(this.id);
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,6 @@ import { asciiHash } from '@/utils/MiscHelpers';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Icon',
|
name: 'Icon',
|
||||||
inject: ['config'],
|
|
||||||
props: {
|
props: {
|
||||||
icon: String, // Path to icon asset
|
icon: String, // Path to icon asset
|
||||||
url: String, // Used for fetching the favicon
|
url: String, // Used for fetching the favicon
|
||||||
|
@ -40,6 +39,10 @@ export default {
|
||||||
BrokenImage,
|
BrokenImage,
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
/* Get appConfig from store */
|
||||||
|
appConfig() {
|
||||||
|
return this.$store.getters.appConfig;
|
||||||
|
},
|
||||||
/* Determines the type of icon */
|
/* Determines the type of icon */
|
||||||
iconType: function iconType() {
|
iconType: function iconType() {
|
||||||
return this.determineImageType(this.icon);
|
return this.determineImageType(this.icon);
|
||||||
|
@ -96,7 +99,7 @@ export default {
|
||||||
if (urlParts.length >= 2) return `${urlParts[0]}/${urlParts[1]}/${urlParts[2]}/${iconCdns.faviconName}`;
|
if (urlParts.length >= 2) return `${urlParts[0]}/${urlParts[1]}/${urlParts[2]}/${iconCdns.faviconName}`;
|
||||||
} else if (fullUrl.includes('http')) { // Service is running publicly
|
} else if (fullUrl.includes('http')) { // Service is running publicly
|
||||||
const host = this.getHostName(fullUrl);
|
const host = this.getHostName(fullUrl);
|
||||||
const faviconApi = specificApi || this.config.appConfig.faviconApi || defaultFaviconApi;
|
const faviconApi = specificApi || this.appConfig.faviconApi || defaultFaviconApi;
|
||||||
const endpoint = faviconApiEndpoints[faviconApi];
|
const endpoint = faviconApiEndpoints[faviconApi];
|
||||||
return endpoint.replace('$URL', host);
|
return endpoint.replace('$URL', host);
|
||||||
}
|
}
|
||||||
|
@ -120,7 +123,7 @@ export default {
|
||||||
/* or if user prefers local favicon, then return true */
|
/* or if user prefers local favicon, then return true */
|
||||||
shouldUseDefaultFavicon(fullUrl) {
|
shouldUseDefaultFavicon(fullUrl) {
|
||||||
const isLocalIP = /(127\.)|(192\.168\.)|(10\.)|(172\.1[6-9]\.)|(172\.2[0-9]\.)|(172\.3[0-1]\.)|(::1$)|([fF][cCdD])|(localhost)/;
|
const isLocalIP = /(127\.)|(192\.168\.)|(10\.)|(172\.1[6-9]\.)|(172\.2[0-9]\.)|(172\.3[0-1]\.)|(::1$)|([fF][cCdD])|(localhost)/;
|
||||||
return (isLocalIP.test(fullUrl) || this.config.appConfig.faviconApi === 'local');
|
return (isLocalIP.test(fullUrl) || this.appConfig.faviconApi === 'local');
|
||||||
},
|
},
|
||||||
/* Fetches the path of local images, from Docker container */
|
/* Fetches the path of local images, from Docker container */
|
||||||
getLocalImagePath(img) {
|
getLocalImagePath(img) {
|
||||||
|
|
|
@ -44,7 +44,6 @@
|
||||||
:ref="`iframeModal-${groupId}`"
|
:ref="`iframeModal-${groupId}`"
|
||||||
:name="`iframeModal-${groupId}`"
|
:name="`iframeModal-${groupId}`"
|
||||||
@closed="$emit('itemClicked')"
|
@closed="$emit('itemClicked')"
|
||||||
@modalChanged="modalChanged"
|
|
||||||
/>
|
/>
|
||||||
</Collapsable>
|
</Collapsable>
|
||||||
</template>
|
</template>
|
||||||
|
@ -58,7 +57,6 @@ import IframeModal from '@/components/LinkItems/IframeModal.vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Section',
|
name: 'Section',
|
||||||
inject: ['config'],
|
|
||||||
props: {
|
props: {
|
||||||
groupId: String,
|
groupId: String,
|
||||||
title: String,
|
title: String,
|
||||||
|
@ -66,7 +64,6 @@ export default {
|
||||||
displayData: Object,
|
displayData: Object,
|
||||||
items: Array,
|
items: Array,
|
||||||
itemSize: String,
|
itemSize: String,
|
||||||
modalOpen: Boolean,
|
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
Collapsable,
|
Collapsable,
|
||||||
|
@ -74,13 +71,16 @@ export default {
|
||||||
IframeModal,
|
IframeModal,
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
appConfig() {
|
||||||
|
return this.$store.getters.appConfig;
|
||||||
|
},
|
||||||
sortOrder() {
|
sortOrder() {
|
||||||
return this.displayData.sortBy || defaultSortOrder;
|
return this.displayData.sortBy || defaultSortOrder;
|
||||||
},
|
},
|
||||||
/* If the sortBy attribute is specified, then return sorted data */
|
/* If the sortBy attribute is specified, then return sorted data */
|
||||||
sortedItems() {
|
sortedItems() {
|
||||||
let { items } = this;
|
let { items } = this;
|
||||||
if (this.config.appConfig.disableSmartSort) return items;
|
if (this.appConfig.disableSmartSort) return items;
|
||||||
if (this.sortOrder === 'alphabetical') {
|
if (this.sortOrder === 'alphabetical') {
|
||||||
this.sortAlphabetically(items);
|
this.sortAlphabetically(items);
|
||||||
} else if (this.sortOrder === 'reverse-alphabetical') {
|
} else if (this.sortOrder === 'reverse-alphabetical') {
|
||||||
|
@ -122,18 +122,14 @@ export default {
|
||||||
triggerModal(url) {
|
triggerModal(url) {
|
||||||
this.$refs[`iframeModal-${this.groupId}`].show(url);
|
this.$refs[`iframeModal-${this.groupId}`].show(url);
|
||||||
},
|
},
|
||||||
/* Emmit value upwards when iframe modal opened/ closed */
|
|
||||||
modalChanged(changedTo) {
|
|
||||||
this.$emit('change-modal-visibility', changedTo);
|
|
||||||
},
|
|
||||||
/* Determines if user has enabled online status checks */
|
/* Determines if user has enabled online status checks */
|
||||||
shouldEnableStatusCheck(itemPreference) {
|
shouldEnableStatusCheck(itemPreference) {
|
||||||
const globalPreference = this.config.appConfig.statusCheck || false;
|
const globalPreference = this.appConfig.statusCheck || false;
|
||||||
return itemPreference !== undefined ? itemPreference : globalPreference;
|
return itemPreference !== undefined ? itemPreference : globalPreference;
|
||||||
},
|
},
|
||||||
/* Determine how often to re-fire status checks */
|
/* Determine how often to re-fire status checks */
|
||||||
getStatusCheckInterval() {
|
getStatusCheckInterval() {
|
||||||
let interval = this.config.appConfig.statusCheckInterval;
|
let interval = this.appConfig.statusCheckInterval;
|
||||||
if (!interval) return 0;
|
if (!interval) return 0;
|
||||||
if (interval > 60) interval = 60;
|
if (interval > 60) interval = 60;
|
||||||
if (interval < 1) interval = 0;
|
if (interval < 1) interval = 0;
|
||||||
|
|
|
@ -12,7 +12,6 @@ import SearchBar from '@/components/Settings/SearchBar';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'MinimalSearch',
|
name: 'MinimalSearch',
|
||||||
inject: ['config'],
|
|
||||||
components: {
|
components: {
|
||||||
SearchBar,
|
SearchBar,
|
||||||
},
|
},
|
||||||
|
@ -24,16 +23,29 @@ export default {
|
||||||
input: '', // Users current search term
|
input: '', // Users current search term
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
computed: {
|
||||||
|
appConfig() {
|
||||||
|
return this.$store.getters.appConfig;
|
||||||
|
},
|
||||||
|
webSearchEnabled() {
|
||||||
|
if (this.appConfig && this.appConfig.webSearch) {
|
||||||
|
return !this.appConfig.webSearch.disableWebSearch;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
/* Emmits users's search term up to parent */
|
/* Emmits users's search term up to parent */
|
||||||
userIsTypingSomething(searchValue) {
|
userIsTypingSomething(searchValue) {
|
||||||
this.input = searchValue;
|
this.input = searchValue;
|
||||||
this.$emit('user-is-searchin', searchValue);
|
this.$emit('user-is-searchin', searchValue);
|
||||||
},
|
},
|
||||||
/* Emmits an event to reset state when user is finished searching */
|
},
|
||||||
clearMinFilterInput() {
|
mounted() {
|
||||||
this.$refs.MinimalSearchBar.clearFilterInput();
|
window.addEventListener('keydown', this.startFiltering);
|
||||||
},
|
},
|
||||||
|
beforeDestroy() {
|
||||||
|
window.removeEventListener('keydown', this.startFiltering);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -26,7 +26,6 @@
|
||||||
:ref="`iframeModal-${groupId}`"
|
:ref="`iframeModal-${groupId}`"
|
||||||
:name="`iframeModal-${groupId}`"
|
:name="`iframeModal-${groupId}`"
|
||||||
@closed="$emit('itemClicked')"
|
@closed="$emit('itemClicked')"
|
||||||
@modalChanged="modalChanged"
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -37,7 +36,6 @@ import IframeModal from '@/components/LinkItems/IframeModal.vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'ItemGroup',
|
name: 'ItemGroup',
|
||||||
inject: ['config'],
|
|
||||||
props: {
|
props: {
|
||||||
groupId: String,
|
groupId: String,
|
||||||
title: String,
|
title: String,
|
||||||
|
@ -50,6 +48,11 @@ export default {
|
||||||
selected: Boolean,
|
selected: Boolean,
|
||||||
showAll: Boolean,
|
showAll: Boolean,
|
||||||
},
|
},
|
||||||
|
computed: {
|
||||||
|
appConfig() {
|
||||||
|
return this.$store.getters.appConfig;
|
||||||
|
},
|
||||||
|
},
|
||||||
components: {
|
components: {
|
||||||
Item,
|
Item,
|
||||||
IframeModal,
|
IframeModal,
|
||||||
|
@ -66,15 +69,12 @@ export default {
|
||||||
triggerModal(url) {
|
triggerModal(url) {
|
||||||
this.$refs[`iframeModal-${this.groupId}`].show(url);
|
this.$refs[`iframeModal-${this.groupId}`].show(url);
|
||||||
},
|
},
|
||||||
modalChanged(changedTo) {
|
|
||||||
this.$emit('change-modal-visibility', changedTo);
|
|
||||||
},
|
|
||||||
shouldEnableStatusCheck(itemPreference) {
|
shouldEnableStatusCheck(itemPreference) {
|
||||||
const globalPreference = this.config.appConfig.statusCheck || false;
|
const globalPreference = this.appConfig.statusCheck || false;
|
||||||
return itemPreference !== undefined ? itemPreference : globalPreference;
|
return itemPreference !== undefined ? itemPreference : globalPreference;
|
||||||
},
|
},
|
||||||
getStatusCheckInterval() {
|
getStatusCheckInterval() {
|
||||||
let interval = this.config.appConfig.statusCheckInterval;
|
let interval = this.appConfig.statusCheckInterval;
|
||||||
if (!interval) return 0;
|
if (!interval) return 0;
|
||||||
if (interval > 60) interval = 60;
|
if (interval > 60) interval = 60;
|
||||||
if (interval < 1) interval = 0;
|
if (interval < 1) interval = 0;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<header v-if="visible">
|
<header v-if="componentVisible">
|
||||||
<PageTitle
|
<PageTitle
|
||||||
v-if="titleVisible"
|
v-if="titleVisible"
|
||||||
:title="pageInfo.title"
|
:title="pageInfo.title"
|
||||||
|
@ -13,12 +13,10 @@
|
||||||
<script>
|
<script>
|
||||||
import PageTitle from '@/components/PageStrcture/PageTitle.vue';
|
import PageTitle from '@/components/PageStrcture/PageTitle.vue';
|
||||||
import Nav from '@/components/PageStrcture/Nav.vue';
|
import Nav from '@/components/PageStrcture/Nav.vue';
|
||||||
import { visibleComponents as defaultVisibleComponents } from '@/utils/defaults';
|
|
||||||
import { shouldBeVisible } from '@/utils/MiscHelpers';
|
import { shouldBeVisible } from '@/utils/MiscHelpers';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Header',
|
name: 'Header',
|
||||||
inject: ['visibleComponents'],
|
|
||||||
components: {
|
components: {
|
||||||
PageTitle,
|
PageTitle,
|
||||||
Nav,
|
Nav,
|
||||||
|
@ -26,16 +24,19 @@ export default {
|
||||||
props: {
|
props: {
|
||||||
pageInfo: Object,
|
pageInfo: Object,
|
||||||
},
|
},
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
titleVisible: (this.visibleComponents || defaultVisibleComponents).pageTitle,
|
|
||||||
navVisible: (this.visibleComponents || defaultVisibleComponents).navigation,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
computed: {
|
computed: {
|
||||||
visible() {
|
componentVisible() {
|
||||||
return shouldBeVisible(this.$route.name);
|
return shouldBeVisible(this.$route.name);
|
||||||
},
|
},
|
||||||
|
visibleComponents() {
|
||||||
|
return this.$store.getters.visibleComponents;
|
||||||
|
},
|
||||||
|
titleVisible() {
|
||||||
|
return this.visibleComponents.pageTitle;
|
||||||
|
},
|
||||||
|
navVisible() {
|
||||||
|
return this.visibleComponents.navigation;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
|
|
||||||
<!-- Modal containing all the configuration options -->
|
<!-- Modal containing all the configuration options -->
|
||||||
<modal :name="modalNames.CONF_EDITOR" :resizable="true" width="60%" height="85%"
|
<modal :name="modalNames.CONF_EDITOR" :resizable="true" width="60%" height="85%"
|
||||||
@closed="$emit('modalChanged', false)" classes="dashy-modal">
|
@closed="editorClosed" classes="dashy-modal">
|
||||||
<ConfigContainer :config="combineConfig()" />
|
<ConfigContainer :config="combineConfig()" />
|
||||||
</modal>
|
</modal>
|
||||||
|
|
||||||
|
@ -48,6 +48,7 @@
|
||||||
import ConfigContainer from '@/components/Configuration/ConfigContainer';
|
import ConfigContainer from '@/components/Configuration/ConfigContainer';
|
||||||
import LanguageSwitcher from '@/components/Settings/LanguageSwitcher';
|
import LanguageSwitcher from '@/components/Settings/LanguageSwitcher';
|
||||||
import { topLevelConfKeys, localStorageKeys, modalNames } from '@/utils/defaults';
|
import { topLevelConfKeys, localStorageKeys, modalNames } from '@/utils/defaults';
|
||||||
|
import Keys from '@/utils/StoreMutations';
|
||||||
import IconSpanner from '@/assets/interface-icons/config-editor.svg';
|
import IconSpanner from '@/assets/interface-icons/config-editor.svg';
|
||||||
import IconViewMode from '@/assets/interface-icons/application-change-view.svg';
|
import IconViewMode from '@/assets/interface-icons/application-change-view.svg';
|
||||||
import IconHome from '@/assets/interface-icons/application-home.svg';
|
import IconHome from '@/assets/interface-icons/application-home.svg';
|
||||||
|
@ -71,15 +72,24 @@ export default {
|
||||||
IconWorkspaceView,
|
IconWorkspaceView,
|
||||||
IconMinimalView,
|
IconMinimalView,
|
||||||
},
|
},
|
||||||
props: {
|
computed: {
|
||||||
sections: Array,
|
sections() {
|
||||||
pageInfo: Object,
|
return this.$store.getters.sections;
|
||||||
appConfig: Object,
|
},
|
||||||
|
appConfig() {
|
||||||
|
return this.$store.getters.appConfig;
|
||||||
|
},
|
||||||
|
pageInfo() {
|
||||||
|
return this.$store.getters.pageInfo;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
showEditor: function show() {
|
showEditor: function show() {
|
||||||
this.$modal.show(modalNames.CONF_EDITOR);
|
this.$modal.show(modalNames.CONF_EDITOR);
|
||||||
this.$emit('modalChanged', true);
|
this.$store.commit(Keys.SET_MODAL_OPEN, true);
|
||||||
|
},
|
||||||
|
editorClosed: function show() {
|
||||||
|
this.$store.commit(Keys.SET_MODAL_OPEN, false);
|
||||||
},
|
},
|
||||||
combineConfig() {
|
combineConfig() {
|
||||||
const conf = {};
|
const conf = {};
|
||||||
|
|
|
@ -28,23 +28,40 @@
|
||||||
import Button from '@/components/FormElements/Button';
|
import Button from '@/components/FormElements/Button';
|
||||||
import SaveConfigIcon from '@/assets/interface-icons/save-config.svg';
|
import SaveConfigIcon from '@/assets/interface-icons/save-config.svg';
|
||||||
import ErrorHandler from '@/utils/ErrorHandler';
|
import ErrorHandler from '@/utils/ErrorHandler';
|
||||||
|
import Keys from '@/utils/StoreMutations';
|
||||||
import { languages } from '@/utils/languages';
|
import { languages } from '@/utils/languages';
|
||||||
import { localStorageKeys, modalNames } from '@/utils/defaults';
|
import { localStorageKeys, modalNames } from '@/utils/defaults';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'LanguageSwitcher',
|
name: 'LanguageSwitcher',
|
||||||
inject: ['config'],
|
|
||||||
components: {
|
components: {
|
||||||
Button,
|
Button,
|
||||||
SaveConfigIcon,
|
SaveConfigIcon,
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
language: this.getCurrentLanguage(), // The currently selected language
|
language: '', // The currently selected language
|
||||||
modalName: modalNames.LANG_SWITCHER, // Key for modal
|
modalName: modalNames.LANG_SWITCHER, // Key for modal
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
created() {
|
||||||
|
// Initiate the current language, with VueX state
|
||||||
|
this.language = this.savedLanguage;
|
||||||
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
/* Get appConfig from store */
|
||||||
|
appConfig() {
|
||||||
|
return this.$store.getters.appConfig;
|
||||||
|
},
|
||||||
|
/* The ISO code for the users language, synced with VueX store */
|
||||||
|
savedLanguage: {
|
||||||
|
get() {
|
||||||
|
return this.getIsoFromLangObj(this.$store.state.lang);
|
||||||
|
},
|
||||||
|
set(newLang) {
|
||||||
|
this.$store.commit(Keys.SET_LANGUAGE, newLang.code);
|
||||||
|
},
|
||||||
|
},
|
||||||
/* Return the array of language objects, plus a friends name */
|
/* Return the array of language objects, plus a friends name */
|
||||||
languageList: () => languages.map((lang) => {
|
languageList: () => languages.map((lang) => {
|
||||||
const newLang = lang;
|
const newLang = lang;
|
||||||
|
@ -73,6 +90,7 @@ export default {
|
||||||
if (this.checkLocale(selectedLanguage)) {
|
if (this.checkLocale(selectedLanguage)) {
|
||||||
localStorage.setItem(localStorageKeys.LANGUAGE, selectedLanguage.code);
|
localStorage.setItem(localStorageKeys.LANGUAGE, selectedLanguage.code);
|
||||||
this.applyLanguageLocally();
|
this.applyLanguageLocally();
|
||||||
|
this.savedLanguage = selectedLanguage;
|
||||||
const successMsg = `${selectedLanguage.flag} `
|
const successMsg = `${selectedLanguage.flag} `
|
||||||
+ `${this.$t('language-switcher.success-msg')} ${selectedLanguage.name}`;
|
+ `${this.$t('language-switcher.success-msg')} ${selectedLanguage.name}`;
|
||||||
this.$toasted.show(successMsg, { className: 'toast-success' });
|
this.$toasted.show(successMsg, { className: 'toast-success' });
|
||||||
|
@ -82,11 +100,10 @@ export default {
|
||||||
ErrorHandler('Unable to apply language');
|
ErrorHandler('Unable to apply language');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
/* Gets the users current language from local storage */
|
/* Gets the ISO code for a given language object */
|
||||||
getCurrentLanguage() {
|
getIsoFromLangObj(langObj) {
|
||||||
const getLanguageFromIso = (iso) => languages.find((lang) => lang.code === iso);
|
const getLanguageFromIso = (iso) => languages.find((lang) => lang.code === iso);
|
||||||
const current = localStorage[localStorageKeys.LANGUAGE] || this.config.appConfig.language;
|
return getLanguageFromIso(langObj);
|
||||||
return getLanguageFromIso(current);
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -35,9 +35,7 @@ import {
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'FilterTile',
|
name: 'FilterTile',
|
||||||
inject: ['config'],
|
|
||||||
props: {
|
props: {
|
||||||
active: Boolean,
|
|
||||||
minimalSearch: Boolean, // If true, then keep it simple
|
minimalSearch: Boolean, // If true, then keep it simple
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
|
@ -48,8 +46,11 @@ export default {
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
active() {
|
||||||
|
return !this.$store.state.modalOpen;
|
||||||
|
},
|
||||||
searchPrefs() {
|
searchPrefs() {
|
||||||
return this.config.appConfig.webSearch || {};
|
return this.$store.getters.webSearch || {};
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
|
|
|
@ -3,16 +3,14 @@
|
||||||
<SearchBar ref="SearchBar"
|
<SearchBar ref="SearchBar"
|
||||||
@user-is-searchin="userIsTypingSomething"
|
@user-is-searchin="userIsTypingSomething"
|
||||||
v-if="searchVisible"
|
v-if="searchVisible"
|
||||||
:active="!modalOpen"
|
|
||||||
/>
|
/>
|
||||||
<div class="options-outer">
|
<div class="options-outer">
|
||||||
<div :class="`options-container ${!settingsVisible ? 'hide' : ''}`">
|
<div :class="`options-container ${!settingsVisible ? 'hide' : ''}`">
|
||||||
<ThemeSelector :externalThemes="externalThemes" @modalChanged="modalChanged"
|
<ThemeSelector :externalThemes="externalThemes"
|
||||||
:confTheme="getInitialTheme()" :userThemes="getUserThemes()" />
|
:confTheme="getInitialTheme()" :userThemes="getUserThemes()" />
|
||||||
<LayoutSelector :displayLayout="displayLayout" @layoutUpdated="updateDisplayLayout"/>
|
<LayoutSelector :displayLayout="displayLayout" @layoutUpdated="updateDisplayLayout"/>
|
||||||
<ItemSizeSelector :iconSize="iconSize" @iconSizeUpdated="updateIconSize" />
|
<ItemSizeSelector :iconSize="iconSize" @iconSizeUpdated="updateIconSize" />
|
||||||
<ConfigLauncher :sections="sections" :pageInfo="pageInfo" :appConfig="appConfig"
|
<ConfigLauncher />
|
||||||
@modalChanged="modalChanged" />
|
|
||||||
<AuthButtons v-if="userState != 'noone'" :userType="userState" />
|
<AuthButtons v-if="userState != 'noone'" :userType="userState" />
|
||||||
</div>
|
</div>
|
||||||
<div :class="`show-hide-container ${settingsVisible? 'hide-btn' : 'show-btn'}`">
|
<div :class="`show-hide-container ${settingsVisible? 'hide-btn' : 'show-btn'}`">
|
||||||
|
@ -52,10 +50,6 @@ export default {
|
||||||
displayLayout: String,
|
displayLayout: String,
|
||||||
iconSize: String,
|
iconSize: String,
|
||||||
externalThemes: Object,
|
externalThemes: Object,
|
||||||
appConfig: Object,
|
|
||||||
pageInfo: Object,
|
|
||||||
sections: Array,
|
|
||||||
modalOpen: Boolean,
|
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
SearchBar,
|
SearchBar,
|
||||||
|
@ -69,7 +63,43 @@ export default {
|
||||||
IconOpen,
|
IconOpen,
|
||||||
IconClose,
|
IconClose,
|
||||||
},
|
},
|
||||||
inject: ['visibleComponents'],
|
data() {
|
||||||
|
return {
|
||||||
|
settingsVisible: true,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
sections() {
|
||||||
|
return this.$store.getters.sections;
|
||||||
|
},
|
||||||
|
appConfig() {
|
||||||
|
return this.$store.getters.appConfig;
|
||||||
|
},
|
||||||
|
pageInfo() {
|
||||||
|
return this.$store.getters.pageInfo;
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Determines which button should display, based on the user type
|
||||||
|
* 0 = Auth not configured, don't show anything
|
||||||
|
* 1 = Auth condifured, and user logged in, show logout button
|
||||||
|
* 2 = Auth configured, guest access enabled, and not logged in, show login
|
||||||
|
* Note that if auth is enabled, but not guest access, and user not logged in,
|
||||||
|
* then they will never be able to view the homepage, so no button needed
|
||||||
|
*/
|
||||||
|
userState() {
|
||||||
|
return getUserState();
|
||||||
|
},
|
||||||
|
/* Object indicating which components should be hidden, based on user preferences */
|
||||||
|
visibleComponents() {
|
||||||
|
return this.$store.getters.visibleComponents;
|
||||||
|
},
|
||||||
|
searchVisible() {
|
||||||
|
return this.$store.getters.visibleComponents.searchBar;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.settingsVisible = this.getSettingsVisibility();
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
userIsTypingSomething(something) {
|
userIsTypingSomething(something) {
|
||||||
this.$emit('user-is-searchin', something);
|
this.$emit('user-is-searchin', something);
|
||||||
|
@ -83,9 +113,6 @@ export default {
|
||||||
updateIconSize(iconSize) {
|
updateIconSize(iconSize) {
|
||||||
this.$emit('change-icon-size', iconSize);
|
this.$emit('change-icon-size', iconSize);
|
||||||
},
|
},
|
||||||
modalChanged(changedTo) {
|
|
||||||
this.$emit('change-modal-visibility', changedTo);
|
|
||||||
},
|
|
||||||
getInitialTheme() {
|
getInitialTheme() {
|
||||||
return this.appConfig.theme || '';
|
return this.appConfig.theme || '';
|
||||||
},
|
},
|
||||||
|
@ -104,25 +131,6 @@ export default {
|
||||||
|| (this.visibleComponents || defaultVisibleComponents).settings);
|
|| (this.visibleComponents || defaultVisibleComponents).settings);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
computed: {
|
|
||||||
/**
|
|
||||||
* Determines which button should display, based on the user type
|
|
||||||
* 0 = Auth not configured, don't show anything
|
|
||||||
* 1 = Auth condifured, and user logged in, show logout button
|
|
||||||
* 2 = Auth configured, guest access enabled, and not logged in, show login
|
|
||||||
* Note that if auth is enabled, but not guest access, and user not logged in,
|
|
||||||
* then they will never be able to view the homepage, so no button needed
|
|
||||||
*/
|
|
||||||
userState() {
|
|
||||||
return getUserState();
|
|
||||||
},
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
settingsVisible: this.getSettingsVisibility(),
|
|
||||||
searchVisible: (this.visibleComponents || defaultVisibleComponents).searchBar,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,7 @@ import {
|
||||||
ApplyCustomVariables,
|
ApplyCustomVariables,
|
||||||
} from '@/utils/ThemeHelper';
|
} from '@/utils/ThemeHelper';
|
||||||
import Defaults, { localStorageKeys } from '@/utils/defaults';
|
import Defaults, { localStorageKeys } from '@/utils/defaults';
|
||||||
|
import Keys from '@/utils/StoreMutations';
|
||||||
import IconPalette from '@/assets/interface-icons/config-color-palette.svg';
|
import IconPalette from '@/assets/interface-icons/config-color-palette.svg';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
@ -94,13 +95,15 @@ export default {
|
||||||
},
|
},
|
||||||
/* Opens the theme color configurator popup */
|
/* Opens the theme color configurator popup */
|
||||||
openThemeConfigurator() {
|
openThemeConfigurator() {
|
||||||
this.$emit('modalChanged', true);
|
this.$store.commit(Keys.SET_MODAL_OPEN, true);
|
||||||
this.themeConfiguratorOpen = true;
|
this.themeConfiguratorOpen = true;
|
||||||
},
|
},
|
||||||
/* Closes the theme color configurator popup */
|
/* Closes the theme color configurator popup */
|
||||||
closeThemeConfigurator() {
|
closeThemeConfigurator() {
|
||||||
// this.$emit('modalChanged', false);
|
if (this.themeConfiguratorOpen) {
|
||||||
this.themeConfiguratorOpen = false;
|
this.$store.commit(Keys.SET_MODAL_OPEN, false);
|
||||||
|
this.themeConfiguratorOpen = false;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
/* Updates theme. Checks if the new theme is local or external,
|
/* Updates theme. Checks if the new theme is local or external,
|
||||||
and calls appropirate updating function. Updates local storage */
|
and calls appropirate updating function. Updates local storage */
|
||||||
|
|
|
@ -36,7 +36,6 @@ import IconMinimalView from '@/assets/interface-icons/application-minimal.svg';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'SideBar',
|
name: 'SideBar',
|
||||||
inject: ['config'],
|
|
||||||
props: {
|
props: {
|
||||||
sections: Array,
|
sections: Array,
|
||||||
initUrl: String,
|
initUrl: String,
|
||||||
|
|
|
@ -12,7 +12,6 @@ import Icon from '@/components/LinkItems/ItemIcon.vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'SideBarItem',
|
name: 'SideBarItem',
|
||||||
inject: ['config'],
|
|
||||||
props: {
|
props: {
|
||||||
icon: String,
|
icon: String,
|
||||||
title: String,
|
title: String,
|
||||||
|
|
|
@ -19,7 +19,6 @@ import SideBarItem from '@/components/Workspace/SideBarItem.vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'SideBarSection',
|
name: 'SideBarSection',
|
||||||
inject: ['config'],
|
|
||||||
props: {
|
props: {
|
||||||
items: Array,
|
items: Array,
|
||||||
},
|
},
|
||||||
|
|
10
src/main.js
10
src/main.js
|
@ -14,6 +14,7 @@ import Toasted from 'vue-toasted'; // Toast component, used to show confirm
|
||||||
// Import base Dashy components and utils
|
// Import base Dashy components and utils
|
||||||
import Dashy from '@/App.vue'; // Main Dashy Vue app
|
import Dashy from '@/App.vue'; // Main Dashy Vue app
|
||||||
import router from '@/router'; // Router, for navigation
|
import router from '@/router'; // Router, for navigation
|
||||||
|
import store from '@/store'; // Store, for local state management
|
||||||
import serviceWorker from '@/utils/InitServiceWorker'; // Service worker initialization
|
import serviceWorker from '@/utils/InitServiceWorker'; // Service worker initialization
|
||||||
import clickOutside from '@/utils/ClickOutside'; // Directive for closing popups, modals, etc
|
import clickOutside from '@/utils/ClickOutside'; // Directive for closing popups, modals, etc
|
||||||
import { messages } from '@/utils/languages'; // Language texts
|
import { messages } from '@/utils/languages'; // Language texts
|
||||||
|
@ -48,9 +49,14 @@ ErrorReporting(Vue, router);
|
||||||
// Render function
|
// Render function
|
||||||
const render = (awesome) => awesome(Dashy);
|
const render = (awesome) => awesome(Dashy);
|
||||||
|
|
||||||
|
// Mount the app, with router, store i18n and render func
|
||||||
|
const mount = () => new Vue({
|
||||||
|
store, router, render, i18n,
|
||||||
|
}).$mount('#app');
|
||||||
|
|
||||||
// If Keycloak not enabled, then proceed straight to the app
|
// If Keycloak not enabled, then proceed straight to the app
|
||||||
if (!isKeycloakEnabled()) {
|
if (!isKeycloakEnabled()) {
|
||||||
new Vue({ router, render, i18n }).$mount('#app');
|
mount();
|
||||||
} else { // Keycloak is enabled, redirect to KC login page
|
} else { // Keycloak is enabled, redirect to KC login page
|
||||||
const { serverUrl, realm, clientId } = getKeycloakConfig();
|
const { serverUrl, realm, clientId } = getKeycloakConfig();
|
||||||
const initOptions = {
|
const initOptions = {
|
||||||
|
@ -63,7 +69,7 @@ if (!isKeycloakEnabled()) {
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
} else {
|
} else {
|
||||||
// Yay - user successfully authenticated with Keycloak, render the app!
|
// Yay - user successfully authenticated with Keycloak, render the app!
|
||||||
new Vue({ router, render, i18n }).$mount('#app');
|
mount();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,10 +14,10 @@ import Home from '@/views/Home.vue';
|
||||||
import Login from '@/views/Login.vue';
|
import Login from '@/views/Login.vue';
|
||||||
import Workspace from '@/views/Workspace.vue';
|
import Workspace from '@/views/Workspace.vue';
|
||||||
import Minimal from '@/views/Minimal.vue';
|
import Minimal from '@/views/Minimal.vue';
|
||||||
|
import ConfigAccumulator from '@/utils/ConfigAccumalator';
|
||||||
|
|
||||||
// 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 { config } 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';
|
||||||
|
|
||||||
|
@ -32,8 +32,18 @@ const isAuthenticated = () => {
|
||||||
return (!authEnabled || userLoggedIn || guestEnabled);
|
return (!authEnabled || userLoggedIn || guestEnabled);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getConfig = () => {
|
||||||
|
const Accumulator = new ConfigAccumulator();
|
||||||
|
return {
|
||||||
|
appConfig: Accumulator.appConfig(),
|
||||||
|
pageInfo: Accumulator.pageInfo(),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const { appConfig, pageInfo } = getConfig();
|
||||||
|
|
||||||
/* Get the users chosen starting view from app config, or return default */
|
/* Get the users chosen starting view from app config, or return default */
|
||||||
const getStartingView = () => config.appConfig.startingView || startingView;
|
const getStartingView = () => appConfig.startingView || startingView;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the component that should be rendered at the base path,
|
* Returns the component that should be rendered at the base path,
|
||||||
|
@ -51,7 +61,7 @@ const getStartingComponent = () => {
|
||||||
|
|
||||||
/* Returns the meta tags for each route */
|
/* Returns the meta tags for each route */
|
||||||
const makeMetaTags = (defaultTitle) => ({
|
const makeMetaTags = (defaultTitle) => ({
|
||||||
title: config.pageInfo.title || defaultTitle,
|
title: pageInfo.title || defaultTitle,
|
||||||
metaTags: metaTagData,
|
metaTags: metaTagData,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -62,37 +72,30 @@ const router = new Router({
|
||||||
path: '/',
|
path: '/',
|
||||||
name: `landing-page-${getStartingView()}`,
|
name: `landing-page-${getStartingView()}`,
|
||||||
component: getStartingComponent(),
|
component: getStartingComponent(),
|
||||||
props: config,
|
|
||||||
meta: makeMetaTags('Home Page'),
|
meta: makeMetaTags('Home Page'),
|
||||||
},
|
},
|
||||||
{ // Default home page
|
{ // Default home page
|
||||||
path: routePaths.home,
|
path: routePaths.home,
|
||||||
name: 'home',
|
name: 'home',
|
||||||
component: Home,
|
component: Home,
|
||||||
props: config,
|
|
||||||
meta: makeMetaTags('Home Page'),
|
meta: makeMetaTags('Home Page'),
|
||||||
},
|
},
|
||||||
{ // Workspace view page
|
{ // Workspace view page
|
||||||
path: routePaths.workspace,
|
path: routePaths.workspace,
|
||||||
name: 'workspace',
|
name: 'workspace',
|
||||||
component: Workspace,
|
component: Workspace,
|
||||||
props: config,
|
|
||||||
meta: makeMetaTags('Workspace'),
|
meta: makeMetaTags('Workspace'),
|
||||||
},
|
},
|
||||||
{ // Minimal view page
|
{ // Minimal view page
|
||||||
path: routePaths.minimal,
|
path: routePaths.minimal,
|
||||||
name: 'minimal',
|
name: 'minimal',
|
||||||
component: Minimal,
|
component: Minimal,
|
||||||
props: config,
|
|
||||||
meta: makeMetaTags('Start Page'),
|
meta: makeMetaTags('Start Page'),
|
||||||
},
|
},
|
||||||
{ // The login page
|
{ // The login page
|
||||||
path: routePaths.login,
|
path: routePaths.login,
|
||||||
name: 'login',
|
name: 'login',
|
||||||
component: Login,
|
component: Login,
|
||||||
props: {
|
|
||||||
appConfig: config.appConfig,
|
|
||||||
},
|
|
||||||
beforeEnter: (to, from, next) => {
|
beforeEnter: (to, from, next) => {
|
||||||
// If the user already logged in + guest mode not enabled, then redirect home
|
// If the user already logged in + guest mode not enabled, then redirect home
|
||||||
if (isAuthenticated() && !isGuestAccessEnabled()) router.push({ path: '/' });
|
if (isAuthenticated() && !isGuestAccessEnabled()) router.push({ path: '/' });
|
||||||
|
@ -109,7 +112,6 @@ const router = new Router({
|
||||||
path: routePaths.download,
|
path: routePaths.download,
|
||||||
name: 'download',
|
name: 'download',
|
||||||
component: () => import('./views/DownloadConfig.vue'),
|
component: () => import('./views/DownloadConfig.vue'),
|
||||||
props: config,
|
|
||||||
meta: makeMetaTags('Download Config'),
|
meta: makeMetaTags('Download Config'),
|
||||||
},
|
},
|
||||||
{ // Page not found, any non-defined routes will land here
|
{ // Page not found, any non-defined routes will land here
|
||||||
|
|
|
@ -0,0 +1,61 @@
|
||||||
|
/* eslint-disable no-param-reassign */
|
||||||
|
import Vue from 'vue';
|
||||||
|
import Vuex from 'vuex';
|
||||||
|
import Keys from '@/utils/StoreMutations';
|
||||||
|
import ConfigAccumulator from '@/utils/ConfigAccumalator';
|
||||||
|
import { componentVisibility } from '@/utils/ConfigHelpers';
|
||||||
|
import filterUserSections from '@/utils/CheckSectionVisibility';
|
||||||
|
|
||||||
|
Vue.use(Vuex);
|
||||||
|
|
||||||
|
const { UPDATE_CONFIG, SET_MODAL_OPEN, SET_LANGUAGE } = Keys;
|
||||||
|
|
||||||
|
const store = new Vuex.Store({
|
||||||
|
state: {
|
||||||
|
config: {},
|
||||||
|
lang: '', // The users language, auto-detected or read from local storage / config
|
||||||
|
modalOpen: false, // KB shortcut functionality will be disabled when modal is open
|
||||||
|
},
|
||||||
|
getters: {
|
||||||
|
config(state) {
|
||||||
|
return state.config;
|
||||||
|
},
|
||||||
|
pageInfo(state) {
|
||||||
|
return state.config.pageInfo || {};
|
||||||
|
},
|
||||||
|
appConfig(state) {
|
||||||
|
return state.config.appConfig || {};
|
||||||
|
},
|
||||||
|
sections(state) {
|
||||||
|
return filterUserSections(state.config.sections || []);
|
||||||
|
},
|
||||||
|
webSearch(state, getters) {
|
||||||
|
return getters.appConfig.webSearch || {};
|
||||||
|
},
|
||||||
|
visibleComponents(state, getters) {
|
||||||
|
return componentVisibility(getters.appConfig);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mutations: {
|
||||||
|
[UPDATE_CONFIG](state, config) {
|
||||||
|
state.config = config;
|
||||||
|
},
|
||||||
|
[SET_LANGUAGE](state, lang) {
|
||||||
|
state.lang = lang;
|
||||||
|
},
|
||||||
|
[SET_MODAL_OPEN](state, modalOpen) {
|
||||||
|
state.modalOpen = modalOpen;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
/* Called when app first loaded. Reads config and sets state */
|
||||||
|
initializeConfig({ commit }) {
|
||||||
|
const Accumulator = new ConfigAccumulator();
|
||||||
|
const config = Accumulator.config();
|
||||||
|
commit(UPDATE_CONFIG, config);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
modules: {},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default store;
|
|
@ -16,9 +16,7 @@ const getAppConfig = () => {
|
||||||
* Support for old user structure will be removed in V 1.7.0
|
* Support for old user structure will be removed in V 1.7.0
|
||||||
*/
|
*/
|
||||||
const printWarning = () => {
|
const printWarning = () => {
|
||||||
const msg = 'From V 1.6.5 onwards, the structure of the users object has changed.';
|
ErrorHandler('From V 1.6.5 onwards, the structure of the users object has changed.');
|
||||||
// eslint-disable-next-line no-console
|
|
||||||
console.warn(msg);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Returns true if keycloak is enabled */
|
/* Returns true if keycloak is enabled */
|
||||||
|
|
|
@ -11,9 +11,8 @@ import {
|
||||||
pageInfo as defaultPageInfo,
|
pageInfo as defaultPageInfo,
|
||||||
iconSize as defaultIconSize,
|
iconSize as defaultIconSize,
|
||||||
layout as defaultLayout,
|
layout as defaultLayout,
|
||||||
// language as defaultLanguage,
|
|
||||||
} from '@/utils/defaults';
|
} from '@/utils/defaults';
|
||||||
|
import ErrorHandler from '@/utils/ErrorHandler';
|
||||||
import conf from '../../public/conf.yml';
|
import conf from '../../public/conf.yml';
|
||||||
|
|
||||||
export default class ConfigAccumulator {
|
export default class ConfigAccumulator {
|
||||||
|
@ -46,24 +45,14 @@ export default class ConfigAccumulator {
|
||||||
|
|
||||||
/* Page Info */
|
/* Page Info */
|
||||||
pageInfo() {
|
pageInfo() {
|
||||||
const defaults = defaultPageInfo;
|
let localPageInfo = {};
|
||||||
let localPageInfo;
|
if (localStorage[localStorageKeys.PAGE_INFO]) {
|
||||||
try {
|
// eslint-disable-next-line brace-style
|
||||||
localPageInfo = JSON.parse(localStorage[localStorageKeys.PAGE_INFO]);
|
try { localPageInfo = JSON.parse(localStorage[localStorageKeys.PAGE_INFO]); }
|
||||||
} catch (e) {
|
catch (e) { ErrorHandler('Malformed pageInfo data in local storage'); }
|
||||||
localPageInfo = {};
|
|
||||||
}
|
}
|
||||||
let filePageInfo = {};
|
const filePageInfo = this.conf ? this.conf.pageInfo || {} : {};
|
||||||
if (this.conf) {
|
return { ...defaultPageInfo, ...filePageInfo, ...localPageInfo };
|
||||||
filePageInfo = this.conf.pageInfo || {};
|
|
||||||
}
|
|
||||||
const pi = filePageInfo || defaults; // The page info object to return
|
|
||||||
pi.title = localPageInfo.title || filePageInfo.title || defaults.title;
|
|
||||||
pi.logo = localPageInfo.logo || filePageInfo.logo || defaults.logo;
|
|
||||||
pi.description = localPageInfo.description || filePageInfo.description || defaults.description;
|
|
||||||
pi.navLinks = localPageInfo.navLinks || filePageInfo.navLinks || defaults.navLinks;
|
|
||||||
pi.footerText = localPageInfo.footerText || filePageInfo.footerText || defaults.footerText;
|
|
||||||
return pi;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Sections */
|
/* Sections */
|
||||||
|
@ -75,13 +64,11 @@ export default class ConfigAccumulator {
|
||||||
const json = JSON.parse(localSections);
|
const json = JSON.parse(localSections);
|
||||||
if (json.length >= 1) return json;
|
if (json.length >= 1) return json;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// The data in local storage has been malformed, will return conf.sections instead
|
ErrorHandler('Malformed section data in local storage');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// If the function hasn't yet returned, then return the config file sections
|
// If the function hasn't yet returned, then return the config file sections
|
||||||
let sectionsFile = [];
|
return this.conf ? this.conf.sections || [] : [];
|
||||||
if (this.conf) sectionsFile = this.conf.sections || [];
|
|
||||||
return sectionsFile;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Complete config */
|
/* Complete config */
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
// A list of mutation names
|
||||||
|
const KEY_NAMES = [
|
||||||
|
'UPDATE_CONFIG',
|
||||||
|
'SET_MODAL_OPEN',
|
||||||
|
'SET_LANGUAGE',
|
||||||
|
];
|
||||||
|
|
||||||
|
// Convert array of key names into an object, and export
|
||||||
|
const MUTATIONS = {};
|
||||||
|
KEY_NAMES.forEach((key) => { MUTATIONS[key] = key; });
|
||||||
|
export default MUTATIONS;
|
|
@ -7,18 +7,13 @@ import JsonToYaml from '@/utils/JsonToYaml';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'DownloadConfig',
|
name: 'DownloadConfig',
|
||||||
props: {
|
computed: {
|
||||||
sections: Array,
|
config() {
|
||||||
appConfig: Object,
|
return this.$store.state.config;
|
||||||
pageInfo: Object,
|
},
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
config: {
|
|
||||||
appConfig: this.appConfig,
|
|
||||||
pageInfo: this.pageInfo,
|
|
||||||
sections: this.sections,
|
|
||||||
},
|
|
||||||
jsonParser: JsonToYaml,
|
jsonParser: JsonToYaml,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
|
@ -10,9 +10,6 @@
|
||||||
:displayLayout="layout"
|
:displayLayout="layout"
|
||||||
:iconSize="itemSizeBound"
|
:iconSize="itemSizeBound"
|
||||||
:externalThemes="getExternalCSSLinks()"
|
:externalThemes="getExternalCSSLinks()"
|
||||||
:sections="allSections"
|
|
||||||
:appConfig="appConfig"
|
|
||||||
:pageInfo="pageInfo"
|
|
||||||
:modalOpen="modalOpen"
|
:modalOpen="modalOpen"
|
||||||
class="settings-outer"
|
class="settings-outer"
|
||||||
/>
|
/>
|
||||||
|
@ -55,11 +52,6 @@ import Defaults, { localStorageKeys, iconCdns } from '@/utils/defaults';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'home',
|
name: 'home',
|
||||||
props: {
|
|
||||||
sections: Array, // Main site content
|
|
||||||
appConfig: Object, // Main site configuation (optional)
|
|
||||||
pageInfo: Object, // Page metadata (optional)
|
|
||||||
},
|
|
||||||
components: {
|
components: {
|
||||||
SettingsContainer,
|
SettingsContainer,
|
||||||
Section,
|
Section,
|
||||||
|
@ -68,9 +60,20 @@ export default {
|
||||||
searchValue: '',
|
searchValue: '',
|
||||||
layout: '',
|
layout: '',
|
||||||
itemSizeBound: '',
|
itemSizeBound: '',
|
||||||
modalOpen: false, // When true, keybindings are disabled
|
|
||||||
}),
|
}),
|
||||||
computed: {
|
computed: {
|
||||||
|
sections() {
|
||||||
|
return this.$store.getters.sections;
|
||||||
|
},
|
||||||
|
appConfig() {
|
||||||
|
return this.$store.getters.appConfig;
|
||||||
|
},
|
||||||
|
pageInfo() {
|
||||||
|
return this.$store.getters.pageInfo;
|
||||||
|
},
|
||||||
|
modalOpen() {
|
||||||
|
return this.$store.state.modalOpen;
|
||||||
|
},
|
||||||
/* Get class for num columns, if specified by user */
|
/* Get class for num columns, if specified by user */
|
||||||
colCount() {
|
colCount() {
|
||||||
let { colCount } = this.appConfig;
|
let { colCount } = this.appConfig;
|
||||||
|
@ -143,7 +146,7 @@ export default {
|
||||||
},
|
},
|
||||||
/* Update data when modal is open (so that key bindings can be disabled) */
|
/* Update data when modal is open (so that key bindings can be disabled) */
|
||||||
updateModalVisibility(modalState) {
|
updateModalVisibility(modalState) {
|
||||||
this.modalOpen = modalState;
|
this.$store.commit('SET_MODAL_OPEN', modalState);
|
||||||
},
|
},
|
||||||
/* Returns an array of links to external CSS from the Config */
|
/* Returns an array of links to external CSS from the Config */
|
||||||
getExternalCSSLinks() {
|
getExternalCSSLinks() {
|
||||||
|
|
|
@ -91,9 +91,6 @@ export default {
|
||||||
Button,
|
Button,
|
||||||
Input,
|
Input,
|
||||||
},
|
},
|
||||||
props: {
|
|
||||||
appConfig: Object,
|
|
||||||
},
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
username: '',
|
username: '',
|
||||||
|
@ -104,6 +101,9 @@ export default {
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
appConfig() {
|
||||||
|
return this.$store.getters.appConfig;
|
||||||
|
},
|
||||||
/* Data for timeout dropdown menu, translated label + value in ms */
|
/* Data for timeout dropdown menu, translated label + value in ms */
|
||||||
dropDownMenu() {
|
dropDownMenu() {
|
||||||
return [
|
return [
|
||||||
|
|
|
@ -2,8 +2,7 @@
|
||||||
<div class="minimal-home" :style="getBackgroundImage() + setColumnCount()">
|
<div class="minimal-home" :style="getBackgroundImage() + setColumnCount()">
|
||||||
<!-- Buttons for config and home page -->
|
<!-- Buttons for config and home page -->
|
||||||
<div class="minimal-buttons">
|
<div class="minimal-buttons">
|
||||||
<ConfigLauncher :sections="sections" :pageInfo="pageInfo" :appConfig="appConfig"
|
<ConfigLauncher @modalChanged="modalChanged" class="config-launcher" />
|
||||||
@modalChanged="modalChanged" class="config-launcher" />
|
|
||||||
</div>
|
</div>
|
||||||
<!-- Page title and search bar -->
|
<!-- Page title and search bar -->
|
||||||
<div class="title-and-search">
|
<div class="title-and-search">
|
||||||
|
@ -62,11 +61,6 @@ import ConfigLauncher from '@/components/Settings/ConfigLauncher';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'home',
|
name: 'home',
|
||||||
props: {
|
|
||||||
sections: Array, // Main site content
|
|
||||||
appConfig: Object, // Main site configuation (optional)
|
|
||||||
pageInfo: Object,
|
|
||||||
},
|
|
||||||
components: {
|
components: {
|
||||||
MinimalSection,
|
MinimalSection,
|
||||||
MinimalHeading,
|
MinimalHeading,
|
||||||
|
@ -81,6 +75,17 @@ export default {
|
||||||
tabbedView: true, // By default use tabs, when searching then show all instead
|
tabbedView: true, // By default use tabs, when searching then show all instead
|
||||||
theme: GetTheme(),
|
theme: GetTheme(),
|
||||||
}),
|
}),
|
||||||
|
computed: {
|
||||||
|
sections() {
|
||||||
|
return this.$store.getters.sections;
|
||||||
|
},
|
||||||
|
appConfig() {
|
||||||
|
return this.$store.getters.appConfig;
|
||||||
|
},
|
||||||
|
pageInfo() {
|
||||||
|
return this.$store.getters.pageInfo;
|
||||||
|
},
|
||||||
|
},
|
||||||
watch: {
|
watch: {
|
||||||
/* When the theme changes, then call the update method */
|
/* When the theme changes, then call the update method */
|
||||||
searchValue() {
|
searchValue() {
|
||||||
|
|
|
@ -16,10 +16,6 @@ import { GetTheme, ApplyLocalTheme, ApplyCustomVariables } from '@/utils/ThemeHe
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Workspace',
|
name: 'Workspace',
|
||||||
props: {
|
|
||||||
sections: Array,
|
|
||||||
appConfig: Object,
|
|
||||||
},
|
|
||||||
data: () => ({
|
data: () => ({
|
||||||
url: '',
|
url: '',
|
||||||
GetTheme,
|
GetTheme,
|
||||||
|
@ -27,6 +23,12 @@ export default {
|
||||||
ApplyCustomVariables,
|
ApplyCustomVariables,
|
||||||
}),
|
}),
|
||||||
computed: {
|
computed: {
|
||||||
|
sections() {
|
||||||
|
return this.$store.getters.sections;
|
||||||
|
},
|
||||||
|
appConfig() {
|
||||||
|
return this.$store.getters.appConfig;
|
||||||
|
},
|
||||||
isMultiTaskingEnabled() {
|
isMultiTaskingEnabled() {
|
||||||
return this.appConfig.enableMultiTasking || false;
|
return this.appConfig.enableMultiTasking || false;
|
||||||
},
|
},
|
||||||
|
|
|
@ -9866,6 +9866,11 @@ vue@^2.6.10:
|
||||||
resolved "https://registry.yarnpkg.com/vue/-/vue-2.6.14.tgz#e51aa5250250d569a3fbad3a8a5a687d6036e235"
|
resolved "https://registry.yarnpkg.com/vue/-/vue-2.6.14.tgz#e51aa5250250d569a3fbad3a8a5a687d6036e235"
|
||||||
integrity sha512-x2284lgYvjOMj3Za7kqzRcUSxBboHqtgRE2zlos1qWaOye5yUmHn42LB1250NJBLRwEcdrB0JRwyPTEPhfQjiQ==
|
integrity sha512-x2284lgYvjOMj3Za7kqzRcUSxBboHqtgRE2zlos1qWaOye5yUmHn42LB1250NJBLRwEcdrB0JRwyPTEPhfQjiQ==
|
||||||
|
|
||||||
|
vuex@^3.6.2:
|
||||||
|
version "3.6.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/vuex/-/vuex-3.6.2.tgz#236bc086a870c3ae79946f107f16de59d5895e71"
|
||||||
|
integrity sha512-ETW44IqCgBpVomy520DT5jf8n0zoCac+sxWnn+hMe/CzaSejb/eVw2YToiXYX+Ex/AuHHia28vWTq4goAexFbw==
|
||||||
|
|
||||||
watchpack-chokidar2@^2.0.1:
|
watchpack-chokidar2@^2.0.1:
|
||||||
version "2.0.1"
|
version "2.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/watchpack-chokidar2/-/watchpack-chokidar2-2.0.1.tgz#38500072ee6ece66f3769936950ea1771be1c957"
|
resolved "https://registry.yarnpkg.com/watchpack-chokidar2/-/watchpack-chokidar2-2.0.1.tgz#38500072ee6ece66f3769936950ea1771be1c957"
|
||||||
|
|
Loading…
Reference in New Issue