CommandsWidget working at a bare minimum level

This commit is contained in:
Jono Targett 2026-03-16 08:05:10 +10:30
parent 566f02ede4
commit 97870827e7
3 changed files with 117 additions and 1 deletions

View File

@ -7,6 +7,7 @@ import RecentActivityWidget from "./components/dashboard/RecentActivityWidget.vu
import ProductOverviewWidget from "./components/dashboard/ProductOverviewWidget.vue";
import PropertiesWidget from "./components/dashboard/PropertiesWidget.vue";
import CommandsWidget from "./components/dashboard/CommandsWidget.vue";
</script>
<template>
@ -14,6 +15,7 @@ import PropertiesWidget from "./components/dashboard/PropertiesWidget.vue";
<AppTopbar />
<div class="layout-grid">
<PropertiesWidget device-id="example-gps-fedora" />
<CommandsWidget device-id="example-gps-fedora" />
<StatsWidget />
<!-- <div class="layout-grid-row">
<SalesTrendWidget />

View File

@ -0,0 +1,114 @@
<script setup>
import { ref, reactive, watch, onMounted } from 'vue'
import MQTTService from '../../services/mqtt.js'
const props = defineProps({
deviceId: String
})
const mqtt2 = new MQTTService()
const filters = ref({})
const filterMode = ref({ label: 'Lenient', value: 'lenient' });
const commands = ref([])
const commandMap = reactive({})
function rebuildList() {
commands.value = Object.values(commandMap)
}
function updateCommand(device, name, field, value) {
if (!commandMap[name]) {
commandMap[name] = {
name,
description: '',
input: ''
}
}
commandMap[name][field] = value
rebuildList()
}
function sendCommand(cmd) {
const topic = `device/${props.deviceId}/command/${cmd.name}`
mqtt2.publish(topic, JSON.stringify(cmd.input))
}
watch(() => props.deviceId, () => {
Object.keys(commandMap).forEach(k => delete commandMap[k])
commands.value = []
})
onMounted(() => {
mqtt2.subscribe('device/+/command/#', (payload, topic) => {
console.log(topic)
const parts = topic.split('/')
const device = parts[1]
if (device !== props.deviceId) return
const command = parts[3]
const field = parts[4]
if (field === 'description') {
updateCommand(device, command, 'description', payload)
}
})
})
</script>
<template>
<div class="layout-card">
<DataView :value="commands">
<template #header>
<div class="flex products-header">
<span class="products-title">Commands</span>
<IconField class="search-field">
<InputIcon class="pi pi-search" />
<InputText v-model="filters['global']" placeholder="Filter by..." />
</IconField>
</div>
</template>
<template #empty> No commands available.</template>
<template #list="slotProps">
<div
v-for="cmd in slotProps.items"
:key="cmd.name"
class="p-card p-mb-3"
style="padding:1rem"
>
<h3>{{ cmd.name }}</h3>
<p>{{ cmd.description }}</p>
<Textarea
v-model="cmd.input"
rows="3"
style="width:100%"
placeholder="JSON arguments..."
/>
<Button
label="Send Command"
icon="pi pi-send"
class="p-mt-2"
@click="sendCommand(cmd)"
/>
</div>
</template>
</DataView>
</div>
</template>

View File

@ -96,7 +96,7 @@ onMounted(() => {
<template>
<div class="card">
<div class="layout-card">
<TreeTable :value="nodes" :filters="filters" :filterMode="filterMode.value">
<template #header>
<div class="flex products-header">