2020-11-21 01:12:08 +01:00
|
|
|
<template>
|
2020-11-26 23:43:16 +01:00
|
|
|
<Loading v-if="loading" />
|
|
|
|
|
2020-11-23 00:44:31 +01:00
|
|
|
<div id="dashboard" class="columns is-mobile" :class="classes" :style="style">
|
|
|
|
<Row v-for="(row, i) in rows" :key="i" :class="row.class" :style="row.style">
|
|
|
|
<keep-alive v-for="(widget, j) in row.widgets" :key="j">
|
|
|
|
<Widget :style="widget.style" :class="widget.class">
|
2021-03-18 01:30:29 +01:00
|
|
|
<component :is="widget.component" v-bind="getWidgetProps(widget)" />
|
2020-11-23 00:44:31 +01:00
|
|
|
</Widget>
|
|
|
|
</keep-alive>
|
|
|
|
</Row>
|
2020-11-21 01:12:08 +01:00
|
|
|
</div>
|
|
|
|
</template>
|
|
|
|
|
|
|
|
<script>
|
|
|
|
import { defineAsyncComponent } from 'vue'
|
|
|
|
import Utils from '@/Utils'
|
|
|
|
import Loading from "@/components/Loading";
|
2020-11-26 00:26:10 +01:00
|
|
|
import Row from "@/components/widgets/Row";
|
|
|
|
import Widget from "@/components/widgets/Widget";
|
2020-11-21 01:12:08 +01:00
|
|
|
|
|
|
|
export default {
|
|
|
|
name: 'Dashboard',
|
|
|
|
mixins: [Utils],
|
2020-11-27 23:12:10 +01:00
|
|
|
components: {Widget, Loading, Row},
|
2020-11-22 14:26:25 +01:00
|
|
|
props: {
|
|
|
|
// Refresh interval in seconds.
|
|
|
|
refreshSeconds: {
|
|
|
|
type: Number,
|
|
|
|
required: false,
|
|
|
|
default: 0,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
|
2020-11-21 01:12:08 +01:00
|
|
|
data() {
|
|
|
|
return {
|
2020-11-23 00:44:31 +01:00
|
|
|
rows: [],
|
2020-11-21 01:12:08 +01:00
|
|
|
loading: false,
|
|
|
|
style: undefined,
|
2020-11-23 00:44:31 +01:00
|
|
|
class: undefined,
|
2020-11-21 01:12:08 +01:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2020-11-23 00:44:31 +01:00
|
|
|
computed: {
|
|
|
|
classes() {
|
|
|
|
return this.class
|
|
|
|
},
|
|
|
|
},
|
|
|
|
|
2020-11-21 01:12:08 +01:00
|
|
|
methods: {
|
2021-03-18 01:30:29 +01:00
|
|
|
getWidgetProps(widget) {
|
|
|
|
const props = {...widget.props}
|
|
|
|
if (props.class)
|
|
|
|
delete props.class
|
|
|
|
|
|
|
|
return props
|
|
|
|
},
|
|
|
|
|
2020-11-21 01:12:08 +01:00
|
|
|
parseTemplate(name, tmpl) {
|
|
|
|
const node = new DOMParser().parseFromString(tmpl, 'text/xml').childNodes[0]
|
2020-11-23 00:44:31 +01:00
|
|
|
const self = this
|
|
|
|
this.style = node.attributes.style ? node.attributes.style.nodeValue : undefined
|
|
|
|
this.class = node.attributes.class ? node.attributes.class.nodeValue : undefined
|
|
|
|
|
|
|
|
this.rows = [...node.getElementsByTagName('Row')].map((row) => {
|
|
|
|
return {
|
|
|
|
style: row.attributes.style ? row.attributes.style.nodeValue : undefined,
|
|
|
|
class: row.attributes.class ? row.attributes.class.nodeValue : undefined,
|
|
|
|
widgets: [...row.children].map((el) => {
|
|
|
|
const component = defineAsyncComponent(
|
2020-11-26 00:26:10 +01:00
|
|
|
() => import(`@/components/widgets/${el.nodeName}/Index`)
|
2020-11-23 00:44:31 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
const style = el.attributes.style ? el.attributes.style.nodeValue : undefined
|
|
|
|
const classes = el.attributes.class ? el.attributes.class.nodeValue : undefined
|
|
|
|
const attrs = [...el.attributes].reduce((obj, node) => {
|
|
|
|
if (node.nodeName !== 'style') {
|
|
|
|
obj[node.nodeName] = node.nodeValue
|
|
|
|
}
|
|
|
|
|
|
|
|
return obj
|
|
|
|
}, {})
|
|
|
|
|
|
|
|
const widget = {
|
|
|
|
component: component,
|
|
|
|
style: style,
|
|
|
|
class: classes,
|
|
|
|
props: attrs || {},
|
|
|
|
}
|
|
|
|
|
|
|
|
self.$options.components[el.nodeName] = component
|
|
|
|
return widget
|
|
|
|
})
|
|
|
|
}
|
2020-11-21 01:12:08 +01:00
|
|
|
})
|
|
|
|
|
|
|
|
this.loading = false
|
|
|
|
},
|
|
|
|
|
|
|
|
async refreshDashboard() {
|
|
|
|
this.loading = true
|
|
|
|
this.widgets = []
|
|
|
|
const name = this.$route.params.name
|
|
|
|
const template = (await this.request('config.get_dashboard', { name: name }))
|
|
|
|
|
|
|
|
if (!template) {
|
|
|
|
this.error(`Dashboard ${name} not found`)
|
|
|
|
}
|
|
|
|
|
|
|
|
this.parseTemplate(name, template)
|
|
|
|
},
|
|
|
|
},
|
|
|
|
|
|
|
|
mounted() {
|
|
|
|
this.refreshDashboard()
|
2020-11-22 14:26:25 +01:00
|
|
|
if (this.refreshSeconds) {
|
|
|
|
const self = this
|
2020-11-23 00:44:31 +01:00
|
|
|
setInterval(() => {
|
2020-11-22 14:26:25 +01:00
|
|
|
self.refreshDashboard()
|
|
|
|
}, parseInt((this.refreshSeconds*1000).toFixed(0)))
|
|
|
|
}
|
2020-11-21 01:12:08 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
</script>
|
|
|
|
|
|
|
|
<style lang="scss" scoped>
|
2021-02-19 02:54:12 +01:00
|
|
|
@import "~lato-font/scss/public-api";
|
|
|
|
$lato-font-path: "~lato-font/fonts";
|
|
|
|
|
|
|
|
@include lato-include-font('medium');
|
|
|
|
|
2020-11-21 01:12:08 +01:00
|
|
|
#dashboard {
|
|
|
|
width: 100%;
|
|
|
|
height: 100%;
|
|
|
|
display: flex;
|
2020-11-26 00:26:10 +01:00
|
|
|
flex-direction: column;
|
2020-11-21 01:12:08 +01:00
|
|
|
margin: 0;
|
|
|
|
padding: 1em 1em 0 1em;
|
|
|
|
background: $dashboard-bg;
|
|
|
|
background-size: cover;
|
2021-02-19 02:54:12 +01:00
|
|
|
font-family: Lato, proxima-nova, Helvetica Neue, Arial, sans-serif;
|
2020-11-21 01:12:08 +01:00
|
|
|
|
|
|
|
.blurred {
|
|
|
|
filter: blur(0.075em);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
</style>
|
2020-11-26 12:53:34 +01:00
|
|
|
|
|
|
|
<style>
|
|
|
|
html {
|
2020-11-26 17:11:03 +01:00
|
|
|
overflow: auto !important;
|
2020-11-26 12:53:34 +01:00
|
|
|
}
|
|
|
|
</style>
|