🔁 Merge pull request #528 from Ateroz/master

Fetch conf.yml from server
This commit is contained in:
Alicia Sykes 2022-03-06 23:32:45 +00:00 committed by GitHub
commit 93911c2520
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 38 additions and 22 deletions

View File

@ -1,5 +1,8 @@
# Changelog
## :sparkles: 2.0.4 - Dynamic Config Loading [PR #528](https://github.com/Lissy93/dashy/pull/528)
- `conf.yml` is now loaded dynamically and the app now only needs a browser refresh on config change, not a full rebuild!
## 🐛 2.0.3 - Bug Fixes [PR #488](https://github.com/Lissy93/dashy/pull/488)
- Press enter to submit login form (Re: #483)
- Allow disabling write to local storage and disk (Re: #485)

View File

@ -39,11 +39,15 @@ WORKDIR ${DIRECTORY}
RUN apk add --no-cache tzdata tini
# Copy built application from build phase
COPY --from=BUILD_IMAGE /app ./
COPY --from=BUILD_IMAGE /app/dist/ public/
COPY --from=BUILD_IMAGE /app/node_modules/ node_modules/
COPY services/ services/
COPY src/utils/ src/utils/
COPY package.json yarn.lock server.js ./
# Finally, run start command to serve up the built application
ENTRYPOINT [ "/sbin/tini", "--" ]
CMD [ "yarn", "build-and-start" ]
CMD [ "yarn", "start" ]
# Expose the port
EXPOSE ${PORT}

View File

@ -1,6 +1,6 @@
{
"name": "Dashy",
"version": "2.0.3",
"version": "2.0.4",
"license": "MIT",
"main": "server",
"author": "Alicia Sykes <alicia@omg.lol> (https://aliciasykes.com)",

View File

@ -68,7 +68,7 @@ const method = (m, mw) => (req, res, next) => (req.method === m ? mw(req, res, n
const app = express()
// Serves up static files
.use(express.static(path.join(__dirname, 'dist')))
.use(express.static(path.join(__dirname, 'public'), { index: 'initialization.html' }))
.use(express.static(path.join(__dirname, 'public')))
// Load middlewares for parsing JSON, and supporting HTML5 history routing
.use(express.json({ limit: '1mb' }))
.use(history())

View File

@ -28,9 +28,6 @@ module.exports = (ip, port, isDocker) => {
+ `${chars.CYAN}Welcome to Dashy! 🚀${chars.RESET}${chars.BR}`
+ `${chars.GREEN}Your new dashboard is now up and running `
+ `${containerId ? `in container ID ${containerId}` : 'with Docker'}${chars.BR}`
+ `${chars.GREEN}After updating your config file, run `
+ `'${chars.BRIGHT}docker exec -it ${containerId || '[container-id]'} yarn build`
+ `${chars.RESET}${chars.GREEN}' to rebuild${chars.BR}`
+ `${chars.BLUE}${stars(91)}${chars.BR}${chars.RESET}`;
} else {
// Prepare message for users running app on bare metal
@ -38,8 +35,6 @@ module.exports = (ip, port, isDocker) => {
+ `${chars.CYAN}Welcome to Dashy! 🚀${blanks(55)}${chars.GREEN}${chars.BR}`
+ `${chars.CYAN}Your new dashboard is now up and running at ${chars.BRIGHT}`
+ `http://${ip}:${port}${chars.RESET}${blanks(18 - ip.length)}${chars.GREEN}${chars.BR}`
+ `${chars.CYAN}After updating your config file, run '${chars.BRIGHT}yarn build`
+ `${chars.RESET}${chars.CYAN}' to rebuild the app${blanks(6)}${chars.GREEN}${chars.BR}`
+ `${line(75)}${chars.BR}${chars.BR}${chars.RESET}`;
}
// Make some sexy ascii art ;)

View File

@ -3,8 +3,8 @@
<EditModeTopBanner v-if="isEditMode" />
<LoadingScreen :isLoading="isLoading" v-if="shouldShowSplash" />
<Header :pageInfo="pageInfo" />
<router-view />
<Footer :text="footerText" v-if="visibleComponents.footer" />
<router-view v-if="!isFetching" />
<Footer :text="footerText" v-if="visibleComponents.footer && !isFetching" />
</div>
</template>
<script>
@ -33,6 +33,7 @@ export default {
data() {
return {
isLoading: true, // Set to false after mount complete
isFetching: true, // Set to false after the conf has been fetched
};
},
watch: {
@ -40,6 +41,9 @@ export default {
// When in edit mode, show confirmation dialog on page exit
window.onbeforeunload = isEditMode ? this.confirmExit : null;
},
config() {
this.isFetching = false;
},
},
computed: {
/* If the user has specified custom text for footer - get it */
@ -69,9 +73,6 @@ export default {
return this.$store.state.editMode;
},
},
created() {
this.$store.dispatch(Keys.INITIALIZE_CONFIG);
},
methods: {
/* Injects the users custom CSS as a style tag */
injectCustomStyles(usersCss) {
@ -135,7 +136,8 @@ export default {
},
},
/* Basic initialization tasks on app load */
mounted() {
async mounted() {
await this.$store.dispatch(Keys.INITIALIZE_CONFIG); // Initialize config before moving on
this.applyLanguage(); // Apply users local language
this.hideSplash(); // Hide the splash screen, if visible
if (this.appConfig.customCss) { // Inject users custom CSS, if present

View File

@ -1,6 +1,8 @@
/* eslint-disable no-param-reassign, prefer-destructuring */
import Vue from 'vue';
import Vuex from 'vuex';
import axios from 'axios';
import yaml from 'js-yaml';
import Keys from '@/utils/StoreMutations';
import ConfigAccumulator from '@/utils/ConfigAccumalator';
import { componentVisibility } from '@/utils/ConfigHelpers';
@ -14,6 +16,7 @@ Vue.use(Vuex);
const {
INITIALIZE_CONFIG,
SET_CONFIG,
SET_REMOTE_CONFIG,
SET_MODAL_OPEN,
SET_LANGUAGE,
SET_ITEM_LAYOUT,
@ -38,6 +41,7 @@ const {
const store = new Vuex.Store({
state: {
config: {},
remoteConfig: {}, // The configuration stored on the server
editMode: false, // While true, the user can drag and edit items + sections
modalOpen: false, // KB shortcut functionality will be disabled when modal is open
navigateConfToTab: undefined, // Used to switch active tab in config modal
@ -126,6 +130,9 @@ const store = new Vuex.Store({
[SET_CONFIG](state, config) {
state.config = config;
},
[SET_REMOTE_CONFIG](state, config) {
state.remoteConfig = config;
},
[SET_LANGUAGE](state, lang) {
const newConfig = state.config;
newConfig.appConfig.language = lang;
@ -271,7 +278,9 @@ const store = new Vuex.Store({
},
actions: {
/* Called when app first loaded. Reads config and sets state */
[INITIALIZE_CONFIG]({ commit }) {
async [INITIALIZE_CONFIG]({ commit }) {
// 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));
const deepCopy = (json) => JSON.parse(JSON.stringify(json));
const config = deepCopy(new ConfigAccumulator().config());
commit(SET_CONFIG, config);

View File

@ -14,11 +14,11 @@ import {
} from '@/utils/defaults';
import ErrorHandler from '@/utils/ErrorHandler';
import { applyItemId } from '@/utils/SectionHelpers';
import conf from '../../public/conf.yml';
import $store from '@/store';
export default class ConfigAccumulator {
constructor() {
this.conf = conf;
this.conf = $store.state.remoteConfig;
}
/* App Config */

View File

@ -1,7 +1,8 @@
import axios from 'axios';
import yaml from 'js-yaml';
import { register } from 'register-service-worker';
import { sessionStorageKeys } from '@/utils/defaults';
import { statusMsg, statusErrorMsg } from '@/utils/CoolConsole';
import conf from '../../public/conf.yml';
/* Sets a local storage item with the state from the SW lifecycle */
const setSwStatus = (swStateToSet) => {
@ -31,7 +32,8 @@ const setSwStatus = (swStateToSet) => {
* Disable if not running in production
* Or disable if user specified to disable
*/
const shouldEnableServiceWorker = () => {
const shouldEnableServiceWorker = async () => {
const conf = yaml.load((await axios.get('conf.yml')).data);
if (conf && conf.appConfig && conf.appConfig.enableServiceWorker) {
setSwStatus({ disabledByUser: false });
return true;
@ -51,8 +53,8 @@ const printSwStatus = (msg) => {
const swUrl = `${process.env.BASE_URL || '/'}service-worker.js`;
/* If service worker enabled, then register it, and print message when status changes */
const registerServiceWorker = () => {
if (shouldEnableServiceWorker()) {
const registerServiceWorker = async () => {
if (await shouldEnableServiceWorker()) {
register(swUrl, {
ready() {
setSwStatus({ ready: true });

View File

@ -2,6 +2,7 @@
const KEY_NAMES = [
'INITIALIZE_CONFIG',
'SET_CONFIG',
'SET_REMOTE_CONFIG',
'SET_MODAL_OPEN',
'SET_LANGUAGE',
'SET_EDIT_MODE',