added device selection widget
This commit is contained in:
parent
53d4fde672
commit
eec756b15e
@ -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>
|
||||||
|
|||||||
@ -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"
|
||||||
|
|||||||
91
console/src/components/dashboard/DevicesWidget.vue
Normal file
91
console/src/components/dashboard/DevicesWidget.vue
Normal 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 |
Loading…
Reference in New Issue
Block a user