diff --git a/src/routes/app/all-devices/+page.svelte b/src/routes/app/all-devices/+page.svelte index 20504d98..ed414a9c 100644 --- a/src/routes/app/all-devices/+page.svelte +++ b/src/routes/app/all-devices/+page.svelte @@ -1,6 +1,6 @@ -
- -
-
+
+
+

All Devices

Manage and view all your monitoring locations

-
-
- - +
+
+
+ + +
@@ -53,67 +55,116 @@
{:then devices} {@const filteredDevices = filterDevices(devices)} -
- {#if filteredDevices.length > 0} + {#if filteredDevices.length > 0} + +
{#each filteredDevices as device, index (device.device_id || device.dev_eui || device.name || index)} -
-
-
- +
+
+
+

+ {device.name || device.dev_eui || 'Unnamed Device'} +

+

+ ID: {device.device_id || device.dev_eui || 'N/A'} +

-

- {device.name || device.dev_eui || 'Unnamed Device'} -

- + {#if device.location_id && device.dev_eui} + + View + + {:else} + View + {/if}
-
-
- {#if device.device_id || device.dev_eui} -
- - ID: {device.device_id || device.dev_eui || 'N/A'} -
- {/if} - {#if device.location_id} -
- - Location ID: {device.location_id} -
- {/if} - {#if device.cw_device_type?.name} -
- - Type: {device.cw_device_type.name} -
- {/if} +
+
+ Location + {device.location_id ?? 'N/A'}
+
+ Type + {device.cw_device_type?.name ?? 'N/A'} +
+ {#if device.dev_eui} +
+ DevEUI + {device.dev_eui} +
+ {/if}
-
+
{/each} - {:else} -
- -

- {searchTerm ? 'No devices match your search.' : 'No devices found.'} -

-
- {/if} -
+
+ {:else} +
+ +

+ {searchTerm ? 'No devices match your search.' : 'No devices found.'} +

+
+ {/if} {:catch error}

Error loading devices: {error.message}

@@ -122,18 +173,69 @@
diff --git a/src/routes/app/all-notifications/+page.svelte b/src/routes/app/all-notifications/+page.svelte index f2bd45e7..cb7e0666 100644 --- a/src/routes/app/all-notifications/+page.svelte +++ b/src/routes/app/all-notifications/+page.svelte @@ -49,26 +49,62 @@ ); const columns = [ - { key: 'name', label: 'Notification', width: 'w-72', align: 'left', sortable: true }, - { key: 'dev_eui', label: 'Device', width: 'w-48', align: 'left', sortable: true }, - { key: 'send_using', label: 'Channel', width: 'w-40', align: 'left', sortable: true }, + { + key: 'name', + label: 'Notification', + width: 'min-w-[14rem] md:w-72', + align: 'left', + sortable: true + }, + { + key: 'dev_eui', + label: 'Device', + width: 'min-w-[12rem] md:w-48', + align: 'left', + sortable: true + }, + { + key: 'send_using', + label: 'Channel', + width: 'min-w-[10rem] md:w-40', + align: 'left', + sortable: true + }, { key: 'action_recipient', label: 'Recipients', - width: 'flex-1', + width: 'flex-1 min-w-[16rem]', align: 'left', sortable: true }, - { key: 'trigger_count', label: 'Total Calls', width: 'w-32', align: 'right', sortable: true }, + { + key: 'trigger_count', + label: 'Total Calls', + width: 'min-w-[6rem] md:w-32', + align: 'right', + sortable: true + }, { key: 'last_triggered', label: 'Last Triggered', - width: 'w-48', + width: 'min-w-[12rem] md:w-48', align: 'left', sortable: true }, - { key: 'is_triggered', label: 'Status', width: 'w-32', align: 'center', sortable: true }, - { key: 'history', label: 'History', width: 'w-32', align: 'center', sortable: false } + { + key: 'is_triggered', + label: 'Status', + width: 'min-w-[7rem] md:w-32', + align: 'center', + sortable: true + }, + { + key: 'history', + label: 'History', + width: 'min-w-[6rem] md:w-32', + align: 'center', + sortable: false + } ] as const; function filterNotifications(list: NotificationRow[]): NotificationRow[] { @@ -177,7 +213,7 @@ } -
+
@@ -186,8 +222,8 @@ Review every alert in a single professional table and monitor performance at a glance.

-
-
+
+
-
-
+
+

Total notifications

{summaryStats.total}

-
+

Active right now

{summaryStats.active}

-
+

Total calls

{summaryStats.totalTriggers}

@@ -222,92 +258,170 @@
{#if tableNotifications.length} -
-
-
- {#each columns as column (column.key)} -
- {#if column.sortable} - + {:else} + {column.label} + {/if} +
+ {/each} +
+
+ +
+ {#each tableNotifications as notification (notification.id)} +
+
+

{notification.name || 'Untitled notification'}

+
+
+

+ {#if notification.cw_device} + + {formatDeviceLabel(notification)} + + {:else} + {formatDeviceLabel(notification)} + {/if} +

+
+
+

{formatChannel(notification)}

+
+
+

{formatRecipients(notification.action_recipient)}

+
+
+

{notification.trigger_count ?? 0}

+
+
+

{formatLastTriggered(notification.last_triggered)}

+
+
+ + {notification.is_triggered ? 'Active' : 'Idle'} + +
+
+ - {:else} - {column.label} - {/if} +
{/each}
- -
- {#each tableNotifications as notification (notification.id)} -
-
-

{notification.name || 'Untitled notification'}

-
-
-

- {#if notification.cw_device} - - {formatDeviceLabel(notification)} - - {:else} - {formatDeviceLabel(notification)} - {/if} +

+
+ {#each tableNotifications as notification (notification.id)} +
+
+
+

+ {notification.name || 'Untitled notification'}

+ {#if notification.cw_device} + + {formatDeviceLabel(notification)} + + {:else} +

+ {formatDeviceLabel(notification)} +

+ {/if}
-
-

{formatChannel(notification)}

-
-
-

{formatRecipients(notification.action_recipient)}

-
-
-

{notification.trigger_count ?? 0}

-
-
-

{formatLastTriggered(notification.last_triggered)}

+ + {notification.is_triggered ? 'Active' : 'Idle'} + +
+
+
+ Channel + {formatChannel(notification)}
-
- + Recipients + {formatRecipients(notification.action_recipient)} - {notification.is_triggered ? 'Active' : 'Idle'} -
-
- +
+
+ Last triggered + {formatLastTriggered(notification.last_triggered)}
- {/each} -
+
+ + {#if notification.cw_device} + + View device + + {/if} +
+
+ {/each}
{:else}
@@ -369,6 +483,12 @@ min-width: 280px; } + @media (max-width: 640px) { + .search-container { + min-width: 100%; + } + } + .search-input { width: 100%; padding: 0.5rem 0.75rem 0.5rem 2.5rem; @@ -390,12 +510,6 @@ color: rgb(156 163 175); } - .stats-grid { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); - gap: 1rem; - } - .stat-card { padding: 1rem 1.25rem; border-radius: 0.75rem; @@ -420,7 +534,7 @@ } .table-shell { - overflow: hidden; + overflow-y: hidden; border: 1px solid rgb(229 231 235); border-radius: 1rem; background: white; @@ -452,6 +566,7 @@ gap: 0.5rem; padding: 0.85rem 1rem; font-size: 0.9rem; + flex-shrink: 0; } .table-body .table-row:nth-child(odd) { diff --git a/src/routes/app/all-reports/+page.svelte b/src/routes/app/all-reports/+page.svelte index a10c780f..7414f7f5 100644 --- a/src/routes/app/all-reports/+page.svelte +++ b/src/routes/app/all-reports/+page.svelte @@ -5,6 +5,7 @@ import { Dialog, DateRangePicker } from 'bits-ui'; import type { DateRange } from 'bits-ui'; import { CalendarDate } from '@internationalized/date'; + import type { DateValue } from '@internationalized/date'; import { mdiAlert, mdiDownload, mdiFileDocument, mdiMagnify } from '$lib/icons/mdi'; import ExportButton from '$lib/components/devices/ExportButton.svelte'; import { onMount } from 'svelte'; @@ -38,7 +39,8 @@ let bulkDownloading = $state(false); let bulkProgress = $state(null); - let selectAllCheckbox: HTMLInputElement | null = null; + let selectAllCheckbox = $state(null); + let mobileSelectAllCheckbox = $state(null); function filterReports(currentReports: any[]) { if (!searchTerm.trim()) return currentReports; @@ -77,8 +79,12 @@ }); $effect(() => { - if (!selectAllCheckbox) return; - selectAllCheckbox.indeterminate = someVisibleSelected; + const checkboxes = [selectAllCheckbox, mobileSelectAllCheckbox].filter( + (checkbox): checkbox is HTMLInputElement => Boolean(checkbox) + ); + for (const checkbox of checkboxes) { + checkbox.indeterminate = someVisibleSelected; + } }); function setSelectedReports(ids: number[]) { @@ -309,7 +315,11 @@ return new CalendarDate(date.getFullYear(), date.getMonth() + 1, date.getDate()); } - function calendarDateToDate(calendarDate: CalendarDate): Date { + function calendarDateToDate(value: DateValue): Date { + if ('toDate' in value && typeof value.toDate === 'function') { + return value.toDate('UTC'); + } + const calendarDate = value as CalendarDate; return new Date(calendarDate.year, calendarDate.month - 1, calendarDate.day); } @@ -343,18 +353,22 @@ } -
-
-
+
+
+

{$_('all_reports_heading')}

{$_('all_reports_subheading')}

-
+
- +
+
+ {$_('selection')} + +
+ @@ -503,14 +532,14 @@
+
+ {#each filteredReports as report (report.id)} + + {/each}
{:else}
@@ -607,8 +701,52 @@