[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>
<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" />
<pre><code class="config-snippet" v-html="highlightedConfigSnippet" /></pre>
</div>
@ -25,19 +31,63 @@ export default {
required: true,
},
config: {
type: Object,
},
configFile: {
type: String,
},
},
data() {
return {
curYamlConfig: null,
}
},
computed: {
highlightedConfigSnippet() {
return hljs.highlight(
'yaml',
`# Add this configuration template to ${this.configFile}\n` +
`# Configuration template. You can add it to ${this.configFile}\n` +
this.extension.config_snippet,
).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>
@ -47,8 +97,31 @@ export default {
.config-container {
width: 100%;
height: 100%;
max-height: 100%;
position: relative;
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>

View File

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

View File

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