added device selection widget

This commit is contained in:
Jono Targett 2026-03-18 18:14:00 +10:30
parent 53d4fde672
commit eec756b15e
4 changed files with 112 additions and 6 deletions

View File

@ -8,6 +8,11 @@ import ProductOverviewWidget from "./components/dashboard/ProductOverviewWidget.
import PropertiesWidget from "./components/dashboard/PropertiesWidget.vue"; import PropertiesWidget from "./components/dashboard/PropertiesWidget.vue";
import CommandsWidget from "./components/dashboard/CommandsWidget.vue"; import CommandsWidget from "./components/dashboard/CommandsWidget.vue";
import { ref } from 'vue'
import DevicesWidget from './components/dashboard/DevicesWidget.vue'
const selectedDevice = ref(null)
</script> </script>
<template> <template>
@ -16,16 +21,26 @@ import CommandsWidget from "./components/dashboard/CommandsWidget.vue";
<div class="layout-container"> <div class="layout-container">
<AppTopbar /> <AppTopbar />
<div class="layout-grid"> <div class="layout-grid">
<div class="layout-grid-row"> <DevicesWidget @select="selectedDevice = $event" />
<PropertiesWidget device-id="mediamtx-fedora" /> <div v-if="selectedDevice" class="layout-grid-row">
<CommandsWidget device-id="example-gps-fedora" /> <PropertiesWidget
v-if="selectedDevice"
:key="'props-' + selectedDevice"
:device-id="selectedDevice"
/>
<CommandsWidget
v-if="selectedDevice"
:key="'cmds-' + selectedDevice"
:device-id="selectedDevice"
/>
</div> </div>
<!-- <StatsWidget /> --> <!-- <StatsWidget /> -->
<!-- <div class="layout-grid-row"> <!-- <div class="layout-grid-row">
<SalesTrendWidget /> <SalesTrendWidget />
<RecentActivityWidget /> <RecentActivityWidget />
</div> </div>-->
<ProductOverviewWidget /> --> <!-- <ProductOverviewWidget /> -->
</div> </div>
<AppFooter /> <AppFooter />
</div> </div>

View File

@ -4,7 +4,7 @@
<div class="footer-copyright">Jono made this by blatantly copy-pasting from the example projects and vibe-coding the rest</div> <div class="footer-copyright">Jono made this by blatantly copy-pasting from the example projects and vibe-coding the rest</div>
<div class="footer-links"> <div class="footer-links">
<a <a
href="https://git.jonotargett.com/mqttdevicemanager" href="https://git.jonotargett.com/jono/mqttdevicemanager"
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
class="footer-link" class="footer-link"

View File

@ -0,0 +1,91 @@
<script setup>
import { ref, onMounted } from 'vue'
import MQTTService from '../../services/mqtt.js'
const emit = defineEmits(['select'])
const mqtt = new MQTTService()
const devices = ref([])
const deviceSet = new Set()
const selected = ref(null)
function upsertDevice(device, status) {
const existing = devices.value.find(d => d.id === device)
if (existing) {
// update reactively
existing.value = status
} else {
deviceSet.add(device)
devices.value = [
...devices.value,
{
id: device,
title: device,
value: status,
subtitle: 'MQTT Device',
icon: status === "ONLINE" ? 'pi-check-circle' : 'pi-times-circle'
}
]
}
}
function selectDevice(device) {
selected.value = device.id
emit('select', device.id)
}
onMounted(() => {
mqtt.subscribe('device/+/property/status', (payload, topic) => {
const parts = topic.split('/')
const device = parts[1]
upsertDevice(device, payload)
})
})
</script>
<template>
<div class="layout-grid-row">
<div
v-for="(device, index) in devices"
:key="device.id"
class="layout-card device-card"
:class="{ 'selected-device': device.id === selected }"
@click="selectDevice(device)"
>
<div class="stats-header">
<span class="stats-title">{{ device.title }}</span>
<span class="stats-icon-box">
<i :class="[
'pi',
device.value === 'ONLINE' ? 'pi-check-circle' : 'pi-times-circle',
device.value === 'ONLINE' ? '' : 'text-red-500'
]"></i>
</span>
</div>
<div class="stats-content">
<div class="stats-value">{{ device.value }}</div>
<div class="stats-subtitle">{{ device.subtitle }}</div>
</div>
</div>
</div>
</template>
<style scoped>
.device-card {
cursor: pointer;
transition: all 0.2s ease;
}
.device-card:hover {
transform: translateY(-2px);
}
/* 🔥 selected state */
.selected-device {
border: 2px solid var(--p-primary-color);
box-shadow: 0 0 8px var(--p-primary-color);
}
</style>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 136 KiB

After

Width:  |  Height:  |  Size: 165 KiB