[Extensions UI] Added current config to extension panel.

If an extension is configured and enabled, then the UI will now include
a tick next to its name and the currently loaded configuration in the
`Configuration` tab.
This commit is contained in:
Fabio Manganiello 2023-10-18 22:51:30 +02:00
parent f0255549c8
commit 2a76a6baa6
Signed by: blacklight
GPG key ID: D90FBA7F76362774
3 changed files with 144 additions and 8 deletions

View file

@ -1,5 +1,11 @@
<template> <template>
<div class="config-container" ref="root"> <div class="config-container current"
v-if="highlightedCurrentConfig">
<CopyButton :text="curYamlConfig" />
<pre><code class="config-snippet" v-html="highlightedCurrentConfig" /></pre>
</div>
<div class="config-container snippet" :class="{'fullscreen': !highlightedCurrentConfig}">
<CopyButton :text="extension.config_snippet" /> <CopyButton :text="extension.config_snippet" />
<pre><code class="config-snippet" v-html="highlightedConfigSnippet" /></pre> <pre><code class="config-snippet" v-html="highlightedConfigSnippet" /></pre>
</div> </div>
@ -25,19 +31,63 @@ export default {
required: true, required: true,
}, },
config: {
type: Object,
},
configFile: { configFile: {
type: String, type: String,
}, },
}, },
data() {
return {
curYamlConfig: null,
}
},
computed: { computed: {
highlightedConfigSnippet() { highlightedConfigSnippet() {
return hljs.highlight( return hljs.highlight(
'yaml', 'yaml',
`# Add this configuration template to ${this.configFile}\n` + `# Configuration template. You can add it to ${this.configFile}\n` +
this.extension.config_snippet, this.extension.config_snippet,
).value.trim() ).value.trim()
}, },
highlightedCurrentConfig() {
if (!this.curYamlConfig) {
return null
}
return hljs.highlight(
'yaml',
'# Currently loaded configuration\n' +
this.curYamlConfig
).value.trim()
},
},
methods: {
async loadCurrentConfig() {
if (!this.config) {
this.curYamlConfig = null
return
}
this.curYamlConfig = await this.request(
'utils.to_yaml', {
obj: {
[this.extension.name]: this.config,
}
}
)
},
},
mounted() {
this.loadCurrentConfig()
this.$watch('config', this.loadCurrentConfig)
}, },
} }
</script> </script>
@ -47,8 +97,31 @@ export default {
.config-container { .config-container {
width: 100%; width: 100%;
height: 100%; max-height: 100%;
position: relative; position: relative;
display: flex; display: flex;
flex-grow: 1;
overflow: auto;
pre {
border-radius: 1em;
}
&.current {
height: 34%;
margin-bottom: 1.5em;
}
&.snippet {
height: 66%;
}
&.fullscreen {
height: 100%;
pre {
border-radius: 0;
}
}
} }
</style> </style>

View file

@ -23,6 +23,7 @@
<Doc v-if="selectedTab === 'doc'" :extension="extension" /> <Doc v-if="selectedTab === 'doc'" :extension="extension" />
<Config v-else-if="selectedTab === 'config'" <Config v-else-if="selectedTab === 'config'"
:extension="extension" :extension="extension"
:config="config"
:config-file="configFile" /> :config-file="configFile" />
<Install v-else-if="selectedTab === 'install'" :extension="extension" /> <Install v-else-if="selectedTab === 'install'" :extension="extension" />
</div> </div>
@ -52,6 +53,10 @@ export default {
required: true, required: true,
}, },
config: {
type: Object,
},
configFile: { configFile: {
type: String, type: String,
}, },

View file

@ -16,15 +16,20 @@
<div class="items"> <div class="items">
<div class="extension-container" v-for="name in extensionNames" :key="name"> <div class="extension-container" v-for="name in extensionNames" :key="name">
<div class="extension" v-if="matchesFilter(name)"> <div class="extension" v-if="matchesFilter(name)">
<div class="item name" <div class="item"
:class="{selected: name === selectedExtension}" :class="{selected: name === selectedExtension}"
:data-name="name" :data-name="name"
@click="onInput(name, false)" @click="onClick(name, false)">
v-text="extensions[name].name" /> <span class="name">{{ extensions[name].name }}</span>
<span class="enabled icon" title="Enabled" v-if="enabledExtensions[name]">
<i class="enabled icon fas fa-circle-check" v-if="enabledExtensions[name]" />
</span>
</div>
<div class="extension-body-container until tablet" <div class="extension-body-container until tablet"
v-if="selectedExtension && name === selectedExtension"> v-if="selectedExtension && name === selectedExtension">
<Extension :extension="extensions[selectedExtension]" <Extension :extension="extensions[selectedExtension]"
:config="enabledExtensions[selectedExtension]"
:config-file="configFile" /> :config-file="configFile" />
</div> </div>
</div> </div>
@ -34,6 +39,7 @@
<div class="extension-body-container from desktop" <div class="extension-body-container from desktop"
v-if="selectedExtension"> v-if="selectedExtension">
<Extension :extension="extensions[selectedExtension]" <Extension :extension="extensions[selectedExtension]"
:config="enabledExtensions[selectedExtension]"
:config-file="configFile" /> :config-file="configFile" />
</div> </div>
</main> </main>
@ -59,9 +65,12 @@ export default {
loading: false, loading: false,
plugins: {}, plugins: {},
backends: {}, backends: {},
enabledPlugins: {},
enabledBackends: {},
filter: '', filter: '',
selectedExtension: null, selectedExtension: null,
configFile: null, configFile: null,
config: {},
} }
}, },
@ -87,12 +96,30 @@ export default {
return extensions return extensions
}, },
enabledExtensions() {
return [this.enabledPlugins, this.enabledBackends].reduce((acc, extensions) => {
Object.entries(extensions).forEach(([name, config]) => {
acc[name] = config
})
return acc
}, {})
},
extensionNames() { extensionNames() {
return Object.keys(this.extensions).sort() return Object.keys(this.extensions).sort()
}, },
}, },
methods: { methods: {
onClick(input, setFilter = true, setUrlArgs = true) {
if (this.selectedExtension === input) {
this.selectedExtension = null
} else {
this.onInput(input, setFilter, setUrlArgs)
}
},
onInput(input, setFilter = true, setUrlArgs = true) { onInput(input, setFilter = true, setUrlArgs = true) {
if (setFilter) { if (setFilter) {
this.filter = input this.filter = input
@ -124,17 +151,38 @@ export default {
async loadExtensions() { async loadExtensions() {
this.loading = true this.loading = true
let [enabledPlugins, enabledBackends] = [[], []]
try { try {
[this.plugins, this.backends] = [
this.plugins,
this.backends,
enabledPlugins,
enabledBackends,
this.config,
] =
await Promise.all([ await Promise.all([
this.request('inspect.get_all_plugins'), this.request('inspect.get_all_plugins'),
this.request('inspect.get_all_backends'), this.request('inspect.get_all_backends'),
this.request('inspect.get_enabled_plugins'),
this.request('inspect.get_enabled_backends'),
this.request('inspect.get_config'),
]) ])
} finally { } finally {
this.loading = false this.loading = false
} }
this.enabledPlugins = enabledPlugins.reduce((acc, name) => {
acc[name] = this.config[name] || {}
return acc
}, {})
this.enabledBackends = enabledBackends.reduce((acc, name) => {
name = `backend.${name}`
acc[name] = this.config[name] || {}
return acc
}, {})
this.loadExtensionFromUrl() this.loadExtensionFromUrl()
this.$watch('$route.hash', () => this.loadExtensionFromUrl()) this.$watch('$route.hash', () => this.loadExtensionFromUrl())
}, },
@ -206,8 +254,18 @@ $header-height: 3.25em;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
.name { .item {
width: 100%;
display: flex;
padding: 1em; padding: 1em;
position: relative;
.icon {
width: 2.5em;
position: absolute;
right: -1em;
top: 0.65em;
}
&.selected { &.selected {
font-weight: bold; font-weight: bold;