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 CommandsWidget from "./components/dashboard/CommandsWidget.vue";
|
||||
|
||||
import { ref } from 'vue'
|
||||
import DevicesWidget from './components/dashboard/DevicesWidget.vue'
|
||||
|
||||
const selectedDevice = ref(null)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@ -16,16 +21,26 @@ import CommandsWidget from "./components/dashboard/CommandsWidget.vue";
|
||||
<div class="layout-container">
|
||||
<AppTopbar />
|
||||
<div class="layout-grid">
|
||||
<div class="layout-grid-row">
|
||||
<PropertiesWidget device-id="mediamtx-fedora" />
|
||||
<CommandsWidget device-id="example-gps-fedora" />
|
||||
<DevicesWidget @select="selectedDevice = $event" />
|
||||
<div v-if="selectedDevice" class="layout-grid-row">
|
||||
<PropertiesWidget
|
||||
v-if="selectedDevice"
|
||||
:key="'props-' + selectedDevice"
|
||||
:device-id="selectedDevice"
|
||||
/>
|
||||
|
||||
<CommandsWidget
|
||||
v-if="selectedDevice"
|
||||
:key="'cmds-' + selectedDevice"
|
||||
:device-id="selectedDevice"
|
||||
/>
|
||||
</div>
|
||||
<!-- <StatsWidget /> -->
|
||||
<!-- <div class="layout-grid-row">
|
||||
<SalesTrendWidget />
|
||||
<RecentActivityWidget />
|
||||
</div>
|
||||
<ProductOverviewWidget /> -->
|
||||
</div>-->
|
||||
<!-- <ProductOverviewWidget /> -->
|
||||
</div>
|
||||
<AppFooter />
|
||||
</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-links">
|
||||
<a
|
||||
href="https://git.jonotargett.com/mqttdevicemanager"
|
||||
href="https://git.jonotargett.com/jono/mqttdevicemanager"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
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