mirror of https://github.com/Lissy93/dashy.git
🔁 Merge pull request #528 from Ateroz/master
Fetch conf.yml from server
This commit is contained in:
commit
93911c2520
|
@ -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)
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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)",
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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 ;)
|
||||
|
|
14
src/App.vue
14
src/App.vue
|
@ -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
|
||||
|
|
11
src/store.js
11
src/store.js
|
@ -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);
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 });
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
const KEY_NAMES = [
|
||||
'INITIALIZE_CONFIG',
|
||||
'SET_CONFIG',
|
||||
'SET_REMOTE_CONFIG',
|
||||
'SET_MODAL_OPEN',
|
||||
'SET_LANGUAGE',
|
||||
'SET_EDIT_MODE',
|
||||
|
|
Loading…
Reference in New Issue