From 371ce48aa4c21d05faab0a4a80d0ec3860db3720 Mon Sep 17 00:00:00 2001 From: arandomogg Date: Sat, 30 May 2026 02:52:35 +0100 Subject: [PATCH] feat: telemetry consent, webhook delivery log panel, responsive tables, offline tx prep --- admin-dashboard/app/admin/dashboard/page.tsx | 8 +- .../components/dashboard/ResponsiveTables.tsx | 1 + .../components/dashboard/StatusBadge.tsx | 15 +- .../dashboard/WebhookDeliveryLog.tsx | 261 ++++++++++-------- .../lib/webhook-delivery-logs-data.test.ts | 71 +++++ .../lib/webhook-delivery-logs-data.ts | 102 ++++--- client/src/index.ts | 11 + client/src/offline-tx.ts | 130 +++++++++ .../testUtils/__tests__/offline-tx.test.ts | 130 +++++++++ 9 files changed, 577 insertions(+), 152 deletions(-) create mode 100644 admin-dashboard/lib/webhook-delivery-logs-data.test.ts create mode 100644 client/src/offline-tx.ts create mode 100644 client/src/testUtils/__tests__/offline-tx.test.ts diff --git a/admin-dashboard/app/admin/dashboard/page.tsx b/admin-dashboard/app/admin/dashboard/page.tsx index 297b8317..3f8edfdf 100644 --- a/admin-dashboard/app/admin/dashboard/page.tsx +++ b/admin-dashboard/app/admin/dashboard/page.tsx @@ -16,6 +16,7 @@ import { getFeeMultiplierData } from "@/lib/fee-multiplier-data"; import { FeeEstimatorWidget } from "@/components/dashboard/FeeEstimatorWidget"; import { ExpenseBreakdown } from "@/components/dashboard/ExpenseBreakdown"; import { getExpenseBreakdownData } from "@/lib/expense-breakdown-data"; +import { TelemetryConsentSettings } from "@/components/dashboard/TelemetryConsentSettings"; export default async function AdminDashboard() { const session = await auth(); @@ -113,8 +114,13 @@ export default async function AdminDashboard() { +
+ +
+ {/* Tables */}
+
); -} \ No newline at end of file +} diff --git a/admin-dashboard/components/dashboard/ResponsiveTables.tsx b/admin-dashboard/components/dashboard/ResponsiveTables.tsx index 80089e05..541a21f2 100644 --- a/admin-dashboard/components/dashboard/ResponsiveTables.tsx +++ b/admin-dashboard/components/dashboard/ResponsiveTables.tsx @@ -122,6 +122,7 @@ export function TransactionsTable({ return ( +
{transaction.amount}
{transaction.asset}
diff --git a/admin-dashboard/components/dashboard/StatusBadge.tsx b/admin-dashboard/components/dashboard/StatusBadge.tsx index 464b76c8..5ec0d56d 100644 --- a/admin-dashboard/components/dashboard/StatusBadge.tsx +++ b/admin-dashboard/components/dashboard/StatusBadge.tsx @@ -1,17 +1,20 @@ "use client"; -import type { TransactionStatus } from "@/components/dashboard/types"; +import type { TransactionStatus, WebhookDeliveryStatus } from "@/components/dashboard/types"; import { Pulse } from "@/components/ui/motion"; type BadgeTone = "green" | "amber" | "slate" | "red"; -function getTone(status: TransactionStatus | "active" | "inactive"): BadgeTone { +type AllowedStatus = TransactionStatus | WebhookDeliveryStatus | "active" | "inactive"; + +function getTone(status: AllowedStatus): BadgeTone { switch (status) { case "success": case "active": return "green"; case "pending": case "submitted": + case "retrying": return "amber"; case "failed": return "red"; @@ -20,16 +23,14 @@ function getTone(status: TransactionStatus | "active" | "inactive"): BadgeTone { } } -function isPendingStatus( - status: TransactionStatus | "active" | "inactive" -): boolean { - return status === "pending" || status === "submitted"; +function isPendingStatus(status: AllowedStatus): boolean { + return status === "pending" || status === "submitted" || status === "retrying"; } export function StatusBadge({ status, }: { - status: TransactionStatus | "active" | "inactive"; + status: AllowedStatus; }) { const toneClassName = { green: diff --git a/admin-dashboard/components/dashboard/WebhookDeliveryLog.tsx b/admin-dashboard/components/dashboard/WebhookDeliveryLog.tsx index 61a697b7..bfec2801 100644 --- a/admin-dashboard/components/dashboard/WebhookDeliveryLog.tsx +++ b/admin-dashboard/components/dashboard/WebhookDeliveryLog.tsx @@ -60,41 +60,45 @@ interface WebhookDeliveryLogProps { onQueryChange: (query: Partial) => void; } +function DrawerSection({ title, children }: { title: string; children: React.ReactNode }) { + return ( +
+
+ {title} +
+ {children} +
+ ); +} + +function JsonBlock({ value }: { value: Record | Record }) { + return ( +
+      {JSON.stringify(value, null, 2)}
+    
+ ); +} + export function WebhookDeliveryLogTable({ data, onPageChange, onQueryChange, }: WebhookDeliveryLogProps) { - const [showPayload, setShowPayload] = useState(null); + const [expandedRow, setExpandedRow] = useState(null); - const getStatusVariant = (status: WebhookDeliveryStatus) => { - switch (status) { - case "success": - return "success"; - case "failed": - return "error"; - case "pending": - return "warning"; - case "retrying": - return "info"; - default: - return "default"; - } - }; - - const formatTimestamp = (timestamp: string) => { - return new Date(timestamp).toLocaleString(); - }; + const formatTimestamp = (timestamp: string) => + new Date(timestamp).toLocaleString(); const filteredRows = useMemo(() => { let rows = [...data.rows]; if (data.search) { + const q = data.search.toLowerCase(); rows = rows.filter( (row) => - row.tenantName?.toLowerCase().includes(data.search.toLowerCase()) || - row.tenantId.toLowerCase().includes(data.search.toLowerCase()) || - row.webhookUrl.toLowerCase().includes(data.search.toLowerCase()) + row.tenantName?.toLowerCase().includes(q) || + row.tenantId.toLowerCase().includes(q) || + row.webhookUrl.toLowerCase().includes(q), ); } @@ -138,7 +142,6 @@ export function WebhookDeliveryLogTable({ - {/* Search */}
- {/* Status Filter */}
@@ -165,7 +167,6 @@ export function WebhookDeliveryLogTable({
- {/* Event Type Filter */}
@@ -182,12 +183,13 @@ export function WebhookDeliveryLogTable({
- {/* Sort */}