@quanticjs/notification-ui 8.1.0 → 9.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +1006 -1005
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +995 -979
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -363,7 +363,7 @@ function NotificationBell({
|
|
|
363
363
|
"span",
|
|
364
364
|
{
|
|
365
365
|
"aria-hidden": "true",
|
|
366
|
-
className: "absolute -end-0.5 -top-0.5 inline-flex min-w-5 items-center justify-center rounded-full bg-
|
|
366
|
+
className: "absolute -end-0.5 -top-0.5 inline-flex min-w-5 items-center justify-center rounded-full bg-coral px-1.5 text-xs font-semibold text-coral-foreground ring-2 ring-background",
|
|
367
367
|
children: count > 99 ? "99+" : count
|
|
368
368
|
}
|
|
369
369
|
)
|
|
@@ -373,7 +373,7 @@ function NotificationBell({
|
|
|
373
373
|
}
|
|
374
374
|
|
|
375
375
|
// src/notification-inbox.tsx
|
|
376
|
-
import { cn as cn3 } from "@quanticjs/react-ui";
|
|
376
|
+
import { Button, Card, EmptyState, Skeleton, cn as cn3 } from "@quanticjs/react-ui";
|
|
377
377
|
import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
378
378
|
function NotificationInbox({
|
|
379
379
|
basePath,
|
|
@@ -387,54 +387,80 @@ function NotificationInbox({
|
|
|
387
387
|
appId
|
|
388
388
|
});
|
|
389
389
|
if (isLoading) {
|
|
390
|
-
return /* @__PURE__ */ jsxs3(
|
|
391
|
-
"
|
|
392
|
-
{
|
|
393
|
-
|
|
394
|
-
"
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
390
|
+
return /* @__PURE__ */ jsxs3("div", { role: "status", "aria-label": "Loading notifications", className: cn3(className), children: [
|
|
391
|
+
/* @__PURE__ */ jsx5("span", { className: "sr-only", children: "Loading notifications" }),
|
|
392
|
+
/* @__PURE__ */ jsxs3(Card, { "aria-hidden": "true", children: [
|
|
393
|
+
/* @__PURE__ */ jsx5(InboxHeader, {}),
|
|
394
|
+
/* @__PURE__ */ jsx5("ul", { className: "divide-y divide-border", children: [0, 1, 2, 3].map((i) => /* @__PURE__ */ jsxs3("li", { className: "flex items-start gap-3 px-4 py-3.5", children: [
|
|
395
|
+
/* @__PURE__ */ jsx5(Skeleton, { className: "mt-1 h-2 w-2 rounded-full" }),
|
|
396
|
+
/* @__PURE__ */ jsxs3("div", { className: "flex min-w-0 flex-1 flex-col gap-2", children: [
|
|
397
|
+
/* @__PURE__ */ jsx5(Skeleton, { className: "h-3.5 w-2/3" }),
|
|
398
|
+
/* @__PURE__ */ jsx5(Skeleton, { className: "h-3 w-1/2" })
|
|
399
|
+
] })
|
|
400
|
+
] }, i)) })
|
|
401
|
+
] })
|
|
402
|
+
] });
|
|
402
403
|
}
|
|
403
404
|
if (isError) {
|
|
404
|
-
return /* @__PURE__ */ jsxs3(
|
|
405
|
-
/* @__PURE__ */ jsx5(
|
|
406
|
-
/* @__PURE__ */
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
405
|
+
return /* @__PURE__ */ jsxs3(Card, { className, children: [
|
|
406
|
+
/* @__PURE__ */ jsx5(InboxHeader, {}),
|
|
407
|
+
/* @__PURE__ */ jsxs3("div", { className: "flex flex-col items-center gap-3 px-6 py-12 text-center", children: [
|
|
408
|
+
/* @__PURE__ */ jsx5(
|
|
409
|
+
"span",
|
|
410
|
+
{
|
|
411
|
+
"aria-hidden": "true",
|
|
412
|
+
className: "grid size-12 place-items-center rounded-full bg-destructive/10 text-destructive [&_svg]:size-6",
|
|
413
|
+
children: /* @__PURE__ */ jsx5(AlertIcon, {})
|
|
414
|
+
}
|
|
415
|
+
),
|
|
416
|
+
/* @__PURE__ */ jsxs3("div", { className: "flex flex-col gap-1", children: [
|
|
417
|
+
/* @__PURE__ */ jsx5("p", { className: "text-sm font-medium text-foreground", children: "Failed to load notifications" }),
|
|
418
|
+
/* @__PURE__ */ jsx5("p", { className: "text-sm text-muted-foreground", children: "Something went wrong while loading your inbox." })
|
|
419
|
+
] }),
|
|
420
|
+
/* @__PURE__ */ jsx5(Button, { type: "button", onClick: () => void refetch(), children: "Try again" })
|
|
421
|
+
] })
|
|
415
422
|
] });
|
|
416
423
|
}
|
|
417
424
|
const items = data?.items ?? [];
|
|
418
425
|
if (items.length === 0) {
|
|
419
|
-
return /* @__PURE__ */
|
|
420
|
-
|
|
421
|
-
return /* @__PURE__ */ jsxs3("section", { "aria-label": "Notifications", className: cn3("flex flex-col", className), children: [
|
|
422
|
-
/* @__PURE__ */ jsxs3("header", { className: "flex items-center justify-between border-b border-border px-4 py-2", children: [
|
|
423
|
-
/* @__PURE__ */ jsx5("h2", { className: "text-sm font-semibold text-foreground", children: "Notifications" }),
|
|
426
|
+
return /* @__PURE__ */ jsxs3(Card, { className, children: [
|
|
427
|
+
/* @__PURE__ */ jsx5(InboxHeader, {}),
|
|
424
428
|
/* @__PURE__ */ jsx5(
|
|
425
|
-
|
|
429
|
+
EmptyState,
|
|
426
430
|
{
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
className: "text-sm text-primary hover:underline focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring disabled:opacity-50",
|
|
431
|
-
children: "Mark all read"
|
|
431
|
+
icon: /* @__PURE__ */ jsx5(BellOffIcon, {}),
|
|
432
|
+
title: "No notifications yet",
|
|
433
|
+
description: "New alerts and updates will appear here."
|
|
432
434
|
}
|
|
433
435
|
)
|
|
434
|
-
] })
|
|
436
|
+
] });
|
|
437
|
+
}
|
|
438
|
+
return /* @__PURE__ */ jsxs3(Card, { role: "region", "aria-label": "Notifications", className, children: [
|
|
439
|
+
/* @__PURE__ */ jsx5(
|
|
440
|
+
InboxHeader,
|
|
441
|
+
{
|
|
442
|
+
action: /* @__PURE__ */ jsx5(
|
|
443
|
+
Button,
|
|
444
|
+
{
|
|
445
|
+
type: "button",
|
|
446
|
+
variant: "ghost",
|
|
447
|
+
size: "sm",
|
|
448
|
+
onClick: () => markAllRead.mutate(),
|
|
449
|
+
disabled: markAllRead.isPending,
|
|
450
|
+
children: "Mark all read"
|
|
451
|
+
}
|
|
452
|
+
)
|
|
453
|
+
}
|
|
454
|
+
),
|
|
435
455
|
/* @__PURE__ */ jsx5("ul", { className: "divide-y divide-border", children: items.map((item) => /* @__PURE__ */ jsx5(InboxRow, { item, onMarkRead: () => markRead.mutate(item.id) }, item.id)) })
|
|
436
456
|
] });
|
|
437
457
|
}
|
|
458
|
+
function InboxHeader({ action }) {
|
|
459
|
+
return /* @__PURE__ */ jsxs3("div", { className: "flex items-center justify-between gap-2 border-b border-border px-4 py-3", children: [
|
|
460
|
+
/* @__PURE__ */ jsx5("h2", { className: "text-sm font-semibold text-foreground", children: "Notifications" }),
|
|
461
|
+
action
|
|
462
|
+
] });
|
|
463
|
+
}
|
|
438
464
|
function InboxRow({
|
|
439
465
|
item,
|
|
440
466
|
onMarkRead
|
|
@@ -445,20 +471,63 @@ function InboxRow({
|
|
|
445
471
|
type: "button",
|
|
446
472
|
onClick: onMarkRead,
|
|
447
473
|
"aria-label": `${item.title}${item.isRead ? "" : " (unread)"}`,
|
|
448
|
-
className:
|
|
449
|
-
"flex w-full flex-col items-start gap-0.5 px-4 py-3 text-start hover:bg-muted focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring",
|
|
450
|
-
item.isRead ? "text-muted-foreground" : "text-foreground"
|
|
451
|
-
),
|
|
474
|
+
className: "flex w-full items-start gap-3 px-4 py-3.5 text-start transition-colors hover:bg-muted focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring",
|
|
452
475
|
children: [
|
|
453
|
-
/* @__PURE__ */
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
476
|
+
/* @__PURE__ */ jsx5("span", { "aria-hidden": "true", className: "mt-1.5 flex size-2 shrink-0 items-center justify-center", children: !item.isRead && /* @__PURE__ */ jsx5("span", { className: "size-2 rounded-full bg-coral" }) }),
|
|
477
|
+
/* @__PURE__ */ jsxs3("span", { className: "flex min-w-0 flex-1 flex-col gap-0.5", children: [
|
|
478
|
+
/* @__PURE__ */ jsx5(
|
|
479
|
+
"span",
|
|
480
|
+
{
|
|
481
|
+
className: cn3(
|
|
482
|
+
"truncate text-sm",
|
|
483
|
+
item.isRead ? "font-normal text-muted-foreground" : "font-semibold text-foreground"
|
|
484
|
+
),
|
|
485
|
+
children: item.title
|
|
486
|
+
}
|
|
487
|
+
),
|
|
488
|
+
item.body && /* @__PURE__ */ jsx5("span", { className: "truncate text-xs text-muted-foreground", children: item.body })
|
|
489
|
+
] })
|
|
458
490
|
]
|
|
459
491
|
}
|
|
460
492
|
) });
|
|
461
493
|
}
|
|
494
|
+
function AlertIcon() {
|
|
495
|
+
return /* @__PURE__ */ jsxs3(
|
|
496
|
+
"svg",
|
|
497
|
+
{
|
|
498
|
+
viewBox: "0 0 24 24",
|
|
499
|
+
fill: "none",
|
|
500
|
+
stroke: "currentColor",
|
|
501
|
+
strokeWidth: "2",
|
|
502
|
+
strokeLinecap: "round",
|
|
503
|
+
strokeLinejoin: "round",
|
|
504
|
+
children: [
|
|
505
|
+
/* @__PURE__ */ jsx5("path", { d: "M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0Z" }),
|
|
506
|
+
/* @__PURE__ */ jsx5("line", { x1: "12", x2: "12", y1: "9", y2: "13" }),
|
|
507
|
+
/* @__PURE__ */ jsx5("line", { x1: "12", x2: "12.01", y1: "17", y2: "17" })
|
|
508
|
+
]
|
|
509
|
+
}
|
|
510
|
+
);
|
|
511
|
+
}
|
|
512
|
+
function BellOffIcon() {
|
|
513
|
+
return /* @__PURE__ */ jsxs3(
|
|
514
|
+
"svg",
|
|
515
|
+
{
|
|
516
|
+
viewBox: "0 0 24 24",
|
|
517
|
+
fill: "none",
|
|
518
|
+
stroke: "currentColor",
|
|
519
|
+
strokeWidth: "2",
|
|
520
|
+
strokeLinecap: "round",
|
|
521
|
+
strokeLinejoin: "round",
|
|
522
|
+
children: [
|
|
523
|
+
/* @__PURE__ */ jsx5("path", { d: "M8.7 3A6 6 0 0 1 18 8a21.3 21.3 0 0 0 .6 5" }),
|
|
524
|
+
/* @__PURE__ */ jsx5("path", { d: "M17 17H3s3-2 3-9a4.67 4.67 0 0 1 .3-1.7" }),
|
|
525
|
+
/* @__PURE__ */ jsx5("path", { d: "M10.3 21a1.94 1.94 0 0 0 3.4 0" }),
|
|
526
|
+
/* @__PURE__ */ jsx5("line", { x1: "2", x2: "22", y1: "2", y2: "22" })
|
|
527
|
+
]
|
|
528
|
+
}
|
|
529
|
+
);
|
|
530
|
+
}
|
|
462
531
|
|
|
463
532
|
// src/notification-center.tsx
|
|
464
533
|
import { useCallback, useEffect as useEffect4, useRef as useRef2, useState as useState3 } from "react";
|
|
@@ -533,7 +602,7 @@ function NotificationCenter({
|
|
|
533
602
|
"span",
|
|
534
603
|
{
|
|
535
604
|
"aria-hidden": true,
|
|
536
|
-
className: "absolute -end-0.5 -top-0.5 inline-flex min-w-5 items-center justify-center rounded-full bg-
|
|
605
|
+
className: "absolute -end-0.5 -top-0.5 inline-flex min-w-5 items-center justify-center rounded-full bg-coral px-1.5 text-xs font-semibold text-coral-foreground ring-2 ring-background",
|
|
537
606
|
children: badge
|
|
538
607
|
}
|
|
539
608
|
)
|
|
@@ -663,14 +732,14 @@ import {
|
|
|
663
732
|
import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
664
733
|
function TrendChart({ data, className }) {
|
|
665
734
|
return /* @__PURE__ */ jsx8("div", { className: cn6("h-72 w-full", className), role: "img", "aria-label": "Delivery trend over time", children: /* @__PURE__ */ jsx8(ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxs6(LineChart, { data, margin: { top: 8, right: 16, bottom: 8, left: 0 }, children: [
|
|
666
|
-
/* @__PURE__ */ jsx8(CartesianGrid, { strokeDasharray: "3 3", stroke: "
|
|
667
|
-
/* @__PURE__ */ jsx8(XAxis, { dataKey: "day", stroke: "
|
|
668
|
-
/* @__PURE__ */ jsx8(YAxis, { stroke: "
|
|
735
|
+
/* @__PURE__ */ jsx8(CartesianGrid, { strokeDasharray: "3 3", stroke: "var(--border)" }),
|
|
736
|
+
/* @__PURE__ */ jsx8(XAxis, { dataKey: "day", stroke: "var(--muted-foreground)", fontSize: 12 }),
|
|
737
|
+
/* @__PURE__ */ jsx8(YAxis, { stroke: "var(--muted-foreground)", fontSize: 12, allowDecimals: false }),
|
|
669
738
|
/* @__PURE__ */ jsx8(Tooltip, {}),
|
|
670
|
-
/* @__PURE__ */ jsx8(Line, { type: "monotone", dataKey: "sends", stroke: "
|
|
671
|
-
/* @__PURE__ */ jsx8(Line, { type: "monotone", dataKey: "delivered", stroke: "
|
|
672
|
-
/* @__PURE__ */ jsx8(Line, { type: "monotone", dataKey: "opened", stroke: "
|
|
673
|
-
/* @__PURE__ */ jsx8(Line, { type: "monotone", dataKey: "clicked", stroke: "
|
|
739
|
+
/* @__PURE__ */ jsx8(Line, { type: "monotone", dataKey: "sends", stroke: "var(--primary)", dot: false }),
|
|
740
|
+
/* @__PURE__ */ jsx8(Line, { type: "monotone", dataKey: "delivered", stroke: "var(--chart-2, var(--primary))", dot: false }),
|
|
741
|
+
/* @__PURE__ */ jsx8(Line, { type: "monotone", dataKey: "opened", stroke: "var(--chart-3, var(--primary))", dot: false }),
|
|
742
|
+
/* @__PURE__ */ jsx8(Line, { type: "monotone", dataKey: "clicked", stroke: "var(--chart-4, var(--primary))", dot: false })
|
|
674
743
|
] }) }) });
|
|
675
744
|
}
|
|
676
745
|
|
|
@@ -820,7 +889,7 @@ function TemplateStatusBadge({
|
|
|
820
889
|
}
|
|
821
890
|
|
|
822
891
|
// src/template-list.tsx
|
|
823
|
-
import { cn as cn10 } from "@quanticjs/react-ui";
|
|
892
|
+
import { Button as Button2, Card as Card2, EmptyState as EmptyState2, Skeleton as Skeleton2, cn as cn10 } from "@quanticjs/react-ui";
|
|
824
893
|
import { useApiQuery as useApiQuery7 } from "@quanticjs/react-query";
|
|
825
894
|
import { jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
826
895
|
function TemplateList({ basePath = "/api/templates", className }) {
|
|
@@ -829,51 +898,134 @@ function TemplateList({ basePath = "/api/templates", className }) {
|
|
|
829
898
|
(client) => client.get(basePath)
|
|
830
899
|
);
|
|
831
900
|
if (isLoading) {
|
|
832
|
-
return /* @__PURE__ */ jsxs9(
|
|
833
|
-
"
|
|
834
|
-
{
|
|
835
|
-
|
|
836
|
-
"
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
901
|
+
return /* @__PURE__ */ jsxs9("div", { role: "status", "aria-label": "Loading templates", className: cn10(className), children: [
|
|
902
|
+
/* @__PURE__ */ jsx12("span", { className: "sr-only", children: "Loading templates" }),
|
|
903
|
+
/* @__PURE__ */ jsxs9(Card2, { "aria-hidden": "true", children: [
|
|
904
|
+
/* @__PURE__ */ jsx12(ListHeader, {}),
|
|
905
|
+
/* @__PURE__ */ jsx12("ul", { className: "divide-y divide-border", children: [0, 1, 2, 3, 4].map((i) => /* @__PURE__ */ jsxs9("li", { className: "flex flex-col gap-2 px-4 py-3.5", children: [
|
|
906
|
+
/* @__PURE__ */ jsxs9("div", { className: "flex items-center gap-2.5", children: [
|
|
907
|
+
/* @__PURE__ */ jsx12(Skeleton2, { className: "h-3.5 w-40" }),
|
|
908
|
+
/* @__PURE__ */ jsx12(Skeleton2, { className: "h-5 w-16 rounded-full" })
|
|
909
|
+
] }),
|
|
910
|
+
/* @__PURE__ */ jsx12(Skeleton2, { className: "h-3 w-56" })
|
|
911
|
+
] }, i)) })
|
|
912
|
+
] })
|
|
913
|
+
] });
|
|
844
914
|
}
|
|
845
915
|
if (isError) {
|
|
846
|
-
return /* @__PURE__ */ jsxs9(
|
|
847
|
-
/* @__PURE__ */ jsx12(
|
|
916
|
+
return /* @__PURE__ */ jsxs9(Card2, { className, children: [
|
|
917
|
+
/* @__PURE__ */ jsx12(ListHeader, {}),
|
|
918
|
+
/* @__PURE__ */ jsxs9("div", { className: "flex flex-col items-center gap-3 px-6 py-12 text-center", children: [
|
|
919
|
+
/* @__PURE__ */ jsx12(
|
|
920
|
+
"span",
|
|
921
|
+
{
|
|
922
|
+
"aria-hidden": "true",
|
|
923
|
+
className: "grid size-12 place-items-center rounded-full bg-destructive/10 text-destructive [&_svg]:size-6",
|
|
924
|
+
children: /* @__PURE__ */ jsx12(AlertIcon2, {})
|
|
925
|
+
}
|
|
926
|
+
),
|
|
927
|
+
/* @__PURE__ */ jsxs9("div", { className: "flex flex-col gap-1", children: [
|
|
928
|
+
/* @__PURE__ */ jsx12("p", { className: "text-sm font-medium text-foreground", children: "Failed to load templates" }),
|
|
929
|
+
/* @__PURE__ */ jsx12("p", { className: "text-sm text-muted-foreground", children: "Something went wrong while loading your templates." })
|
|
930
|
+
] }),
|
|
931
|
+
/* @__PURE__ */ jsx12(Button2, { type: "button", onClick: () => void refetch(), children: "Try again" })
|
|
932
|
+
] })
|
|
933
|
+
] });
|
|
934
|
+
}
|
|
935
|
+
const items = data ?? [];
|
|
936
|
+
if (items.length === 0) {
|
|
937
|
+
return /* @__PURE__ */ jsxs9(Card2, { className, children: [
|
|
938
|
+
/* @__PURE__ */ jsx12(ListHeader, {}),
|
|
848
939
|
/* @__PURE__ */ jsx12(
|
|
849
|
-
|
|
940
|
+
EmptyState2,
|
|
850
941
|
{
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
children: "Try again"
|
|
942
|
+
icon: /* @__PURE__ */ jsx12(FileIcon, {}),
|
|
943
|
+
title: "No templates found",
|
|
944
|
+
description: "This workspace doesn't have any notification templates yet."
|
|
855
945
|
}
|
|
856
946
|
)
|
|
857
947
|
] });
|
|
858
948
|
}
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
}
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
/* @__PURE__ */ jsx12("
|
|
868
|
-
/* @__PURE__ */ jsx12("
|
|
869
|
-
] })
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
949
|
+
return /* @__PURE__ */ jsxs9(Card2, { role: "region", "aria-label": "Templates", className, children: [
|
|
950
|
+
/* @__PURE__ */ jsx12(ListHeader, { count: items.length }),
|
|
951
|
+
/* @__PURE__ */ jsx12("ul", { className: "divide-y divide-border", children: items.map((item) => /* @__PURE__ */ jsx12(TemplateRow, { item }, item.templateId)) })
|
|
952
|
+
] });
|
|
953
|
+
}
|
|
954
|
+
function ListHeader({ count }) {
|
|
955
|
+
return /* @__PURE__ */ jsxs9("div", { className: "flex items-center justify-between gap-2 border-b border-border px-4 py-3", children: [
|
|
956
|
+
/* @__PURE__ */ jsxs9("div", { className: "flex flex-col", children: [
|
|
957
|
+
/* @__PURE__ */ jsx12("h2", { className: "text-sm font-semibold text-foreground", children: "Templates" }),
|
|
958
|
+
/* @__PURE__ */ jsx12("p", { className: "text-xs text-muted-foreground", children: "Read-only view of all notification templates" })
|
|
959
|
+
] }),
|
|
960
|
+
count != null && count > 0 && /* @__PURE__ */ jsxs9("span", { className: "inline-flex items-center rounded-full bg-muted px-2 py-0.5 text-xs font-medium tabular-nums text-muted-foreground", children: [
|
|
961
|
+
count,
|
|
962
|
+
" templates"
|
|
963
|
+
] })
|
|
964
|
+
] });
|
|
965
|
+
}
|
|
966
|
+
function TemplateRow({ item }) {
|
|
967
|
+
return /* @__PURE__ */ jsxs9("li", { className: "flex flex-col gap-1.5 px-4 py-3.5", children: [
|
|
968
|
+
/* @__PURE__ */ jsxs9("div", { className: "flex items-center gap-2.5", children: [
|
|
969
|
+
/* @__PURE__ */ jsx12("span", { className: "truncate text-sm font-medium text-foreground", children: item.templateId }),
|
|
970
|
+
/* @__PURE__ */ jsx12(TemplateStatusBadge, { status: item.latestStatus })
|
|
971
|
+
] }),
|
|
972
|
+
/* @__PURE__ */ jsxs9("div", { className: "flex flex-wrap items-center gap-x-3 gap-y-1 text-xs text-muted-foreground", children: [
|
|
973
|
+
/* @__PURE__ */ jsxs9("span", { className: "tabular-nums", children: [
|
|
974
|
+
item.versionCount,
|
|
975
|
+
" versions"
|
|
976
|
+
] }),
|
|
977
|
+
/* @__PURE__ */ jsx12("span", { "aria-hidden": "true", className: "text-border", children: "\xB7" }),
|
|
978
|
+
/* @__PURE__ */ jsxs9("span", { className: "flex flex-wrap items-center gap-1", children: [
|
|
979
|
+
/* @__PURE__ */ jsx12("span", { children: "Locales:" }),
|
|
980
|
+
item.locales.map((locale) => /* @__PURE__ */ jsx12(
|
|
981
|
+
"span",
|
|
982
|
+
{
|
|
983
|
+
className: "inline-flex items-center rounded bg-muted px-1.5 py-0.5 text-[11px] font-medium uppercase tracking-wide text-muted-foreground",
|
|
984
|
+
children: locale
|
|
985
|
+
},
|
|
986
|
+
locale
|
|
987
|
+
))
|
|
988
|
+
] })
|
|
989
|
+
] })
|
|
990
|
+
] });
|
|
991
|
+
}
|
|
992
|
+
function AlertIcon2() {
|
|
993
|
+
return /* @__PURE__ */ jsxs9(
|
|
994
|
+
"svg",
|
|
995
|
+
{
|
|
996
|
+
viewBox: "0 0 24 24",
|
|
997
|
+
fill: "none",
|
|
998
|
+
stroke: "currentColor",
|
|
999
|
+
strokeWidth: "2",
|
|
1000
|
+
strokeLinecap: "round",
|
|
1001
|
+
strokeLinejoin: "round",
|
|
1002
|
+
children: [
|
|
1003
|
+
/* @__PURE__ */ jsx12("path", { d: "M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0Z" }),
|
|
1004
|
+
/* @__PURE__ */ jsx12("line", { x1: "12", x2: "12", y1: "9", y2: "13" }),
|
|
1005
|
+
/* @__PURE__ */ jsx12("line", { x1: "12", x2: "12.01", y1: "17", y2: "17" })
|
|
1006
|
+
]
|
|
1007
|
+
}
|
|
1008
|
+
);
|
|
1009
|
+
}
|
|
1010
|
+
function FileIcon() {
|
|
1011
|
+
return /* @__PURE__ */ jsxs9(
|
|
1012
|
+
"svg",
|
|
1013
|
+
{
|
|
1014
|
+
viewBox: "0 0 24 24",
|
|
1015
|
+
fill: "none",
|
|
1016
|
+
stroke: "currentColor",
|
|
1017
|
+
strokeWidth: "2",
|
|
1018
|
+
strokeLinecap: "round",
|
|
1019
|
+
strokeLinejoin: "round",
|
|
1020
|
+
children: [
|
|
1021
|
+
/* @__PURE__ */ jsx12("path", { d: "M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z" }),
|
|
1022
|
+
/* @__PURE__ */ jsx12("path", { d: "M14 2v4a2 2 0 0 0 2 2h4" }),
|
|
1023
|
+
/* @__PURE__ */ jsx12("path", { d: "M10 9H8" }),
|
|
1024
|
+
/* @__PURE__ */ jsx12("path", { d: "M16 13H8" }),
|
|
1025
|
+
/* @__PURE__ */ jsx12("path", { d: "M16 17H8" })
|
|
1026
|
+
]
|
|
1027
|
+
}
|
|
1028
|
+
);
|
|
877
1029
|
}
|
|
878
1030
|
|
|
879
1031
|
// src/template-editor.tsx
|
|
@@ -2087,9 +2239,74 @@ function SegmentBuilder({
|
|
|
2087
2239
|
|
|
2088
2240
|
// src/suppression-manager.tsx
|
|
2089
2241
|
import { useState as useState10 } from "react";
|
|
2090
|
-
import { cn as cn20, formatDateTime as formatDateTime3, useToast as useToast8 } from "@quanticjs/react-ui";
|
|
2242
|
+
import { Button as Button4, Card as Card3, EmptyState as EmptyState3, cn as cn20, formatDateTime as formatDateTime3, useToast as useToast8 } from "@quanticjs/react-ui";
|
|
2091
2243
|
import { useApiMutation as useApiMutation9, useApiQuery as useApiQuery14 } from "@quanticjs/react-query";
|
|
2092
|
-
|
|
2244
|
+
|
|
2245
|
+
// src/admin-panel.tsx
|
|
2246
|
+
import { Button as Button3, Skeleton as Skeleton3 } from "@quanticjs/react-ui";
|
|
2247
|
+
import { jsx as jsx22, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
2248
|
+
function PanelHeader({ title, subtitle }) {
|
|
2249
|
+
return /* @__PURE__ */ jsx22("div", { className: "flex items-center justify-between gap-2 border-b border-border px-4 py-3", children: /* @__PURE__ */ jsxs19("div", { className: "flex flex-col", children: [
|
|
2250
|
+
/* @__PURE__ */ jsx22("h2", { className: "text-sm font-semibold text-foreground", children: title }),
|
|
2251
|
+
subtitle && /* @__PURE__ */ jsx22("p", { className: "text-xs text-muted-foreground tabular-nums", children: subtitle })
|
|
2252
|
+
] }) });
|
|
2253
|
+
}
|
|
2254
|
+
function SkeletonRows({ label, rows = 4 }) {
|
|
2255
|
+
return /* @__PURE__ */ jsxs19("div", { role: "status", "aria-label": label, className: "flex flex-col gap-2 p-4", children: [
|
|
2256
|
+
/* @__PURE__ */ jsx22("span", { className: "sr-only", children: label }),
|
|
2257
|
+
Array.from({ length: rows }).map((_, i) => /* @__PURE__ */ jsx22(Skeleton3, { className: "h-10 w-full" }, i))
|
|
2258
|
+
] });
|
|
2259
|
+
}
|
|
2260
|
+
function ErrorPanel({ message, onRetry }) {
|
|
2261
|
+
return /* @__PURE__ */ jsxs19("div", { className: "flex flex-col items-center gap-3 px-6 py-12 text-center", children: [
|
|
2262
|
+
/* @__PURE__ */ jsx22(
|
|
2263
|
+
"span",
|
|
2264
|
+
{
|
|
2265
|
+
"aria-hidden": "true",
|
|
2266
|
+
className: "grid size-12 place-items-center rounded-full bg-destructive/10 text-destructive [&_svg]:size-6",
|
|
2267
|
+
children: /* @__PURE__ */ jsx22(AlertIcon3, {})
|
|
2268
|
+
}
|
|
2269
|
+
),
|
|
2270
|
+
/* @__PURE__ */ jsx22("p", { className: "text-sm font-medium text-foreground", children: message }),
|
|
2271
|
+
/* @__PURE__ */ jsx22(Button3, { type: "button", onClick: onRetry, children: "Try again" })
|
|
2272
|
+
] });
|
|
2273
|
+
}
|
|
2274
|
+
function Pager({
|
|
2275
|
+
label,
|
|
2276
|
+
page,
|
|
2277
|
+
totalPages,
|
|
2278
|
+
onPrev,
|
|
2279
|
+
onNext
|
|
2280
|
+
}) {
|
|
2281
|
+
return /* @__PURE__ */ jsxs19(
|
|
2282
|
+
"nav",
|
|
2283
|
+
{
|
|
2284
|
+
"aria-label": label,
|
|
2285
|
+
className: "flex items-center justify-between gap-2 border-t border-border px-4 py-3",
|
|
2286
|
+
children: [
|
|
2287
|
+
/* @__PURE__ */ jsx22(Button3, { type: "button", variant: "outline", size: "sm", onClick: onPrev, disabled: page <= 1, children: "Previous" }),
|
|
2288
|
+
/* @__PURE__ */ jsxs19("span", { className: "text-xs text-muted-foreground tabular-nums", children: [
|
|
2289
|
+
"Page ",
|
|
2290
|
+
page,
|
|
2291
|
+
" of ",
|
|
2292
|
+
totalPages
|
|
2293
|
+
] }),
|
|
2294
|
+
/* @__PURE__ */ jsx22(Button3, { type: "button", variant: "outline", size: "sm", onClick: onNext, disabled: page >= totalPages, children: "Next" })
|
|
2295
|
+
]
|
|
2296
|
+
}
|
|
2297
|
+
);
|
|
2298
|
+
}
|
|
2299
|
+
var FIELD_CLASS = "rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring";
|
|
2300
|
+
function AlertIcon3() {
|
|
2301
|
+
return /* @__PURE__ */ jsxs19("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
2302
|
+
/* @__PURE__ */ jsx22("path", { d: "M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0Z" }),
|
|
2303
|
+
/* @__PURE__ */ jsx22("line", { x1: "12", x2: "12", y1: "9", y2: "13" }),
|
|
2304
|
+
/* @__PURE__ */ jsx22("line", { x1: "12", x2: "12.01", y1: "17", y2: "17" })
|
|
2305
|
+
] });
|
|
2306
|
+
}
|
|
2307
|
+
|
|
2308
|
+
// src/suppression-manager.tsx
|
|
2309
|
+
import { Fragment, jsx as jsx23, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
2093
2310
|
var LIMIT3 = 20;
|
|
2094
2311
|
var CHANNELS3 = ["inapp", "email", "push", "sms"];
|
|
2095
2312
|
function SuppressionManager({ basePath = "/api", className }) {
|
|
@@ -2133,154 +2350,96 @@ function SuppressionManager({ basePath = "/api", className }) {
|
|
|
2133
2350
|
event.preventDefault();
|
|
2134
2351
|
add.mutate({ channel, address: address.trim(), reason: reason.trim() });
|
|
2135
2352
|
};
|
|
2136
|
-
const
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
{
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
/* @__PURE__ */
|
|
2153
|
-
"
|
|
2154
|
-
{
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
/* @__PURE__ */
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
className: "rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring"
|
|
2173
|
-
}
|
|
2174
|
-
)
|
|
2175
|
-
] }),
|
|
2176
|
-
/* @__PURE__ */ jsx22(
|
|
2177
|
-
"button",
|
|
2178
|
-
{
|
|
2179
|
-
type: "submit",
|
|
2180
|
-
disabled: add.isPending,
|
|
2181
|
-
className: "rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring disabled:opacity-50",
|
|
2182
|
-
children: add.isPending ? "Adding\u2026" : "Add suppression"
|
|
2183
|
-
}
|
|
2184
|
-
)
|
|
2185
|
-
] });
|
|
2186
|
-
let body;
|
|
2187
|
-
if (isLoading) {
|
|
2188
|
-
body = /* @__PURE__ */ jsxs19("div", { role: "status", "aria-label": "Loading suppressions", className: "flex flex-col gap-2 p-4", children: [
|
|
2189
|
-
/* @__PURE__ */ jsx22("span", { className: "sr-only", children: "Loading suppressions" }),
|
|
2190
|
-
[0, 1, 2].map((i) => /* @__PURE__ */ jsx22("div", { "aria-hidden": "true", className: "h-10 animate-pulse rounded bg-muted" }, i))
|
|
2191
|
-
] });
|
|
2192
|
-
} else if (isError) {
|
|
2193
|
-
body = /* @__PURE__ */ jsxs19("div", { className: "flex flex-col items-start gap-3 p-4", children: [
|
|
2194
|
-
/* @__PURE__ */ jsx22("p", { className: "text-sm text-foreground", children: "Failed to load suppressions" }),
|
|
2195
|
-
/* @__PURE__ */ jsx22(
|
|
2196
|
-
"button",
|
|
2197
|
-
{
|
|
2198
|
-
type: "button",
|
|
2199
|
-
onClick: () => void refetch(),
|
|
2200
|
-
className: "rounded bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring",
|
|
2201
|
-
children: "Try again"
|
|
2202
|
-
}
|
|
2203
|
-
)
|
|
2204
|
-
] });
|
|
2205
|
-
} else {
|
|
2206
|
-
const rows = data?.items ?? [];
|
|
2207
|
-
const totalPages = data?.totalPages ?? 1;
|
|
2208
|
-
if (rows.length === 0) {
|
|
2209
|
-
body = /* @__PURE__ */ jsx22("div", { className: "p-6 text-center text-sm text-muted-foreground", children: "No suppressions" });
|
|
2210
|
-
} else {
|
|
2211
|
-
body = /* @__PURE__ */ jsxs19(Fragment, { children: [
|
|
2212
|
-
/* @__PURE__ */ jsxs19("table", { className: "w-full text-sm", children: [
|
|
2213
|
-
/* @__PURE__ */ jsx22("thead", { children: /* @__PURE__ */ jsxs19("tr", { className: "border-b border-border text-start text-muted-foreground", children: [
|
|
2214
|
-
/* @__PURE__ */ jsx22("th", { scope: "col", className: "py-2 pe-4 font-medium", children: "Channel" }),
|
|
2215
|
-
/* @__PURE__ */ jsx22("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Address" }),
|
|
2216
|
-
/* @__PURE__ */ jsx22("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Reason" }),
|
|
2217
|
-
/* @__PURE__ */ jsx22("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Created" }),
|
|
2218
|
-
/* @__PURE__ */ jsx22("th", { scope: "col", className: "px-4 py-2 font-medium", children: /* @__PURE__ */ jsx22("span", { className: "sr-only", children: "Actions" }) })
|
|
2353
|
+
const rows = data?.items ?? [];
|
|
2354
|
+
const totalPages = data?.totalPages ?? 1;
|
|
2355
|
+
return /* @__PURE__ */ jsxs20("section", { "aria-label": "Suppression list", className: cn20("flex flex-col gap-4", className), children: [
|
|
2356
|
+
/* @__PURE__ */ jsx23(Card3, { children: /* @__PURE__ */ jsxs20("form", { onSubmit: onAdd, className: "flex flex-wrap items-end gap-3 p-4", noValidate: true, children: [
|
|
2357
|
+
/* @__PURE__ */ jsxs20("label", { className: "flex flex-col gap-1 text-sm", children: [
|
|
2358
|
+
/* @__PURE__ */ jsx23("span", { className: "font-medium text-foreground", children: "Channel" }),
|
|
2359
|
+
/* @__PURE__ */ jsx23(
|
|
2360
|
+
"select",
|
|
2361
|
+
{
|
|
2362
|
+
value: channel,
|
|
2363
|
+
onChange: (e) => setChannel(e.target.value),
|
|
2364
|
+
className: FIELD_CLASS,
|
|
2365
|
+
children: CHANNELS3.map((c) => /* @__PURE__ */ jsx23("option", { value: c, children: c }, c))
|
|
2366
|
+
}
|
|
2367
|
+
)
|
|
2368
|
+
] }),
|
|
2369
|
+
/* @__PURE__ */ jsxs20("label", { className: "flex flex-1 flex-col gap-1 text-sm", children: [
|
|
2370
|
+
/* @__PURE__ */ jsx23("span", { className: "font-medium text-foreground", children: "Address" }),
|
|
2371
|
+
/* @__PURE__ */ jsx23("input", { type: "text", value: address, onChange: (e) => setAddress(e.target.value), className: FIELD_CLASS })
|
|
2372
|
+
] }),
|
|
2373
|
+
/* @__PURE__ */ jsxs20("label", { className: "flex flex-1 flex-col gap-1 text-sm", children: [
|
|
2374
|
+
/* @__PURE__ */ jsx23("span", { className: "font-medium text-foreground", children: "Reason" }),
|
|
2375
|
+
/* @__PURE__ */ jsx23("input", { type: "text", value: reason, onChange: (e) => setReason(e.target.value), className: FIELD_CLASS })
|
|
2376
|
+
] }),
|
|
2377
|
+
/* @__PURE__ */ jsx23(Button4, { type: "submit", disabled: add.isPending, children: add.isPending ? "Adding\u2026" : "Add suppression" })
|
|
2378
|
+
] }) }),
|
|
2379
|
+
/* @__PURE__ */ jsxs20(Card3, { children: [
|
|
2380
|
+
/* @__PURE__ */ jsx23(PanelHeader, { title: "Suppressions", subtitle: `${data?.total ?? rows.length} entries` }),
|
|
2381
|
+
isLoading ? /* @__PURE__ */ jsx23(SkeletonRows, { label: "Loading suppressions" }) : isError ? /* @__PURE__ */ jsx23(ErrorPanel, { message: "Failed to load suppressions", onRetry: () => void refetch() }) : rows.length === 0 ? /* @__PURE__ */ jsx23(EmptyState3, { icon: /* @__PURE__ */ jsx23(BanIcon, {}), title: "No suppressions", description: "No addresses are suppressed." }) : /* @__PURE__ */ jsxs20(Fragment, { children: [
|
|
2382
|
+
/* @__PURE__ */ jsxs20("table", { className: "w-full text-sm", children: [
|
|
2383
|
+
/* @__PURE__ */ jsx23("thead", { children: /* @__PURE__ */ jsxs20("tr", { className: "border-b border-border text-start text-muted-foreground", children: [
|
|
2384
|
+
/* @__PURE__ */ jsx23("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Channel" }),
|
|
2385
|
+
/* @__PURE__ */ jsx23("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Address" }),
|
|
2386
|
+
/* @__PURE__ */ jsx23("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Reason" }),
|
|
2387
|
+
/* @__PURE__ */ jsx23("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Created" }),
|
|
2388
|
+
/* @__PURE__ */ jsx23("th", { scope: "col", className: "px-4 py-2 font-medium", children: /* @__PURE__ */ jsx23("span", { className: "sr-only", children: "Actions" }) })
|
|
2219
2389
|
] }) }),
|
|
2220
|
-
/* @__PURE__ */
|
|
2221
|
-
/* @__PURE__ */
|
|
2222
|
-
/* @__PURE__ */
|
|
2223
|
-
/* @__PURE__ */
|
|
2224
|
-
/* @__PURE__ */
|
|
2225
|
-
/* @__PURE__ */
|
|
2226
|
-
|
|
2390
|
+
/* @__PURE__ */ jsx23("tbody", { children: rows.map((row) => /* @__PURE__ */ jsxs20("tr", { className: "border-b border-border last:border-0 hover:bg-muted/40", children: [
|
|
2391
|
+
/* @__PURE__ */ jsx23("td", { className: "px-4 py-3", children: /* @__PURE__ */ jsx23("span", { className: "inline-flex items-center rounded bg-muted px-1.5 py-0.5 text-[11px] font-medium uppercase tracking-wide text-muted-foreground", children: row.channel }) }),
|
|
2392
|
+
/* @__PURE__ */ jsx23("td", { className: "px-4 py-3 text-foreground", children: row.address }),
|
|
2393
|
+
/* @__PURE__ */ jsx23("td", { className: "px-4 py-3 text-muted-foreground", children: row.reason }),
|
|
2394
|
+
/* @__PURE__ */ jsx23("td", { className: "px-4 py-3 text-muted-foreground", children: formatDateTime3(row.createdAt) }),
|
|
2395
|
+
/* @__PURE__ */ jsx23("td", { className: "px-4 py-3 text-end", children: /* @__PURE__ */ jsx23(
|
|
2396
|
+
Button4,
|
|
2227
2397
|
{
|
|
2228
2398
|
type: "button",
|
|
2399
|
+
variant: "ghost",
|
|
2400
|
+
size: "sm",
|
|
2401
|
+
className: "text-destructive",
|
|
2229
2402
|
disabled: remove.isPending,
|
|
2230
2403
|
onClick: () => remove.mutate(row.id),
|
|
2231
|
-
className: "rounded-md border border-border px-3 py-1 text-sm font-medium text-destructive hover:bg-muted focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring disabled:opacity-50",
|
|
2232
2404
|
children: "Remove"
|
|
2233
2405
|
}
|
|
2234
2406
|
) })
|
|
2235
2407
|
] }, row.id)) })
|
|
2236
2408
|
] }),
|
|
2237
|
-
/* @__PURE__ */
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
type: "button",
|
|
2242
|
-
onClick: () => setPage((p) => Math.max(1, p - 1)),
|
|
2243
|
-
disabled: page <= 1,
|
|
2244
|
-
className: "rounded-md border border-border px-3 py-1 text-sm text-foreground hover:bg-muted focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring disabled:opacity-50",
|
|
2245
|
-
children: "Previous"
|
|
2246
|
-
}
|
|
2247
|
-
),
|
|
2248
|
-
/* @__PURE__ */ jsxs19("span", { className: "text-xs text-muted-foreground", children: [
|
|
2249
|
-
"Page ",
|
|
2409
|
+
/* @__PURE__ */ jsx23(
|
|
2410
|
+
Pager,
|
|
2411
|
+
{
|
|
2412
|
+
label: "Suppression pagination",
|
|
2250
2413
|
page,
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
] })
|
|
2265
|
-
] });
|
|
2266
|
-
}
|
|
2267
|
-
}
|
|
2268
|
-
return /* @__PURE__ */ jsxs19("section", { "aria-label": "Suppression list", className: cn20("flex flex-col gap-4", className), children: [
|
|
2269
|
-
addForm,
|
|
2270
|
-
body
|
|
2414
|
+
totalPages,
|
|
2415
|
+
onPrev: () => setPage((p) => Math.max(1, p - 1)),
|
|
2416
|
+
onNext: () => setPage((p) => Math.min(totalPages, p + 1))
|
|
2417
|
+
}
|
|
2418
|
+
)
|
|
2419
|
+
] })
|
|
2420
|
+
] })
|
|
2421
|
+
] });
|
|
2422
|
+
}
|
|
2423
|
+
function BanIcon() {
|
|
2424
|
+
return /* @__PURE__ */ jsxs20("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
2425
|
+
/* @__PURE__ */ jsx23("circle", { cx: "12", cy: "12", r: "10" }),
|
|
2426
|
+
/* @__PURE__ */ jsx23("path", { d: "m4.9 4.9 14.2 14.2" })
|
|
2271
2427
|
] });
|
|
2272
2428
|
}
|
|
2273
2429
|
|
|
2274
2430
|
// src/dlq-console.tsx
|
|
2275
2431
|
import { Fragment as Fragment2, useState as useState11 } from "react";
|
|
2276
2432
|
import {
|
|
2433
|
+
Button as Button5,
|
|
2434
|
+
Card as Card4,
|
|
2435
|
+
EmptyState as EmptyState4,
|
|
2436
|
+
StatusBadge as StatusBadge4,
|
|
2277
2437
|
cn as cn21,
|
|
2278
2438
|
formatDateTime as formatDateTime4,
|
|
2279
|
-
StatusBadge as StatusBadge4,
|
|
2280
2439
|
useToast as useToast9
|
|
2281
2440
|
} from "@quanticjs/react-ui";
|
|
2282
2441
|
import { useApiMutation as useApiMutation10, useApiQuery as useApiQuery15 } from "@quanticjs/react-query";
|
|
2283
|
-
import { Fragment as Fragment3, jsx as
|
|
2442
|
+
import { Fragment as Fragment3, jsx as jsx24, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
2284
2443
|
var LIMIT4 = 20;
|
|
2285
2444
|
var STATUS_FILTERS = ["queued", "replayed", "discarded"];
|
|
2286
2445
|
function buildErrorDescription(error) {
|
|
@@ -2304,31 +2463,26 @@ function DlqMessageDetailRow({ id, basePath }) {
|
|
|
2304
2463
|
(client) => client.get(`${basePath}/admin/dlq/${id}`)
|
|
2305
2464
|
);
|
|
2306
2465
|
if (isLoading) {
|
|
2307
|
-
return /* @__PURE__ */
|
|
2308
|
-
/* @__PURE__ */
|
|
2309
|
-
/* @__PURE__ */
|
|
2466
|
+
return /* @__PURE__ */ jsxs21("div", { role: "status", "aria-label": "Loading message detail", className: "p-4", children: [
|
|
2467
|
+
/* @__PURE__ */ jsx24("span", { className: "sr-only", children: "Loading message detail" }),
|
|
2468
|
+
/* @__PURE__ */ jsx24("div", { "aria-hidden": "true", className: "h-16 animate-pulse rounded bg-muted motion-reduce:animate-none" })
|
|
2310
2469
|
] });
|
|
2311
2470
|
}
|
|
2312
2471
|
if (isError) {
|
|
2313
|
-
return /* @__PURE__ */
|
|
2314
|
-
/* @__PURE__ */
|
|
2315
|
-
/* @__PURE__ */
|
|
2316
|
-
"button",
|
|
2317
|
-
{
|
|
2318
|
-
type: "button",
|
|
2319
|
-
onClick: () => void refetch(),
|
|
2320
|
-
className: "rounded bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring",
|
|
2321
|
-
children: "Try again"
|
|
2322
|
-
}
|
|
2323
|
-
)
|
|
2472
|
+
return /* @__PURE__ */ jsxs21("div", { className: "flex flex-col items-start gap-3 p-4", children: [
|
|
2473
|
+
/* @__PURE__ */ jsx24("p", { className: "text-sm text-foreground", children: "Failed to load message detail" }),
|
|
2474
|
+
/* @__PURE__ */ jsx24(Button5, { type: "button", size: "sm", onClick: () => void refetch(), children: "Try again" })
|
|
2324
2475
|
] });
|
|
2325
2476
|
}
|
|
2326
|
-
return /* @__PURE__ */
|
|
2327
|
-
/* @__PURE__ */
|
|
2328
|
-
"
|
|
2329
|
-
/* @__PURE__ */
|
|
2477
|
+
return /* @__PURE__ */ jsxs21("div", { className: "flex flex-col gap-3 px-5 py-4 text-sm", children: [
|
|
2478
|
+
/* @__PURE__ */ jsxs21("div", { children: [
|
|
2479
|
+
/* @__PURE__ */ jsx24("div", { className: "mb-1 text-[11px] font-medium uppercase tracking-wider text-muted-foreground", children: "Error" }),
|
|
2480
|
+
/* @__PURE__ */ jsx24("div", { className: "font-mono text-xs text-destructive", children: data?.errorMessage ?? "\u2014" })
|
|
2330
2481
|
] }),
|
|
2331
|
-
/* @__PURE__ */
|
|
2482
|
+
/* @__PURE__ */ jsxs21("div", { children: [
|
|
2483
|
+
/* @__PURE__ */ jsx24("div", { className: "mb-1 text-[11px] font-medium uppercase tracking-wider text-muted-foreground", children: "Payload" }),
|
|
2484
|
+
/* @__PURE__ */ jsx24("pre", { className: "max-h-64 overflow-auto rounded-md border border-border bg-card p-3 font-mono text-xs leading-relaxed text-foreground", children: JSON.stringify(data?.payload ?? {}, null, 2) })
|
|
2485
|
+
] })
|
|
2332
2486
|
] });
|
|
2333
2487
|
}
|
|
2334
2488
|
function DlqConsole({ basePath = "/api", className }) {
|
|
@@ -2376,150 +2530,108 @@ function DlqConsole({ basePath = "/api", className }) {
|
|
|
2376
2530
|
})
|
|
2377
2531
|
}
|
|
2378
2532
|
);
|
|
2379
|
-
const
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
{
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
onChange: (e) => {
|
|
2387
|
-
setStatusFilter(e.target.value);
|
|
2388
|
-
setPage(1);
|
|
2389
|
-
},
|
|
2390
|
-
className: "rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring",
|
|
2391
|
-
children: [
|
|
2392
|
-
/* @__PURE__ */ jsx23("option", { value: "", children: "All" }),
|
|
2393
|
-
STATUS_FILTERS.map((s) => /* @__PURE__ */ jsx23("option", { value: s, children: s }, s))
|
|
2394
|
-
]
|
|
2395
|
-
}
|
|
2396
|
-
)
|
|
2397
|
-
] });
|
|
2398
|
-
let body;
|
|
2399
|
-
if (isLoading) {
|
|
2400
|
-
body = /* @__PURE__ */ jsxs20(
|
|
2401
|
-
"div",
|
|
2402
|
-
{
|
|
2403
|
-
role: "status",
|
|
2404
|
-
"aria-label": "Loading dead-letter messages",
|
|
2405
|
-
className: "flex flex-col gap-2 p-4",
|
|
2406
|
-
children: [
|
|
2407
|
-
/* @__PURE__ */ jsx23("span", { className: "sr-only", children: "Loading dead-letter messages" }),
|
|
2408
|
-
[0, 1, 2].map((i) => /* @__PURE__ */ jsx23("div", { "aria-hidden": "true", className: "h-10 animate-pulse rounded bg-muted" }, i))
|
|
2409
|
-
]
|
|
2410
|
-
}
|
|
2411
|
-
);
|
|
2412
|
-
} else if (isError) {
|
|
2413
|
-
body = /* @__PURE__ */ jsxs20("div", { className: "flex flex-col items-start gap-3 p-4", children: [
|
|
2414
|
-
/* @__PURE__ */ jsx23("p", { className: "text-sm text-foreground", children: "Failed to load dead-letter messages" }),
|
|
2415
|
-
/* @__PURE__ */ jsx23(
|
|
2416
|
-
"button",
|
|
2533
|
+
const rows = data?.items ?? [];
|
|
2534
|
+
const totalPages = data?.totalPages ?? 1;
|
|
2535
|
+
return /* @__PURE__ */ jsxs21("section", { "aria-label": "Dead-letter queue", className: cn21("flex flex-col gap-4", className), children: [
|
|
2536
|
+
/* @__PURE__ */ jsxs21("div", { className: "flex items-center justify-end gap-2", children: [
|
|
2537
|
+
/* @__PURE__ */ jsx24("label", { htmlFor: "dlq-status", className: "text-sm font-medium text-foreground", children: "Status" }),
|
|
2538
|
+
/* @__PURE__ */ jsxs21(
|
|
2539
|
+
"select",
|
|
2417
2540
|
{
|
|
2418
|
-
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
|
|
2541
|
+
id: "dlq-status",
|
|
2542
|
+
value: statusFilter,
|
|
2543
|
+
onChange: (e) => {
|
|
2544
|
+
setStatusFilter(e.target.value);
|
|
2545
|
+
setPage(1);
|
|
2546
|
+
},
|
|
2547
|
+
className: FIELD_CLASS,
|
|
2548
|
+
children: [
|
|
2549
|
+
/* @__PURE__ */ jsx24("option", { value: "", children: "All" }),
|
|
2550
|
+
STATUS_FILTERS.map((s) => /* @__PURE__ */ jsx24("option", { value: s, children: s }, s))
|
|
2551
|
+
]
|
|
2422
2552
|
}
|
|
2423
2553
|
)
|
|
2424
|
-
] })
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
"
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
}
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
/* @__PURE__ */ jsx23(
|
|
2461
|
-
"button",
|
|
2462
|
-
{
|
|
2463
|
-
type: "button",
|
|
2464
|
-
disabled: replay.isPending,
|
|
2465
|
-
onClick: () => replay.mutate(row.id),
|
|
2466
|
-
className: "rounded-md border border-border px-3 py-1 text-sm font-medium text-foreground hover:bg-muted focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring disabled:opacity-50",
|
|
2467
|
-
children: "Replay"
|
|
2468
|
-
}
|
|
2469
|
-
),
|
|
2470
|
-
/* @__PURE__ */ jsx23(
|
|
2471
|
-
"button",
|
|
2472
|
-
{
|
|
2473
|
-
type: "button",
|
|
2474
|
-
disabled: discard.isPending,
|
|
2475
|
-
onClick: () => discard.mutate(row.id),
|
|
2476
|
-
className: "rounded-md border border-border px-3 py-1 text-sm font-medium text-destructive hover:bg-muted focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring disabled:opacity-50",
|
|
2477
|
-
children: "Discard"
|
|
2478
|
-
}
|
|
2479
|
-
)
|
|
2480
|
-
] }) })
|
|
2554
|
+
] }),
|
|
2555
|
+
/* @__PURE__ */ jsxs21(Card4, { children: [
|
|
2556
|
+
/* @__PURE__ */ jsx24(PanelHeader, { title: "Messages", subtitle: !isLoading && !isError ? `${data?.total ?? rows.length} messages` : void 0 }),
|
|
2557
|
+
isLoading ? /* @__PURE__ */ jsx24(SkeletonRows, { label: "Loading dead-letter messages" }) : isError ? /* @__PURE__ */ jsx24(ErrorPanel, { message: "Failed to load dead-letter messages", onRetry: () => void refetch() }) : rows.length === 0 ? /* @__PURE__ */ jsx24(EmptyState4, { icon: /* @__PURE__ */ jsx24(SkullIcon, {}), title: "No dead-letter messages", description: "The queue is empty for the current filter." }) : /* @__PURE__ */ jsxs21(Fragment3, { children: [
|
|
2558
|
+
/* @__PURE__ */ jsx24("ul", { className: "divide-y divide-border", children: rows.map((row) => {
|
|
2559
|
+
const isExpanded = expandedId === row.id;
|
|
2560
|
+
return /* @__PURE__ */ jsxs21(Fragment2, { children: [
|
|
2561
|
+
/* @__PURE__ */ jsxs21("li", { className: "flex items-start gap-3 px-4 py-3.5", children: [
|
|
2562
|
+
/* @__PURE__ */ jsx24(
|
|
2563
|
+
"button",
|
|
2564
|
+
{
|
|
2565
|
+
type: "button",
|
|
2566
|
+
"aria-expanded": isExpanded,
|
|
2567
|
+
"aria-label": isExpanded ? "Collapse" : "Expand",
|
|
2568
|
+
onClick: () => setExpandedId(isExpanded ? null : row.id),
|
|
2569
|
+
className: "mt-0.5 grid size-5 shrink-0 place-items-center rounded text-muted-foreground hover:bg-muted focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring [&_svg]:size-4",
|
|
2570
|
+
children: /* @__PURE__ */ jsx24(ChevronIcon, { open: isExpanded })
|
|
2571
|
+
}
|
|
2572
|
+
),
|
|
2573
|
+
/* @__PURE__ */ jsxs21("div", { className: "min-w-0 flex-1", children: [
|
|
2574
|
+
/* @__PURE__ */ jsxs21("div", { className: "flex flex-wrap items-center gap-2", children: [
|
|
2575
|
+
/* @__PURE__ */ jsx24("span", { className: "font-mono text-xs text-muted-foreground", children: row.requestId ?? row.id }),
|
|
2576
|
+
/* @__PURE__ */ jsx24(StatusBadge4, { variant: statusVariant3(row.status), appearance: "dot", children: row.status })
|
|
2577
|
+
] }),
|
|
2578
|
+
/* @__PURE__ */ jsx24("div", { className: "mt-1 truncate text-sm font-medium text-foreground", children: row.failureReason }),
|
|
2579
|
+
/* @__PURE__ */ jsxs21("div", { className: "mt-1 flex flex-wrap items-center gap-x-3 text-xs text-muted-foreground", children: [
|
|
2580
|
+
/* @__PURE__ */ jsxs21("span", { className: "tabular-nums", children: [
|
|
2581
|
+
row.attemptCount,
|
|
2582
|
+
" attempts"
|
|
2583
|
+
] }),
|
|
2584
|
+
/* @__PURE__ */ jsx24("span", { "aria-hidden": "true", className: "text-border", children: "\xB7" }),
|
|
2585
|
+
/* @__PURE__ */ jsxs21("span", { className: "tabular-nums", children: [
|
|
2586
|
+
"first seen ",
|
|
2587
|
+
formatDateTime4(row.firstSeenAt)
|
|
2588
|
+
] })
|
|
2589
|
+
] })
|
|
2481
2590
|
] }),
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
children: "Previous"
|
|
2495
|
-
}
|
|
2496
|
-
),
|
|
2497
|
-
/* @__PURE__ */ jsxs20("span", { className: "text-xs text-muted-foreground", children: [
|
|
2498
|
-
"Page ",
|
|
2591
|
+
/* @__PURE__ */ jsxs21("div", { className: "flex shrink-0 items-center gap-1.5", children: [
|
|
2592
|
+
/* @__PURE__ */ jsx24(Button5, { type: "button", variant: "outline", size: "sm", disabled: replay.isPending, onClick: () => replay.mutate(row.id), children: "Replay" }),
|
|
2593
|
+
/* @__PURE__ */ jsx24(Button5, { type: "button", variant: "ghost", size: "sm", className: "text-destructive", disabled: discard.isPending, onClick: () => discard.mutate(row.id), children: "Discard" })
|
|
2594
|
+
] })
|
|
2595
|
+
] }),
|
|
2596
|
+
isExpanded && /* @__PURE__ */ jsx24("li", { className: "border-t border-border bg-muted/40", children: /* @__PURE__ */ jsx24(DlqMessageDetailRow, { id: row.id, basePath }) })
|
|
2597
|
+
] }, row.id);
|
|
2598
|
+
}) }),
|
|
2599
|
+
/* @__PURE__ */ jsx24(
|
|
2600
|
+
Pager,
|
|
2601
|
+
{
|
|
2602
|
+
label: "Dead-letter pagination",
|
|
2499
2603
|
page,
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
|
|
2604
|
+
totalPages,
|
|
2605
|
+
onPrev: () => setPage((p) => Math.max(1, p - 1)),
|
|
2606
|
+
onNext: () => setPage((p) => Math.min(totalPages, p + 1))
|
|
2607
|
+
}
|
|
2608
|
+
)
|
|
2609
|
+
] })
|
|
2610
|
+
] })
|
|
2611
|
+
] });
|
|
2612
|
+
}
|
|
2613
|
+
function ChevronIcon({ open }) {
|
|
2614
|
+
return /* @__PURE__ */ jsx24(
|
|
2615
|
+
"svg",
|
|
2616
|
+
{
|
|
2617
|
+
viewBox: "0 0 24 24",
|
|
2618
|
+
fill: "none",
|
|
2619
|
+
stroke: "currentColor",
|
|
2620
|
+
strokeWidth: "2",
|
|
2621
|
+
strokeLinecap: "round",
|
|
2622
|
+
strokeLinejoin: "round",
|
|
2623
|
+
className: cn21("transition-transform motion-reduce:transition-none", open && "rotate-90"),
|
|
2624
|
+
children: /* @__PURE__ */ jsx24("path", { d: "m9 18 6-6-6-6" })
|
|
2515
2625
|
}
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
2626
|
+
);
|
|
2627
|
+
}
|
|
2628
|
+
function SkullIcon() {
|
|
2629
|
+
return /* @__PURE__ */ jsxs21("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
2630
|
+
/* @__PURE__ */ jsx24("circle", { cx: "9", cy: "12", r: "1" }),
|
|
2631
|
+
/* @__PURE__ */ jsx24("circle", { cx: "15", cy: "12", r: "1" }),
|
|
2632
|
+
/* @__PURE__ */ jsx24("path", { d: "M8 20v2h8v-2" }),
|
|
2633
|
+
/* @__PURE__ */ jsx24("path", { d: "m12.5 17-.5-1-.5 1h1Z" }),
|
|
2634
|
+
/* @__PURE__ */ jsx24("path", { d: "M16 20a2 2 0 0 0 1.56-3.25 8 8 0 1 0-11.12 0A2 2 0 0 0 8 20" })
|
|
2523
2635
|
] });
|
|
2524
2636
|
}
|
|
2525
2637
|
|
|
@@ -2527,7 +2639,7 @@ function DlqConsole({ basePath = "/api", className }) {
|
|
|
2527
2639
|
import { useMemo as useMemo3, useState as useState12 } from "react";
|
|
2528
2640
|
import { cn as cn22, useToast as useToast10 } from "@quanticjs/react-ui";
|
|
2529
2641
|
import { useApiMutation as useApiMutation11, useApiQuery as useApiQuery16 } from "@quanticjs/react-query";
|
|
2530
|
-
import { Fragment as Fragment4, jsx as
|
|
2642
|
+
import { Fragment as Fragment4, jsx as jsx25, jsxs as jsxs22 } from "react/jsx-runtime";
|
|
2531
2643
|
function normalize2(data) {
|
|
2532
2644
|
if (!data) return [];
|
|
2533
2645
|
if (Array.isArray(data)) return data;
|
|
@@ -2609,10 +2721,10 @@ function CatalogEditor({ basePath = "/api", className }) {
|
|
|
2609
2721
|
setEditingId(`${entry.key}:${entry.locale}`);
|
|
2610
2722
|
setEditValue(entry.value);
|
|
2611
2723
|
};
|
|
2612
|
-
const addForm = /* @__PURE__ */
|
|
2613
|
-
/* @__PURE__ */
|
|
2614
|
-
/* @__PURE__ */
|
|
2615
|
-
/* @__PURE__ */
|
|
2724
|
+
const addForm = /* @__PURE__ */ jsxs22("form", { onSubmit: onAdd, className: "flex flex-wrap items-end gap-3", noValidate: true, children: [
|
|
2725
|
+
/* @__PURE__ */ jsxs22("div", { className: "flex flex-col gap-1", children: [
|
|
2726
|
+
/* @__PURE__ */ jsx25("label", { htmlFor: "catalog-new-key", className: "text-sm font-medium text-foreground", children: "Key" }),
|
|
2727
|
+
/* @__PURE__ */ jsx25(
|
|
2616
2728
|
"input",
|
|
2617
2729
|
{
|
|
2618
2730
|
id: "catalog-new-key",
|
|
@@ -2623,9 +2735,9 @@ function CatalogEditor({ basePath = "/api", className }) {
|
|
|
2623
2735
|
}
|
|
2624
2736
|
)
|
|
2625
2737
|
] }),
|
|
2626
|
-
/* @__PURE__ */
|
|
2627
|
-
/* @__PURE__ */
|
|
2628
|
-
/* @__PURE__ */
|
|
2738
|
+
/* @__PURE__ */ jsxs22("div", { className: "flex flex-col gap-1", children: [
|
|
2739
|
+
/* @__PURE__ */ jsx25("label", { htmlFor: "catalog-new-locale", className: "text-sm font-medium text-foreground", children: "Locale" }),
|
|
2740
|
+
/* @__PURE__ */ jsx25(
|
|
2629
2741
|
"input",
|
|
2630
2742
|
{
|
|
2631
2743
|
id: "catalog-new-locale",
|
|
@@ -2636,9 +2748,9 @@ function CatalogEditor({ basePath = "/api", className }) {
|
|
|
2636
2748
|
}
|
|
2637
2749
|
)
|
|
2638
2750
|
] }),
|
|
2639
|
-
/* @__PURE__ */
|
|
2640
|
-
/* @__PURE__ */
|
|
2641
|
-
/* @__PURE__ */
|
|
2751
|
+
/* @__PURE__ */ jsxs22("div", { className: "flex flex-col gap-1", children: [
|
|
2752
|
+
/* @__PURE__ */ jsx25("label", { htmlFor: "catalog-new-value", className: "text-sm font-medium text-foreground", children: "Value" }),
|
|
2753
|
+
/* @__PURE__ */ jsx25(
|
|
2642
2754
|
"input",
|
|
2643
2755
|
{
|
|
2644
2756
|
id: "catalog-new-value",
|
|
@@ -2649,7 +2761,7 @@ function CatalogEditor({ basePath = "/api", className }) {
|
|
|
2649
2761
|
}
|
|
2650
2762
|
)
|
|
2651
2763
|
] }),
|
|
2652
|
-
/* @__PURE__ */
|
|
2764
|
+
/* @__PURE__ */ jsx25(
|
|
2653
2765
|
"button",
|
|
2654
2766
|
{
|
|
2655
2767
|
type: "submit",
|
|
@@ -2659,9 +2771,9 @@ function CatalogEditor({ basePath = "/api", className }) {
|
|
|
2659
2771
|
}
|
|
2660
2772
|
)
|
|
2661
2773
|
] });
|
|
2662
|
-
const filterInput = /* @__PURE__ */
|
|
2663
|
-
/* @__PURE__ */
|
|
2664
|
-
/* @__PURE__ */
|
|
2774
|
+
const filterInput = /* @__PURE__ */ jsxs22("div", { className: "flex flex-col gap-1", children: [
|
|
2775
|
+
/* @__PURE__ */ jsx25("label", { htmlFor: "catalog-filter", className: "text-sm font-medium text-foreground", children: "Filter by key" }),
|
|
2776
|
+
/* @__PURE__ */ jsx25(
|
|
2665
2777
|
"input",
|
|
2666
2778
|
{
|
|
2667
2779
|
id: "catalog-filter",
|
|
@@ -2674,14 +2786,14 @@ function CatalogEditor({ basePath = "/api", className }) {
|
|
|
2674
2786
|
] });
|
|
2675
2787
|
let body;
|
|
2676
2788
|
if (isLoading) {
|
|
2677
|
-
body = /* @__PURE__ */
|
|
2678
|
-
/* @__PURE__ */
|
|
2679
|
-
[0, 1, 2].map((i) => /* @__PURE__ */
|
|
2789
|
+
body = /* @__PURE__ */ jsxs22("div", { role: "status", "aria-label": "Loading catalog", className: "flex flex-col gap-2 p-4", children: [
|
|
2790
|
+
/* @__PURE__ */ jsx25("span", { className: "sr-only", children: "Loading catalog" }),
|
|
2791
|
+
[0, 1, 2].map((i) => /* @__PURE__ */ jsx25("div", { "aria-hidden": "true", className: "h-10 animate-pulse rounded bg-muted" }, i))
|
|
2680
2792
|
] });
|
|
2681
2793
|
} else if (isError) {
|
|
2682
|
-
body = /* @__PURE__ */
|
|
2683
|
-
/* @__PURE__ */
|
|
2684
|
-
/* @__PURE__ */
|
|
2794
|
+
body = /* @__PURE__ */ jsxs22("div", { className: "flex flex-col items-start gap-3 p-4", children: [
|
|
2795
|
+
/* @__PURE__ */ jsx25("p", { className: "text-sm text-foreground", children: "Failed to load catalog" }),
|
|
2796
|
+
/* @__PURE__ */ jsx25(
|
|
2685
2797
|
"button",
|
|
2686
2798
|
{
|
|
2687
2799
|
type: "button",
|
|
@@ -2692,22 +2804,22 @@ function CatalogEditor({ basePath = "/api", className }) {
|
|
|
2692
2804
|
)
|
|
2693
2805
|
] });
|
|
2694
2806
|
} else if (filtered.length === 0) {
|
|
2695
|
-
body = /* @__PURE__ */
|
|
2807
|
+
body = /* @__PURE__ */ jsx25("div", { className: "p-6 text-center text-sm text-muted-foreground", children: entries.length === 0 ? "No catalog entries" : "No entries match your filter" });
|
|
2696
2808
|
} else {
|
|
2697
|
-
body = /* @__PURE__ */
|
|
2698
|
-
/* @__PURE__ */
|
|
2699
|
-
/* @__PURE__ */
|
|
2700
|
-
/* @__PURE__ */
|
|
2701
|
-
/* @__PURE__ */
|
|
2702
|
-
/* @__PURE__ */
|
|
2809
|
+
body = /* @__PURE__ */ jsxs22("table", { className: "w-full text-sm", children: [
|
|
2810
|
+
/* @__PURE__ */ jsx25("thead", { children: /* @__PURE__ */ jsxs22("tr", { className: "border-b border-border text-start text-muted-foreground", children: [
|
|
2811
|
+
/* @__PURE__ */ jsx25("th", { scope: "col", className: "py-2 pe-4 font-medium", children: "Key" }),
|
|
2812
|
+
/* @__PURE__ */ jsx25("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Locale" }),
|
|
2813
|
+
/* @__PURE__ */ jsx25("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Value" }),
|
|
2814
|
+
/* @__PURE__ */ jsx25("th", { scope: "col", className: "px-4 py-2 font-medium", children: /* @__PURE__ */ jsx25("span", { className: "sr-only", children: "Actions" }) })
|
|
2703
2815
|
] }) }),
|
|
2704
|
-
/* @__PURE__ */
|
|
2816
|
+
/* @__PURE__ */ jsx25("tbody", { children: filtered.map((entry) => {
|
|
2705
2817
|
const rowId = `${entry.key}:${entry.locale}`;
|
|
2706
2818
|
const isEditing = editingId === rowId;
|
|
2707
|
-
return /* @__PURE__ */
|
|
2708
|
-
/* @__PURE__ */
|
|
2709
|
-
/* @__PURE__ */
|
|
2710
|
-
/* @__PURE__ */
|
|
2819
|
+
return /* @__PURE__ */ jsxs22("tr", { className: "border-b border-border", children: [
|
|
2820
|
+
/* @__PURE__ */ jsx25("td", { className: "py-3 pe-4 font-mono text-foreground", children: entry.key }),
|
|
2821
|
+
/* @__PURE__ */ jsx25("td", { className: "px-4 py-3 text-foreground", children: entry.locale }),
|
|
2822
|
+
/* @__PURE__ */ jsx25("td", { className: "px-4 py-3 text-foreground", children: isEditing ? /* @__PURE__ */ jsx25(
|
|
2711
2823
|
"input",
|
|
2712
2824
|
{
|
|
2713
2825
|
type: "text",
|
|
@@ -2717,8 +2829,8 @@ function CatalogEditor({ basePath = "/api", className }) {
|
|
|
2717
2829
|
className: "w-full rounded-md border border-border bg-background px-3 py-1.5 text-sm text-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring"
|
|
2718
2830
|
}
|
|
2719
2831
|
) : entry.value }),
|
|
2720
|
-
/* @__PURE__ */
|
|
2721
|
-
/* @__PURE__ */
|
|
2832
|
+
/* @__PURE__ */ jsx25("td", { className: "px-4 py-3", children: /* @__PURE__ */ jsx25("div", { className: "flex items-center gap-2", children: isEditing ? /* @__PURE__ */ jsxs22(Fragment4, { children: [
|
|
2833
|
+
/* @__PURE__ */ jsx25(
|
|
2722
2834
|
"button",
|
|
2723
2835
|
{
|
|
2724
2836
|
type: "button",
|
|
@@ -2732,7 +2844,7 @@ function CatalogEditor({ basePath = "/api", className }) {
|
|
|
2732
2844
|
children: "Save"
|
|
2733
2845
|
}
|
|
2734
2846
|
),
|
|
2735
|
-
/* @__PURE__ */
|
|
2847
|
+
/* @__PURE__ */ jsx25(
|
|
2736
2848
|
"button",
|
|
2737
2849
|
{
|
|
2738
2850
|
type: "button",
|
|
@@ -2741,8 +2853,8 @@ function CatalogEditor({ basePath = "/api", className }) {
|
|
|
2741
2853
|
children: "Cancel"
|
|
2742
2854
|
}
|
|
2743
2855
|
)
|
|
2744
|
-
] }) : /* @__PURE__ */
|
|
2745
|
-
/* @__PURE__ */
|
|
2856
|
+
] }) : /* @__PURE__ */ jsxs22(Fragment4, { children: [
|
|
2857
|
+
/* @__PURE__ */ jsx25(
|
|
2746
2858
|
"button",
|
|
2747
2859
|
{
|
|
2748
2860
|
type: "button",
|
|
@@ -2751,7 +2863,7 @@ function CatalogEditor({ basePath = "/api", className }) {
|
|
|
2751
2863
|
children: "Edit"
|
|
2752
2864
|
}
|
|
2753
2865
|
),
|
|
2754
|
-
/* @__PURE__ */
|
|
2866
|
+
/* @__PURE__ */ jsx25(
|
|
2755
2867
|
"button",
|
|
2756
2868
|
{
|
|
2757
2869
|
type: "button",
|
|
@@ -2766,7 +2878,7 @@ function CatalogEditor({ basePath = "/api", className }) {
|
|
|
2766
2878
|
}) })
|
|
2767
2879
|
] });
|
|
2768
2880
|
}
|
|
2769
|
-
return /* @__PURE__ */
|
|
2881
|
+
return /* @__PURE__ */ jsxs22("section", { "aria-label": "Catalog editor", className: cn22("flex flex-col gap-4", className), children: [
|
|
2770
2882
|
addForm,
|
|
2771
2883
|
filterInput,
|
|
2772
2884
|
body
|
|
@@ -2776,7 +2888,7 @@ function CatalogEditor({ basePath = "/api", className }) {
|
|
|
2776
2888
|
// src/missing-translations-panel.tsx
|
|
2777
2889
|
import { cn as cn23 } from "@quanticjs/react-ui";
|
|
2778
2890
|
import { useApiQuery as useApiQuery17 } from "@quanticjs/react-query";
|
|
2779
|
-
import { jsx as
|
|
2891
|
+
import { jsx as jsx26, jsxs as jsxs23 } from "react/jsx-runtime";
|
|
2780
2892
|
function normalize3(data) {
|
|
2781
2893
|
if (Array.isArray(data)) return data;
|
|
2782
2894
|
return data?.missing ?? [];
|
|
@@ -2790,23 +2902,23 @@ function MissingTranslationsPanel({
|
|
|
2790
2902
|
(client) => client.get(`${basePath}/i18n/catalog/missing`)
|
|
2791
2903
|
);
|
|
2792
2904
|
if (isLoading) {
|
|
2793
|
-
return /* @__PURE__ */
|
|
2905
|
+
return /* @__PURE__ */ jsxs23(
|
|
2794
2906
|
"div",
|
|
2795
2907
|
{
|
|
2796
2908
|
role: "status",
|
|
2797
2909
|
"aria-label": "Loading missing translations",
|
|
2798
2910
|
className: cn23("flex flex-col gap-2 p-4", className),
|
|
2799
2911
|
children: [
|
|
2800
|
-
/* @__PURE__ */
|
|
2801
|
-
[0, 1, 2].map((i) => /* @__PURE__ */
|
|
2912
|
+
/* @__PURE__ */ jsx26("span", { className: "sr-only", children: "Loading missing translations" }),
|
|
2913
|
+
[0, 1, 2].map((i) => /* @__PURE__ */ jsx26("div", { "aria-hidden": "true", className: "h-10 animate-pulse rounded bg-muted" }, i))
|
|
2802
2914
|
]
|
|
2803
2915
|
}
|
|
2804
2916
|
);
|
|
2805
2917
|
}
|
|
2806
2918
|
if (isError) {
|
|
2807
|
-
return /* @__PURE__ */
|
|
2808
|
-
/* @__PURE__ */
|
|
2809
|
-
/* @__PURE__ */
|
|
2919
|
+
return /* @__PURE__ */ jsxs23("div", { className: cn23("flex flex-col items-start gap-3 p-4", className), children: [
|
|
2920
|
+
/* @__PURE__ */ jsx26("p", { className: "text-sm text-foreground", children: "Failed to load missing translations" }),
|
|
2921
|
+
/* @__PURE__ */ jsx26(
|
|
2810
2922
|
"button",
|
|
2811
2923
|
{
|
|
2812
2924
|
type: "button",
|
|
@@ -2819,18 +2931,18 @@ function MissingTranslationsPanel({
|
|
|
2819
2931
|
}
|
|
2820
2932
|
const rows = normalize3(data);
|
|
2821
2933
|
if (rows.length === 0) {
|
|
2822
|
-
return /* @__PURE__ */
|
|
2934
|
+
return /* @__PURE__ */ jsx26("div", { className: cn23("p-6 text-center text-sm text-muted-foreground", className), children: "No missing translations" });
|
|
2823
2935
|
}
|
|
2824
|
-
return /* @__PURE__ */
|
|
2825
|
-
/* @__PURE__ */
|
|
2826
|
-
/* @__PURE__ */
|
|
2827
|
-
/* @__PURE__ */
|
|
2828
|
-
/* @__PURE__ */
|
|
2936
|
+
return /* @__PURE__ */ jsx26("section", { "aria-label": "Missing translations", className: cn23("flex flex-col gap-3", className), children: /* @__PURE__ */ jsxs23("table", { className: "w-full text-sm", children: [
|
|
2937
|
+
/* @__PURE__ */ jsx26("thead", { children: /* @__PURE__ */ jsxs23("tr", { className: "border-b border-border text-start text-muted-foreground", children: [
|
|
2938
|
+
/* @__PURE__ */ jsx26("th", { scope: "col", className: "py-2 pe-4 font-medium", children: "Key" }),
|
|
2939
|
+
/* @__PURE__ */ jsx26("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Locale" }),
|
|
2940
|
+
/* @__PURE__ */ jsx26("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Type" })
|
|
2829
2941
|
] }) }),
|
|
2830
|
-
/* @__PURE__ */
|
|
2831
|
-
/* @__PURE__ */
|
|
2832
|
-
/* @__PURE__ */
|
|
2833
|
-
/* @__PURE__ */
|
|
2942
|
+
/* @__PURE__ */ jsx26("tbody", { children: rows.map((row, i) => /* @__PURE__ */ jsxs23("tr", { className: "border-b border-border", children: [
|
|
2943
|
+
/* @__PURE__ */ jsx26("td", { className: "py-3 pe-4 font-mono text-foreground", children: row.key }),
|
|
2944
|
+
/* @__PURE__ */ jsx26("td", { className: "px-4 py-3 text-foreground", children: row.locale }),
|
|
2945
|
+
/* @__PURE__ */ jsx26("td", { className: "px-4 py-3 text-muted-foreground", children: row.type ?? "\u2014" })
|
|
2834
2946
|
] }, `${row.key}:${row.locale}:${i}`)) })
|
|
2835
2947
|
] }) });
|
|
2836
2948
|
}
|
|
@@ -2838,7 +2950,7 @@ function MissingTranslationsPanel({
|
|
|
2838
2950
|
// src/fallback-report-panel.tsx
|
|
2839
2951
|
import { cn as cn24 } from "@quanticjs/react-ui";
|
|
2840
2952
|
import { useApiQuery as useApiQuery18 } from "@quanticjs/react-query";
|
|
2841
|
-
import { jsx as
|
|
2953
|
+
import { jsx as jsx27, jsxs as jsxs24 } from "react/jsx-runtime";
|
|
2842
2954
|
function normalize4(data) {
|
|
2843
2955
|
if (Array.isArray(data)) return data;
|
|
2844
2956
|
return data?.entries ?? [];
|
|
@@ -2849,23 +2961,23 @@ function FallbackReportPanel({ basePath = "/api", className }) {
|
|
|
2849
2961
|
(client) => client.get(`${basePath}/i18n/catalog/fallback-report`)
|
|
2850
2962
|
);
|
|
2851
2963
|
if (isLoading) {
|
|
2852
|
-
return /* @__PURE__ */
|
|
2964
|
+
return /* @__PURE__ */ jsxs24(
|
|
2853
2965
|
"div",
|
|
2854
2966
|
{
|
|
2855
2967
|
role: "status",
|
|
2856
2968
|
"aria-label": "Loading fallback report",
|
|
2857
2969
|
className: cn24("flex flex-col gap-2 p-4", className),
|
|
2858
2970
|
children: [
|
|
2859
|
-
/* @__PURE__ */
|
|
2860
|
-
[0, 1, 2].map((i) => /* @__PURE__ */
|
|
2971
|
+
/* @__PURE__ */ jsx27("span", { className: "sr-only", children: "Loading fallback report" }),
|
|
2972
|
+
[0, 1, 2].map((i) => /* @__PURE__ */ jsx27("div", { "aria-hidden": "true", className: "h-10 animate-pulse rounded bg-muted" }, i))
|
|
2861
2973
|
]
|
|
2862
2974
|
}
|
|
2863
2975
|
);
|
|
2864
2976
|
}
|
|
2865
2977
|
if (isError) {
|
|
2866
|
-
return /* @__PURE__ */
|
|
2867
|
-
/* @__PURE__ */
|
|
2868
|
-
/* @__PURE__ */
|
|
2978
|
+
return /* @__PURE__ */ jsxs24("div", { className: cn24("flex flex-col items-start gap-3 p-4", className), children: [
|
|
2979
|
+
/* @__PURE__ */ jsx27("p", { className: "text-sm text-foreground", children: "Failed to load fallback report" }),
|
|
2980
|
+
/* @__PURE__ */ jsx27(
|
|
2869
2981
|
"button",
|
|
2870
2982
|
{
|
|
2871
2983
|
type: "button",
|
|
@@ -2878,22 +2990,22 @@ function FallbackReportPanel({ basePath = "/api", className }) {
|
|
|
2878
2990
|
}
|
|
2879
2991
|
const rows = normalize4(data);
|
|
2880
2992
|
if (rows.length === 0) {
|
|
2881
|
-
return /* @__PURE__ */
|
|
2993
|
+
return /* @__PURE__ */ jsx27("div", { className: cn24("p-6 text-center text-sm text-muted-foreground", className), children: "No fallbacks reported" });
|
|
2882
2994
|
}
|
|
2883
|
-
return /* @__PURE__ */
|
|
2884
|
-
/* @__PURE__ */
|
|
2885
|
-
/* @__PURE__ */
|
|
2886
|
-
/* @__PURE__ */
|
|
2887
|
-
/* @__PURE__ */
|
|
2888
|
-
/* @__PURE__ */
|
|
2995
|
+
return /* @__PURE__ */ jsx27("section", { "aria-label": "Fallback report", className: cn24("flex flex-col gap-3", className), children: /* @__PURE__ */ jsxs24("table", { className: "w-full text-sm", children: [
|
|
2996
|
+
/* @__PURE__ */ jsx27("thead", { children: /* @__PURE__ */ jsxs24("tr", { className: "border-b border-border text-start text-muted-foreground", children: [
|
|
2997
|
+
/* @__PURE__ */ jsx27("th", { scope: "col", className: "py-2 pe-4 font-medium", children: "Key" }),
|
|
2998
|
+
/* @__PURE__ */ jsx27("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Requested" }),
|
|
2999
|
+
/* @__PURE__ */ jsx27("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Resolved" }),
|
|
3000
|
+
/* @__PURE__ */ jsx27("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Chain" })
|
|
2889
3001
|
] }) }),
|
|
2890
|
-
/* @__PURE__ */
|
|
2891
|
-
/* @__PURE__ */
|
|
2892
|
-
/* @__PURE__ */
|
|
2893
|
-
/* @__PURE__ */
|
|
2894
|
-
/* @__PURE__ */
|
|
2895
|
-
/* @__PURE__ */
|
|
2896
|
-
si < (row.steps?.length ?? 0) - 1 && /* @__PURE__ */
|
|
3002
|
+
/* @__PURE__ */ jsx27("tbody", { children: rows.map((row, i) => /* @__PURE__ */ jsxs24("tr", { className: "border-b border-border", children: [
|
|
3003
|
+
/* @__PURE__ */ jsx27("td", { className: "py-3 pe-4 font-mono text-foreground", children: row.key }),
|
|
3004
|
+
/* @__PURE__ */ jsx27("td", { className: "px-4 py-3 text-foreground", children: row.requestedLocale }),
|
|
3005
|
+
/* @__PURE__ */ jsx27("td", { className: "px-4 py-3 text-foreground", children: row.resolvedLocale }),
|
|
3006
|
+
/* @__PURE__ */ jsx27("td", { className: "px-4 py-3 text-muted-foreground", children: row.steps && row.steps.length > 0 ? /* @__PURE__ */ jsx27("ol", { className: "flex flex-wrap items-center gap-1", children: row.steps.map((step, si) => /* @__PURE__ */ jsxs24("li", { className: "flex items-center gap-1", children: [
|
|
3007
|
+
/* @__PURE__ */ jsx27("span", { className: "rounded bg-muted px-1.5 py-0.5 text-xs text-foreground", children: step }),
|
|
3008
|
+
si < (row.steps?.length ?? 0) - 1 && /* @__PURE__ */ jsx27("span", { "aria-hidden": "true", className: "text-muted-foreground", children: "\u2192" })
|
|
2897
3009
|
] }, `${step}:${si}`)) }) : "\u2014" })
|
|
2898
3010
|
] }, `${row.key}:${row.requestedLocale}:${i}`)) })
|
|
2899
3011
|
] }) });
|
|
@@ -2903,7 +3015,7 @@ function FallbackReportPanel({ basePath = "/api", className }) {
|
|
|
2903
3015
|
import { useState as useState13 } from "react";
|
|
2904
3016
|
import { cn as cn25, formatDateTime as formatDateTime5, useToast as useToast11 } from "@quanticjs/react-ui";
|
|
2905
3017
|
import { useApiMutation as useApiMutation12, useApiQuery as useApiQuery19 } from "@quanticjs/react-query";
|
|
2906
|
-
import { Fragment as Fragment5, jsx as
|
|
3018
|
+
import { Fragment as Fragment5, jsx as jsx28, jsxs as jsxs25 } from "react/jsx-runtime";
|
|
2907
3019
|
var LIMIT5 = 20;
|
|
2908
3020
|
function RecipientAdminPanel({ basePath = "/api", className }) {
|
|
2909
3021
|
const toast = useToast11();
|
|
@@ -2954,10 +3066,10 @@ function RecipientAdminPanel({ basePath = "/api", className }) {
|
|
|
2954
3066
|
if (row.consentSms) active.push("sms");
|
|
2955
3067
|
return active.length > 0 ? active.join(", ") : "none";
|
|
2956
3068
|
};
|
|
2957
|
-
const searchForm = /* @__PURE__ */
|
|
2958
|
-
/* @__PURE__ */
|
|
2959
|
-
/* @__PURE__ */
|
|
2960
|
-
/* @__PURE__ */
|
|
3069
|
+
const searchForm = /* @__PURE__ */ jsxs25("form", { onSubmit: onSearch, className: "flex flex-wrap items-end gap-3", noValidate: true, children: [
|
|
3070
|
+
/* @__PURE__ */ jsxs25("div", { className: "flex flex-col gap-1", children: [
|
|
3071
|
+
/* @__PURE__ */ jsx28("label", { htmlFor: "recipient-search", className: "text-sm font-medium text-foreground", children: "Search recipients" }),
|
|
3072
|
+
/* @__PURE__ */ jsx28(
|
|
2961
3073
|
"input",
|
|
2962
3074
|
{
|
|
2963
3075
|
id: "recipient-search",
|
|
@@ -2968,7 +3080,7 @@ function RecipientAdminPanel({ basePath = "/api", className }) {
|
|
|
2968
3080
|
}
|
|
2969
3081
|
)
|
|
2970
3082
|
] }),
|
|
2971
|
-
/* @__PURE__ */
|
|
3083
|
+
/* @__PURE__ */ jsx28(
|
|
2972
3084
|
"button",
|
|
2973
3085
|
{
|
|
2974
3086
|
type: "submit",
|
|
@@ -2979,14 +3091,14 @@ function RecipientAdminPanel({ basePath = "/api", className }) {
|
|
|
2979
3091
|
] });
|
|
2980
3092
|
let body;
|
|
2981
3093
|
if (isLoading) {
|
|
2982
|
-
body = /* @__PURE__ */
|
|
2983
|
-
/* @__PURE__ */
|
|
2984
|
-
[0, 1, 2].map((i) => /* @__PURE__ */
|
|
3094
|
+
body = /* @__PURE__ */ jsxs25("div", { role: "status", "aria-label": "Loading recipients", className: "flex flex-col gap-2 p-4", children: [
|
|
3095
|
+
/* @__PURE__ */ jsx28("span", { className: "sr-only", children: "Loading recipients" }),
|
|
3096
|
+
[0, 1, 2].map((i) => /* @__PURE__ */ jsx28("div", { "aria-hidden": "true", className: "h-10 animate-pulse rounded bg-muted" }, i))
|
|
2985
3097
|
] });
|
|
2986
3098
|
} else if (isError) {
|
|
2987
|
-
body = /* @__PURE__ */
|
|
2988
|
-
/* @__PURE__ */
|
|
2989
|
-
/* @__PURE__ */
|
|
3099
|
+
body = /* @__PURE__ */ jsxs25("div", { className: "flex flex-col items-start gap-3 p-4", children: [
|
|
3100
|
+
/* @__PURE__ */ jsx28("p", { className: "text-sm text-foreground", children: "Failed to load recipients" }),
|
|
3101
|
+
/* @__PURE__ */ jsx28(
|
|
2990
3102
|
"button",
|
|
2991
3103
|
{
|
|
2992
3104
|
type: "button",
|
|
@@ -3000,26 +3112,26 @@ function RecipientAdminPanel({ basePath = "/api", className }) {
|
|
|
3000
3112
|
const rows = data?.items ?? [];
|
|
3001
3113
|
const totalPages = data?.totalPages ?? 1;
|
|
3002
3114
|
if (rows.length === 0) {
|
|
3003
|
-
body = /* @__PURE__ */
|
|
3115
|
+
body = /* @__PURE__ */ jsx28("div", { className: "p-6 text-center text-sm text-muted-foreground", children: "No recipients" });
|
|
3004
3116
|
} else {
|
|
3005
|
-
body = /* @__PURE__ */
|
|
3006
|
-
/* @__PURE__ */
|
|
3007
|
-
/* @__PURE__ */
|
|
3008
|
-
/* @__PURE__ */
|
|
3009
|
-
/* @__PURE__ */
|
|
3010
|
-
/* @__PURE__ */
|
|
3011
|
-
/* @__PURE__ */
|
|
3012
|
-
/* @__PURE__ */
|
|
3013
|
-
/* @__PURE__ */
|
|
3117
|
+
body = /* @__PURE__ */ jsxs25(Fragment5, { children: [
|
|
3118
|
+
/* @__PURE__ */ jsxs25("table", { className: "w-full text-sm", children: [
|
|
3119
|
+
/* @__PURE__ */ jsx28("thead", { children: /* @__PURE__ */ jsxs25("tr", { className: "border-b border-border text-start text-muted-foreground", children: [
|
|
3120
|
+
/* @__PURE__ */ jsx28("th", { scope: "col", className: "py-2 pe-4 font-medium", children: "User" }),
|
|
3121
|
+
/* @__PURE__ */ jsx28("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Email" }),
|
|
3122
|
+
/* @__PURE__ */ jsx28("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Phone" }),
|
|
3123
|
+
/* @__PURE__ */ jsx28("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Consents" }),
|
|
3124
|
+
/* @__PURE__ */ jsx28("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Created" }),
|
|
3125
|
+
/* @__PURE__ */ jsx28("th", { scope: "col", className: "px-4 py-2 font-medium", children: /* @__PURE__ */ jsx28("span", { className: "sr-only", children: "Actions" }) })
|
|
3014
3126
|
] }) }),
|
|
3015
|
-
/* @__PURE__ */
|
|
3016
|
-
/* @__PURE__ */
|
|
3017
|
-
/* @__PURE__ */
|
|
3018
|
-
/* @__PURE__ */
|
|
3019
|
-
/* @__PURE__ */
|
|
3020
|
-
/* @__PURE__ */
|
|
3021
|
-
/* @__PURE__ */
|
|
3022
|
-
/* @__PURE__ */
|
|
3127
|
+
/* @__PURE__ */ jsx28("tbody", { children: rows.map((row) => /* @__PURE__ */ jsxs25("tr", { className: "border-b border-border", children: [
|
|
3128
|
+
/* @__PURE__ */ jsx28("td", { className: "py-3 pe-4 font-mono text-foreground", children: row.userId }),
|
|
3129
|
+
/* @__PURE__ */ jsx28("td", { className: "px-4 py-3 text-foreground", children: row.email ?? "\u2014" }),
|
|
3130
|
+
/* @__PURE__ */ jsx28("td", { className: "px-4 py-3 text-foreground", children: row.phone ?? "\u2014" }),
|
|
3131
|
+
/* @__PURE__ */ jsx28("td", { className: "px-4 py-3 text-muted-foreground", children: consents(row) }),
|
|
3132
|
+
/* @__PURE__ */ jsx28("td", { className: "px-4 py-3 text-muted-foreground", children: formatDateTime5(row.createdAt) }),
|
|
3133
|
+
/* @__PURE__ */ jsx28("td", { className: "px-4 py-3", children: /* @__PURE__ */ jsxs25("div", { className: "flex items-center gap-2", children: [
|
|
3134
|
+
/* @__PURE__ */ jsx28(
|
|
3023
3135
|
"button",
|
|
3024
3136
|
{
|
|
3025
3137
|
type: "button",
|
|
@@ -3029,7 +3141,7 @@ function RecipientAdminPanel({ basePath = "/api", className }) {
|
|
|
3029
3141
|
children: "Export"
|
|
3030
3142
|
}
|
|
3031
3143
|
),
|
|
3032
|
-
/* @__PURE__ */
|
|
3144
|
+
/* @__PURE__ */ jsx28(
|
|
3033
3145
|
"button",
|
|
3034
3146
|
{
|
|
3035
3147
|
type: "button",
|
|
@@ -3042,8 +3154,8 @@ function RecipientAdminPanel({ basePath = "/api", className }) {
|
|
|
3042
3154
|
] }) })
|
|
3043
3155
|
] }, row.userId)) })
|
|
3044
3156
|
] }),
|
|
3045
|
-
/* @__PURE__ */
|
|
3046
|
-
/* @__PURE__ */
|
|
3157
|
+
/* @__PURE__ */ jsxs25("nav", { "aria-label": "Recipient pagination", className: "flex items-center justify-between", children: [
|
|
3158
|
+
/* @__PURE__ */ jsx28(
|
|
3047
3159
|
"button",
|
|
3048
3160
|
{
|
|
3049
3161
|
type: "button",
|
|
@@ -3053,13 +3165,13 @@ function RecipientAdminPanel({ basePath = "/api", className }) {
|
|
|
3053
3165
|
children: "Previous"
|
|
3054
3166
|
}
|
|
3055
3167
|
),
|
|
3056
|
-
/* @__PURE__ */
|
|
3168
|
+
/* @__PURE__ */ jsxs25("span", { className: "text-xs text-muted-foreground", children: [
|
|
3057
3169
|
"Page ",
|
|
3058
3170
|
page,
|
|
3059
3171
|
" of ",
|
|
3060
3172
|
totalPages
|
|
3061
3173
|
] }),
|
|
3062
|
-
/* @__PURE__ */
|
|
3174
|
+
/* @__PURE__ */ jsx28(
|
|
3063
3175
|
"button",
|
|
3064
3176
|
{
|
|
3065
3177
|
type: "button",
|
|
@@ -3073,7 +3185,7 @@ function RecipientAdminPanel({ basePath = "/api", className }) {
|
|
|
3073
3185
|
] });
|
|
3074
3186
|
}
|
|
3075
3187
|
}
|
|
3076
|
-
return /* @__PURE__ */
|
|
3188
|
+
return /* @__PURE__ */ jsxs25("section", { "aria-label": "Recipient administration", className: cn25("flex flex-col gap-4", className), children: [
|
|
3077
3189
|
searchForm,
|
|
3078
3190
|
body
|
|
3079
3191
|
] });
|
|
@@ -3083,7 +3195,7 @@ function RecipientAdminPanel({ basePath = "/api", className }) {
|
|
|
3083
3195
|
import { Fragment as Fragment6, useState as useState14 } from "react";
|
|
3084
3196
|
import { cn as cn26, formatDateTime as formatDateTime6, useToast as useToast12, StatusBadge as StatusBadge5 } from "@quanticjs/react-ui";
|
|
3085
3197
|
import { useApiMutation as useApiMutation13, useApiQuery as useApiQuery20 } from "@quanticjs/react-query";
|
|
3086
|
-
import { jsx as
|
|
3198
|
+
import { jsx as jsx29, jsxs as jsxs26 } from "react/jsx-runtime";
|
|
3087
3199
|
var EVENT_TYPES = [
|
|
3088
3200
|
"notification.sent",
|
|
3089
3201
|
"notification.delivered",
|
|
@@ -3109,15 +3221,15 @@ function WebhookDeliveries({ endpointId, basePath }) {
|
|
|
3109
3221
|
(client) => client.get(`${basePath}/webhook-endpoints/${endpointId}/deliveries`)
|
|
3110
3222
|
);
|
|
3111
3223
|
if (isLoading) {
|
|
3112
|
-
return /* @__PURE__ */
|
|
3113
|
-
/* @__PURE__ */
|
|
3114
|
-
[0, 1].map((i) => /* @__PURE__ */
|
|
3224
|
+
return /* @__PURE__ */ jsxs26("div", { role: "status", "aria-label": "Loading deliveries", className: "flex flex-col gap-2 p-3", children: [
|
|
3225
|
+
/* @__PURE__ */ jsx29("span", { className: "sr-only", children: "Loading deliveries" }),
|
|
3226
|
+
[0, 1].map((i) => /* @__PURE__ */ jsx29("div", { "aria-hidden": "true", className: "h-8 animate-pulse rounded bg-muted" }, i))
|
|
3115
3227
|
] });
|
|
3116
3228
|
}
|
|
3117
3229
|
if (isError) {
|
|
3118
|
-
return /* @__PURE__ */
|
|
3119
|
-
/* @__PURE__ */
|
|
3120
|
-
/* @__PURE__ */
|
|
3230
|
+
return /* @__PURE__ */ jsxs26("div", { className: "flex flex-col items-start gap-2 p-3", children: [
|
|
3231
|
+
/* @__PURE__ */ jsx29("p", { className: "text-sm text-foreground", children: "Failed to load deliveries" }),
|
|
3232
|
+
/* @__PURE__ */ jsx29(
|
|
3121
3233
|
"button",
|
|
3122
3234
|
{
|
|
3123
3235
|
type: "button",
|
|
@@ -3130,18 +3242,18 @@ function WebhookDeliveries({ endpointId, basePath }) {
|
|
|
3130
3242
|
}
|
|
3131
3243
|
const rows = normalizeDeliveries(data);
|
|
3132
3244
|
if (rows.length === 0) {
|
|
3133
|
-
return /* @__PURE__ */
|
|
3245
|
+
return /* @__PURE__ */ jsx29("div", { className: "p-3 text-center text-sm text-muted-foreground", children: "No deliveries" });
|
|
3134
3246
|
}
|
|
3135
|
-
return /* @__PURE__ */
|
|
3136
|
-
/* @__PURE__ */
|
|
3137
|
-
/* @__PURE__ */
|
|
3138
|
-
/* @__PURE__ */
|
|
3139
|
-
/* @__PURE__ */
|
|
3247
|
+
return /* @__PURE__ */ jsxs26("table", { className: "w-full text-sm", children: [
|
|
3248
|
+
/* @__PURE__ */ jsx29("thead", { children: /* @__PURE__ */ jsxs26("tr", { className: "border-b border-border text-start text-muted-foreground", children: [
|
|
3249
|
+
/* @__PURE__ */ jsx29("th", { scope: "col", className: "py-2 pe-4 font-medium", children: "Delivery" }),
|
|
3250
|
+
/* @__PURE__ */ jsx29("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Status" }),
|
|
3251
|
+
/* @__PURE__ */ jsx29("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Created" })
|
|
3140
3252
|
] }) }),
|
|
3141
|
-
/* @__PURE__ */
|
|
3142
|
-
/* @__PURE__ */
|
|
3143
|
-
/* @__PURE__ */
|
|
3144
|
-
/* @__PURE__ */
|
|
3253
|
+
/* @__PURE__ */ jsx29("tbody", { children: rows.map((row) => /* @__PURE__ */ jsxs26("tr", { className: "border-b border-border", children: [
|
|
3254
|
+
/* @__PURE__ */ jsx29("td", { className: "py-2 pe-4 font-mono text-foreground", children: row.id }),
|
|
3255
|
+
/* @__PURE__ */ jsx29("td", { className: "px-4 py-2 text-muted-foreground", children: row.status }),
|
|
3256
|
+
/* @__PURE__ */ jsx29("td", { className: "px-4 py-2 text-muted-foreground", children: formatDateTime6(row.createdAt) })
|
|
3145
3257
|
] }, row.id)) })
|
|
3146
3258
|
] });
|
|
3147
3259
|
}
|
|
@@ -3216,10 +3328,10 @@ function WebhookEndpointManager({
|
|
|
3216
3328
|
remove.mutate(id);
|
|
3217
3329
|
}
|
|
3218
3330
|
};
|
|
3219
|
-
const createForm = /* @__PURE__ */
|
|
3220
|
-
/* @__PURE__ */
|
|
3221
|
-
/* @__PURE__ */
|
|
3222
|
-
/* @__PURE__ */
|
|
3331
|
+
const createForm = /* @__PURE__ */ jsxs26("form", { onSubmit: onCreate, className: "flex flex-col gap-3", noValidate: true, children: [
|
|
3332
|
+
/* @__PURE__ */ jsxs26("div", { className: "flex flex-col gap-1", children: [
|
|
3333
|
+
/* @__PURE__ */ jsx29("label", { htmlFor: "webhook-url", className: "text-sm font-medium text-foreground", children: "Endpoint URL" }),
|
|
3334
|
+
/* @__PURE__ */ jsx29(
|
|
3223
3335
|
"input",
|
|
3224
3336
|
{
|
|
3225
3337
|
id: "webhook-url",
|
|
@@ -3231,19 +3343,19 @@ function WebhookEndpointManager({
|
|
|
3231
3343
|
className: "rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring"
|
|
3232
3344
|
}
|
|
3233
3345
|
),
|
|
3234
|
-
urlError && /* @__PURE__ */
|
|
3346
|
+
urlError && /* @__PURE__ */ jsx29("p", { id: "webhook-url-error", className: "text-xs text-destructive", children: urlError })
|
|
3235
3347
|
] }),
|
|
3236
|
-
/* @__PURE__ */
|
|
3237
|
-
/* @__PURE__ */
|
|
3238
|
-
/* @__PURE__ */
|
|
3348
|
+
/* @__PURE__ */ jsxs26("fieldset", { className: "flex flex-col gap-2", children: [
|
|
3349
|
+
/* @__PURE__ */ jsx29("legend", { className: "text-sm font-medium text-foreground", children: "Events" }),
|
|
3350
|
+
/* @__PURE__ */ jsx29("div", { className: "flex flex-wrap gap-3", children: EVENT_TYPES.map((evt) => {
|
|
3239
3351
|
const id = `webhook-event-${evt}`;
|
|
3240
|
-
return /* @__PURE__ */
|
|
3352
|
+
return /* @__PURE__ */ jsxs26(
|
|
3241
3353
|
"label",
|
|
3242
3354
|
{
|
|
3243
3355
|
htmlFor: id,
|
|
3244
3356
|
className: "flex items-center gap-2 text-sm text-foreground",
|
|
3245
3357
|
children: [
|
|
3246
|
-
/* @__PURE__ */
|
|
3358
|
+
/* @__PURE__ */ jsx29(
|
|
3247
3359
|
"input",
|
|
3248
3360
|
{
|
|
3249
3361
|
id,
|
|
@@ -3260,8 +3372,8 @@ function WebhookEndpointManager({
|
|
|
3260
3372
|
);
|
|
3261
3373
|
}) })
|
|
3262
3374
|
] }),
|
|
3263
|
-
/* @__PURE__ */
|
|
3264
|
-
/* @__PURE__ */
|
|
3375
|
+
/* @__PURE__ */ jsxs26("label", { htmlFor: "webhook-active", className: "flex items-center gap-2 text-sm text-foreground", children: [
|
|
3376
|
+
/* @__PURE__ */ jsx29(
|
|
3265
3377
|
"input",
|
|
3266
3378
|
{
|
|
3267
3379
|
id: "webhook-active",
|
|
@@ -3273,7 +3385,7 @@ function WebhookEndpointManager({
|
|
|
3273
3385
|
),
|
|
3274
3386
|
"Active"
|
|
3275
3387
|
] }),
|
|
3276
|
-
/* @__PURE__ */
|
|
3388
|
+
/* @__PURE__ */ jsx29("div", { children: /* @__PURE__ */ jsx29(
|
|
3277
3389
|
"button",
|
|
3278
3390
|
{
|
|
3279
3391
|
type: "submit",
|
|
@@ -3285,14 +3397,14 @@ function WebhookEndpointManager({
|
|
|
3285
3397
|
] });
|
|
3286
3398
|
let body;
|
|
3287
3399
|
if (isLoading) {
|
|
3288
|
-
body = /* @__PURE__ */
|
|
3289
|
-
/* @__PURE__ */
|
|
3290
|
-
[0, 1, 2].map((i) => /* @__PURE__ */
|
|
3400
|
+
body = /* @__PURE__ */ jsxs26("div", { role: "status", "aria-label": "Loading webhook endpoints", className: "flex flex-col gap-2 p-4", children: [
|
|
3401
|
+
/* @__PURE__ */ jsx29("span", { className: "sr-only", children: "Loading webhook endpoints" }),
|
|
3402
|
+
[0, 1, 2].map((i) => /* @__PURE__ */ jsx29("div", { "aria-hidden": "true", className: "h-10 animate-pulse rounded bg-muted" }, i))
|
|
3291
3403
|
] });
|
|
3292
3404
|
} else if (isError) {
|
|
3293
|
-
body = /* @__PURE__ */
|
|
3294
|
-
/* @__PURE__ */
|
|
3295
|
-
/* @__PURE__ */
|
|
3405
|
+
body = /* @__PURE__ */ jsxs26("div", { className: "flex flex-col items-start gap-3 p-4", children: [
|
|
3406
|
+
/* @__PURE__ */ jsx29("p", { className: "text-sm text-foreground", children: "Failed to load webhook endpoints" }),
|
|
3407
|
+
/* @__PURE__ */ jsx29(
|
|
3296
3408
|
"button",
|
|
3297
3409
|
{
|
|
3298
3410
|
type: "button",
|
|
@@ -3305,26 +3417,26 @@ function WebhookEndpointManager({
|
|
|
3305
3417
|
} else {
|
|
3306
3418
|
const rows = normalizeEndpoints(data);
|
|
3307
3419
|
if (rows.length === 0) {
|
|
3308
|
-
body = /* @__PURE__ */
|
|
3420
|
+
body = /* @__PURE__ */ jsx29("div", { className: "p-6 text-center text-sm text-muted-foreground", children: "No webhook endpoints" });
|
|
3309
3421
|
} else {
|
|
3310
|
-
body = /* @__PURE__ */
|
|
3311
|
-
/* @__PURE__ */
|
|
3312
|
-
/* @__PURE__ */
|
|
3313
|
-
/* @__PURE__ */
|
|
3314
|
-
/* @__PURE__ */
|
|
3315
|
-
/* @__PURE__ */
|
|
3316
|
-
/* @__PURE__ */
|
|
3422
|
+
body = /* @__PURE__ */ jsxs26("table", { className: "w-full text-sm", children: [
|
|
3423
|
+
/* @__PURE__ */ jsx29("thead", { children: /* @__PURE__ */ jsxs26("tr", { className: "border-b border-border text-start text-muted-foreground", children: [
|
|
3424
|
+
/* @__PURE__ */ jsx29("th", { scope: "col", className: "py-2 pe-4 font-medium", children: "URL" }),
|
|
3425
|
+
/* @__PURE__ */ jsx29("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Events" }),
|
|
3426
|
+
/* @__PURE__ */ jsx29("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Active" }),
|
|
3427
|
+
/* @__PURE__ */ jsx29("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Created" }),
|
|
3428
|
+
/* @__PURE__ */ jsx29("th", { scope: "col", className: "px-4 py-2 font-medium", children: /* @__PURE__ */ jsx29("span", { className: "sr-only", children: "Actions" }) })
|
|
3317
3429
|
] }) }),
|
|
3318
|
-
/* @__PURE__ */
|
|
3430
|
+
/* @__PURE__ */ jsx29("tbody", { children: rows.map((row) => {
|
|
3319
3431
|
const isExpanded = expandedId === row.id;
|
|
3320
|
-
return /* @__PURE__ */
|
|
3321
|
-
/* @__PURE__ */
|
|
3322
|
-
/* @__PURE__ */
|
|
3323
|
-
/* @__PURE__ */
|
|
3324
|
-
/* @__PURE__ */
|
|
3325
|
-
/* @__PURE__ */
|
|
3326
|
-
/* @__PURE__ */
|
|
3327
|
-
/* @__PURE__ */
|
|
3432
|
+
return /* @__PURE__ */ jsxs26(Fragment6, { children: [
|
|
3433
|
+
/* @__PURE__ */ jsxs26("tr", { className: "border-b border-border", children: [
|
|
3434
|
+
/* @__PURE__ */ jsx29("td", { className: "py-3 pe-4 font-mono text-foreground", children: row.url }),
|
|
3435
|
+
/* @__PURE__ */ jsx29("td", { className: "px-4 py-3 text-muted-foreground", children: row.events.length > 0 ? row.events.join(", ") : "\u2014" }),
|
|
3436
|
+
/* @__PURE__ */ jsx29("td", { className: "px-4 py-3", children: /* @__PURE__ */ jsx29(StatusBadge5, { variant: row.active ? "success" : "neutral", appearance: "dot", children: row.active ? "active" : "inactive" }) }),
|
|
3437
|
+
/* @__PURE__ */ jsx29("td", { className: "px-4 py-3 text-muted-foreground", children: formatDateTime6(row.createdAt) }),
|
|
3438
|
+
/* @__PURE__ */ jsx29("td", { className: "px-4 py-3", children: /* @__PURE__ */ jsxs26("div", { className: "flex items-center gap-2", children: [
|
|
3439
|
+
/* @__PURE__ */ jsx29(
|
|
3328
3440
|
"button",
|
|
3329
3441
|
{
|
|
3330
3442
|
type: "button",
|
|
@@ -3334,7 +3446,7 @@ function WebhookEndpointManager({
|
|
|
3334
3446
|
children: row.active ? "Disable" : "Enable"
|
|
3335
3447
|
}
|
|
3336
3448
|
),
|
|
3337
|
-
/* @__PURE__ */
|
|
3449
|
+
/* @__PURE__ */ jsx29(
|
|
3338
3450
|
"button",
|
|
3339
3451
|
{
|
|
3340
3452
|
type: "button",
|
|
@@ -3344,7 +3456,7 @@ function WebhookEndpointManager({
|
|
|
3344
3456
|
children: "Deliveries"
|
|
3345
3457
|
}
|
|
3346
3458
|
),
|
|
3347
|
-
/* @__PURE__ */
|
|
3459
|
+
/* @__PURE__ */ jsx29(
|
|
3348
3460
|
"button",
|
|
3349
3461
|
{
|
|
3350
3462
|
type: "button",
|
|
@@ -3356,57 +3468,65 @@ function WebhookEndpointManager({
|
|
|
3356
3468
|
)
|
|
3357
3469
|
] }) })
|
|
3358
3470
|
] }),
|
|
3359
|
-
isExpanded && /* @__PURE__ */
|
|
3471
|
+
isExpanded && /* @__PURE__ */ jsx29("tr", { className: "border-b border-border", children: /* @__PURE__ */ jsx29("td", { colSpan: 5, className: "bg-muted px-4 py-3", children: /* @__PURE__ */ jsx29(WebhookDeliveries, { endpointId: row.id, basePath }) }) })
|
|
3360
3472
|
] }, row.id);
|
|
3361
3473
|
}) })
|
|
3362
3474
|
] });
|
|
3363
3475
|
}
|
|
3364
3476
|
}
|
|
3365
|
-
return /* @__PURE__ */
|
|
3477
|
+
return /* @__PURE__ */ jsxs26("section", { "aria-label": "Webhook endpoints", className: cn26("flex flex-col gap-4", className), children: [
|
|
3366
3478
|
createForm,
|
|
3367
3479
|
body
|
|
3368
3480
|
] });
|
|
3369
3481
|
}
|
|
3370
3482
|
|
|
3371
3483
|
// src/operations-overview.tsx
|
|
3372
|
-
import {
|
|
3484
|
+
import {
|
|
3485
|
+
Button as Button6,
|
|
3486
|
+
Card as Card5,
|
|
3487
|
+
CardContent,
|
|
3488
|
+
CardHeader,
|
|
3489
|
+
CardTitle,
|
|
3490
|
+
EmptyState as EmptyState5,
|
|
3491
|
+
Skeleton as Skeleton4,
|
|
3492
|
+
StatCard,
|
|
3493
|
+
StatusBadge as StatusBadge6,
|
|
3494
|
+
cn as cn27,
|
|
3495
|
+
formatDateTime as formatDateTime7
|
|
3496
|
+
} from "@quanticjs/react-ui";
|
|
3373
3497
|
import { useApiQuery as useApiQuery21 } from "@quanticjs/react-query";
|
|
3374
|
-
import { jsx as
|
|
3498
|
+
import { jsx as jsx30, jsxs as jsxs27 } from "react/jsx-runtime";
|
|
3375
3499
|
function OperationsOverview({ basePath = "/api", className }) {
|
|
3376
3500
|
const { data, isLoading, isError, refetch } = useApiQuery21(
|
|
3377
3501
|
["operations-overview"],
|
|
3378
3502
|
(client) => client.get(`${basePath}/v1/admin/overview`)
|
|
3379
3503
|
);
|
|
3380
3504
|
if (isLoading) {
|
|
3381
|
-
return /* @__PURE__ */
|
|
3505
|
+
return /* @__PURE__ */ jsxs27(
|
|
3382
3506
|
"div",
|
|
3383
3507
|
{
|
|
3384
3508
|
role: "status",
|
|
3385
3509
|
"aria-label": "Loading operations overview",
|
|
3386
|
-
className: cn27("flex flex-col gap-
|
|
3510
|
+
className: cn27("flex flex-col gap-4", className),
|
|
3387
3511
|
children: [
|
|
3388
|
-
/* @__PURE__ */
|
|
3389
|
-
[0, 1, 2].map((i) => /* @__PURE__ */
|
|
3512
|
+
/* @__PURE__ */ jsx30("span", { className: "sr-only", children: "Loading operations overview" }),
|
|
3513
|
+
/* @__PURE__ */ jsx30("div", { "aria-hidden": "true", className: "grid grid-cols-1 gap-4 sm:grid-cols-3", children: [0, 1, 2].map((i) => /* @__PURE__ */ jsx30(Card5, { children: /* @__PURE__ */ jsxs27(CardContent, { className: "space-y-3 p-5", children: [
|
|
3514
|
+
/* @__PURE__ */ jsx30(Skeleton4, { className: "h-3 w-24" }),
|
|
3515
|
+
/* @__PURE__ */ jsx30(Skeleton4, { className: "h-7 w-28" })
|
|
3516
|
+
] }) }, i)) }),
|
|
3517
|
+
/* @__PURE__ */ jsx30(Card5, { "aria-hidden": "true", children: /* @__PURE__ */ jsx30(CardContent, { className: "space-y-2 p-5", children: [0, 1, 2, 3].map((i) => /* @__PURE__ */ jsx30(Skeleton4, { className: "h-10 w-full" }, i)) }) })
|
|
3390
3518
|
]
|
|
3391
3519
|
}
|
|
3392
3520
|
);
|
|
3393
3521
|
}
|
|
3394
3522
|
if (isError) {
|
|
3395
|
-
return /* @__PURE__ */
|
|
3396
|
-
/* @__PURE__ */
|
|
3397
|
-
/* @__PURE__ */
|
|
3398
|
-
|
|
3399
|
-
{
|
|
3400
|
-
type: "button",
|
|
3401
|
-
onClick: () => void refetch(),
|
|
3402
|
-
className: "rounded bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring",
|
|
3403
|
-
children: "Try again"
|
|
3404
|
-
}
|
|
3405
|
-
)
|
|
3406
|
-
] });
|
|
3523
|
+
return /* @__PURE__ */ jsx30(Card5, { className, children: /* @__PURE__ */ jsxs27(CardContent, { className: "flex flex-col items-center gap-3 p-8 text-center", children: [
|
|
3524
|
+
/* @__PURE__ */ jsx30("p", { className: "text-sm text-foreground", children: "Failed to load operations overview" }),
|
|
3525
|
+
/* @__PURE__ */ jsx30(Button6, { type: "button", onClick: () => void refetch(), children: "Try again" })
|
|
3526
|
+
] }) });
|
|
3407
3527
|
}
|
|
3408
3528
|
if (!data) {
|
|
3409
|
-
return /* @__PURE__ */
|
|
3529
|
+
return /* @__PURE__ */ jsx30(EmptyState5, { className, title: "No overview data" });
|
|
3410
3530
|
}
|
|
3411
3531
|
const windowHours = data.windowHours;
|
|
3412
3532
|
const channels = data.channels ?? [];
|
|
@@ -3416,51 +3536,68 @@ function OperationsOverview({ basePath = "/api", className }) {
|
|
|
3416
3536
|
{ label: `Delivered (${windowHours}h)`, value: data.totalDelivered },
|
|
3417
3537
|
{ label: `Failed (${windowHours}h)`, value: data.totalFailed }
|
|
3418
3538
|
];
|
|
3419
|
-
return /* @__PURE__ */
|
|
3420
|
-
/* @__PURE__ */
|
|
3421
|
-
/* @__PURE__ */
|
|
3422
|
-
|
|
3423
|
-
|
|
3424
|
-
|
|
3425
|
-
|
|
3426
|
-
|
|
3427
|
-
|
|
3428
|
-
] }),
|
|
3429
|
-
/* @__PURE__ */ jsxs26("div", { className: "flex items-center gap-2", children: [
|
|
3430
|
-
/* @__PURE__ */ jsx29("span", { className: "text-sm text-muted-foreground", children: "Broadcasts in flight" }),
|
|
3431
|
-
/* @__PURE__ */ jsx29("span", { className: "text-sm font-medium text-foreground", children: data.broadcastsInFlight })
|
|
3539
|
+
return /* @__PURE__ */ jsxs27("section", { "aria-label": "Operations overview", className: cn27("flex flex-col gap-5", className), children: [
|
|
3540
|
+
/* @__PURE__ */ jsxs27("div", { className: "flex flex-wrap items-baseline justify-between gap-2", children: [
|
|
3541
|
+
/* @__PURE__ */ jsxs27("div", { children: [
|
|
3542
|
+
/* @__PURE__ */ jsx30("h2", { className: "text-base font-semibold tracking-tight text-foreground", children: "Operations overview" }),
|
|
3543
|
+
/* @__PURE__ */ jsxs27("p", { className: "mt-0.5 text-xs text-muted-foreground", children: [
|
|
3544
|
+
"Last ",
|
|
3545
|
+
windowHours,
|
|
3546
|
+
"h"
|
|
3547
|
+
] })
|
|
3432
3548
|
] }),
|
|
3433
|
-
/* @__PURE__ */
|
|
3434
|
-
|
|
3435
|
-
|
|
3549
|
+
/* @__PURE__ */ jsxs27("p", { className: "text-xs text-muted-foreground", children: [
|
|
3550
|
+
"Generated ",
|
|
3551
|
+
formatDateTime7(data.generatedAt)
|
|
3436
3552
|
] })
|
|
3437
3553
|
] }),
|
|
3438
|
-
/* @__PURE__ */
|
|
3439
|
-
|
|
3440
|
-
|
|
3441
|
-
/* @__PURE__ */
|
|
3442
|
-
/* @__PURE__ */
|
|
3443
|
-
|
|
3444
|
-
|
|
3445
|
-
|
|
3446
|
-
/* @__PURE__ */
|
|
3447
|
-
|
|
3448
|
-
|
|
3449
|
-
/* @__PURE__ */
|
|
3450
|
-
|
|
3451
|
-
|
|
3452
|
-
|
|
3453
|
-
|
|
3454
|
-
|
|
3554
|
+
/* @__PURE__ */ jsx30("div", { className: "grid grid-cols-1 gap-4 sm:grid-cols-3", children: cards.map((card) => /* @__PURE__ */ jsx30(StatCard, { label: card.label, value: card.value }, card.label)) }),
|
|
3555
|
+
/* @__PURE__ */ jsx30(Card5, { children: /* @__PURE__ */ jsxs27(CardContent, { className: "flex flex-wrap items-center gap-x-8 gap-y-3 p-5", children: [
|
|
3556
|
+
/* @__PURE__ */ jsxs27("div", { className: "flex items-center gap-2", children: [
|
|
3557
|
+
/* @__PURE__ */ jsx30("span", { className: "text-sm text-muted-foreground", children: "DLQ pending" }),
|
|
3558
|
+
/* @__PURE__ */ jsx30(StatusBadge6, { variant: dlqPending > 0 ? "destructive" : "success", appearance: "solid", children: dlqPending })
|
|
3559
|
+
] }),
|
|
3560
|
+
/* @__PURE__ */ jsxs27("div", { className: "flex items-center gap-2", children: [
|
|
3561
|
+
/* @__PURE__ */ jsx30("span", { className: "text-sm text-muted-foreground", children: "Broadcasts in flight" }),
|
|
3562
|
+
/* @__PURE__ */ jsx30("span", { className: "text-sm font-semibold tabular-nums text-foreground", children: data.broadcastsInFlight })
|
|
3563
|
+
] }),
|
|
3564
|
+
/* @__PURE__ */ jsxs27("div", { className: "flex items-center gap-2", children: [
|
|
3565
|
+
/* @__PURE__ */ jsx30("span", { className: "text-sm text-muted-foreground", children: "Queue" }),
|
|
3566
|
+
/* @__PURE__ */ jsx30(StatusBadge6, { variant: data.queueHealthy ? "success" : "destructive", appearance: "solid", children: data.queueHealthy ? "Healthy" : "Unhealthy" })
|
|
3567
|
+
] })
|
|
3568
|
+
] }) }),
|
|
3569
|
+
/* @__PURE__ */ jsxs27(Card5, { children: [
|
|
3570
|
+
/* @__PURE__ */ jsx30(CardHeader, { children: /* @__PURE__ */ jsx30(CardTitle, { children: "Channel breakdown" }) }),
|
|
3571
|
+
/* @__PURE__ */ jsx30(CardContent, { className: "p-0", children: /* @__PURE__ */ jsxs27("table", { className: "w-full text-sm", children: [
|
|
3572
|
+
/* @__PURE__ */ jsx30("thead", { children: /* @__PURE__ */ jsxs27("tr", { className: "border-b border-border text-start text-xs uppercase tracking-wide text-muted-foreground", children: [
|
|
3573
|
+
/* @__PURE__ */ jsx30("th", { scope: "col", className: "px-5 py-2.5 font-medium", children: "Channel" }),
|
|
3574
|
+
/* @__PURE__ */ jsx30("th", { scope: "col", className: "px-4 py-2.5 text-end font-medium", children: "Sends" }),
|
|
3575
|
+
/* @__PURE__ */ jsx30("th", { scope: "col", className: "px-4 py-2.5 text-end font-medium", children: "Delivered" }),
|
|
3576
|
+
/* @__PURE__ */ jsx30("th", { scope: "col", className: "px-4 py-2.5 text-end font-medium", children: "Failed" })
|
|
3577
|
+
] }) }),
|
|
3578
|
+
/* @__PURE__ */ jsx30("tbody", { children: channels.length === 0 ? /* @__PURE__ */ jsx30("tr", { children: /* @__PURE__ */ jsx30("td", { colSpan: 4, className: "px-5 py-8 text-center text-muted-foreground", children: "No channel activity" }) }) : channels.map((row) => /* @__PURE__ */ jsxs27(
|
|
3579
|
+
"tr",
|
|
3580
|
+
{
|
|
3581
|
+
className: "border-b border-border last:border-0 hover:bg-muted/40",
|
|
3582
|
+
children: [
|
|
3583
|
+
/* @__PURE__ */ jsx30("td", { className: "px-5 py-3 font-medium text-foreground", children: row.channel }),
|
|
3584
|
+
/* @__PURE__ */ jsx30("td", { className: "px-4 py-3 text-end tabular-nums text-muted-foreground", children: row.sends }),
|
|
3585
|
+
/* @__PURE__ */ jsx30("td", { className: "px-4 py-3 text-end tabular-nums text-muted-foreground", children: row.delivered }),
|
|
3586
|
+
/* @__PURE__ */ jsx30("td", { className: "px-4 py-3 text-end tabular-nums text-muted-foreground", children: row.failed })
|
|
3587
|
+
]
|
|
3588
|
+
},
|
|
3589
|
+
row.channel
|
|
3590
|
+
)) })
|
|
3591
|
+
] }) })
|
|
3455
3592
|
] })
|
|
3456
3593
|
] });
|
|
3457
3594
|
}
|
|
3458
3595
|
|
|
3459
3596
|
// src/delivery-log-explorer.tsx
|
|
3460
3597
|
import { useState as useState15 } from "react";
|
|
3461
|
-
import {
|
|
3598
|
+
import { Button as Button7, Card as Card6, EmptyState as EmptyState6, StatusBadge as StatusBadge7, cn as cn28, formatDateTime as formatDateTime8 } from "@quanticjs/react-ui";
|
|
3462
3599
|
import { useApiQuery as useApiQuery22 } from "@quanticjs/react-query";
|
|
3463
|
-
import { Fragment as Fragment7, jsx as
|
|
3600
|
+
import { Fragment as Fragment7, jsx as jsx31, jsxs as jsxs28 } from "react/jsx-runtime";
|
|
3464
3601
|
var LIMIT6 = 20;
|
|
3465
3602
|
var EMPTY_FILTERS = {
|
|
3466
3603
|
channel: "",
|
|
@@ -3513,178 +3650,90 @@ function DeliveryLogExplorer({ basePath = "/api", className }) {
|
|
|
3513
3650
|
});
|
|
3514
3651
|
};
|
|
3515
3652
|
const setField = (key, value) => setDraft((prev) => ({ ...prev, [key]: value }));
|
|
3516
|
-
const
|
|
3517
|
-
|
|
3518
|
-
|
|
3519
|
-
|
|
3520
|
-
|
|
3521
|
-
{
|
|
3522
|
-
|
|
3523
|
-
|
|
3524
|
-
|
|
3525
|
-
|
|
3526
|
-
|
|
3527
|
-
|
|
3528
|
-
|
|
3529
|
-
|
|
3530
|
-
|
|
3531
|
-
|
|
3532
|
-
|
|
3533
|
-
|
|
3534
|
-
|
|
3535
|
-
|
|
3536
|
-
|
|
3537
|
-
|
|
3538
|
-
{
|
|
3539
|
-
|
|
3540
|
-
|
|
3541
|
-
|
|
3542
|
-
|
|
3543
|
-
|
|
3544
|
-
|
|
3545
|
-
|
|
3546
|
-
|
|
3547
|
-
|
|
3548
|
-
|
|
3549
|
-
/* @__PURE__ */
|
|
3550
|
-
"
|
|
3551
|
-
{
|
|
3552
|
-
|
|
3553
|
-
|
|
3554
|
-
|
|
3555
|
-
|
|
3556
|
-
|
|
3557
|
-
|
|
3558
|
-
|
|
3559
|
-
|
|
3560
|
-
|
|
3561
|
-
/* @__PURE__ */
|
|
3562
|
-
|
|
3563
|
-
|
|
3564
|
-
|
|
3565
|
-
|
|
3566
|
-
|
|
3567
|
-
|
|
3568
|
-
|
|
3569
|
-
|
|
3570
|
-
|
|
3571
|
-
)
|
|
3572
|
-
] }),
|
|
3573
|
-
/* @__PURE__ */ jsxs27("div", { className: "flex flex-col gap-1", children: [
|
|
3574
|
-
/* @__PURE__ */ jsx30("label", { htmlFor: "dle-from", className: "text-sm font-medium text-foreground", children: "From" }),
|
|
3575
|
-
/* @__PURE__ */ jsx30(
|
|
3576
|
-
"input",
|
|
3577
|
-
{
|
|
3578
|
-
id: "dle-from",
|
|
3579
|
-
type: "date",
|
|
3580
|
-
value: draft.from,
|
|
3581
|
-
onChange: (e) => setField("from", e.target.value),
|
|
3582
|
-
className: "rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring"
|
|
3583
|
-
}
|
|
3584
|
-
)
|
|
3585
|
-
] }),
|
|
3586
|
-
/* @__PURE__ */ jsxs27("div", { className: "flex flex-col gap-1", children: [
|
|
3587
|
-
/* @__PURE__ */ jsx30("label", { htmlFor: "dle-to", className: "text-sm font-medium text-foreground", children: "To" }),
|
|
3588
|
-
/* @__PURE__ */ jsx30(
|
|
3589
|
-
"input",
|
|
3590
|
-
{
|
|
3591
|
-
id: "dle-to",
|
|
3592
|
-
type: "date",
|
|
3593
|
-
value: draft.to,
|
|
3594
|
-
onChange: (e) => setField("to", e.target.value),
|
|
3595
|
-
className: "rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring"
|
|
3596
|
-
}
|
|
3597
|
-
)
|
|
3598
|
-
] }),
|
|
3599
|
-
/* @__PURE__ */ jsx30(
|
|
3600
|
-
"button",
|
|
3601
|
-
{
|
|
3602
|
-
type: "submit",
|
|
3603
|
-
className: "rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring",
|
|
3604
|
-
children: "Apply"
|
|
3605
|
-
}
|
|
3606
|
-
)
|
|
3607
|
-
] });
|
|
3608
|
-
let body;
|
|
3609
|
-
if (isLoading) {
|
|
3610
|
-
body = /* @__PURE__ */ jsxs27("div", { role: "status", "aria-label": "Loading delivery logs", className: "flex flex-col gap-2 p-4", children: [
|
|
3611
|
-
/* @__PURE__ */ jsx30("span", { className: "sr-only", children: "Loading delivery logs" }),
|
|
3612
|
-
[0, 1, 2].map((i) => /* @__PURE__ */ jsx30("div", { "aria-hidden": "true", className: "h-10 animate-pulse rounded bg-muted" }, i))
|
|
3613
|
-
] });
|
|
3614
|
-
} else if (isError) {
|
|
3615
|
-
body = /* @__PURE__ */ jsxs27("div", { className: "flex flex-col items-start gap-3 p-4", children: [
|
|
3616
|
-
/* @__PURE__ */ jsx30("p", { className: "text-sm text-foreground", children: "Failed to load delivery logs" }),
|
|
3617
|
-
/* @__PURE__ */ jsx30(
|
|
3618
|
-
"button",
|
|
3619
|
-
{
|
|
3620
|
-
type: "button",
|
|
3621
|
-
onClick: () => void refetch(),
|
|
3622
|
-
className: "rounded bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring",
|
|
3623
|
-
children: "Try again"
|
|
3624
|
-
}
|
|
3625
|
-
)
|
|
3626
|
-
] });
|
|
3627
|
-
} else {
|
|
3628
|
-
const rows = data?.items ?? [];
|
|
3629
|
-
const totalPages = data?.totalPages ?? 1;
|
|
3630
|
-
if (rows.length === 0) {
|
|
3631
|
-
body = /* @__PURE__ */ jsx30("div", { className: "p-6 text-center text-sm text-muted-foreground", children: "No delivery logs" });
|
|
3632
|
-
} else {
|
|
3633
|
-
body = /* @__PURE__ */ jsxs27(Fragment7, { children: [
|
|
3634
|
-
/* @__PURE__ */ jsxs27("table", { className: "w-full text-sm", children: [
|
|
3635
|
-
/* @__PURE__ */ jsx30("thead", { children: /* @__PURE__ */ jsxs27("tr", { className: "border-b border-border text-start text-muted-foreground", children: [
|
|
3636
|
-
/* @__PURE__ */ jsx30("th", { scope: "col", className: "py-2 pe-4 font-medium", children: "Channel" }),
|
|
3637
|
-
/* @__PURE__ */ jsx30("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Recipient" }),
|
|
3638
|
-
/* @__PURE__ */ jsx30("th", { scope: "col", className: "px-4 py-2 font-medium", children: "User" }),
|
|
3639
|
-
/* @__PURE__ */ jsx30("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Status" }),
|
|
3640
|
-
/* @__PURE__ */ jsx30("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Provider" }),
|
|
3641
|
-
/* @__PURE__ */ jsx30("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Attempts" }),
|
|
3642
|
-
/* @__PURE__ */ jsx30("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Created" })
|
|
3653
|
+
const rows = data?.items ?? [];
|
|
3654
|
+
const totalPages = data?.totalPages ?? 1;
|
|
3655
|
+
return /* @__PURE__ */ jsxs28("section", { "aria-label": "Delivery log explorer", className: cn28("flex flex-col gap-4", className), children: [
|
|
3656
|
+
/* @__PURE__ */ jsx31(Card6, { children: /* @__PURE__ */ jsxs28("form", { onSubmit: onApply, className: "flex flex-wrap items-end gap-3 p-4", noValidate: true, children: [
|
|
3657
|
+
/* @__PURE__ */ jsxs28("label", { htmlFor: "dle-channel", className: "flex flex-col gap-1 text-sm", children: [
|
|
3658
|
+
/* @__PURE__ */ jsx31("span", { className: "font-medium text-foreground", children: "Channel" }),
|
|
3659
|
+
/* @__PURE__ */ jsxs28(
|
|
3660
|
+
"select",
|
|
3661
|
+
{
|
|
3662
|
+
id: "dle-channel",
|
|
3663
|
+
value: draft.channel,
|
|
3664
|
+
onChange: (e) => setField("channel", e.target.value),
|
|
3665
|
+
className: FIELD_CLASS,
|
|
3666
|
+
children: [
|
|
3667
|
+
/* @__PURE__ */ jsx31("option", { value: "", children: "All" }),
|
|
3668
|
+
/* @__PURE__ */ jsx31("option", { value: "email", children: "Email" }),
|
|
3669
|
+
/* @__PURE__ */ jsx31("option", { value: "sms", children: "SMS" })
|
|
3670
|
+
]
|
|
3671
|
+
}
|
|
3672
|
+
)
|
|
3673
|
+
] }),
|
|
3674
|
+
/* @__PURE__ */ jsxs28("label", { htmlFor: "dle-status", className: "flex flex-col gap-1 text-sm", children: [
|
|
3675
|
+
/* @__PURE__ */ jsx31("span", { className: "font-medium text-foreground", children: "Status" }),
|
|
3676
|
+
/* @__PURE__ */ jsx31("input", { id: "dle-status", type: "text", value: draft.status, onChange: (e) => setField("status", e.target.value), className: FIELD_CLASS })
|
|
3677
|
+
] }),
|
|
3678
|
+
/* @__PURE__ */ jsxs28("label", { htmlFor: "dle-recipient", className: "flex flex-col gap-1 text-sm", children: [
|
|
3679
|
+
/* @__PURE__ */ jsx31("span", { className: "font-medium text-foreground", children: "Recipient" }),
|
|
3680
|
+
/* @__PURE__ */ jsx31("input", { id: "dle-recipient", type: "text", value: draft.recipient, onChange: (e) => setField("recipient", e.target.value), className: FIELD_CLASS })
|
|
3681
|
+
] }),
|
|
3682
|
+
/* @__PURE__ */ jsxs28("label", { htmlFor: "dle-user", className: "flex flex-col gap-1 text-sm", children: [
|
|
3683
|
+
/* @__PURE__ */ jsx31("span", { className: "font-medium text-foreground", children: "User ID" }),
|
|
3684
|
+
/* @__PURE__ */ jsx31("input", { id: "dle-user", type: "text", value: draft.userId, onChange: (e) => setField("userId", e.target.value), className: FIELD_CLASS })
|
|
3685
|
+
] }),
|
|
3686
|
+
/* @__PURE__ */ jsxs28("label", { htmlFor: "dle-from", className: "flex flex-col gap-1 text-sm", children: [
|
|
3687
|
+
/* @__PURE__ */ jsx31("span", { className: "font-medium text-foreground", children: "From" }),
|
|
3688
|
+
/* @__PURE__ */ jsx31("input", { id: "dle-from", type: "date", value: draft.from, onChange: (e) => setField("from", e.target.value), className: FIELD_CLASS })
|
|
3689
|
+
] }),
|
|
3690
|
+
/* @__PURE__ */ jsxs28("label", { htmlFor: "dle-to", className: "flex flex-col gap-1 text-sm", children: [
|
|
3691
|
+
/* @__PURE__ */ jsx31("span", { className: "font-medium text-foreground", children: "To" }),
|
|
3692
|
+
/* @__PURE__ */ jsx31("input", { id: "dle-to", type: "date", value: draft.to, onChange: (e) => setField("to", e.target.value), className: FIELD_CLASS })
|
|
3693
|
+
] }),
|
|
3694
|
+
/* @__PURE__ */ jsx31(Button7, { type: "submit", className: "ms-auto", children: "Apply" })
|
|
3695
|
+
] }) }),
|
|
3696
|
+
/* @__PURE__ */ jsxs28(Card6, { children: [
|
|
3697
|
+
/* @__PURE__ */ jsx31(PanelHeader, { title: "Attempts", subtitle: !isLoading && !isError ? `${data?.total ?? rows.length} matching entries` : void 0 }),
|
|
3698
|
+
isLoading ? /* @__PURE__ */ jsx31(SkeletonRows, { label: "Loading delivery logs" }) : isError ? /* @__PURE__ */ jsx31(ErrorPanel, { message: "Failed to load delivery logs", onRetry: () => void refetch() }) : rows.length === 0 ? /* @__PURE__ */ jsx31(EmptyState6, { icon: /* @__PURE__ */ jsx31(InboxIcon, {}), title: "No delivery logs", description: "No attempts match the current filters." }) : /* @__PURE__ */ jsxs28(Fragment7, { children: [
|
|
3699
|
+
/* @__PURE__ */ jsxs28("table", { className: "w-full text-sm", children: [
|
|
3700
|
+
/* @__PURE__ */ jsx31("thead", { children: /* @__PURE__ */ jsxs28("tr", { className: "border-b border-border text-start text-muted-foreground", children: [
|
|
3701
|
+
/* @__PURE__ */ jsx31("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Channel" }),
|
|
3702
|
+
/* @__PURE__ */ jsx31("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Recipient" }),
|
|
3703
|
+
/* @__PURE__ */ jsx31("th", { scope: "col", className: "px-4 py-2 font-medium", children: "User" }),
|
|
3704
|
+
/* @__PURE__ */ jsx31("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Status" }),
|
|
3705
|
+
/* @__PURE__ */ jsx31("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Provider" }),
|
|
3706
|
+
/* @__PURE__ */ jsx31("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Attempts" }),
|
|
3707
|
+
/* @__PURE__ */ jsx31("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Created" })
|
|
3643
3708
|
] }) }),
|
|
3644
|
-
/* @__PURE__ */
|
|
3645
|
-
/* @__PURE__ */
|
|
3646
|
-
/* @__PURE__ */
|
|
3647
|
-
/* @__PURE__ */
|
|
3648
|
-
/* @__PURE__ */
|
|
3649
|
-
/* @__PURE__ */
|
|
3650
|
-
/* @__PURE__ */
|
|
3651
|
-
/* @__PURE__ */
|
|
3709
|
+
/* @__PURE__ */ jsx31("tbody", { children: rows.map((row) => /* @__PURE__ */ jsxs28("tr", { className: "border-b border-border last:border-0 hover:bg-muted/40", children: [
|
|
3710
|
+
/* @__PURE__ */ jsx31("td", { className: "px-4 py-3", children: /* @__PURE__ */ jsx31(StatusBadge7, { variant: channelVariant(row.channel), appearance: "dot", children: row.channel }) }),
|
|
3711
|
+
/* @__PURE__ */ jsx31("td", { className: "px-4 py-3 text-foreground", children: row.recipient ?? "\u2014" }),
|
|
3712
|
+
/* @__PURE__ */ jsx31("td", { className: "px-4 py-3 font-mono text-foreground", children: row.userId }),
|
|
3713
|
+
/* @__PURE__ */ jsx31("td", { className: "px-4 py-3 text-foreground", children: row.status }),
|
|
3714
|
+
/* @__PURE__ */ jsx31("td", { className: "px-4 py-3 text-muted-foreground", children: row.provider ?? "\u2014" }),
|
|
3715
|
+
/* @__PURE__ */ jsx31("td", { className: "px-4 py-3 tabular-nums text-muted-foreground", children: row.attempts }),
|
|
3716
|
+
/* @__PURE__ */ jsx31("td", { className: "px-4 py-3 text-muted-foreground", children: formatDateTime8(row.createdAt) })
|
|
3652
3717
|
] }, row.id)) })
|
|
3653
3718
|
] }),
|
|
3654
|
-
/* @__PURE__ */
|
|
3655
|
-
|
|
3656
|
-
|
|
3657
|
-
|
|
3658
|
-
type: "button",
|
|
3659
|
-
onClick: () => setPage((p) => Math.max(1, p - 1)),
|
|
3660
|
-
disabled: page <= 1,
|
|
3661
|
-
className: "rounded-md border border-border px-3 py-1 text-sm text-foreground hover:bg-muted focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring disabled:opacity-50",
|
|
3662
|
-
children: "Previous"
|
|
3663
|
-
}
|
|
3664
|
-
),
|
|
3665
|
-
/* @__PURE__ */ jsxs27("span", { className: "text-xs text-muted-foreground", children: [
|
|
3666
|
-
"Page ",
|
|
3719
|
+
/* @__PURE__ */ jsx31(
|
|
3720
|
+
Pager,
|
|
3721
|
+
{
|
|
3722
|
+
label: "Delivery log pagination",
|
|
3667
3723
|
page,
|
|
3668
|
-
|
|
3669
|
-
|
|
3670
|
-
|
|
3671
|
-
|
|
3672
|
-
|
|
3673
|
-
|
|
3674
|
-
|
|
3675
|
-
|
|
3676
|
-
|
|
3677
|
-
|
|
3678
|
-
|
|
3679
|
-
|
|
3680
|
-
|
|
3681
|
-
] })
|
|
3682
|
-
] });
|
|
3683
|
-
}
|
|
3684
|
-
}
|
|
3685
|
-
return /* @__PURE__ */ jsxs27("section", { "aria-label": "Delivery log explorer", className: cn28("flex flex-col gap-4", className), children: [
|
|
3686
|
-
filterForm,
|
|
3687
|
-
body
|
|
3724
|
+
totalPages,
|
|
3725
|
+
onPrev: () => setPage((p) => Math.max(1, p - 1)),
|
|
3726
|
+
onNext: () => setPage((p) => Math.min(totalPages, p + 1))
|
|
3727
|
+
}
|
|
3728
|
+
)
|
|
3729
|
+
] })
|
|
3730
|
+
] })
|
|
3731
|
+
] });
|
|
3732
|
+
}
|
|
3733
|
+
function InboxIcon() {
|
|
3734
|
+
return /* @__PURE__ */ jsxs28("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
3735
|
+
/* @__PURE__ */ jsx31("path", { d: "M22 12h-6l-2 3h-4l-2-3H2" }),
|
|
3736
|
+
/* @__PURE__ */ jsx31("path", { d: "M5.45 5.11 2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.45-6.89A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11Z" })
|
|
3688
3737
|
] });
|
|
3689
3738
|
}
|
|
3690
3739
|
|
|
@@ -3692,7 +3741,7 @@ function DeliveryLogExplorer({ basePath = "/api", className }) {
|
|
|
3692
3741
|
import { useEffect as useEffect6, useState as useState16 } from "react";
|
|
3693
3742
|
import { cn as cn29, useToast as useToast13 } from "@quanticjs/react-ui";
|
|
3694
3743
|
import { useApiMutation as useApiMutation14, useApiQuery as useApiQuery23 } from "@quanticjs/react-query";
|
|
3695
|
-
import { jsx as
|
|
3744
|
+
import { jsx as jsx32, jsxs as jsxs29 } from "react/jsx-runtime";
|
|
3696
3745
|
var DEFAULTS = {
|
|
3697
3746
|
enabled: false,
|
|
3698
3747
|
start: "22:00",
|
|
@@ -3733,23 +3782,23 @@ function QuietHoursForm({ basePath = "/api", className }) {
|
|
|
3733
3782
|
save.mutate(form);
|
|
3734
3783
|
};
|
|
3735
3784
|
if (isLoading) {
|
|
3736
|
-
return /* @__PURE__ */
|
|
3785
|
+
return /* @__PURE__ */ jsxs29(
|
|
3737
3786
|
"div",
|
|
3738
3787
|
{
|
|
3739
3788
|
role: "status",
|
|
3740
3789
|
"aria-label": "Loading quiet hours",
|
|
3741
3790
|
className: cn29("flex flex-col gap-2 p-4", className),
|
|
3742
3791
|
children: [
|
|
3743
|
-
/* @__PURE__ */
|
|
3744
|
-
[0, 1, 2].map((i) => /* @__PURE__ */
|
|
3792
|
+
/* @__PURE__ */ jsx32("span", { className: "sr-only", children: "Loading quiet hours" }),
|
|
3793
|
+
[0, 1, 2].map((i) => /* @__PURE__ */ jsx32("div", { "aria-hidden": "true", className: "h-10 animate-pulse rounded bg-muted" }, i))
|
|
3745
3794
|
]
|
|
3746
3795
|
}
|
|
3747
3796
|
);
|
|
3748
3797
|
}
|
|
3749
3798
|
if (isError) {
|
|
3750
|
-
return /* @__PURE__ */
|
|
3751
|
-
/* @__PURE__ */
|
|
3752
|
-
/* @__PURE__ */
|
|
3799
|
+
return /* @__PURE__ */ jsxs29("div", { className: cn29("flex flex-col items-start gap-3 p-4", className), children: [
|
|
3800
|
+
/* @__PURE__ */ jsx32("p", { className: "text-sm text-foreground", children: "Failed to load quiet hours" }),
|
|
3801
|
+
/* @__PURE__ */ jsx32(
|
|
3753
3802
|
"button",
|
|
3754
3803
|
{
|
|
3755
3804
|
type: "button",
|
|
@@ -3760,10 +3809,10 @@ function QuietHoursForm({ basePath = "/api", className }) {
|
|
|
3760
3809
|
)
|
|
3761
3810
|
] });
|
|
3762
3811
|
}
|
|
3763
|
-
return /* @__PURE__ */
|
|
3764
|
-
/* @__PURE__ */
|
|
3765
|
-
/* @__PURE__ */
|
|
3766
|
-
/* @__PURE__ */
|
|
3812
|
+
return /* @__PURE__ */ jsxs29("form", { onSubmit, className: cn29("flex flex-col gap-4", className), noValidate: true, children: [
|
|
3813
|
+
/* @__PURE__ */ jsx32("h2", { className: "text-sm font-semibold text-foreground", children: "Quiet hours" }),
|
|
3814
|
+
/* @__PURE__ */ jsxs29("label", { className: "flex items-center gap-2 text-sm text-foreground", children: [
|
|
3815
|
+
/* @__PURE__ */ jsx32(
|
|
3767
3816
|
"input",
|
|
3768
3817
|
{
|
|
3769
3818
|
type: "checkbox",
|
|
@@ -3774,10 +3823,10 @@ function QuietHoursForm({ basePath = "/api", className }) {
|
|
|
3774
3823
|
),
|
|
3775
3824
|
"Enable quiet hours"
|
|
3776
3825
|
] }),
|
|
3777
|
-
/* @__PURE__ */
|
|
3778
|
-
/* @__PURE__ */
|
|
3779
|
-
/* @__PURE__ */
|
|
3780
|
-
/* @__PURE__ */
|
|
3826
|
+
/* @__PURE__ */ jsxs29("div", { className: "flex flex-wrap gap-4", children: [
|
|
3827
|
+
/* @__PURE__ */ jsxs29("div", { className: "flex flex-col gap-1", children: [
|
|
3828
|
+
/* @__PURE__ */ jsx32("label", { htmlFor: "qh-start", className: "text-sm font-medium text-foreground", children: "Start" }),
|
|
3829
|
+
/* @__PURE__ */ jsx32(
|
|
3781
3830
|
"input",
|
|
3782
3831
|
{
|
|
3783
3832
|
id: "qh-start",
|
|
@@ -3788,9 +3837,9 @@ function QuietHoursForm({ basePath = "/api", className }) {
|
|
|
3788
3837
|
}
|
|
3789
3838
|
)
|
|
3790
3839
|
] }),
|
|
3791
|
-
/* @__PURE__ */
|
|
3792
|
-
/* @__PURE__ */
|
|
3793
|
-
/* @__PURE__ */
|
|
3840
|
+
/* @__PURE__ */ jsxs29("div", { className: "flex flex-col gap-1", children: [
|
|
3841
|
+
/* @__PURE__ */ jsx32("label", { htmlFor: "qh-end", className: "text-sm font-medium text-foreground", children: "End" }),
|
|
3842
|
+
/* @__PURE__ */ jsx32(
|
|
3794
3843
|
"input",
|
|
3795
3844
|
{
|
|
3796
3845
|
id: "qh-end",
|
|
@@ -3801,9 +3850,9 @@ function QuietHoursForm({ basePath = "/api", className }) {
|
|
|
3801
3850
|
}
|
|
3802
3851
|
)
|
|
3803
3852
|
] }),
|
|
3804
|
-
/* @__PURE__ */
|
|
3805
|
-
/* @__PURE__ */
|
|
3806
|
-
/* @__PURE__ */
|
|
3853
|
+
/* @__PURE__ */ jsxs29("div", { className: "flex flex-col gap-1", children: [
|
|
3854
|
+
/* @__PURE__ */ jsx32("label", { htmlFor: "qh-tz", className: "text-sm font-medium text-foreground", children: "Timezone" }),
|
|
3855
|
+
/* @__PURE__ */ jsx32(
|
|
3807
3856
|
"input",
|
|
3808
3857
|
{
|
|
3809
3858
|
id: "qh-tz",
|
|
@@ -3815,7 +3864,7 @@ function QuietHoursForm({ basePath = "/api", className }) {
|
|
|
3815
3864
|
)
|
|
3816
3865
|
] })
|
|
3817
3866
|
] }),
|
|
3818
|
-
/* @__PURE__ */
|
|
3867
|
+
/* @__PURE__ */ jsx32("div", { children: /* @__PURE__ */ jsx32(
|
|
3819
3868
|
"button",
|
|
3820
3869
|
{
|
|
3821
3870
|
type: "submit",
|
|
@@ -3831,7 +3880,7 @@ function QuietHoursForm({ basePath = "/api", className }) {
|
|
|
3831
3880
|
import { useEffect as useEffect7, useState as useState17 } from "react";
|
|
3832
3881
|
import { cn as cn30, useToast as useToast14 } from "@quanticjs/react-ui";
|
|
3833
3882
|
import { useApiMutation as useApiMutation15, useApiQuery as useApiQuery24 } from "@quanticjs/react-query";
|
|
3834
|
-
import { jsx as
|
|
3883
|
+
import { jsx as jsx33, jsxs as jsxs30 } from "react/jsx-runtime";
|
|
3835
3884
|
function normalize6(raw) {
|
|
3836
3885
|
const list = Array.isArray(raw) ? raw : Array.isArray(raw?.caps) ? raw.caps : [];
|
|
3837
3886
|
return list.map((entry) => {
|
|
@@ -3876,23 +3925,23 @@ function FrequencyCapTable({ basePath = "/api", className }) {
|
|
|
3876
3925
|
setNewMax(0);
|
|
3877
3926
|
};
|
|
3878
3927
|
if (isLoading) {
|
|
3879
|
-
return /* @__PURE__ */
|
|
3928
|
+
return /* @__PURE__ */ jsxs30(
|
|
3880
3929
|
"div",
|
|
3881
3930
|
{
|
|
3882
3931
|
role: "status",
|
|
3883
3932
|
"aria-label": "Loading frequency caps",
|
|
3884
3933
|
className: cn30("flex flex-col gap-2 p-4", className),
|
|
3885
3934
|
children: [
|
|
3886
|
-
/* @__PURE__ */
|
|
3887
|
-
[0, 1, 2].map((i) => /* @__PURE__ */
|
|
3935
|
+
/* @__PURE__ */ jsx33("span", { className: "sr-only", children: "Loading frequency caps" }),
|
|
3936
|
+
[0, 1, 2].map((i) => /* @__PURE__ */ jsx33("div", { "aria-hidden": "true", className: "h-10 animate-pulse rounded bg-muted" }, i))
|
|
3888
3937
|
]
|
|
3889
3938
|
}
|
|
3890
3939
|
);
|
|
3891
3940
|
}
|
|
3892
3941
|
if (isError) {
|
|
3893
|
-
return /* @__PURE__ */
|
|
3894
|
-
/* @__PURE__ */
|
|
3895
|
-
/* @__PURE__ */
|
|
3942
|
+
return /* @__PURE__ */ jsxs30("div", { className: cn30("flex flex-col items-start gap-3 p-4", className), children: [
|
|
3943
|
+
/* @__PURE__ */ jsx33("p", { className: "text-sm text-foreground", children: "Failed to load frequency caps" }),
|
|
3944
|
+
/* @__PURE__ */ jsx33(
|
|
3896
3945
|
"button",
|
|
3897
3946
|
{
|
|
3898
3947
|
type: "button",
|
|
@@ -3903,24 +3952,24 @@ function FrequencyCapTable({ basePath = "/api", className }) {
|
|
|
3903
3952
|
)
|
|
3904
3953
|
] });
|
|
3905
3954
|
}
|
|
3906
|
-
return /* @__PURE__ */
|
|
3907
|
-
/* @__PURE__ */
|
|
3908
|
-
/* @__PURE__ */
|
|
3909
|
-
/* @__PURE__ */
|
|
3910
|
-
/* @__PURE__ */
|
|
3911
|
-
/* @__PURE__ */
|
|
3912
|
-
/* @__PURE__ */
|
|
3955
|
+
return /* @__PURE__ */ jsxs30("section", { "aria-label": "Frequency caps", className: cn30("flex flex-col gap-4", className), children: [
|
|
3956
|
+
/* @__PURE__ */ jsx33("h2", { className: "text-sm font-semibold text-foreground", children: "Frequency caps" }),
|
|
3957
|
+
/* @__PURE__ */ jsxs30("table", { className: "w-full text-sm", children: [
|
|
3958
|
+
/* @__PURE__ */ jsx33("thead", { children: /* @__PURE__ */ jsxs30("tr", { className: "border-b border-border text-start text-muted-foreground", children: [
|
|
3959
|
+
/* @__PURE__ */ jsx33("th", { scope: "col", className: "py-2 pe-4 font-medium", children: "Type" }),
|
|
3960
|
+
/* @__PURE__ */ jsx33("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Max per day" }),
|
|
3961
|
+
/* @__PURE__ */ jsx33("th", { scope: "col", className: "px-4 py-2 font-medium", children: /* @__PURE__ */ jsx33("span", { className: "sr-only", children: "Actions" }) })
|
|
3913
3962
|
] }) }),
|
|
3914
|
-
/* @__PURE__ */
|
|
3963
|
+
/* @__PURE__ */ jsx33("tbody", { children: caps.map((cap, index) => {
|
|
3915
3964
|
const inputId = `cap-${index}`;
|
|
3916
|
-
return /* @__PURE__ */
|
|
3917
|
-
/* @__PURE__ */
|
|
3918
|
-
/* @__PURE__ */
|
|
3919
|
-
/* @__PURE__ */
|
|
3965
|
+
return /* @__PURE__ */ jsxs30("tr", { className: "border-b border-border", children: [
|
|
3966
|
+
/* @__PURE__ */ jsx33("td", { className: "py-3 pe-4 text-foreground", children: cap.type }),
|
|
3967
|
+
/* @__PURE__ */ jsxs30("td", { className: "px-4 py-3", children: [
|
|
3968
|
+
/* @__PURE__ */ jsxs30("label", { htmlFor: inputId, className: "sr-only", children: [
|
|
3920
3969
|
"Max per day for ",
|
|
3921
3970
|
cap.type
|
|
3922
3971
|
] }),
|
|
3923
|
-
/* @__PURE__ */
|
|
3972
|
+
/* @__PURE__ */ jsx33(
|
|
3924
3973
|
"input",
|
|
3925
3974
|
{
|
|
3926
3975
|
id: inputId,
|
|
@@ -3932,7 +3981,7 @@ function FrequencyCapTable({ basePath = "/api", className }) {
|
|
|
3932
3981
|
}
|
|
3933
3982
|
)
|
|
3934
3983
|
] }),
|
|
3935
|
-
/* @__PURE__ */
|
|
3984
|
+
/* @__PURE__ */ jsx33("td", { className: "px-4 py-3", children: /* @__PURE__ */ jsx33(
|
|
3936
3985
|
"button",
|
|
3937
3986
|
{
|
|
3938
3987
|
type: "button",
|
|
@@ -3944,10 +3993,10 @@ function FrequencyCapTable({ basePath = "/api", className }) {
|
|
|
3944
3993
|
] }, `${cap.type}-${index}`);
|
|
3945
3994
|
}) })
|
|
3946
3995
|
] }),
|
|
3947
|
-
/* @__PURE__ */
|
|
3948
|
-
/* @__PURE__ */
|
|
3949
|
-
/* @__PURE__ */
|
|
3950
|
-
/* @__PURE__ */
|
|
3996
|
+
/* @__PURE__ */ jsxs30("form", { onSubmit: addRow, className: "flex flex-wrap items-end gap-3", noValidate: true, children: [
|
|
3997
|
+
/* @__PURE__ */ jsxs30("div", { className: "flex flex-col gap-1", children: [
|
|
3998
|
+
/* @__PURE__ */ jsx33("label", { htmlFor: "cap-new-type", className: "text-sm font-medium text-foreground", children: "New type" }),
|
|
3999
|
+
/* @__PURE__ */ jsx33(
|
|
3951
4000
|
"input",
|
|
3952
4001
|
{
|
|
3953
4002
|
id: "cap-new-type",
|
|
@@ -3958,9 +4007,9 @@ function FrequencyCapTable({ basePath = "/api", className }) {
|
|
|
3958
4007
|
}
|
|
3959
4008
|
)
|
|
3960
4009
|
] }),
|
|
3961
|
-
/* @__PURE__ */
|
|
3962
|
-
/* @__PURE__ */
|
|
3963
|
-
/* @__PURE__ */
|
|
4010
|
+
/* @__PURE__ */ jsxs30("div", { className: "flex flex-col gap-1", children: [
|
|
4011
|
+
/* @__PURE__ */ jsx33("label", { htmlFor: "cap-new-max", className: "text-sm font-medium text-foreground", children: "Max per day" }),
|
|
4012
|
+
/* @__PURE__ */ jsx33(
|
|
3964
4013
|
"input",
|
|
3965
4014
|
{
|
|
3966
4015
|
id: "cap-new-max",
|
|
@@ -3972,7 +4021,7 @@ function FrequencyCapTable({ basePath = "/api", className }) {
|
|
|
3972
4021
|
}
|
|
3973
4022
|
)
|
|
3974
4023
|
] }),
|
|
3975
|
-
/* @__PURE__ */
|
|
4024
|
+
/* @__PURE__ */ jsx33(
|
|
3976
4025
|
"button",
|
|
3977
4026
|
{
|
|
3978
4027
|
type: "submit",
|
|
@@ -3981,7 +4030,7 @@ function FrequencyCapTable({ basePath = "/api", className }) {
|
|
|
3981
4030
|
}
|
|
3982
4031
|
)
|
|
3983
4032
|
] }),
|
|
3984
|
-
/* @__PURE__ */
|
|
4033
|
+
/* @__PURE__ */ jsx33("div", { children: /* @__PURE__ */ jsx33(
|
|
3985
4034
|
"button",
|
|
3986
4035
|
{
|
|
3987
4036
|
type: "button",
|
|
@@ -3998,7 +4047,7 @@ function FrequencyCapTable({ basePath = "/api", className }) {
|
|
|
3998
4047
|
import { useEffect as useEffect8, useState as useState18 } from "react";
|
|
3999
4048
|
import { cn as cn31, useToast as useToast15 } from "@quanticjs/react-ui";
|
|
4000
4049
|
import { useApiMutation as useApiMutation16, useApiQuery as useApiQuery25 } from "@quanticjs/react-query";
|
|
4001
|
-
import { jsx as
|
|
4050
|
+
import { jsx as jsx34, jsxs as jsxs31 } from "react/jsx-runtime";
|
|
4002
4051
|
function normalize7(raw) {
|
|
4003
4052
|
const obj = raw ?? {};
|
|
4004
4053
|
const toList = (value) => Array.isArray(value) ? value.filter((v) => typeof v === "string") : [];
|
|
@@ -4016,15 +4065,15 @@ function TagEditor({ id, label, values, onAdd, onRemove }) {
|
|
|
4016
4065
|
onAdd(value);
|
|
4017
4066
|
setDraft("");
|
|
4018
4067
|
};
|
|
4019
|
-
return /* @__PURE__ */
|
|
4020
|
-
/* @__PURE__ */
|
|
4021
|
-
/* @__PURE__ */
|
|
4068
|
+
return /* @__PURE__ */ jsxs31("div", { className: "flex flex-col gap-2", children: [
|
|
4069
|
+
/* @__PURE__ */ jsx34("span", { className: "text-sm font-medium text-foreground", children: label }),
|
|
4070
|
+
/* @__PURE__ */ jsx34("ul", { className: "flex flex-wrap gap-2", children: values.length === 0 ? /* @__PURE__ */ jsx34("li", { className: "text-sm text-muted-foreground", children: "None" }) : values.map((value) => /* @__PURE__ */ jsxs31(
|
|
4022
4071
|
"li",
|
|
4023
4072
|
{
|
|
4024
4073
|
className: "flex items-center gap-1 rounded-md border border-border bg-card px-2 py-1 text-sm text-foreground",
|
|
4025
4074
|
children: [
|
|
4026
4075
|
value,
|
|
4027
|
-
/* @__PURE__ */
|
|
4076
|
+
/* @__PURE__ */ jsx34(
|
|
4028
4077
|
"button",
|
|
4029
4078
|
{
|
|
4030
4079
|
type: "button",
|
|
@@ -4038,13 +4087,13 @@ function TagEditor({ id, label, values, onAdd, onRemove }) {
|
|
|
4038
4087
|
},
|
|
4039
4088
|
value
|
|
4040
4089
|
)) }),
|
|
4041
|
-
/* @__PURE__ */
|
|
4042
|
-
/* @__PURE__ */
|
|
4043
|
-
/* @__PURE__ */
|
|
4090
|
+
/* @__PURE__ */ jsxs31("form", { onSubmit: add, className: "flex items-end gap-2", noValidate: true, children: [
|
|
4091
|
+
/* @__PURE__ */ jsxs31("div", { className: "flex flex-col gap-1", children: [
|
|
4092
|
+
/* @__PURE__ */ jsxs31("label", { htmlFor: id, className: "sr-only", children: [
|
|
4044
4093
|
"Add to ",
|
|
4045
4094
|
label
|
|
4046
4095
|
] }),
|
|
4047
|
-
/* @__PURE__ */
|
|
4096
|
+
/* @__PURE__ */ jsx34(
|
|
4048
4097
|
"input",
|
|
4049
4098
|
{
|
|
4050
4099
|
id,
|
|
@@ -4055,7 +4104,7 @@ function TagEditor({ id, label, values, onAdd, onRemove }) {
|
|
|
4055
4104
|
}
|
|
4056
4105
|
)
|
|
4057
4106
|
] }),
|
|
4058
|
-
/* @__PURE__ */
|
|
4107
|
+
/* @__PURE__ */ jsx34(
|
|
4059
4108
|
"button",
|
|
4060
4109
|
{
|
|
4061
4110
|
type: "submit",
|
|
@@ -4120,23 +4169,23 @@ function TenantConfigForm({ basePath = "/api", className }) {
|
|
|
4120
4169
|
save.mutate(config);
|
|
4121
4170
|
};
|
|
4122
4171
|
if (isLoading) {
|
|
4123
|
-
return /* @__PURE__ */
|
|
4172
|
+
return /* @__PURE__ */ jsxs31(
|
|
4124
4173
|
"div",
|
|
4125
4174
|
{
|
|
4126
4175
|
role: "status",
|
|
4127
4176
|
"aria-label": "Loading tenant configuration",
|
|
4128
4177
|
className: cn31("flex flex-col gap-2 p-4", className),
|
|
4129
4178
|
children: [
|
|
4130
|
-
/* @__PURE__ */
|
|
4131
|
-
[0, 1, 2].map((i) => /* @__PURE__ */
|
|
4179
|
+
/* @__PURE__ */ jsx34("span", { className: "sr-only", children: "Loading tenant configuration" }),
|
|
4180
|
+
[0, 1, 2].map((i) => /* @__PURE__ */ jsx34("div", { "aria-hidden": "true", className: "h-10 animate-pulse rounded bg-muted" }, i))
|
|
4132
4181
|
]
|
|
4133
4182
|
}
|
|
4134
4183
|
);
|
|
4135
4184
|
}
|
|
4136
4185
|
if (isError) {
|
|
4137
|
-
return /* @__PURE__ */
|
|
4138
|
-
/* @__PURE__ */
|
|
4139
|
-
/* @__PURE__ */
|
|
4186
|
+
return /* @__PURE__ */ jsxs31("div", { className: cn31("flex flex-col items-start gap-3 p-4", className), children: [
|
|
4187
|
+
/* @__PURE__ */ jsx34("p", { className: "text-sm text-foreground", children: "Failed to load tenant configuration" }),
|
|
4188
|
+
/* @__PURE__ */ jsx34(
|
|
4140
4189
|
"button",
|
|
4141
4190
|
{
|
|
4142
4191
|
type: "button",
|
|
@@ -4148,7 +4197,7 @@ function TenantConfigForm({ basePath = "/api", className }) {
|
|
|
4148
4197
|
] });
|
|
4149
4198
|
}
|
|
4150
4199
|
const errorId = "tenant-config-subset-error";
|
|
4151
|
-
return /* @__PURE__ */
|
|
4200
|
+
return /* @__PURE__ */ jsxs31(
|
|
4152
4201
|
"form",
|
|
4153
4202
|
{
|
|
4154
4203
|
onSubmit,
|
|
@@ -4157,8 +4206,8 @@ function TenantConfigForm({ basePath = "/api", className }) {
|
|
|
4157
4206
|
"aria-invalid": subsetError ? "true" : void 0,
|
|
4158
4207
|
"aria-describedby": subsetError ? errorId : void 0,
|
|
4159
4208
|
children: [
|
|
4160
|
-
/* @__PURE__ */
|
|
4161
|
-
/* @__PURE__ */
|
|
4209
|
+
/* @__PURE__ */ jsx34("h2", { className: "text-sm font-semibold text-foreground", children: "Notification configuration" }),
|
|
4210
|
+
/* @__PURE__ */ jsx34(
|
|
4162
4211
|
TagEditor,
|
|
4163
4212
|
{
|
|
4164
4213
|
id: "tc-notification-types",
|
|
@@ -4168,7 +4217,7 @@ function TenantConfigForm({ basePath = "/api", className }) {
|
|
|
4168
4217
|
onRemove: removeType
|
|
4169
4218
|
}
|
|
4170
4219
|
),
|
|
4171
|
-
/* @__PURE__ */
|
|
4220
|
+
/* @__PURE__ */ jsx34(
|
|
4172
4221
|
TagEditor,
|
|
4173
4222
|
{
|
|
4174
4223
|
id: "tc-immediate-email-types",
|
|
@@ -4178,8 +4227,8 @@ function TenantConfigForm({ basePath = "/api", className }) {
|
|
|
4178
4227
|
onRemove: removeImmediate
|
|
4179
4228
|
}
|
|
4180
4229
|
),
|
|
4181
|
-
subsetError && /* @__PURE__ */
|
|
4182
|
-
/* @__PURE__ */
|
|
4230
|
+
subsetError && /* @__PURE__ */ jsx34("p", { id: errorId, className: "text-xs text-destructive", children: subsetError }),
|
|
4231
|
+
/* @__PURE__ */ jsx34("div", { children: /* @__PURE__ */ jsx34(
|
|
4183
4232
|
"button",
|
|
4184
4233
|
{
|
|
4185
4234
|
type: "submit",
|
|
@@ -4197,7 +4246,7 @@ function TenantConfigForm({ basePath = "/api", className }) {
|
|
|
4197
4246
|
import { useEffect as useEffect9, useState as useState19 } from "react";
|
|
4198
4247
|
import { cn as cn32, useToast as useToast16 } from "@quanticjs/react-ui";
|
|
4199
4248
|
import { useApiMutation as useApiMutation17, useApiQuery as useApiQuery26 } from "@quanticjs/react-query";
|
|
4200
|
-
import { jsx as
|
|
4249
|
+
import { jsx as jsx35, jsxs as jsxs32 } from "react/jsx-runtime";
|
|
4201
4250
|
function normalize8(raw) {
|
|
4202
4251
|
const obj = raw ?? {};
|
|
4203
4252
|
const bool = (...keys) => {
|
|
@@ -4242,23 +4291,23 @@ function TrackingConfigForm({ basePath = "/api", className }) {
|
|
|
4242
4291
|
save.mutate(form);
|
|
4243
4292
|
};
|
|
4244
4293
|
if (isLoading) {
|
|
4245
|
-
return /* @__PURE__ */
|
|
4294
|
+
return /* @__PURE__ */ jsxs32(
|
|
4246
4295
|
"div",
|
|
4247
4296
|
{
|
|
4248
4297
|
role: "status",
|
|
4249
4298
|
"aria-label": "Loading tracking configuration",
|
|
4250
4299
|
className: cn32("flex flex-col gap-2 p-4", className),
|
|
4251
4300
|
children: [
|
|
4252
|
-
/* @__PURE__ */
|
|
4253
|
-
[0, 1].map((i) => /* @__PURE__ */
|
|
4301
|
+
/* @__PURE__ */ jsx35("span", { className: "sr-only", children: "Loading tracking configuration" }),
|
|
4302
|
+
[0, 1].map((i) => /* @__PURE__ */ jsx35("div", { "aria-hidden": "true", className: "h-10 animate-pulse rounded bg-muted" }, i))
|
|
4254
4303
|
]
|
|
4255
4304
|
}
|
|
4256
4305
|
);
|
|
4257
4306
|
}
|
|
4258
4307
|
if (isError) {
|
|
4259
|
-
return /* @__PURE__ */
|
|
4260
|
-
/* @__PURE__ */
|
|
4261
|
-
/* @__PURE__ */
|
|
4308
|
+
return /* @__PURE__ */ jsxs32("div", { className: cn32("flex flex-col items-start gap-3 p-4", className), children: [
|
|
4309
|
+
/* @__PURE__ */ jsx35("p", { className: "text-sm text-foreground", children: "Failed to load tracking configuration" }),
|
|
4310
|
+
/* @__PURE__ */ jsx35(
|
|
4262
4311
|
"button",
|
|
4263
4312
|
{
|
|
4264
4313
|
type: "button",
|
|
@@ -4269,10 +4318,10 @@ function TrackingConfigForm({ basePath = "/api", className }) {
|
|
|
4269
4318
|
)
|
|
4270
4319
|
] });
|
|
4271
4320
|
}
|
|
4272
|
-
return /* @__PURE__ */
|
|
4273
|
-
/* @__PURE__ */
|
|
4274
|
-
/* @__PURE__ */
|
|
4275
|
-
/* @__PURE__ */
|
|
4321
|
+
return /* @__PURE__ */ jsxs32("form", { onSubmit, className: cn32("flex flex-col gap-4", className), noValidate: true, children: [
|
|
4322
|
+
/* @__PURE__ */ jsx35("h2", { className: "text-sm font-semibold text-foreground", children: "Tracking configuration" }),
|
|
4323
|
+
/* @__PURE__ */ jsxs32("label", { className: "flex items-center gap-2 text-sm text-foreground", children: [
|
|
4324
|
+
/* @__PURE__ */ jsx35(
|
|
4276
4325
|
"input",
|
|
4277
4326
|
{
|
|
4278
4327
|
type: "checkbox",
|
|
@@ -4283,8 +4332,8 @@ function TrackingConfigForm({ basePath = "/api", className }) {
|
|
|
4283
4332
|
),
|
|
4284
4333
|
"Open tracking"
|
|
4285
4334
|
] }),
|
|
4286
|
-
/* @__PURE__ */
|
|
4287
|
-
/* @__PURE__ */
|
|
4335
|
+
/* @__PURE__ */ jsxs32("label", { className: "flex items-center gap-2 text-sm text-foreground", children: [
|
|
4336
|
+
/* @__PURE__ */ jsx35(
|
|
4288
4337
|
"input",
|
|
4289
4338
|
{
|
|
4290
4339
|
type: "checkbox",
|
|
@@ -4295,7 +4344,7 @@ function TrackingConfigForm({ basePath = "/api", className }) {
|
|
|
4295
4344
|
),
|
|
4296
4345
|
"Click tracking"
|
|
4297
4346
|
] }),
|
|
4298
|
-
/* @__PURE__ */
|
|
4347
|
+
/* @__PURE__ */ jsx35("div", { children: /* @__PURE__ */ jsx35(
|
|
4299
4348
|
"button",
|
|
4300
4349
|
{
|
|
4301
4350
|
type: "submit",
|
|
@@ -4309,9 +4358,9 @@ function TrackingConfigForm({ basePath = "/api", className }) {
|
|
|
4309
4358
|
|
|
4310
4359
|
// src/api-key-manager.tsx
|
|
4311
4360
|
import { useState as useState20 } from "react";
|
|
4312
|
-
import {
|
|
4361
|
+
import { Button as Button8, Card as Card7, EmptyState as EmptyState7, StatusBadge as StatusBadge8, cn as cn33, formatDateTime as formatDateTime9, useToast as useToast17 } from "@quanticjs/react-ui";
|
|
4313
4362
|
import { useApiMutation as useApiMutation18, useApiQuery as useApiQuery27 } from "@quanticjs/react-query";
|
|
4314
|
-
import { jsx as
|
|
4363
|
+
import { jsx as jsx36, jsxs as jsxs33 } from "react/jsx-runtime";
|
|
4315
4364
|
function normalize9(raw) {
|
|
4316
4365
|
const list = Array.isArray(raw) ? raw : Array.isArray(raw?.items) ? raw.items : [];
|
|
4317
4366
|
return list;
|
|
@@ -4369,102 +4418,69 @@ function ApiKeyManager({ basePath = "/api", className }) {
|
|
|
4369
4418
|
revoke.mutate(id);
|
|
4370
4419
|
}
|
|
4371
4420
|
};
|
|
4372
|
-
const
|
|
4373
|
-
|
|
4374
|
-
|
|
4375
|
-
/* @__PURE__ */
|
|
4376
|
-
"
|
|
4377
|
-
{
|
|
4378
|
-
|
|
4379
|
-
|
|
4380
|
-
|
|
4381
|
-
|
|
4382
|
-
|
|
4383
|
-
|
|
4384
|
-
|
|
4385
|
-
|
|
4386
|
-
|
|
4387
|
-
|
|
4388
|
-
|
|
4389
|
-
|
|
4390
|
-
|
|
4391
|
-
|
|
4392
|
-
|
|
4393
|
-
|
|
4394
|
-
|
|
4395
|
-
|
|
4396
|
-
|
|
4397
|
-
|
|
4398
|
-
|
|
4399
|
-
|
|
4400
|
-
|
|
4401
|
-
|
|
4402
|
-
|
|
4403
|
-
|
|
4404
|
-
|
|
4405
|
-
className: "rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring disabled:opacity-50",
|
|
4406
|
-
children: create.isPending ? "Creating\u2026" : "Create key"
|
|
4407
|
-
}
|
|
4408
|
-
)
|
|
4409
|
-
] });
|
|
4410
|
-
let body;
|
|
4411
|
-
if (isLoading) {
|
|
4412
|
-
body = /* @__PURE__ */ jsxs32("div", { role: "status", "aria-label": "Loading API keys", className: "flex flex-col gap-2 p-4", children: [
|
|
4413
|
-
/* @__PURE__ */ jsx35("span", { className: "sr-only", children: "Loading API keys" }),
|
|
4414
|
-
[0, 1, 2].map((i) => /* @__PURE__ */ jsx35("div", { "aria-hidden": "true", className: "h-10 animate-pulse rounded bg-muted" }, i))
|
|
4415
|
-
] });
|
|
4416
|
-
} else if (isError) {
|
|
4417
|
-
body = /* @__PURE__ */ jsxs32("div", { className: "flex flex-col items-start gap-3 p-4", children: [
|
|
4418
|
-
/* @__PURE__ */ jsx35("p", { className: "text-sm text-foreground", children: "Failed to load API keys" }),
|
|
4419
|
-
/* @__PURE__ */ jsx35(
|
|
4420
|
-
"button",
|
|
4421
|
-
{
|
|
4422
|
-
type: "button",
|
|
4423
|
-
onClick: () => void refetch(),
|
|
4424
|
-
className: "rounded bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring",
|
|
4425
|
-
children: "Try again"
|
|
4426
|
-
}
|
|
4427
|
-
)
|
|
4428
|
-
] });
|
|
4429
|
-
} else {
|
|
4430
|
-
const rows = normalize9(data);
|
|
4431
|
-
if (rows.length === 0) {
|
|
4432
|
-
body = /* @__PURE__ */ jsx35("div", { className: "p-6 text-center text-sm text-muted-foreground", children: "No API keys" });
|
|
4433
|
-
} else {
|
|
4434
|
-
body = /* @__PURE__ */ jsxs32("table", { className: "w-full text-sm", children: [
|
|
4435
|
-
/* @__PURE__ */ jsx35("thead", { children: /* @__PURE__ */ jsxs32("tr", { className: "border-b border-border text-start text-muted-foreground", children: [
|
|
4436
|
-
/* @__PURE__ */ jsx35("th", { scope: "col", className: "py-2 pe-4 font-medium", children: "Name" }),
|
|
4437
|
-
/* @__PURE__ */ jsx35("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Prefix" }),
|
|
4438
|
-
/* @__PURE__ */ jsx35("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Application" }),
|
|
4439
|
-
/* @__PURE__ */ jsx35("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Status" }),
|
|
4440
|
-
/* @__PURE__ */ jsx35("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Created" }),
|
|
4441
|
-
/* @__PURE__ */ jsx35("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Last used" }),
|
|
4442
|
-
/* @__PURE__ */ jsx35("th", { scope: "col", className: "px-4 py-2 font-medium", children: /* @__PURE__ */ jsx35("span", { className: "sr-only", children: "Actions" }) })
|
|
4421
|
+
const rows = normalize9(data);
|
|
4422
|
+
return /* @__PURE__ */ jsxs33("section", { "aria-label": "API key management", className: cn33("flex flex-col gap-4", className), children: [
|
|
4423
|
+
/* @__PURE__ */ jsx36(Card7, { children: /* @__PURE__ */ jsxs33("form", { onSubmit: onCreate, className: "flex flex-wrap items-end gap-3 p-4", noValidate: true, children: [
|
|
4424
|
+
/* @__PURE__ */ jsxs33("label", { className: "flex flex-1 flex-col gap-1 text-sm", children: [
|
|
4425
|
+
/* @__PURE__ */ jsx36("span", { className: "font-medium text-foreground", children: "New key name" }),
|
|
4426
|
+
/* @__PURE__ */ jsx36("input", { type: "text", value: name, onChange: (e) => setName(e.target.value), className: FIELD_CLASS })
|
|
4427
|
+
] }),
|
|
4428
|
+
/* @__PURE__ */ jsxs33("label", { className: "flex flex-1 flex-col gap-1 text-sm", children: [
|
|
4429
|
+
/* @__PURE__ */ jsx36("span", { className: "font-medium text-foreground", children: "Application (optional)" }),
|
|
4430
|
+
/* @__PURE__ */ jsx36(
|
|
4431
|
+
"input",
|
|
4432
|
+
{
|
|
4433
|
+
type: "text",
|
|
4434
|
+
value: applicationKey,
|
|
4435
|
+
onChange: (e) => setApplicationKey(e.target.value),
|
|
4436
|
+
placeholder: "delivery-hub",
|
|
4437
|
+
className: FIELD_CLASS
|
|
4438
|
+
}
|
|
4439
|
+
)
|
|
4440
|
+
] }),
|
|
4441
|
+
/* @__PURE__ */ jsx36(Button8, { type: "submit", disabled: create.isPending, children: create.isPending ? "Creating\u2026" : "Create key" })
|
|
4442
|
+
] }) }),
|
|
4443
|
+
/* @__PURE__ */ jsxs33(Card7, { children: [
|
|
4444
|
+
/* @__PURE__ */ jsx36(PanelHeader, { title: "Keys", subtitle: !isLoading && !isError ? `${rows.length} keys` : void 0 }),
|
|
4445
|
+
isLoading ? /* @__PURE__ */ jsx36(SkeletonRows, { label: "Loading API keys" }) : isError ? /* @__PURE__ */ jsx36(ErrorPanel, { message: "Failed to load API keys", onRetry: () => void refetch() }) : rows.length === 0 ? /* @__PURE__ */ jsx36(EmptyState7, { icon: /* @__PURE__ */ jsx36(KeyIcon, {}), title: "No API keys", description: "Create a key to get started." }) : /* @__PURE__ */ jsxs33("table", { className: "w-full text-sm", children: [
|
|
4446
|
+
/* @__PURE__ */ jsx36("thead", { children: /* @__PURE__ */ jsxs33("tr", { className: "border-b border-border text-start text-muted-foreground", children: [
|
|
4447
|
+
/* @__PURE__ */ jsx36("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Name" }),
|
|
4448
|
+
/* @__PURE__ */ jsx36("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Prefix" }),
|
|
4449
|
+
/* @__PURE__ */ jsx36("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Application" }),
|
|
4450
|
+
/* @__PURE__ */ jsx36("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Status" }),
|
|
4451
|
+
/* @__PURE__ */ jsx36("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Created" }),
|
|
4452
|
+
/* @__PURE__ */ jsx36("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Last used" }),
|
|
4453
|
+
/* @__PURE__ */ jsx36("th", { scope: "col", className: "px-4 py-2 font-medium", children: /* @__PURE__ */ jsx36("span", { className: "sr-only", children: "Actions" }) })
|
|
4443
4454
|
] }) }),
|
|
4444
|
-
/* @__PURE__ */
|
|
4445
|
-
/* @__PURE__ */
|
|
4446
|
-
/* @__PURE__ */
|
|
4447
|
-
/* @__PURE__ */
|
|
4448
|
-
/* @__PURE__ */
|
|
4449
|
-
/* @__PURE__ */
|
|
4450
|
-
/* @__PURE__ */
|
|
4451
|
-
/* @__PURE__ */
|
|
4452
|
-
|
|
4455
|
+
/* @__PURE__ */ jsx36("tbody", { children: rows.map((row) => /* @__PURE__ */ jsxs33("tr", { className: "border-b border-border last:border-0 hover:bg-muted/40", children: [
|
|
4456
|
+
/* @__PURE__ */ jsx36("td", { className: "px-4 py-3 text-foreground", children: row.name }),
|
|
4457
|
+
/* @__PURE__ */ jsx36("td", { className: "px-4 py-3 font-mono text-muted-foreground", children: row.prefix ?? "\u2014" }),
|
|
4458
|
+
/* @__PURE__ */ jsx36("td", { className: "px-4 py-3 font-mono text-muted-foreground", children: row.applicationKey ?? "\u2014" }),
|
|
4459
|
+
/* @__PURE__ */ jsx36("td", { className: "px-4 py-3", children: /* @__PURE__ */ jsx36(StatusBadge8, { variant: row.revoked ? "destructive" : "success", children: row.revoked ? "Revoked" : "Active" }) }),
|
|
4460
|
+
/* @__PURE__ */ jsx36("td", { className: "px-4 py-3 text-muted-foreground", children: formatDateTime9(row.createdAt) }),
|
|
4461
|
+
/* @__PURE__ */ jsx36("td", { className: "px-4 py-3 text-muted-foreground", children: row.lastUsedAt ? formatDateTime9(row.lastUsedAt) : "\u2014" }),
|
|
4462
|
+
/* @__PURE__ */ jsx36("td", { className: "px-4 py-3 text-end", children: /* @__PURE__ */ jsx36(
|
|
4463
|
+
Button8,
|
|
4453
4464
|
{
|
|
4454
4465
|
type: "button",
|
|
4466
|
+
variant: "ghost",
|
|
4467
|
+
size: "sm",
|
|
4468
|
+
className: "text-destructive",
|
|
4455
4469
|
disabled: revoke.isPending || row.revoked,
|
|
4456
4470
|
onClick: () => onRevoke(row.id),
|
|
4457
|
-
className: "rounded-md border border-border px-3 py-1 text-sm font-medium text-destructive hover:bg-muted focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring disabled:opacity-50",
|
|
4458
4471
|
children: "Revoke"
|
|
4459
4472
|
}
|
|
4460
4473
|
) })
|
|
4461
4474
|
] }, row.id)) })
|
|
4462
|
-
] })
|
|
4463
|
-
}
|
|
4464
|
-
}
|
|
4465
|
-
|
|
4466
|
-
|
|
4467
|
-
|
|
4475
|
+
] })
|
|
4476
|
+
] })
|
|
4477
|
+
] });
|
|
4478
|
+
}
|
|
4479
|
+
function KeyIcon() {
|
|
4480
|
+
return /* @__PURE__ */ jsxs33("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
4481
|
+
/* @__PURE__ */ jsx36("path", { d: "m15.5 7.5 2.3 2.3a1 1 0 0 0 1.4 0l2.1-2.1a1 1 0 0 0 0-1.4L19 4" }),
|
|
4482
|
+
/* @__PURE__ */ jsx36("path", { d: "m21 2-9.6 9.6" }),
|
|
4483
|
+
/* @__PURE__ */ jsx36("circle", { cx: "7.5", cy: "15.5", r: "5.5" })
|
|
4468
4484
|
] });
|
|
4469
4485
|
}
|
|
4470
4486
|
|
|
@@ -4472,7 +4488,7 @@ function ApiKeyManager({ basePath = "/api", className }) {
|
|
|
4472
4488
|
import { useState as useState21 } from "react";
|
|
4473
4489
|
import { cn as cn34, formatDateTime as formatDateTime10, StatusBadge as StatusBadge9, useToast as useToast18 } from "@quanticjs/react-ui";
|
|
4474
4490
|
import { useApiMutation as useApiMutation19, useApiQuery as useApiQuery28 } from "@quanticjs/react-query";
|
|
4475
|
-
import { jsx as
|
|
4491
|
+
import { jsx as jsx37, jsxs as jsxs34 } from "react/jsx-runtime";
|
|
4476
4492
|
function normalize10(raw) {
|
|
4477
4493
|
const list = Array.isArray(raw) ? raw : Array.isArray(raw?.items) ? raw.items : [];
|
|
4478
4494
|
return list;
|
|
@@ -4518,10 +4534,10 @@ function ApplicationRegistryPanel({
|
|
|
4518
4534
|
if (!k || !name) return;
|
|
4519
4535
|
register.mutate({ key: k, displayName: name, description: description.trim() || void 0 });
|
|
4520
4536
|
};
|
|
4521
|
-
const registerForm = /* @__PURE__ */
|
|
4522
|
-
/* @__PURE__ */
|
|
4523
|
-
/* @__PURE__ */
|
|
4524
|
-
/* @__PURE__ */
|
|
4537
|
+
const registerForm = /* @__PURE__ */ jsxs34("form", { onSubmit: onRegister, className: "flex flex-wrap items-end gap-3", noValidate: true, children: [
|
|
4538
|
+
/* @__PURE__ */ jsxs34("div", { className: "flex flex-col gap-1", children: [
|
|
4539
|
+
/* @__PURE__ */ jsx37("label", { htmlFor: "application-key", className: "text-sm font-medium text-foreground", children: "Key (slug)" }),
|
|
4540
|
+
/* @__PURE__ */ jsx37(
|
|
4525
4541
|
"input",
|
|
4526
4542
|
{
|
|
4527
4543
|
id: "application-key",
|
|
@@ -4533,9 +4549,9 @@ function ApplicationRegistryPanel({
|
|
|
4533
4549
|
}
|
|
4534
4550
|
)
|
|
4535
4551
|
] }),
|
|
4536
|
-
/* @__PURE__ */
|
|
4537
|
-
/* @__PURE__ */
|
|
4538
|
-
/* @__PURE__ */
|
|
4552
|
+
/* @__PURE__ */ jsxs34("div", { className: "flex flex-col gap-1", children: [
|
|
4553
|
+
/* @__PURE__ */ jsx37("label", { htmlFor: "application-name", className: "text-sm font-medium text-foreground", children: "Display name" }),
|
|
4554
|
+
/* @__PURE__ */ jsx37(
|
|
4539
4555
|
"input",
|
|
4540
4556
|
{
|
|
4541
4557
|
id: "application-name",
|
|
@@ -4547,9 +4563,9 @@ function ApplicationRegistryPanel({
|
|
|
4547
4563
|
}
|
|
4548
4564
|
)
|
|
4549
4565
|
] }),
|
|
4550
|
-
/* @__PURE__ */
|
|
4551
|
-
/* @__PURE__ */
|
|
4552
|
-
/* @__PURE__ */
|
|
4566
|
+
/* @__PURE__ */ jsxs34("div", { className: "flex flex-col gap-1", children: [
|
|
4567
|
+
/* @__PURE__ */ jsx37("label", { htmlFor: "application-description", className: "text-sm font-medium text-foreground", children: "Description (optional)" }),
|
|
4568
|
+
/* @__PURE__ */ jsx37(
|
|
4553
4569
|
"input",
|
|
4554
4570
|
{
|
|
4555
4571
|
id: "application-description",
|
|
@@ -4560,7 +4576,7 @@ function ApplicationRegistryPanel({
|
|
|
4560
4576
|
}
|
|
4561
4577
|
)
|
|
4562
4578
|
] }),
|
|
4563
|
-
/* @__PURE__ */
|
|
4579
|
+
/* @__PURE__ */ jsx37(
|
|
4564
4580
|
"button",
|
|
4565
4581
|
{
|
|
4566
4582
|
type: "submit",
|
|
@@ -4571,23 +4587,23 @@ function ApplicationRegistryPanel({
|
|
|
4571
4587
|
)
|
|
4572
4588
|
] });
|
|
4573
4589
|
if (isLoading) {
|
|
4574
|
-
return /* @__PURE__ */
|
|
4590
|
+
return /* @__PURE__ */ jsxs34(
|
|
4575
4591
|
"div",
|
|
4576
4592
|
{
|
|
4577
4593
|
role: "status",
|
|
4578
4594
|
"aria-label": "Loading applications",
|
|
4579
4595
|
className: cn34("flex flex-col gap-2 p-4", className),
|
|
4580
4596
|
children: [
|
|
4581
|
-
/* @__PURE__ */
|
|
4582
|
-
[0, 1, 2].map((i) => /* @__PURE__ */
|
|
4597
|
+
/* @__PURE__ */ jsx37("span", { className: "sr-only", children: "Loading applications" }),
|
|
4598
|
+
[0, 1, 2].map((i) => /* @__PURE__ */ jsx37("div", { "aria-hidden": "true", className: "h-10 animate-pulse rounded bg-muted" }, i))
|
|
4583
4599
|
]
|
|
4584
4600
|
}
|
|
4585
4601
|
);
|
|
4586
4602
|
}
|
|
4587
4603
|
if (isError) {
|
|
4588
|
-
return /* @__PURE__ */
|
|
4589
|
-
/* @__PURE__ */
|
|
4590
|
-
/* @__PURE__ */
|
|
4604
|
+
return /* @__PURE__ */ jsxs34("div", { className: cn34("flex flex-col items-start gap-3 p-4", className), children: [
|
|
4605
|
+
/* @__PURE__ */ jsx37("p", { className: "text-sm text-foreground", children: "Failed to load applications" }),
|
|
4606
|
+
/* @__PURE__ */ jsx37(
|
|
4591
4607
|
"button",
|
|
4592
4608
|
{
|
|
4593
4609
|
type: "button",
|
|
@@ -4599,22 +4615,22 @@ function ApplicationRegistryPanel({
|
|
|
4599
4615
|
] });
|
|
4600
4616
|
}
|
|
4601
4617
|
const apps = normalize10(data);
|
|
4602
|
-
return /* @__PURE__ */
|
|
4618
|
+
return /* @__PURE__ */ jsxs34("section", { "aria-label": "Applications", className: cn34("flex flex-col gap-4 p-4", className), children: [
|
|
4603
4619
|
registerForm,
|
|
4604
|
-
apps.length === 0 ? /* @__PURE__ */
|
|
4605
|
-
/* @__PURE__ */
|
|
4606
|
-
/* @__PURE__ */
|
|
4607
|
-
/* @__PURE__ */
|
|
4608
|
-
/* @__PURE__ */
|
|
4609
|
-
/* @__PURE__ */
|
|
4610
|
-
/* @__PURE__ */
|
|
4620
|
+
apps.length === 0 ? /* @__PURE__ */ jsx37("p", { className: "p-6 text-center text-sm text-muted-foreground", children: "No applications registered" }) : /* @__PURE__ */ jsxs34("table", { className: "w-full text-sm", children: [
|
|
4621
|
+
/* @__PURE__ */ jsx37("thead", { children: /* @__PURE__ */ jsxs34("tr", { className: "border-b border-border text-start text-muted-foreground", children: [
|
|
4622
|
+
/* @__PURE__ */ jsx37("th", { className: "py-2 font-medium", children: "Key" }),
|
|
4623
|
+
/* @__PURE__ */ jsx37("th", { className: "py-2 font-medium", children: "Name" }),
|
|
4624
|
+
/* @__PURE__ */ jsx37("th", { className: "py-2 font-medium", children: "Status" }),
|
|
4625
|
+
/* @__PURE__ */ jsx37("th", { className: "py-2 font-medium", children: "Created" }),
|
|
4626
|
+
/* @__PURE__ */ jsx37("th", { className: "py-2 font-medium", children: "Actions" })
|
|
4611
4627
|
] }) }),
|
|
4612
|
-
/* @__PURE__ */
|
|
4613
|
-
/* @__PURE__ */
|
|
4614
|
-
/* @__PURE__ */
|
|
4615
|
-
/* @__PURE__ */
|
|
4616
|
-
/* @__PURE__ */
|
|
4617
|
-
/* @__PURE__ */
|
|
4628
|
+
/* @__PURE__ */ jsx37("tbody", { children: apps.map((app) => /* @__PURE__ */ jsxs34("tr", { className: "border-b border-border", children: [
|
|
4629
|
+
/* @__PURE__ */ jsx37("td", { className: "py-2 font-mono text-foreground", children: app.key }),
|
|
4630
|
+
/* @__PURE__ */ jsx37("td", { className: "py-2 text-foreground", children: app.displayName }),
|
|
4631
|
+
/* @__PURE__ */ jsx37("td", { className: "py-2", children: /* @__PURE__ */ jsx37(StatusBadge9, { variant: app.status === "active" ? "success" : "neutral", children: app.status }) }),
|
|
4632
|
+
/* @__PURE__ */ jsx37("td", { className: "py-2 text-muted-foreground", children: formatDateTime10(app.createdAt) }),
|
|
4633
|
+
/* @__PURE__ */ jsx37("td", { className: "py-2", children: /* @__PURE__ */ jsx37(
|
|
4618
4634
|
"button",
|
|
4619
4635
|
{
|
|
4620
4636
|
type: "button",
|