Added proper code editor to the commands list
This commit is contained in:
parent
300b1de7de
commit
d8cdbcd0cc
184
console/package-lock.json
generated
184
console/package-lock.json
generated
@ -8,9 +8,16 @@
|
||||
"name": "primevue-vite-quickstart",
|
||||
"version": "0.0.0",
|
||||
"dependencies": {
|
||||
"@codemirror/autocomplete": "^6.20.1",
|
||||
"@codemirror/commands": "^6.10.3",
|
||||
"@codemirror/lang-json": "^6.0.2",
|
||||
"@codemirror/state": "^6.6.0",
|
||||
"@codemirror/theme-one-dark": "^6.1.3",
|
||||
"@codemirror/view": "^6.40.0",
|
||||
"@primeuix/themes": "^1.0.0",
|
||||
"@primevue/core": "^4.2.5",
|
||||
"chart.js": "^4.4.7",
|
||||
"codemirror": "^6.0.2",
|
||||
"mqtt": "^5.15.0",
|
||||
"primeicons": "^7.0.0",
|
||||
"primevue": "^4.2.5",
|
||||
@ -78,6 +85,109 @@
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@codemirror/autocomplete": {
|
||||
"version": "6.20.1",
|
||||
"resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.20.1.tgz",
|
||||
"integrity": "sha512-1cvg3Vz1dSSToCNlJfRA2WSI4ht3K+WplO0UMOgmUYPivCyy2oueZY6Lx7M9wThm7SDUBViRmuT+OG/i8+ON9A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@codemirror/language": "^6.0.0",
|
||||
"@codemirror/state": "^6.0.0",
|
||||
"@codemirror/view": "^6.17.0",
|
||||
"@lezer/common": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@codemirror/commands": {
|
||||
"version": "6.10.3",
|
||||
"resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.10.3.tgz",
|
||||
"integrity": "sha512-JFRiqhKu+bvSkDLI+rUhJwSxQxYb759W5GBezE8Uc8mHLqC9aV/9aTC7yJSqCtB3F00pylrLCwnyS91Ap5ej4Q==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@codemirror/language": "^6.0.0",
|
||||
"@codemirror/state": "^6.6.0",
|
||||
"@codemirror/view": "^6.27.0",
|
||||
"@lezer/common": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@codemirror/lang-json": {
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@codemirror/lang-json/-/lang-json-6.0.2.tgz",
|
||||
"integrity": "sha512-x2OtO+AvwEHrEwR0FyyPtfDUiloG3rnVTSZV1W8UteaLL8/MajQd8DpvUb2YVzC+/T18aSDv0H9mu+xw0EStoQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@codemirror/language": "^6.0.0",
|
||||
"@lezer/json": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@codemirror/language": {
|
||||
"version": "6.12.2",
|
||||
"resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.12.2.tgz",
|
||||
"integrity": "sha512-jEPmz2nGGDxhRTg3lTpzmIyGKxz3Gp3SJES4b0nAuE5SWQoKdT5GoQ69cwMmFd+wvFUhYirtDTr0/DRHpQAyWg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@codemirror/state": "^6.0.0",
|
||||
"@codemirror/view": "^6.23.0",
|
||||
"@lezer/common": "^1.5.0",
|
||||
"@lezer/highlight": "^1.0.0",
|
||||
"@lezer/lr": "^1.0.0",
|
||||
"style-mod": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@codemirror/lint": {
|
||||
"version": "6.9.5",
|
||||
"resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-6.9.5.tgz",
|
||||
"integrity": "sha512-GElsbU9G7QT9xXhpUg1zWGmftA/7jamh+7+ydKRuT0ORpWS3wOSP0yT1FOlIZa7mIJjpVPipErsyvVqB9cfTFA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@codemirror/state": "^6.0.0",
|
||||
"@codemirror/view": "^6.35.0",
|
||||
"crelt": "^1.0.5"
|
||||
}
|
||||
},
|
||||
"node_modules/@codemirror/search": {
|
||||
"version": "6.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@codemirror/search/-/search-6.6.0.tgz",
|
||||
"integrity": "sha512-koFuNXcDvyyotWcgOnZGmY7LZqEOXZaaxD/j6n18TCLx2/9HieZJ5H6hs1g8FiRxBD0DNfs0nXn17g872RmYdw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@codemirror/state": "^6.0.0",
|
||||
"@codemirror/view": "^6.37.0",
|
||||
"crelt": "^1.0.5"
|
||||
}
|
||||
},
|
||||
"node_modules/@codemirror/state": {
|
||||
"version": "6.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.6.0.tgz",
|
||||
"integrity": "sha512-4nbvra5R5EtiCzr9BTHiTLc+MLXK2QGiAVYMyi8PkQd3SR+6ixar/Q/01Fa21TBIDOZXgeWV4WppsQolSreAPQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@marijn/find-cluster-break": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@codemirror/theme-one-dark": {
|
||||
"version": "6.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@codemirror/theme-one-dark/-/theme-one-dark-6.1.3.tgz",
|
||||
"integrity": "sha512-NzBdIvEJmx6fjeremiGp3t/okrLPYT0d9orIc7AFun8oZcRk58aejkqhv6spnz4MLAevrKNPMQYXEWMg4s+sKA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@codemirror/language": "^6.0.0",
|
||||
"@codemirror/state": "^6.0.0",
|
||||
"@codemirror/view": "^6.0.0",
|
||||
"@lezer/highlight": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@codemirror/view": {
|
||||
"version": "6.40.0",
|
||||
"resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.40.0.tgz",
|
||||
"integrity": "sha512-WA0zdU7xfF10+5I3HhUUq3kqOx3KjqmtQ9lqZjfK7jtYk4G72YW9rezcSywpaUMCWOMlq+6E0pO1IWg1TNIhtg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@codemirror/state": "^6.6.0",
|
||||
"crelt": "^1.0.6",
|
||||
"style-mod": "^4.1.0",
|
||||
"w3c-keyname": "^2.2.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/aix-ppc64": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz",
|
||||
@ -524,6 +634,47 @@
|
||||
"integrity": "sha512-M5UknZPHRu3DEDWoipU6sE8PdkZ6Z/S+v4dD+Ke8IaNlpdSQah50lz1KtcFBa2vsdOnwbbnxJwVM4wty6udA5w==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@lezer/common": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.5.1.tgz",
|
||||
"integrity": "sha512-6YRVG9vBkaY7p1IVxL4s44n5nUnaNnGM2/AckNgYOnxTG2kWh1vR8BMxPseWPjRNpb5VtXnMpeYAEAADoRV1Iw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@lezer/highlight": {
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.2.3.tgz",
|
||||
"integrity": "sha512-qXdH7UqTvGfdVBINrgKhDsVTJTxactNNxLk7+UMwZhU13lMHaOBlJe9Vqp907ya56Y3+ed2tlqzys7jDkTmW0g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@lezer/common": "^1.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@lezer/json": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@lezer/json/-/json-1.0.3.tgz",
|
||||
"integrity": "sha512-BP9KzdF9Y35PDpv04r0VeSTKDeox5vVr3efE7eBbx3r4s3oNLfunchejZhjArmeieBH+nVOpgIiBJpEAv8ilqQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@lezer/common": "^1.2.0",
|
||||
"@lezer/highlight": "^1.0.0",
|
||||
"@lezer/lr": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@lezer/lr": {
|
||||
"version": "1.4.8",
|
||||
"resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.4.8.tgz",
|
||||
"integrity": "sha512-bPWa0Pgx69ylNlMlPvBPryqeLYQjyJjqPx+Aupm5zydLIF3NE+6MMLT8Yi23Bd9cif9VS00aUebn+6fDIGBcDA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@lezer/common": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@marijn/find-cluster-break": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@marijn/find-cluster-break/-/find-cluster-break-1.0.2.tgz",
|
||||
"integrity": "sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@primeuix/styled": {
|
||||
"version": "0.7.4",
|
||||
"resolved": "https://registry.npmjs.org/@primeuix/styled/-/styled-0.7.4.tgz",
|
||||
@ -1289,6 +1440,21 @@
|
||||
"fsevents": "~2.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/codemirror": {
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/codemirror/-/codemirror-6.0.2.tgz",
|
||||
"integrity": "sha512-VhydHotNW5w1UGK0Qj96BwSk/Zqbp9WbnyK2W/eVMv4QyF41INRGpjUhFJY7/uDNuudSc33a/PKr4iDqRduvHw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@codemirror/autocomplete": "^6.0.0",
|
||||
"@codemirror/commands": "^6.0.0",
|
||||
"@codemirror/language": "^6.0.0",
|
||||
"@codemirror/lint": "^6.0.0",
|
||||
"@codemirror/search": "^6.0.0",
|
||||
"@codemirror/state": "^6.0.0",
|
||||
"@codemirror/view": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/commist": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/commist/-/commist-3.2.0.tgz",
|
||||
@ -1331,6 +1497,12 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/crelt": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.6.tgz",
|
||||
"integrity": "sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/csstype": {
|
||||
"version": "3.2.3",
|
||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz",
|
||||
@ -2019,6 +2191,12 @@
|
||||
"safe-buffer": "~5.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/style-mod": {
|
||||
"version": "4.1.3",
|
||||
"resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.1.3.tgz",
|
||||
"integrity": "sha512-i/n8VsZydrugj3Iuzll8+x/00GH2vnYsk1eomD8QiRrSAeW6ItbCQDtfXCeJHd0iwiNagqjQkvpvREEPtW3IoQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/tinyglobby": {
|
||||
"version": "0.2.15",
|
||||
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz",
|
||||
@ -2287,6 +2465,12 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/w3c-keyname": {
|
||||
"version": "2.2.8",
|
||||
"resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz",
|
||||
"integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/webpack-virtual-modules": {
|
||||
"version": "0.6.2",
|
||||
"resolved": "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz",
|
||||
|
||||
@ -8,9 +8,16 @@
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@codemirror/autocomplete": "^6.20.1",
|
||||
"@codemirror/commands": "^6.10.3",
|
||||
"@codemirror/lang-json": "^6.0.2",
|
||||
"@codemirror/state": "^6.6.0",
|
||||
"@codemirror/theme-one-dark": "^6.1.3",
|
||||
"@codemirror/view": "^6.40.0",
|
||||
"@primeuix/themes": "^1.0.0",
|
||||
"@primevue/core": "^4.2.5",
|
||||
"chart.js": "^4.4.7",
|
||||
"codemirror": "^6.0.2",
|
||||
"mqtt": "^5.15.0",
|
||||
"primeicons": "^7.0.0",
|
||||
"primevue": "^4.2.5",
|
||||
|
||||
@ -7,6 +7,22 @@ import AccordionPanel from 'primevue/accordionpanel';
|
||||
import AccordionHeader from 'primevue/accordionheader';
|
||||
import AccordionContent from 'primevue/accordioncontent';
|
||||
|
||||
import { nextTick } from 'vue'
|
||||
|
||||
import {basicSetup} from "codemirror"
|
||||
import { oneDark } from "@codemirror/theme-one-dark"
|
||||
import { EditorView } from "@codemirror/view"
|
||||
import { EditorState, StateEffect } from "@codemirror/state"
|
||||
|
||||
const lightTheme = EditorView.theme({}, { dark: false })
|
||||
const darkTheme = oneDark //EditorView.theme({}, { dark: true })
|
||||
|
||||
import { json } from "@codemirror/lang-json"
|
||||
|
||||
const editorContainers = reactive({})
|
||||
const editors = reactive({})
|
||||
const openTabs = ref([])
|
||||
|
||||
const props = defineProps({
|
||||
deviceId: String
|
||||
})
|
||||
@ -45,6 +61,91 @@ function sendCommand(cmd) {
|
||||
mqtt2.publish(topic, cmd.input || '{}')
|
||||
}
|
||||
|
||||
function setEditorRef(name, el) {
|
||||
if (el) {
|
||||
editorContainers[name] = el
|
||||
}
|
||||
}
|
||||
|
||||
function onAccordionChange(value) {
|
||||
|
||||
const opened = Array.isArray(value) ? value : [value]
|
||||
|
||||
opened.forEach(name => {
|
||||
|
||||
if (editors[name]) return
|
||||
|
||||
const cmd = commands.value.find(c => c.name === name)
|
||||
if (!cmd) return
|
||||
|
||||
const el = editorContainers[name]
|
||||
if (!el) return
|
||||
|
||||
nextTick(() => createEditor(cmd, el))
|
||||
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
function createEditor(cmd, el) {
|
||||
if (editors[cmd.name]) return
|
||||
|
||||
const initialDoc =
|
||||
cmd.input ||
|
||||
cmd.schema ||
|
||||
''
|
||||
|
||||
const state = EditorState.create({
|
||||
doc: initialDoc,
|
||||
extensions: baseExtensions(currentThemeExtension)
|
||||
})
|
||||
|
||||
const view = new EditorView({
|
||||
state,
|
||||
parent: el
|
||||
})
|
||||
|
||||
editors[cmd.name] = view
|
||||
|
||||
}
|
||||
|
||||
function baseExtensions(theme) {
|
||||
return [
|
||||
basicSetup,
|
||||
json(),
|
||||
theme,
|
||||
EditorView.updateListener.of(update => {
|
||||
if (update.docChanged) {
|
||||
const name = update.view.dom.dataset.command
|
||||
if (name && commandMap[name]) {
|
||||
commandMap[name].input = update.state.doc.toString()
|
||||
}
|
||||
}
|
||||
})
|
||||
]
|
||||
}
|
||||
|
||||
function updateEditorTheme() {
|
||||
|
||||
const dark = isDarkMode()
|
||||
currentThemeExtension = dark ? darkTheme : lightTheme
|
||||
|
||||
Object.values(editors).forEach(view => {
|
||||
|
||||
view.dispatch({
|
||||
effects: StateEffect.reconfigure.of(baseExtensions(currentThemeExtension))
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
function isDarkMode() {
|
||||
return document.documentElement.classList.contains('p-dark')
|
||||
}
|
||||
|
||||
let currentThemeExtension = isDarkMode() ? darkTheme : lightTheme
|
||||
|
||||
watch(() => props.deviceId, () => {
|
||||
Object.keys(commandMap).forEach(k => delete commandMap[k])
|
||||
commands.value = []
|
||||
@ -54,8 +155,6 @@ onMounted(() => {
|
||||
|
||||
mqtt2.subscribe('device/+/command/#', (payload, topic) => {
|
||||
|
||||
console.log(topic)
|
||||
|
||||
const parts = topic.split('/')
|
||||
|
||||
const device = parts[1]
|
||||
@ -68,11 +167,21 @@ onMounted(() => {
|
||||
updateCommand(device, command, 'description', payload)
|
||||
}
|
||||
if (field === 'schema') {
|
||||
updateCommand(device, command, 'schema', payload)
|
||||
const pretty = JSON.stringify(JSON.parse(payload), null, 2)
|
||||
updateCommand(device, command, 'schema', pretty)
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
const observer = new MutationObserver(() => {
|
||||
updateEditorTheme()
|
||||
})
|
||||
|
||||
observer.observe(document.documentElement, {
|
||||
attributes: true,
|
||||
attributeFilter: ['class']
|
||||
})
|
||||
|
||||
})
|
||||
</script>
|
||||
|
||||
@ -90,7 +199,7 @@ onMounted(() => {
|
||||
</template>
|
||||
<template #empty> No commands available.</template>
|
||||
<template #list="slotProps">
|
||||
<Accordion>
|
||||
<Accordion v-model:value="openTabs" @update:value="onAccordionChange">
|
||||
|
||||
<AccordionPanel
|
||||
v-for="cmd in slotProps.items"
|
||||
@ -107,11 +216,9 @@ onMounted(() => {
|
||||
<AccordionContent>
|
||||
<div class="command-body">
|
||||
|
||||
<Textarea
|
||||
v-model="cmd.input"
|
||||
rows="4"
|
||||
style="width:100%"
|
||||
:placeholder="cmd.schema || 'JSON arguments...'"
|
||||
<div
|
||||
class="json-editor"
|
||||
:ref="el => setEditorRef(cmd.name, el)"
|
||||
/>
|
||||
|
||||
<Button
|
||||
@ -153,4 +260,53 @@ onMounted(() => {
|
||||
padding-top: 0.5rem;
|
||||
}
|
||||
|
||||
.cm-editor {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.json-editor {
|
||||
border: 1px solid var(--surface-border);
|
||||
border-radius: var(--border-radius);
|
||||
background: var(--surface-card);
|
||||
}
|
||||
|
||||
/* editor root */
|
||||
.json-editor .cm-editor {
|
||||
font-family: var(--font-family);
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
/* content area */
|
||||
.json-editor .cm-content {
|
||||
padding: 0.75rem;
|
||||
caret-color: var(--text-color);
|
||||
}
|
||||
|
||||
/* background */
|
||||
.json-editor .cm-scroller {
|
||||
background: var(--surface-card);
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
/* cursor */
|
||||
.json-editor .cm-cursor {
|
||||
border-left: 2px solid var(--primary-color);
|
||||
}
|
||||
|
||||
/* selection */
|
||||
.json-editor .cm-selectionBackground {
|
||||
background: var(--highlight-bg);
|
||||
}
|
||||
|
||||
/* gutters if enabled later */
|
||||
.json-editor .cm-gutters {
|
||||
background: var(--surface-ground);
|
||||
border-right: 1px solid var(--surface-border);
|
||||
}
|
||||
|
||||
.json-editor .cm-editor.cm-focused {
|
||||
outline: 1px solid var(--primary-color);
|
||||
outline-offset: 0;
|
||||
}
|
||||
|
||||
</style>
|
||||
@ -3,6 +3,7 @@ import asyncio
|
||||
import inspect
|
||||
import paho
|
||||
import signal
|
||||
import json
|
||||
from dataclasses import dataclass
|
||||
|
||||
from command import (
|
||||
@ -63,7 +64,7 @@ class MQTTHandler:
|
||||
for name, command in self.get_available_commands().items():
|
||||
await self.mqtt_client.publish(
|
||||
f"{self.command_topic}/{command.name}/schema",
|
||||
str(command.schema),
|
||||
json.dumps(command.schema),
|
||||
qos=1,
|
||||
retain=True,
|
||||
)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user