Skip to content

Commit c76541d

Browse files
committed
refactor(ui): remove stats store usage from device UI components
Replace deprecated statsStore with values from devicesStore across DevicesDropdown and Home views. Adds fetchDeviceCounts to devicesStore for centralized device stats management. Updates all affected tests. BREAKING CHANGE: statsStore is no longer used in device-related views
1 parent fb2c7ce commit c76541d

5 files changed

Lines changed: 224 additions & 292 deletions

File tree

ui/src/components/AppBar/DevicesDropdown.vue

Lines changed: 60 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
<template>
22
<v-badge
3-
:model-value="pendingDevicesCount > 0"
4-
:content="pendingDevicesCount"
3+
:model-value="pendingDevices > 0"
4+
:content="pendingDevices"
55
offset-y="-5"
66
location="top right"
77
color="success"
88
size="x-small"
99
data-test="device-dropdown-badge"
10-
:class="{ 'mr-1': pendingDevicesCount > 0 }"
10+
:class="{ 'mr-1': pendingDevices > 0 }"
1111
>
1212
<v-icon
1313
color="primary"
@@ -47,12 +47,11 @@
4747
variant="tonal"
4848
data-test="total-devices-card"
4949
>
50-
<div class="text-h4 font-weight-bold">
51-
{{ stats.registered_devices }}
52-
</div>
50+
<div class="text-h4 font-weight-bold">{{ totalDevices }}</div>
5351
<div class="text-caption text-medium-emphasis">Total</div>
5452
</v-card>
5553
</v-col>
54+
5655
<v-col
5756
cols="6"
5857
sm="3"
@@ -62,12 +61,11 @@
6261
variant="tonal"
6362
data-test="online-devices-card"
6463
>
65-
<div class="text-h4 font-weight-bold">
66-
{{ stats.online_devices }}
67-
</div>
64+
<div class="text-h4 font-weight-bold">{{ onlineDevices }}</div>
6865
<div class="text-caption text-medium-emphasis">Online</div>
6966
</v-card>
7067
</v-col>
68+
7169
<v-col
7270
cols="6"
7371
sm="3"
@@ -77,12 +75,11 @@
7775
variant="tonal"
7876
data-test="pending-devices-card"
7977
>
80-
<div class="text-h4 font-weight-bold">
81-
{{ stats.pending_devices }}
82-
</div>
78+
<div class="text-h4 font-weight-bold">{{ pendingDevices }}</div>
8379
<div class="text-caption text-medium-emphasis">Pending</div>
8480
</v-card>
8581
</v-col>
82+
8683
<v-col
8784
cols="6"
8885
sm="3"
@@ -92,13 +89,12 @@
9289
variant="tonal"
9390
data-test="offline-devices-card"
9491
>
95-
<div class="text-h4 font-weight-bold">
96-
{{ offlineDevices }}
97-
</div>
92+
<div class="text-h4 font-weight-bold">{{ offlineDevices }}</div>
9893
<div class="text-caption text-medium-emphasis">Offline</div>
9994
</v-card>
10095
</v-col>
10196
</v-row>
97+
10298
<v-btn-toggle
10399
v-model="activeTab"
104100
mandatory
@@ -120,14 +116,15 @@
120116
/>
121117
<span v-if="smAndUp">Pending Approval</span>
122118
<v-chip
123-
v-if="stats.pending_devices > 0"
119+
v-if="pendingDevices > 0"
124120
color="warning"
125121
size="x-small"
126122
class="ml-2"
127123
>
128-
{{ stats.pending_devices }}
124+
{{ pendingDevices }}
129125
</v-chip>
130126
</v-btn>
127+
131128
<v-btn
132129
value="recent"
133130
data-test="recent-tab"
@@ -141,6 +138,7 @@
141138
<span v-if="smAndUp">Recent Activity</span>
142139
</v-btn>
143140
</v-btn-toggle>
141+
144142
<v-window
145143
v-model="activeTab"
146144
class="overflow-visible"
@@ -151,7 +149,7 @@
151149
class="overflow-y-auto border"
152150
>
153151
<v-list
154-
v-if="pendingDevicesCount > 0"
152+
v-if="pendingDevicesList.length > 0"
155153
density="compact"
156154
class="bg-v-theme-surface pa-0"
157155
>
@@ -232,12 +230,8 @@
232230
color="success"
233231
class="opacity-50 mb-3"
234232
/>
235-
<p class="text-body-2 text-medium-emphasis">
236-
No pending devices
237-
</p>
238-
<p class="text-caption text-disabled mt-1">
239-
All devices have been approved
240-
</p>
233+
<p class="text-body-2 text-medium-emphasis">No pending devices</p>
234+
<p class="text-caption text-disabled mt-1">All devices have been approved</p>
241235
</div>
242236
</v-card>
243237
</v-window-item>
@@ -292,9 +286,7 @@
292286
color="primary"
293287
class="opacity-50 mb-3"
294288
/>
295-
<p class="text-body-2 text-medium-emphasis">
296-
No recent activity
297-
</p>
289+
<p class="text-body-2 text-medium-emphasis">No recent activity</p>
298290
</div>
299291
</v-card>
300292
</v-window-item>
@@ -322,77 +314,79 @@
322314
<script setup lang="ts">
323315
import { computed, onBeforeMount, ref } from "vue";
324316
import { useDisplay } from "vuetify";
325-
import useStatsStore from "@/store/modules/stats";
326317
import useDevicesStore from "@/store/modules/devices";
327318
import handleError from "@/utils/handleError";
328319
import useSnackbar from "@/helpers/snackbar";
329320
import moment from "moment";
330-
import { IDevice } from "@/interfaces/IDevice";
321+
import type { IDevice } from "@/interfaces/IDevice";
331322
import DeviceActionButton from "@/components/Devices/DeviceActionButton.vue";
332323
333324
const { smAndUp, thresholds } = useDisplay();
334-
const statsStore = useStatsStore();
335325
const devicesStore = useDevicesStore();
336326
const snackbar = useSnackbar();
337327
338328
const isDrawerOpen = ref(false);
339329
const activeTab = ref<"pending" | "recent">("pending");
330+
331+
const totalDevices = computed(() => devicesStore.totalDevicesCount);
332+
const onlineDevices = computed(() => devicesStore.onlineDevicesCount);
333+
const offlineDevices = computed(() => devicesStore.offlineDevicesCount);
334+
const pendingDevices = computed(() => devicesStore.pendingDevicesCount);
335+
340336
const pendingDevicesList = ref<IDevice[]>([]);
341-
const pendingDevicesCount = computed(() => pendingDevicesList.value.length);
342337
const recentDevicesList = ref<IDevice[]>([]);
343-
const stats = computed(() => statsStore.stats);
344-
const offlineDevices = computed(
345-
() => stats.value.registered_devices - stats.value.online_devices,
346-
);
338+
347339
const toggleDrawer = () => {
348340
isDrawerOpen.value = !isDrawerOpen.value;
349341
};
350342
351-
const formatTimeAgo = (date: string | Date) => {
352-
if (!date) return "Unknown";
353-
return moment(date).fromNow();
354-
};
355-
356-
const handleUpdate = async () => {
357-
await fetchStats();
358-
await fetchPendingDevices();
359-
await fetchRecentDevices();
360-
};
361-
362-
const fetchStats = async () => {
363-
try {
364-
await statsStore.fetchStats();
365-
} catch (error: unknown) {
366-
snackbar.showError("Failed to load device statistics");
367-
handleError(error);
368-
}
369-
};
343+
const formatTimeAgo = (date: string | Date) =>
344+
date ? moment(date).fromNow() : "Unknown";
370345
371346
const fetchPendingDevices = async () => {
372347
try {
373-
await devicesStore.fetchDeviceList({ status: "pending", perPage: 100 });
348+
await devicesStore.fetchDeviceList({
349+
status: "pending",
350+
perPage: 100,
351+
filter: undefined,
352+
});
374353
pendingDevicesList.value = [...devicesStore.devices];
375-
} catch (error: unknown) {
376-
handleError(error);
354+
} catch (e) {
355+
snackbar.showError("Failed to load pending devices");
356+
handleError(e);
377357
}
378358
};
379359
380360
const fetchRecentDevices = async () => {
381361
try {
382-
await devicesStore.fetchDeviceList({ status: "accepted" });
362+
await devicesStore.fetchDeviceList({
363+
status: "accepted",
364+
perPage: 100,
365+
filter: undefined,
366+
});
383367
recentDevicesList.value = [...devicesStore.devices].sort(
384368
(a, b) =>
385369
new Date(b.last_seen).getTime() - new Date(a.last_seen).getTime(),
386370
);
387-
} catch (error: unknown) {
388-
handleError(error);
371+
} catch (e) {
372+
snackbar.showError("Failed to load recent devices");
373+
handleError(e);
374+
}
375+
};
376+
377+
const handleUpdate = async () => {
378+
try {
379+
await devicesStore.fetchDeviceCounts();
380+
await fetchPendingDevices();
381+
await fetchRecentDevices();
382+
} catch (e) {
383+
snackbar.showError("Failed to update device data");
384+
handleError(e);
389385
}
390386
};
391387
392388
onBeforeMount(async () => {
393-
await fetchStats();
394-
await fetchPendingDevices();
395-
await fetchRecentDevices();
389+
await handleUpdate();
396390
});
397391
398392
defineExpose({
@@ -403,7 +397,9 @@ defineExpose({
403397
activeTab,
404398
pendingDevicesList,
405399
recentDevicesList,
406-
stats,
400+
totalDevices,
401+
onlineDevices,
407402
offlineDevices,
403+
pendingDevices,
408404
});
409405
</script>

ui/src/store/modules/devices.ts

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,15 @@ const useDevicesStore = defineStore("devices", () => {
99
const device = ref<IDevice>({} as IDevice);
1010
const showDevices = ref<boolean>(false);
1111
const deviceCount = ref<number>(0);
12+
13+
const totalDevicesCount = ref<number>(0);
14+
const onlineDevicesCount = ref<number>(0);
15+
const offlineDevicesCount = ref<number>(0);
16+
const pendingDevicesCount = ref<number>(0);
17+
1218
const duplicatedDeviceName = ref<string>("");
1319
const deviceListFilter = ref<string>();
14-
1520
const onlineDevices = ref<Array<IDevice>>([]);
16-
1721
const showDeviceChooser = ref<boolean>(false);
1822
const suggestedDevices = ref<Array<IDevice>>([]);
1923
const selectedDevices = ref<Array<IDevice>>([]);
@@ -40,6 +44,26 @@ const useDevicesStore = defineStore("devices", () => {
4044
}
4145
};
4246

47+
const fetchDeviceCounts = async () => {
48+
const acceptedRes = await devicesApi.fetchDevices(1, 1, "accepted");
49+
totalDevicesCount.value = parseInt(acceptedRes.headers["x-total-count"] as string, 10);
50+
51+
const pendingRes = await devicesApi.fetchDevices(1, 1, "pending");
52+
pendingDevicesCount.value = parseInt(pendingRes.headers["x-total-count"] as string, 10);
53+
54+
const onlineFilter = Buffer.from(JSON.stringify([
55+
{ type: "property", params: { name: "online", operator: "eq", value: true } },
56+
])).toString("base64");
57+
const onlineRes = await devicesApi.fetchDevices(1, 1, "accepted", onlineFilter);
58+
onlineDevicesCount.value = parseInt(onlineRes.headers["x-total-count"] as string, 10);
59+
60+
const offlineFilter = Buffer.from(JSON.stringify([
61+
{ type: "property", params: { name: "online", operator: "eq", value: false } },
62+
])).toString("base64");
63+
const offlineRes = await devicesApi.fetchDevices(1, 1, "accepted", offlineFilter);
64+
offlineDevicesCount.value = parseInt(offlineRes.headers["x-total-count"] as string, 10);
65+
};
66+
4367
const setDeviceListVisibility = async () => {
4468
const { headers } = await devicesApi.fetchDevices(1, 1);
4569
if (parseInt(headers["x-total-count"] as string, 10)) showDevices.value = true;
@@ -117,14 +141,18 @@ const useDevicesStore = defineStore("devices", () => {
117141
device,
118142
showDevices,
119143
deviceCount,
144+
totalDevicesCount,
145+
onlineDevicesCount,
146+
offlineDevicesCount,
147+
pendingDevicesCount,
120148
onlineDevices,
121149
showDeviceChooser,
122150
suggestedDevices,
123151
selectedDevices,
124152
duplicatedDeviceName,
125153
deviceListFilter,
126-
127154
fetchDeviceList,
155+
fetchDeviceCounts,
128156
setDeviceListVisibility,
129157
fetchOnlineDevices,
130158
removeDevice,

0 commit comments

Comments
 (0)