platypush/platypush/backend/http/webapp/src/components/panels/Switches/Index.vue

215 lines
4.7 KiB
Vue

<template>
<div class="switches-container">
<Loading v-if="loading" />
<div class="switch-plugins">
<div class="no-content" v-if="!Object.keys(plugins).length">No switch plugins configured</div>
<div class="switch-plugin" v-for="pluginName in Object.keys(plugins)" :key="pluginName"
@click="selectedPlugin = selectedPlugin === pluginName ? null : pluginName">
<div class="header" :class="{selected: selectedPlugin === pluginName}">
<div class="name col-10" v-text="pluginName" />
<div class="refresh col-2" v-if="selectedPlugin === pluginName">
<button @click.stop="bus.emit('refresh', pluginName)" title="Refresh plugin" :disabled="loading">
<i class="fa fa-sync" />
</button>
</div>
</div>
<div class="body" :class="{hidden: selectedPlugin !== pluginName}">
<component :is="components[pluginName]" :config="plugins[pluginName]" :plugin-name="pluginName"
:selected="selectedPlugin === pluginName" :bus="bus" />
</div>
</div>
</div>
<div class="refresh-button">
<button @click="refresh" :disabled="loading" title="Refresh plugins">
<i class="fa fa-sync" />
</button>
</div>
</div>
</template>
<script>
import Loading from "@/components/Loading";
import Utils from "@/Utils";
import {defineAsyncComponent} from "vue";
import mitt from "mitt";
export default {
name: "Switches",
components: {Loading},
mixins: [Utils],
data() {
return {
loading: false,
plugins: {},
components: {},
selectedPlugin: null,
bus: mitt(),
}
},
methods: {
initPanels() {
this.components = {}
Object.keys(this.plugins).forEach(async (pluginName) => {
const componentName = pluginName.split('.').map((token) => token[0].toUpperCase() + token.slice(1)).join('')
let comp = null
try {
comp = await import(`@/components/panels/Switches/${componentName}/Index`)
} catch (e) {
return
}
const component = defineAsyncComponent(async () => { return comp })
this.$options.components[pluginName] = component
this.components[pluginName] = component
})
},
async refresh() {
this.loading = true
try {
this.plugins = await this.request('utils.get_switch_plugins')
this.initPanels()
} finally {
this.loading = false
}
},
},
mounted() {
this.refresh()
},
}
</script>
<style lang="scss" scoped>
@import "vars";
.switches-container {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
overflow: auto;
.switch-plugins {
background: $background-color;
display: flex;
flex-direction: column;
box-shadow: $border-shadow-bottom-right;
@media screen and (max-width: calc(#{$tablet - 1px})) {
width: 100%;
}
@media screen and (min-width: $tablet) {
width: 90%;
border-radius: 1em;
margin-top: 2em;
}
@media screen and (min-width: $desktop) {
width: 500pt;
margin-top: 3em;
}
}
.no-content {
padding: 1.5em;
}
.switch-plugin {
display: flex;
flex-direction: column;
.header {
display: flex;
align-items: center;
padding: 1em 1.5em 1em .5em;
text-transform: uppercase;
letter-spacing: .075em;
border-bottom: $default-border-2;
cursor: pointer;
&:hover {
background: $hover-bg;
}
&.selected {
background: $selected-bg;
box-shadow: $border-shadow-bottom-right;
border: none;
}
.refresh {
text-align: right;
}
button {
padding: 0;
margin: 0;
border: none;
background: none;
&:hover {
color: $default-hover-fg-2;
}
}
}
@media screen and (min-width: $tablet) {
&:first-child {
.header {
border-radius: 1em 1em 0 0;
}
}
&:last-child {
.header {
border-radius: 0 0 1em 1em;
}
}
}
.body {
display: flex;
border: $default-border-2;
border-bottom: 0;
box-shadow: $border-shadow-bottom;
}
}
.refresh-button {
position: fixed;
bottom: 1.5em;
right: 1.5em;
button {
width: 4em;
height: 4em;
border-radius: 2em;
background: $refresh-button-bg;
color: $refresh-button-fg;
border: none;
box-shadow: $border-shadow-bottom-right;
&:hover {
color: $default-hover-fg-2;
}
&:disabled {
opacity: .7;
}
}
}
}
</style>