|
2 | 2 | import { DownloadCloud, RotateCcw } from '@lucide/svelte'; |
3 | 3 | import { page } from '$app/state'; |
4 | 4 | import { hubManagementV1Api } from '$lib/api'; |
5 | | - import { |
6 | | - type OtaItem, |
7 | | - type OtaItemIReadOnlyCollectionLegacyDataResponse, |
8 | | - OtaUpdateStatus, |
9 | | - } from '$lib/api/internal/v1'; |
| 5 | + import { type OtaItem, OtaUpdateStatus } from '$lib/api/internal/v1'; |
10 | 6 | import Container from '$lib/components/Container.svelte'; |
11 | 7 | import FirmwareChannelSelector from '$lib/components/FirmwareChannelSelector.svelte'; |
12 | 8 | import Button from '$lib/components/ui/button/button.svelte'; |
|
19 | 15 | import { cn } from '$lib/utils'; |
20 | 16 | import { NumberToHexPadded } from '$lib/utils/convert'; |
21 | 17 |
|
22 | | - let hubId = $derived(page.params.hubId); |
23 | | - let hub = $derived<HubOnlineState>( |
24 | | - $OnlineHubsStore.get(hubId) ?? { |
25 | | - hubId, |
26 | | - isOnline: false, |
27 | | - firmwareVersion: null, |
28 | | - otaInstall: null, |
29 | | - } |
30 | | - ); |
31 | | -
|
32 | | - let isValidHubId = $state(false); |
| 18 | + let hub = $state<HubOnlineState | null>(null); |
33 | 19 | let otaLogs = $state<OtaItem[]>([]); |
34 | 20 | let version = $state<string | null>(null); |
35 | 21 |
|
36 | | - function handleGetOtaUpdateHistoryResponse(resp: OtaItemIReadOnlyCollectionLegacyDataResponse) { |
37 | | - otaLogs = resp.data ?? []; |
38 | | - isValidHubId = true; |
39 | | - } |
40 | | -
|
41 | 22 | function startUpdate() { |
42 | | - if (!isValidHubId || $SignalR_Connection === null || version === null) return; |
43 | | - $SignalR_Connection.invoke('OtaInstall', hubId, version); |
| 23 | + if ($SignalR_Connection === null || hub === null || version === null) return; |
| 24 | + $SignalR_Connection.invoke('OtaInstall', hub.hubId, version); |
44 | 25 | } |
45 | 26 |
|
46 | | - $effect(() => { |
| 27 | + let isLoading = $state<boolean>(false); |
| 28 | + function fetchOtaLogs(hubId: string | undefined) { |
| 29 | + if (hubId === undefined) { |
| 30 | + hub = null; |
| 31 | + return; |
| 32 | + } |
| 33 | +
|
| 34 | + isLoading = true; |
47 | 35 | hubManagementV1Api |
48 | 36 | .devicesOtaGetOtaUpdateHistory(hubId) |
49 | | - .then(handleGetOtaUpdateHistoryResponse) |
50 | | - .catch(handleApiError); |
51 | | - }); |
| 37 | + .then((resp) => { |
| 38 | + if (resp.data === null) { |
| 39 | + hub = null; |
| 40 | + return; |
| 41 | + } |
| 42 | +
|
| 43 | + hub = $OnlineHubsStore.get(hubId) ?? { |
| 44 | + hubId, |
| 45 | + isOnline: false, |
| 46 | + firmwareVersion: null, |
| 47 | + otaInstall: null, |
| 48 | + }; |
| 49 | + otaLogs = resp.data; |
| 50 | + }) |
| 51 | + .catch(handleApiError) |
| 52 | + .finally(() => (isLoading = false)); |
| 53 | + } |
| 54 | +
|
| 55 | + $effect(() => fetchOtaLogs(page.params.hubId)); |
52 | 56 | </script> |
53 | 57 |
|
54 | 58 | <Container> |
55 | 59 | <Card.Header> |
56 | 60 | <Card.Title class="flex items-center justify-between space-x-2 text-3xl">Update Hub</Card.Title> |
57 | 61 | </Card.Header> |
58 | 62 | <Card.Content class="flex flex-col space-y-3"> |
59 | | - <div> |
60 | | - {#if hub.isOnline} |
61 | | - <p class="text-green-500">Status: Online</p> |
62 | | - {:else} |
63 | | - <p class="text-red-500">Status: Offline</p> |
64 | | - {/if} |
65 | | - <p>Firmware Version: {hub.firmwareVersion}</p> |
66 | | - </div> |
| 63 | + {#if hub} |
| 64 | + <div> |
| 65 | + {#if hub.isOnline} |
| 66 | + <p class="text-green-500">Status: Online</p> |
| 67 | + {:else} |
| 68 | + <p class="text-red-500">Status: Offline</p> |
| 69 | + {/if} |
| 70 | + <p>Firmware Version: {hub.firmwareVersion}</p> |
| 71 | + </div> |
67 | 72 |
|
68 | | - <FirmwareChannelSelector bind:version /> |
| 73 | + <FirmwareChannelSelector bind:version /> |
69 | 74 |
|
70 | | - <Button class="cursor-pointer text-xl" onclick={startUpdate} disabled={!isValidHubId}> |
71 | | - <DownloadCloud /> |
72 | | - <span> Update to {version} </span> |
73 | | - </Button> |
| 75 | + <Button |
| 76 | + class="cursor-pointer text-xl" |
| 77 | + onclick={startUpdate} |
| 78 | + disabled={$SignalR_Connection === null || hub === null || version === null || !hub.isOnline} |
| 79 | + > |
| 80 | + <DownloadCloud /> |
| 81 | + <span> Update to {version} </span> |
| 82 | + </Button> |
74 | 83 |
|
75 | | - <h2 class="text-3xl font-semibold">Progress</h2> |
76 | | - <div class="grid grid-cols-[auto_1fr] grid-rows-2 items-center gap-2"> |
77 | | - Total |
78 | | - <Progress value={33} /> |
79 | | - Task |
80 | | - <Progress value={(hub.otaInstall?.progress ?? 0) * 100} /> |
81 | | - </div> |
82 | | - <p>{hub.otaInstall?.task}</p> |
83 | | - <p>Flashing...</p> |
| 84 | + <h2 class="text-3xl font-semibold">Progress</h2> |
| 85 | + <div class="grid grid-cols-[auto_1fr] grid-rows-2 items-center gap-2"> |
| 86 | + Total |
| 87 | + <Progress value={33} /> |
| 88 | + Task |
| 89 | + <Progress value={(hub.otaInstall?.progress ?? 0) * 100} /> |
| 90 | + </div> |
| 91 | + <p>{hub.otaInstall?.task}</p> |
| 92 | + <p>Flashing...</p> |
84 | 93 |
|
85 | | - <div class="flex w-full justify-between"> |
86 | | - <h2 class="text-3xl font-semibold">Logs</h2> |
87 | | - <Button class="cursor-pointer text-xl" onclick={() => (hubId = hubId)}> |
88 | | - <RotateCcw /> |
89 | | - <span> Refresh Logs </span> |
90 | | - </Button> |
91 | | - </div> |
92 | | - <Table.Root class="border-2"> |
93 | | - <Table.Header> |
94 | | - <Table.Row> |
95 | | - <Table.Head>ID</Table.Head> |
96 | | - <Table.Head>Started At</Table.Head> |
97 | | - <Table.Head>Status</Table.Head> |
98 | | - <Table.Head>Version</Table.Head> |
99 | | - </Table.Row> |
100 | | - </Table.Header> |
101 | | - <Table.Body> |
102 | | - {#each otaLogs as otaLog (otaLog.id)} |
| 94 | + <div class="flex w-full justify-between"> |
| 95 | + <h2 class="text-3xl font-semibold">Logs</h2> |
| 96 | + <Button |
| 97 | + class="cursor-pointer text-xl" |
| 98 | + onclick={() => fetchOtaLogs(page.params.hubId)} |
| 99 | + disabled={isLoading} |
| 100 | + > |
| 101 | + <RotateCcw /> |
| 102 | + <span> Refresh Logs </span> |
| 103 | + </Button> |
| 104 | + </div> |
| 105 | + <Table.Root class="border-2"> |
| 106 | + <Table.Header> |
103 | 107 | <Table.Row> |
104 | | - <Table.Cell class="font-mono text-blue-200"> |
105 | | - {NumberToHexPadded(otaLog.id, 8)} |
106 | | - </Table.Cell> |
107 | | - <Table.Cell class="font-medium">{otaLog.startedAt.toDateString()}</Table.Cell> |
108 | | - <Table.Cell |
109 | | - class={cn('font-medium', { |
110 | | - 'text-red-500': otaLog.status !== OtaUpdateStatus.Finished, |
111 | | - })} |
112 | | - > |
113 | | - {otaLog.status} |
114 | | - </Table.Cell> |
115 | | - <Table.Cell class="font-medium">{otaLog.version}</Table.Cell> |
| 108 | + <Table.Head>ID</Table.Head> |
| 109 | + <Table.Head>Started At</Table.Head> |
| 110 | + <Table.Head>Status</Table.Head> |
| 111 | + <Table.Head>Version</Table.Head> |
116 | 112 | </Table.Row> |
117 | | - {/each} |
118 | | - </Table.Body> |
119 | | - </Table.Root> |
| 113 | + </Table.Header> |
| 114 | + <Table.Body> |
| 115 | + {#each otaLogs as otaLog (otaLog.id)} |
| 116 | + <Table.Row> |
| 117 | + <Table.Cell class="font-mono text-blue-200"> |
| 118 | + {NumberToHexPadded(otaLog.id, 8)} |
| 119 | + </Table.Cell> |
| 120 | + <Table.Cell class="font-medium">{otaLog.startedAt.toDateString()}</Table.Cell> |
| 121 | + <Table.Cell |
| 122 | + class={cn('font-medium', { |
| 123 | + 'text-red-500': otaLog.status !== OtaUpdateStatus.Finished, |
| 124 | + })} |
| 125 | + > |
| 126 | + {otaLog.status} |
| 127 | + </Table.Cell> |
| 128 | + <Table.Cell class="font-medium">{otaLog.version}</Table.Cell> |
| 129 | + </Table.Row> |
| 130 | + {/each} |
| 131 | + </Table.Body> |
| 132 | + </Table.Root> |
| 133 | + {/if} |
120 | 134 | </Card.Content> |
121 | 135 | </Container> |
0 commit comments