@quanticjs/notification-ui 9.0.0 → 9.0.2
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 +1106 -1013
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1082 -974
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -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";
|
|
@@ -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,111 +3468,228 @@ 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 ?? [];
|
|
3413
3533
|
const dlqPending = data.dlqPending;
|
|
3414
|
-
const
|
|
3415
|
-
|
|
3416
|
-
|
|
3417
|
-
|
|
3418
|
-
|
|
3419
|
-
|
|
3420
|
-
|
|
3421
|
-
|
|
3422
|
-
|
|
3423
|
-
|
|
3424
|
-
|
|
3425
|
-
/* @__PURE__ */ jsxs26("div", { className: "flex items-center gap-2", children: [
|
|
3426
|
-
/* @__PURE__ */ jsx29("span", { className: "text-sm text-muted-foreground", children: "DLQ pending" }),
|
|
3427
|
-
/* @__PURE__ */ jsx29(StatusBadge6, { variant: dlqPending > 0 ? "destructive" : "success", children: dlqPending })
|
|
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 })
|
|
3534
|
+
const deliveryRate = ratePct(data.totalDelivered, data.totalSends);
|
|
3535
|
+
const failureRate = ratePct(data.totalFailed, data.totalSends);
|
|
3536
|
+
return /* @__PURE__ */ jsxs27("section", { "aria-label": "Operations overview", className: cn27("flex flex-col gap-5", className), children: [
|
|
3537
|
+
/* @__PURE__ */ jsxs27("div", { className: "flex flex-wrap items-baseline justify-between gap-2", children: [
|
|
3538
|
+
/* @__PURE__ */ jsxs27("div", { children: [
|
|
3539
|
+
/* @__PURE__ */ jsx30("h2", { className: "text-base font-semibold tracking-tight text-foreground", children: "Operations overview" }),
|
|
3540
|
+
/* @__PURE__ */ jsxs27("p", { className: "mt-0.5 text-xs text-muted-foreground", children: [
|
|
3541
|
+
"Last ",
|
|
3542
|
+
windowHours,
|
|
3543
|
+
"h"
|
|
3544
|
+
] })
|
|
3432
3545
|
] }),
|
|
3433
|
-
/* @__PURE__ */
|
|
3434
|
-
|
|
3435
|
-
|
|
3546
|
+
/* @__PURE__ */ jsxs27("p", { className: "text-xs text-muted-foreground", children: [
|
|
3547
|
+
"Generated ",
|
|
3548
|
+
formatDateTime7(data.generatedAt)
|
|
3436
3549
|
] })
|
|
3437
3550
|
] }),
|
|
3438
|
-
/* @__PURE__ */
|
|
3439
|
-
/* @__PURE__ */
|
|
3440
|
-
|
|
3441
|
-
|
|
3442
|
-
|
|
3443
|
-
|
|
3444
|
-
|
|
3445
|
-
|
|
3446
|
-
|
|
3447
|
-
|
|
3448
|
-
|
|
3449
|
-
|
|
3450
|
-
|
|
3551
|
+
/* @__PURE__ */ jsxs27("div", { className: "grid grid-cols-1 gap-4 sm:grid-cols-3", children: [
|
|
3552
|
+
/* @__PURE__ */ jsx30(StatCard, { label: `Sent (${windowHours}h)`, value: data.totalSends, icon: /* @__PURE__ */ jsx30(SendIcon, {}) }),
|
|
3553
|
+
/* @__PURE__ */ jsx30(
|
|
3554
|
+
StatCard,
|
|
3555
|
+
{
|
|
3556
|
+
label: "Delivery rate",
|
|
3557
|
+
value: deliveryRate,
|
|
3558
|
+
icon: /* @__PURE__ */ jsx30(CheckIcon, {}),
|
|
3559
|
+
delta: `${data.totalDelivered} delivered`,
|
|
3560
|
+
trend: "up"
|
|
3561
|
+
}
|
|
3562
|
+
),
|
|
3563
|
+
/* @__PURE__ */ jsx30(
|
|
3564
|
+
StatCard,
|
|
3565
|
+
{
|
|
3566
|
+
label: "Failure rate",
|
|
3567
|
+
value: failureRate,
|
|
3568
|
+
icon: /* @__PURE__ */ jsx30(AlertIcon4, {}),
|
|
3569
|
+
delta: `${data.totalFailed} failed`,
|
|
3570
|
+
trend: data.totalFailed > 0 ? "down" : "flat"
|
|
3571
|
+
}
|
|
3572
|
+
)
|
|
3451
3573
|
] }),
|
|
3452
|
-
/* @__PURE__ */
|
|
3453
|
-
"
|
|
3454
|
-
|
|
3574
|
+
/* @__PURE__ */ jsx30(Card5, { children: /* @__PURE__ */ jsxs27(CardContent, { className: "flex flex-wrap items-center gap-x-8 gap-y-3 p-5", children: [
|
|
3575
|
+
/* @__PURE__ */ jsxs27("div", { className: "flex items-center gap-2", children: [
|
|
3576
|
+
/* @__PURE__ */ jsx30("span", { className: "text-sm text-muted-foreground", children: "DLQ pending" }),
|
|
3577
|
+
/* @__PURE__ */ jsx30(StatusBadge6, { variant: dlqPending > 0 ? "destructive" : "success", appearance: "solid", children: dlqPending })
|
|
3578
|
+
] }),
|
|
3579
|
+
/* @__PURE__ */ jsxs27("div", { className: "flex items-center gap-2", children: [
|
|
3580
|
+
/* @__PURE__ */ jsx30("span", { className: "text-sm text-muted-foreground", children: "Broadcasts in flight" }),
|
|
3581
|
+
/* @__PURE__ */ jsx30("span", { className: "text-sm font-semibold tabular-nums text-foreground", children: data.broadcastsInFlight })
|
|
3582
|
+
] }),
|
|
3583
|
+
/* @__PURE__ */ jsxs27("div", { className: "flex items-center gap-2", children: [
|
|
3584
|
+
/* @__PURE__ */ jsx30("span", { className: "text-sm text-muted-foreground", children: "Queue" }),
|
|
3585
|
+
/* @__PURE__ */ jsx30(StatusBadge6, { variant: data.queueHealthy ? "success" : "destructive", appearance: "solid", children: data.queueHealthy ? "Healthy" : "Unhealthy" })
|
|
3586
|
+
] })
|
|
3587
|
+
] }) }),
|
|
3588
|
+
/* @__PURE__ */ jsxs27(Card5, { children: [
|
|
3589
|
+
/* @__PURE__ */ jsxs27(CardHeader, { children: [
|
|
3590
|
+
/* @__PURE__ */ jsx30(CardTitle, { children: "Channel health" }),
|
|
3591
|
+
/* @__PURE__ */ jsx30("p", { className: "text-sm text-muted-foreground", children: "Delivery success by channel" })
|
|
3592
|
+
] }),
|
|
3593
|
+
/* @__PURE__ */ jsx30(CardContent, { className: "p-0", children: channels.length === 0 ? /* @__PURE__ */ jsx30("p", { className: "px-5 py-8 text-center text-sm text-muted-foreground", children: "No channel activity" }) : /* @__PURE__ */ jsx30("ul", { className: "divide-y divide-border", children: channels.map((row) => {
|
|
3594
|
+
const success = ratePct(row.delivered, row.sends);
|
|
3595
|
+
return /* @__PURE__ */ jsxs27("li", { className: "flex items-center gap-3 px-5 py-3.5", children: [
|
|
3596
|
+
/* @__PURE__ */ jsx30(
|
|
3597
|
+
"span",
|
|
3598
|
+
{
|
|
3599
|
+
"aria-hidden": "true",
|
|
3600
|
+
className: "grid size-9 shrink-0 place-items-center rounded-md bg-primary/10 text-primary [&_svg]:size-4",
|
|
3601
|
+
children: /* @__PURE__ */ jsx30(ChannelIcon, { channel: row.channel })
|
|
3602
|
+
}
|
|
3603
|
+
),
|
|
3604
|
+
/* @__PURE__ */ jsxs27("div", { className: "min-w-0 flex-1", children: [
|
|
3605
|
+
/* @__PURE__ */ jsxs27("div", { className: "flex items-center justify-between gap-2", children: [
|
|
3606
|
+
/* @__PURE__ */ jsxs27("span", { className: "flex items-center gap-2 text-sm font-medium capitalize text-foreground", children: [
|
|
3607
|
+
row.channel,
|
|
3608
|
+
/* @__PURE__ */ jsxs27(StatusBadge6, { variant: row.failed > 0 ? "warning" : "success", appearance: "dot", children: [
|
|
3609
|
+
success,
|
|
3610
|
+
" success"
|
|
3611
|
+
] })
|
|
3612
|
+
] }),
|
|
3613
|
+
/* @__PURE__ */ jsxs27("span", { className: "shrink-0 text-xs tabular-nums text-muted-foreground", children: [
|
|
3614
|
+
row.sends,
|
|
3615
|
+
" sent"
|
|
3616
|
+
] })
|
|
3617
|
+
] }),
|
|
3618
|
+
/* @__PURE__ */ jsxs27("div", { className: "mt-2 flex h-1.5 overflow-hidden rounded-full bg-muted", children: [
|
|
3619
|
+
/* @__PURE__ */ jsx30("span", { className: "bg-success", style: { width: `${barPct(row.delivered, row.sends)}%` } }),
|
|
3620
|
+
/* @__PURE__ */ jsx30("span", { className: "bg-destructive", style: { width: `${barPct(row.failed, row.sends)}%` } })
|
|
3621
|
+
] }),
|
|
3622
|
+
/* @__PURE__ */ jsxs27("div", { className: "mt-1.5 text-xs tabular-nums text-muted-foreground", children: [
|
|
3623
|
+
row.delivered,
|
|
3624
|
+
" delivered \xB7 ",
|
|
3625
|
+
row.failed,
|
|
3626
|
+
" failed"
|
|
3627
|
+
] })
|
|
3628
|
+
] })
|
|
3629
|
+
] }, row.channel);
|
|
3630
|
+
}) }) })
|
|
3455
3631
|
] })
|
|
3456
3632
|
] });
|
|
3457
3633
|
}
|
|
3634
|
+
function ratePct(n, total) {
|
|
3635
|
+
if (total <= 0) return "\u2014";
|
|
3636
|
+
return `${(n / total * 100).toFixed(2)}%`;
|
|
3637
|
+
}
|
|
3638
|
+
function barPct(n, total) {
|
|
3639
|
+
if (total <= 0) return 0;
|
|
3640
|
+
return Math.min(100, n / total * 100);
|
|
3641
|
+
}
|
|
3642
|
+
function SendIcon() {
|
|
3643
|
+
return /* @__PURE__ */ jsxs27("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
3644
|
+
/* @__PURE__ */ jsx30("path", { d: "M14.536 21.686a.5.5 0 0 0 .937-.024l6.5-19a.496.496 0 0 0-.635-.635l-19 6.5a.5.5 0 0 0-.024.937l7.93 3.18a2 2 0 0 1 1.112 1.11z" }),
|
|
3645
|
+
/* @__PURE__ */ jsx30("path", { d: "m21.854 2.147-10.94 10.939" })
|
|
3646
|
+
] });
|
|
3647
|
+
}
|
|
3648
|
+
function CheckIcon() {
|
|
3649
|
+
return /* @__PURE__ */ jsxs27("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
3650
|
+
/* @__PURE__ */ jsx30("path", { d: "M21.801 10A10 10 0 1 1 17 3.335" }),
|
|
3651
|
+
/* @__PURE__ */ jsx30("path", { d: "m9 11 3 3L22 4" })
|
|
3652
|
+
] });
|
|
3653
|
+
}
|
|
3654
|
+
function AlertIcon4() {
|
|
3655
|
+
return /* @__PURE__ */ jsxs27("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
3656
|
+
/* @__PURE__ */ jsx30("circle", { cx: "12", cy: "12", r: "10" }),
|
|
3657
|
+
/* @__PURE__ */ jsx30("path", { d: "m15 9-6 6" }),
|
|
3658
|
+
/* @__PURE__ */ jsx30("path", { d: "m9 9 6 6" })
|
|
3659
|
+
] });
|
|
3660
|
+
}
|
|
3661
|
+
function ChannelIcon({ channel }) {
|
|
3662
|
+
switch (channel) {
|
|
3663
|
+
case "email":
|
|
3664
|
+
return /* @__PURE__ */ jsxs27("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
3665
|
+
/* @__PURE__ */ jsx30("rect", { width: "20", height: "16", x: "2", y: "4", rx: "2" }),
|
|
3666
|
+
/* @__PURE__ */ jsx30("path", { d: "m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7" })
|
|
3667
|
+
] });
|
|
3668
|
+
case "sms":
|
|
3669
|
+
return /* @__PURE__ */ jsx30("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx30("path", { d: "M7.9 20A9 9 0 1 0 4 16.1L2 22Z" }) });
|
|
3670
|
+
case "push":
|
|
3671
|
+
case "inapp":
|
|
3672
|
+
case "in-app":
|
|
3673
|
+
return /* @__PURE__ */ jsxs27("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
3674
|
+
/* @__PURE__ */ jsx30("path", { d: "M10.268 21a2 2 0 0 0 3.464 0" }),
|
|
3675
|
+
/* @__PURE__ */ jsx30("path", { d: "M3.262 15.326A1 1 0 0 0 4 17h16a1 1 0 0 0 .74-1.673C19.41 13.956 18 12.499 18 8A6 6 0 0 0 6 8c0 4.499-1.411 5.956-2.738 7.326" })
|
|
3676
|
+
] });
|
|
3677
|
+
case "webhook":
|
|
3678
|
+
return /* @__PURE__ */ jsxs27("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
3679
|
+
/* @__PURE__ */ jsx30("path", { d: "M10 6.5a3.5 3.5 0 1 1 6 2.45" }),
|
|
3680
|
+
/* @__PURE__ */ jsx30("path", { d: "M6 10.5a3.5 3.5 0 1 0 5 3.15" }),
|
|
3681
|
+
/* @__PURE__ */ jsx30("path", { d: "M14 17.5a3.5 3.5 0 1 0 1-6.85" })
|
|
3682
|
+
] });
|
|
3683
|
+
default:
|
|
3684
|
+
return /* @__PURE__ */ jsx30("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx30("circle", { cx: "12", cy: "12", r: "4" }) });
|
|
3685
|
+
}
|
|
3686
|
+
}
|
|
3458
3687
|
|
|
3459
3688
|
// src/delivery-log-explorer.tsx
|
|
3460
3689
|
import { useState as useState15 } from "react";
|
|
3461
|
-
import {
|
|
3690
|
+
import { Button as Button7, Card as Card6, EmptyState as EmptyState6, StatusBadge as StatusBadge7, cn as cn28, formatDateTime as formatDateTime8 } from "@quanticjs/react-ui";
|
|
3462
3691
|
import { useApiQuery as useApiQuery22 } from "@quanticjs/react-query";
|
|
3463
|
-
import { Fragment as Fragment7, jsx as
|
|
3692
|
+
import { Fragment as Fragment7, jsx as jsx31, jsxs as jsxs28 } from "react/jsx-runtime";
|
|
3464
3693
|
var LIMIT6 = 20;
|
|
3465
3694
|
var EMPTY_FILTERS = {
|
|
3466
3695
|
channel: "",
|
|
@@ -3513,178 +3742,90 @@ function DeliveryLogExplorer({ basePath = "/api", className }) {
|
|
|
3513
3742
|
});
|
|
3514
3743
|
};
|
|
3515
3744
|
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" })
|
|
3745
|
+
const rows = data?.items ?? [];
|
|
3746
|
+
const totalPages = data?.totalPages ?? 1;
|
|
3747
|
+
return /* @__PURE__ */ jsxs28("section", { "aria-label": "Delivery log explorer", className: cn28("flex flex-col gap-4", className), children: [
|
|
3748
|
+
/* @__PURE__ */ jsx31(Card6, { children: /* @__PURE__ */ jsxs28("form", { onSubmit: onApply, className: "flex flex-wrap items-end gap-3 p-4", noValidate: true, children: [
|
|
3749
|
+
/* @__PURE__ */ jsxs28("label", { htmlFor: "dle-channel", className: "flex flex-col gap-1 text-sm", children: [
|
|
3750
|
+
/* @__PURE__ */ jsx31("span", { className: "font-medium text-foreground", children: "Channel" }),
|
|
3751
|
+
/* @__PURE__ */ jsxs28(
|
|
3752
|
+
"select",
|
|
3753
|
+
{
|
|
3754
|
+
id: "dle-channel",
|
|
3755
|
+
value: draft.channel,
|
|
3756
|
+
onChange: (e) => setField("channel", e.target.value),
|
|
3757
|
+
className: FIELD_CLASS,
|
|
3758
|
+
children: [
|
|
3759
|
+
/* @__PURE__ */ jsx31("option", { value: "", children: "All" }),
|
|
3760
|
+
/* @__PURE__ */ jsx31("option", { value: "email", children: "Email" }),
|
|
3761
|
+
/* @__PURE__ */ jsx31("option", { value: "sms", children: "SMS" })
|
|
3762
|
+
]
|
|
3763
|
+
}
|
|
3764
|
+
)
|
|
3765
|
+
] }),
|
|
3766
|
+
/* @__PURE__ */ jsxs28("label", { htmlFor: "dle-status", className: "flex flex-col gap-1 text-sm", children: [
|
|
3767
|
+
/* @__PURE__ */ jsx31("span", { className: "font-medium text-foreground", children: "Status" }),
|
|
3768
|
+
/* @__PURE__ */ jsx31("input", { id: "dle-status", type: "text", value: draft.status, onChange: (e) => setField("status", e.target.value), className: FIELD_CLASS })
|
|
3769
|
+
] }),
|
|
3770
|
+
/* @__PURE__ */ jsxs28("label", { htmlFor: "dle-recipient", className: "flex flex-col gap-1 text-sm", children: [
|
|
3771
|
+
/* @__PURE__ */ jsx31("span", { className: "font-medium text-foreground", children: "Recipient" }),
|
|
3772
|
+
/* @__PURE__ */ jsx31("input", { id: "dle-recipient", type: "text", value: draft.recipient, onChange: (e) => setField("recipient", e.target.value), className: FIELD_CLASS })
|
|
3773
|
+
] }),
|
|
3774
|
+
/* @__PURE__ */ jsxs28("label", { htmlFor: "dle-user", className: "flex flex-col gap-1 text-sm", children: [
|
|
3775
|
+
/* @__PURE__ */ jsx31("span", { className: "font-medium text-foreground", children: "User ID" }),
|
|
3776
|
+
/* @__PURE__ */ jsx31("input", { id: "dle-user", type: "text", value: draft.userId, onChange: (e) => setField("userId", e.target.value), className: FIELD_CLASS })
|
|
3777
|
+
] }),
|
|
3778
|
+
/* @__PURE__ */ jsxs28("label", { htmlFor: "dle-from", className: "flex flex-col gap-1 text-sm", children: [
|
|
3779
|
+
/* @__PURE__ */ jsx31("span", { className: "font-medium text-foreground", children: "From" }),
|
|
3780
|
+
/* @__PURE__ */ jsx31("input", { id: "dle-from", type: "date", value: draft.from, onChange: (e) => setField("from", e.target.value), className: FIELD_CLASS })
|
|
3781
|
+
] }),
|
|
3782
|
+
/* @__PURE__ */ jsxs28("label", { htmlFor: "dle-to", className: "flex flex-col gap-1 text-sm", children: [
|
|
3783
|
+
/* @__PURE__ */ jsx31("span", { className: "font-medium text-foreground", children: "To" }),
|
|
3784
|
+
/* @__PURE__ */ jsx31("input", { id: "dle-to", type: "date", value: draft.to, onChange: (e) => setField("to", e.target.value), className: FIELD_CLASS })
|
|
3785
|
+
] }),
|
|
3786
|
+
/* @__PURE__ */ jsx31(Button7, { type: "submit", className: "ms-auto", children: "Apply" })
|
|
3787
|
+
] }) }),
|
|
3788
|
+
/* @__PURE__ */ jsxs28(Card6, { children: [
|
|
3789
|
+
/* @__PURE__ */ jsx31(PanelHeader, { title: "Attempts", subtitle: !isLoading && !isError ? `${data?.total ?? rows.length} matching entries` : void 0 }),
|
|
3790
|
+
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: [
|
|
3791
|
+
/* @__PURE__ */ jsxs28("table", { className: "w-full text-sm", children: [
|
|
3792
|
+
/* @__PURE__ */ jsx31("thead", { children: /* @__PURE__ */ jsxs28("tr", { className: "border-b border-border text-start text-muted-foreground", children: [
|
|
3793
|
+
/* @__PURE__ */ jsx31("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Channel" }),
|
|
3794
|
+
/* @__PURE__ */ jsx31("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Recipient" }),
|
|
3795
|
+
/* @__PURE__ */ jsx31("th", { scope: "col", className: "px-4 py-2 font-medium", children: "User" }),
|
|
3796
|
+
/* @__PURE__ */ jsx31("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Status" }),
|
|
3797
|
+
/* @__PURE__ */ jsx31("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Provider" }),
|
|
3798
|
+
/* @__PURE__ */ jsx31("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Attempts" }),
|
|
3799
|
+
/* @__PURE__ */ jsx31("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Created" })
|
|
3643
3800
|
] }) }),
|
|
3644
|
-
/* @__PURE__ */
|
|
3645
|
-
/* @__PURE__ */
|
|
3646
|
-
/* @__PURE__ */
|
|
3647
|
-
/* @__PURE__ */
|
|
3648
|
-
/* @__PURE__ */
|
|
3649
|
-
/* @__PURE__ */
|
|
3650
|
-
/* @__PURE__ */
|
|
3651
|
-
/* @__PURE__ */
|
|
3801
|
+
/* @__PURE__ */ jsx31("tbody", { children: rows.map((row) => /* @__PURE__ */ jsxs28("tr", { className: "border-b border-border last:border-0 hover:bg-muted/40", children: [
|
|
3802
|
+
/* @__PURE__ */ jsx31("td", { className: "px-4 py-3", children: /* @__PURE__ */ jsx31(StatusBadge7, { variant: channelVariant(row.channel), appearance: "dot", children: row.channel }) }),
|
|
3803
|
+
/* @__PURE__ */ jsx31("td", { className: "px-4 py-3 text-foreground", children: row.recipient ?? "\u2014" }),
|
|
3804
|
+
/* @__PURE__ */ jsx31("td", { className: "px-4 py-3 font-mono text-foreground", children: row.userId }),
|
|
3805
|
+
/* @__PURE__ */ jsx31("td", { className: "px-4 py-3 text-foreground", children: row.status }),
|
|
3806
|
+
/* @__PURE__ */ jsx31("td", { className: "px-4 py-3 text-muted-foreground", children: row.provider ?? "\u2014" }),
|
|
3807
|
+
/* @__PURE__ */ jsx31("td", { className: "px-4 py-3 tabular-nums text-muted-foreground", children: row.attempts }),
|
|
3808
|
+
/* @__PURE__ */ jsx31("td", { className: "px-4 py-3 text-muted-foreground", children: formatDateTime8(row.createdAt) })
|
|
3652
3809
|
] }, row.id)) })
|
|
3653
3810
|
] }),
|
|
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 ",
|
|
3811
|
+
/* @__PURE__ */ jsx31(
|
|
3812
|
+
Pager,
|
|
3813
|
+
{
|
|
3814
|
+
label: "Delivery log pagination",
|
|
3667
3815
|
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
|
|
3816
|
+
totalPages,
|
|
3817
|
+
onPrev: () => setPage((p) => Math.max(1, p - 1)),
|
|
3818
|
+
onNext: () => setPage((p) => Math.min(totalPages, p + 1))
|
|
3819
|
+
}
|
|
3820
|
+
)
|
|
3821
|
+
] })
|
|
3822
|
+
] })
|
|
3823
|
+
] });
|
|
3824
|
+
}
|
|
3825
|
+
function InboxIcon() {
|
|
3826
|
+
return /* @__PURE__ */ jsxs28("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
3827
|
+
/* @__PURE__ */ jsx31("path", { d: "M22 12h-6l-2 3h-4l-2-3H2" }),
|
|
3828
|
+
/* @__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
3829
|
] });
|
|
3689
3830
|
}
|
|
3690
3831
|
|
|
@@ -3692,7 +3833,7 @@ function DeliveryLogExplorer({ basePath = "/api", className }) {
|
|
|
3692
3833
|
import { useEffect as useEffect6, useState as useState16 } from "react";
|
|
3693
3834
|
import { cn as cn29, useToast as useToast13 } from "@quanticjs/react-ui";
|
|
3694
3835
|
import { useApiMutation as useApiMutation14, useApiQuery as useApiQuery23 } from "@quanticjs/react-query";
|
|
3695
|
-
import { jsx as
|
|
3836
|
+
import { jsx as jsx32, jsxs as jsxs29 } from "react/jsx-runtime";
|
|
3696
3837
|
var DEFAULTS = {
|
|
3697
3838
|
enabled: false,
|
|
3698
3839
|
start: "22:00",
|
|
@@ -3733,23 +3874,23 @@ function QuietHoursForm({ basePath = "/api", className }) {
|
|
|
3733
3874
|
save.mutate(form);
|
|
3734
3875
|
};
|
|
3735
3876
|
if (isLoading) {
|
|
3736
|
-
return /* @__PURE__ */
|
|
3877
|
+
return /* @__PURE__ */ jsxs29(
|
|
3737
3878
|
"div",
|
|
3738
3879
|
{
|
|
3739
3880
|
role: "status",
|
|
3740
3881
|
"aria-label": "Loading quiet hours",
|
|
3741
3882
|
className: cn29("flex flex-col gap-2 p-4", className),
|
|
3742
3883
|
children: [
|
|
3743
|
-
/* @__PURE__ */
|
|
3744
|
-
[0, 1, 2].map((i) => /* @__PURE__ */
|
|
3884
|
+
/* @__PURE__ */ jsx32("span", { className: "sr-only", children: "Loading quiet hours" }),
|
|
3885
|
+
[0, 1, 2].map((i) => /* @__PURE__ */ jsx32("div", { "aria-hidden": "true", className: "h-10 animate-pulse rounded bg-muted" }, i))
|
|
3745
3886
|
]
|
|
3746
3887
|
}
|
|
3747
3888
|
);
|
|
3748
3889
|
}
|
|
3749
3890
|
if (isError) {
|
|
3750
|
-
return /* @__PURE__ */
|
|
3751
|
-
/* @__PURE__ */
|
|
3752
|
-
/* @__PURE__ */
|
|
3891
|
+
return /* @__PURE__ */ jsxs29("div", { className: cn29("flex flex-col items-start gap-3 p-4", className), children: [
|
|
3892
|
+
/* @__PURE__ */ jsx32("p", { className: "text-sm text-foreground", children: "Failed to load quiet hours" }),
|
|
3893
|
+
/* @__PURE__ */ jsx32(
|
|
3753
3894
|
"button",
|
|
3754
3895
|
{
|
|
3755
3896
|
type: "button",
|
|
@@ -3760,10 +3901,10 @@ function QuietHoursForm({ basePath = "/api", className }) {
|
|
|
3760
3901
|
)
|
|
3761
3902
|
] });
|
|
3762
3903
|
}
|
|
3763
|
-
return /* @__PURE__ */
|
|
3764
|
-
/* @__PURE__ */
|
|
3765
|
-
/* @__PURE__ */
|
|
3766
|
-
/* @__PURE__ */
|
|
3904
|
+
return /* @__PURE__ */ jsxs29("form", { onSubmit, className: cn29("flex flex-col gap-4", className), noValidate: true, children: [
|
|
3905
|
+
/* @__PURE__ */ jsx32("h2", { className: "text-sm font-semibold text-foreground", children: "Quiet hours" }),
|
|
3906
|
+
/* @__PURE__ */ jsxs29("label", { className: "flex items-center gap-2 text-sm text-foreground", children: [
|
|
3907
|
+
/* @__PURE__ */ jsx32(
|
|
3767
3908
|
"input",
|
|
3768
3909
|
{
|
|
3769
3910
|
type: "checkbox",
|
|
@@ -3774,10 +3915,10 @@ function QuietHoursForm({ basePath = "/api", className }) {
|
|
|
3774
3915
|
),
|
|
3775
3916
|
"Enable quiet hours"
|
|
3776
3917
|
] }),
|
|
3777
|
-
/* @__PURE__ */
|
|
3778
|
-
/* @__PURE__ */
|
|
3779
|
-
/* @__PURE__ */
|
|
3780
|
-
/* @__PURE__ */
|
|
3918
|
+
/* @__PURE__ */ jsxs29("div", { className: "flex flex-wrap gap-4", children: [
|
|
3919
|
+
/* @__PURE__ */ jsxs29("div", { className: "flex flex-col gap-1", children: [
|
|
3920
|
+
/* @__PURE__ */ jsx32("label", { htmlFor: "qh-start", className: "text-sm font-medium text-foreground", children: "Start" }),
|
|
3921
|
+
/* @__PURE__ */ jsx32(
|
|
3781
3922
|
"input",
|
|
3782
3923
|
{
|
|
3783
3924
|
id: "qh-start",
|
|
@@ -3788,9 +3929,9 @@ function QuietHoursForm({ basePath = "/api", className }) {
|
|
|
3788
3929
|
}
|
|
3789
3930
|
)
|
|
3790
3931
|
] }),
|
|
3791
|
-
/* @__PURE__ */
|
|
3792
|
-
/* @__PURE__ */
|
|
3793
|
-
/* @__PURE__ */
|
|
3932
|
+
/* @__PURE__ */ jsxs29("div", { className: "flex flex-col gap-1", children: [
|
|
3933
|
+
/* @__PURE__ */ jsx32("label", { htmlFor: "qh-end", className: "text-sm font-medium text-foreground", children: "End" }),
|
|
3934
|
+
/* @__PURE__ */ jsx32(
|
|
3794
3935
|
"input",
|
|
3795
3936
|
{
|
|
3796
3937
|
id: "qh-end",
|
|
@@ -3801,9 +3942,9 @@ function QuietHoursForm({ basePath = "/api", className }) {
|
|
|
3801
3942
|
}
|
|
3802
3943
|
)
|
|
3803
3944
|
] }),
|
|
3804
|
-
/* @__PURE__ */
|
|
3805
|
-
/* @__PURE__ */
|
|
3806
|
-
/* @__PURE__ */
|
|
3945
|
+
/* @__PURE__ */ jsxs29("div", { className: "flex flex-col gap-1", children: [
|
|
3946
|
+
/* @__PURE__ */ jsx32("label", { htmlFor: "qh-tz", className: "text-sm font-medium text-foreground", children: "Timezone" }),
|
|
3947
|
+
/* @__PURE__ */ jsx32(
|
|
3807
3948
|
"input",
|
|
3808
3949
|
{
|
|
3809
3950
|
id: "qh-tz",
|
|
@@ -3815,7 +3956,7 @@ function QuietHoursForm({ basePath = "/api", className }) {
|
|
|
3815
3956
|
)
|
|
3816
3957
|
] })
|
|
3817
3958
|
] }),
|
|
3818
|
-
/* @__PURE__ */
|
|
3959
|
+
/* @__PURE__ */ jsx32("div", { children: /* @__PURE__ */ jsx32(
|
|
3819
3960
|
"button",
|
|
3820
3961
|
{
|
|
3821
3962
|
type: "submit",
|
|
@@ -3831,7 +3972,7 @@ function QuietHoursForm({ basePath = "/api", className }) {
|
|
|
3831
3972
|
import { useEffect as useEffect7, useState as useState17 } from "react";
|
|
3832
3973
|
import { cn as cn30, useToast as useToast14 } from "@quanticjs/react-ui";
|
|
3833
3974
|
import { useApiMutation as useApiMutation15, useApiQuery as useApiQuery24 } from "@quanticjs/react-query";
|
|
3834
|
-
import { jsx as
|
|
3975
|
+
import { jsx as jsx33, jsxs as jsxs30 } from "react/jsx-runtime";
|
|
3835
3976
|
function normalize6(raw) {
|
|
3836
3977
|
const list = Array.isArray(raw) ? raw : Array.isArray(raw?.caps) ? raw.caps : [];
|
|
3837
3978
|
return list.map((entry) => {
|
|
@@ -3876,23 +4017,23 @@ function FrequencyCapTable({ basePath = "/api", className }) {
|
|
|
3876
4017
|
setNewMax(0);
|
|
3877
4018
|
};
|
|
3878
4019
|
if (isLoading) {
|
|
3879
|
-
return /* @__PURE__ */
|
|
4020
|
+
return /* @__PURE__ */ jsxs30(
|
|
3880
4021
|
"div",
|
|
3881
4022
|
{
|
|
3882
4023
|
role: "status",
|
|
3883
4024
|
"aria-label": "Loading frequency caps",
|
|
3884
4025
|
className: cn30("flex flex-col gap-2 p-4", className),
|
|
3885
4026
|
children: [
|
|
3886
|
-
/* @__PURE__ */
|
|
3887
|
-
[0, 1, 2].map((i) => /* @__PURE__ */
|
|
4027
|
+
/* @__PURE__ */ jsx33("span", { className: "sr-only", children: "Loading frequency caps" }),
|
|
4028
|
+
[0, 1, 2].map((i) => /* @__PURE__ */ jsx33("div", { "aria-hidden": "true", className: "h-10 animate-pulse rounded bg-muted" }, i))
|
|
3888
4029
|
]
|
|
3889
4030
|
}
|
|
3890
4031
|
);
|
|
3891
4032
|
}
|
|
3892
4033
|
if (isError) {
|
|
3893
|
-
return /* @__PURE__ */
|
|
3894
|
-
/* @__PURE__ */
|
|
3895
|
-
/* @__PURE__ */
|
|
4034
|
+
return /* @__PURE__ */ jsxs30("div", { className: cn30("flex flex-col items-start gap-3 p-4", className), children: [
|
|
4035
|
+
/* @__PURE__ */ jsx33("p", { className: "text-sm text-foreground", children: "Failed to load frequency caps" }),
|
|
4036
|
+
/* @__PURE__ */ jsx33(
|
|
3896
4037
|
"button",
|
|
3897
4038
|
{
|
|
3898
4039
|
type: "button",
|
|
@@ -3903,24 +4044,24 @@ function FrequencyCapTable({ basePath = "/api", className }) {
|
|
|
3903
4044
|
)
|
|
3904
4045
|
] });
|
|
3905
4046
|
}
|
|
3906
|
-
return /* @__PURE__ */
|
|
3907
|
-
/* @__PURE__ */
|
|
3908
|
-
/* @__PURE__ */
|
|
3909
|
-
/* @__PURE__ */
|
|
3910
|
-
/* @__PURE__ */
|
|
3911
|
-
/* @__PURE__ */
|
|
3912
|
-
/* @__PURE__ */
|
|
4047
|
+
return /* @__PURE__ */ jsxs30("section", { "aria-label": "Frequency caps", className: cn30("flex flex-col gap-4", className), children: [
|
|
4048
|
+
/* @__PURE__ */ jsx33("h2", { className: "text-sm font-semibold text-foreground", children: "Frequency caps" }),
|
|
4049
|
+
/* @__PURE__ */ jsxs30("table", { className: "w-full text-sm", children: [
|
|
4050
|
+
/* @__PURE__ */ jsx33("thead", { children: /* @__PURE__ */ jsxs30("tr", { className: "border-b border-border text-start text-muted-foreground", children: [
|
|
4051
|
+
/* @__PURE__ */ jsx33("th", { scope: "col", className: "py-2 pe-4 font-medium", children: "Type" }),
|
|
4052
|
+
/* @__PURE__ */ jsx33("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Max per day" }),
|
|
4053
|
+
/* @__PURE__ */ jsx33("th", { scope: "col", className: "px-4 py-2 font-medium", children: /* @__PURE__ */ jsx33("span", { className: "sr-only", children: "Actions" }) })
|
|
3913
4054
|
] }) }),
|
|
3914
|
-
/* @__PURE__ */
|
|
4055
|
+
/* @__PURE__ */ jsx33("tbody", { children: caps.map((cap, index) => {
|
|
3915
4056
|
const inputId = `cap-${index}`;
|
|
3916
|
-
return /* @__PURE__ */
|
|
3917
|
-
/* @__PURE__ */
|
|
3918
|
-
/* @__PURE__ */
|
|
3919
|
-
/* @__PURE__ */
|
|
4057
|
+
return /* @__PURE__ */ jsxs30("tr", { className: "border-b border-border", children: [
|
|
4058
|
+
/* @__PURE__ */ jsx33("td", { className: "py-3 pe-4 text-foreground", children: cap.type }),
|
|
4059
|
+
/* @__PURE__ */ jsxs30("td", { className: "px-4 py-3", children: [
|
|
4060
|
+
/* @__PURE__ */ jsxs30("label", { htmlFor: inputId, className: "sr-only", children: [
|
|
3920
4061
|
"Max per day for ",
|
|
3921
4062
|
cap.type
|
|
3922
4063
|
] }),
|
|
3923
|
-
/* @__PURE__ */
|
|
4064
|
+
/* @__PURE__ */ jsx33(
|
|
3924
4065
|
"input",
|
|
3925
4066
|
{
|
|
3926
4067
|
id: inputId,
|
|
@@ -3932,7 +4073,7 @@ function FrequencyCapTable({ basePath = "/api", className }) {
|
|
|
3932
4073
|
}
|
|
3933
4074
|
)
|
|
3934
4075
|
] }),
|
|
3935
|
-
/* @__PURE__ */
|
|
4076
|
+
/* @__PURE__ */ jsx33("td", { className: "px-4 py-3", children: /* @__PURE__ */ jsx33(
|
|
3936
4077
|
"button",
|
|
3937
4078
|
{
|
|
3938
4079
|
type: "button",
|
|
@@ -3944,10 +4085,10 @@ function FrequencyCapTable({ basePath = "/api", className }) {
|
|
|
3944
4085
|
] }, `${cap.type}-${index}`);
|
|
3945
4086
|
}) })
|
|
3946
4087
|
] }),
|
|
3947
|
-
/* @__PURE__ */
|
|
3948
|
-
/* @__PURE__ */
|
|
3949
|
-
/* @__PURE__ */
|
|
3950
|
-
/* @__PURE__ */
|
|
4088
|
+
/* @__PURE__ */ jsxs30("form", { onSubmit: addRow, className: "flex flex-wrap items-end gap-3", noValidate: true, children: [
|
|
4089
|
+
/* @__PURE__ */ jsxs30("div", { className: "flex flex-col gap-1", children: [
|
|
4090
|
+
/* @__PURE__ */ jsx33("label", { htmlFor: "cap-new-type", className: "text-sm font-medium text-foreground", children: "New type" }),
|
|
4091
|
+
/* @__PURE__ */ jsx33(
|
|
3951
4092
|
"input",
|
|
3952
4093
|
{
|
|
3953
4094
|
id: "cap-new-type",
|
|
@@ -3958,9 +4099,9 @@ function FrequencyCapTable({ basePath = "/api", className }) {
|
|
|
3958
4099
|
}
|
|
3959
4100
|
)
|
|
3960
4101
|
] }),
|
|
3961
|
-
/* @__PURE__ */
|
|
3962
|
-
/* @__PURE__ */
|
|
3963
|
-
/* @__PURE__ */
|
|
4102
|
+
/* @__PURE__ */ jsxs30("div", { className: "flex flex-col gap-1", children: [
|
|
4103
|
+
/* @__PURE__ */ jsx33("label", { htmlFor: "cap-new-max", className: "text-sm font-medium text-foreground", children: "Max per day" }),
|
|
4104
|
+
/* @__PURE__ */ jsx33(
|
|
3964
4105
|
"input",
|
|
3965
4106
|
{
|
|
3966
4107
|
id: "cap-new-max",
|
|
@@ -3972,7 +4113,7 @@ function FrequencyCapTable({ basePath = "/api", className }) {
|
|
|
3972
4113
|
}
|
|
3973
4114
|
)
|
|
3974
4115
|
] }),
|
|
3975
|
-
/* @__PURE__ */
|
|
4116
|
+
/* @__PURE__ */ jsx33(
|
|
3976
4117
|
"button",
|
|
3977
4118
|
{
|
|
3978
4119
|
type: "submit",
|
|
@@ -3981,7 +4122,7 @@ function FrequencyCapTable({ basePath = "/api", className }) {
|
|
|
3981
4122
|
}
|
|
3982
4123
|
)
|
|
3983
4124
|
] }),
|
|
3984
|
-
/* @__PURE__ */
|
|
4125
|
+
/* @__PURE__ */ jsx33("div", { children: /* @__PURE__ */ jsx33(
|
|
3985
4126
|
"button",
|
|
3986
4127
|
{
|
|
3987
4128
|
type: "button",
|
|
@@ -3998,7 +4139,7 @@ function FrequencyCapTable({ basePath = "/api", className }) {
|
|
|
3998
4139
|
import { useEffect as useEffect8, useState as useState18 } from "react";
|
|
3999
4140
|
import { cn as cn31, useToast as useToast15 } from "@quanticjs/react-ui";
|
|
4000
4141
|
import { useApiMutation as useApiMutation16, useApiQuery as useApiQuery25 } from "@quanticjs/react-query";
|
|
4001
|
-
import { jsx as
|
|
4142
|
+
import { jsx as jsx34, jsxs as jsxs31 } from "react/jsx-runtime";
|
|
4002
4143
|
function normalize7(raw) {
|
|
4003
4144
|
const obj = raw ?? {};
|
|
4004
4145
|
const toList = (value) => Array.isArray(value) ? value.filter((v) => typeof v === "string") : [];
|
|
@@ -4016,15 +4157,15 @@ function TagEditor({ id, label, values, onAdd, onRemove }) {
|
|
|
4016
4157
|
onAdd(value);
|
|
4017
4158
|
setDraft("");
|
|
4018
4159
|
};
|
|
4019
|
-
return /* @__PURE__ */
|
|
4020
|
-
/* @__PURE__ */
|
|
4021
|
-
/* @__PURE__ */
|
|
4160
|
+
return /* @__PURE__ */ jsxs31("div", { className: "flex flex-col gap-2", children: [
|
|
4161
|
+
/* @__PURE__ */ jsx34("span", { className: "text-sm font-medium text-foreground", children: label }),
|
|
4162
|
+
/* @__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
4163
|
"li",
|
|
4023
4164
|
{
|
|
4024
4165
|
className: "flex items-center gap-1 rounded-md border border-border bg-card px-2 py-1 text-sm text-foreground",
|
|
4025
4166
|
children: [
|
|
4026
4167
|
value,
|
|
4027
|
-
/* @__PURE__ */
|
|
4168
|
+
/* @__PURE__ */ jsx34(
|
|
4028
4169
|
"button",
|
|
4029
4170
|
{
|
|
4030
4171
|
type: "button",
|
|
@@ -4038,13 +4179,13 @@ function TagEditor({ id, label, values, onAdd, onRemove }) {
|
|
|
4038
4179
|
},
|
|
4039
4180
|
value
|
|
4040
4181
|
)) }),
|
|
4041
|
-
/* @__PURE__ */
|
|
4042
|
-
/* @__PURE__ */
|
|
4043
|
-
/* @__PURE__ */
|
|
4182
|
+
/* @__PURE__ */ jsxs31("form", { onSubmit: add, className: "flex items-end gap-2", noValidate: true, children: [
|
|
4183
|
+
/* @__PURE__ */ jsxs31("div", { className: "flex flex-col gap-1", children: [
|
|
4184
|
+
/* @__PURE__ */ jsxs31("label", { htmlFor: id, className: "sr-only", children: [
|
|
4044
4185
|
"Add to ",
|
|
4045
4186
|
label
|
|
4046
4187
|
] }),
|
|
4047
|
-
/* @__PURE__ */
|
|
4188
|
+
/* @__PURE__ */ jsx34(
|
|
4048
4189
|
"input",
|
|
4049
4190
|
{
|
|
4050
4191
|
id,
|
|
@@ -4055,7 +4196,7 @@ function TagEditor({ id, label, values, onAdd, onRemove }) {
|
|
|
4055
4196
|
}
|
|
4056
4197
|
)
|
|
4057
4198
|
] }),
|
|
4058
|
-
/* @__PURE__ */
|
|
4199
|
+
/* @__PURE__ */ jsx34(
|
|
4059
4200
|
"button",
|
|
4060
4201
|
{
|
|
4061
4202
|
type: "submit",
|
|
@@ -4120,23 +4261,23 @@ function TenantConfigForm({ basePath = "/api", className }) {
|
|
|
4120
4261
|
save.mutate(config);
|
|
4121
4262
|
};
|
|
4122
4263
|
if (isLoading) {
|
|
4123
|
-
return /* @__PURE__ */
|
|
4264
|
+
return /* @__PURE__ */ jsxs31(
|
|
4124
4265
|
"div",
|
|
4125
4266
|
{
|
|
4126
4267
|
role: "status",
|
|
4127
4268
|
"aria-label": "Loading tenant configuration",
|
|
4128
4269
|
className: cn31("flex flex-col gap-2 p-4", className),
|
|
4129
4270
|
children: [
|
|
4130
|
-
/* @__PURE__ */
|
|
4131
|
-
[0, 1, 2].map((i) => /* @__PURE__ */
|
|
4271
|
+
/* @__PURE__ */ jsx34("span", { className: "sr-only", children: "Loading tenant configuration" }),
|
|
4272
|
+
[0, 1, 2].map((i) => /* @__PURE__ */ jsx34("div", { "aria-hidden": "true", className: "h-10 animate-pulse rounded bg-muted" }, i))
|
|
4132
4273
|
]
|
|
4133
4274
|
}
|
|
4134
4275
|
);
|
|
4135
4276
|
}
|
|
4136
4277
|
if (isError) {
|
|
4137
|
-
return /* @__PURE__ */
|
|
4138
|
-
/* @__PURE__ */
|
|
4139
|
-
/* @__PURE__ */
|
|
4278
|
+
return /* @__PURE__ */ jsxs31("div", { className: cn31("flex flex-col items-start gap-3 p-4", className), children: [
|
|
4279
|
+
/* @__PURE__ */ jsx34("p", { className: "text-sm text-foreground", children: "Failed to load tenant configuration" }),
|
|
4280
|
+
/* @__PURE__ */ jsx34(
|
|
4140
4281
|
"button",
|
|
4141
4282
|
{
|
|
4142
4283
|
type: "button",
|
|
@@ -4148,7 +4289,7 @@ function TenantConfigForm({ basePath = "/api", className }) {
|
|
|
4148
4289
|
] });
|
|
4149
4290
|
}
|
|
4150
4291
|
const errorId = "tenant-config-subset-error";
|
|
4151
|
-
return /* @__PURE__ */
|
|
4292
|
+
return /* @__PURE__ */ jsxs31(
|
|
4152
4293
|
"form",
|
|
4153
4294
|
{
|
|
4154
4295
|
onSubmit,
|
|
@@ -4157,8 +4298,8 @@ function TenantConfigForm({ basePath = "/api", className }) {
|
|
|
4157
4298
|
"aria-invalid": subsetError ? "true" : void 0,
|
|
4158
4299
|
"aria-describedby": subsetError ? errorId : void 0,
|
|
4159
4300
|
children: [
|
|
4160
|
-
/* @__PURE__ */
|
|
4161
|
-
/* @__PURE__ */
|
|
4301
|
+
/* @__PURE__ */ jsx34("h2", { className: "text-sm font-semibold text-foreground", children: "Notification configuration" }),
|
|
4302
|
+
/* @__PURE__ */ jsx34(
|
|
4162
4303
|
TagEditor,
|
|
4163
4304
|
{
|
|
4164
4305
|
id: "tc-notification-types",
|
|
@@ -4168,7 +4309,7 @@ function TenantConfigForm({ basePath = "/api", className }) {
|
|
|
4168
4309
|
onRemove: removeType
|
|
4169
4310
|
}
|
|
4170
4311
|
),
|
|
4171
|
-
/* @__PURE__ */
|
|
4312
|
+
/* @__PURE__ */ jsx34(
|
|
4172
4313
|
TagEditor,
|
|
4173
4314
|
{
|
|
4174
4315
|
id: "tc-immediate-email-types",
|
|
@@ -4178,8 +4319,8 @@ function TenantConfigForm({ basePath = "/api", className }) {
|
|
|
4178
4319
|
onRemove: removeImmediate
|
|
4179
4320
|
}
|
|
4180
4321
|
),
|
|
4181
|
-
subsetError && /* @__PURE__ */
|
|
4182
|
-
/* @__PURE__ */
|
|
4322
|
+
subsetError && /* @__PURE__ */ jsx34("p", { id: errorId, className: "text-xs text-destructive", children: subsetError }),
|
|
4323
|
+
/* @__PURE__ */ jsx34("div", { children: /* @__PURE__ */ jsx34(
|
|
4183
4324
|
"button",
|
|
4184
4325
|
{
|
|
4185
4326
|
type: "submit",
|
|
@@ -4197,7 +4338,7 @@ function TenantConfigForm({ basePath = "/api", className }) {
|
|
|
4197
4338
|
import { useEffect as useEffect9, useState as useState19 } from "react";
|
|
4198
4339
|
import { cn as cn32, useToast as useToast16 } from "@quanticjs/react-ui";
|
|
4199
4340
|
import { useApiMutation as useApiMutation17, useApiQuery as useApiQuery26 } from "@quanticjs/react-query";
|
|
4200
|
-
import { jsx as
|
|
4341
|
+
import { jsx as jsx35, jsxs as jsxs32 } from "react/jsx-runtime";
|
|
4201
4342
|
function normalize8(raw) {
|
|
4202
4343
|
const obj = raw ?? {};
|
|
4203
4344
|
const bool = (...keys) => {
|
|
@@ -4242,23 +4383,23 @@ function TrackingConfigForm({ basePath = "/api", className }) {
|
|
|
4242
4383
|
save.mutate(form);
|
|
4243
4384
|
};
|
|
4244
4385
|
if (isLoading) {
|
|
4245
|
-
return /* @__PURE__ */
|
|
4386
|
+
return /* @__PURE__ */ jsxs32(
|
|
4246
4387
|
"div",
|
|
4247
4388
|
{
|
|
4248
4389
|
role: "status",
|
|
4249
4390
|
"aria-label": "Loading tracking configuration",
|
|
4250
4391
|
className: cn32("flex flex-col gap-2 p-4", className),
|
|
4251
4392
|
children: [
|
|
4252
|
-
/* @__PURE__ */
|
|
4253
|
-
[0, 1].map((i) => /* @__PURE__ */
|
|
4393
|
+
/* @__PURE__ */ jsx35("span", { className: "sr-only", children: "Loading tracking configuration" }),
|
|
4394
|
+
[0, 1].map((i) => /* @__PURE__ */ jsx35("div", { "aria-hidden": "true", className: "h-10 animate-pulse rounded bg-muted" }, i))
|
|
4254
4395
|
]
|
|
4255
4396
|
}
|
|
4256
4397
|
);
|
|
4257
4398
|
}
|
|
4258
4399
|
if (isError) {
|
|
4259
|
-
return /* @__PURE__ */
|
|
4260
|
-
/* @__PURE__ */
|
|
4261
|
-
/* @__PURE__ */
|
|
4400
|
+
return /* @__PURE__ */ jsxs32("div", { className: cn32("flex flex-col items-start gap-3 p-4", className), children: [
|
|
4401
|
+
/* @__PURE__ */ jsx35("p", { className: "text-sm text-foreground", children: "Failed to load tracking configuration" }),
|
|
4402
|
+
/* @__PURE__ */ jsx35(
|
|
4262
4403
|
"button",
|
|
4263
4404
|
{
|
|
4264
4405
|
type: "button",
|
|
@@ -4269,10 +4410,10 @@ function TrackingConfigForm({ basePath = "/api", className }) {
|
|
|
4269
4410
|
)
|
|
4270
4411
|
] });
|
|
4271
4412
|
}
|
|
4272
|
-
return /* @__PURE__ */
|
|
4273
|
-
/* @__PURE__ */
|
|
4274
|
-
/* @__PURE__ */
|
|
4275
|
-
/* @__PURE__ */
|
|
4413
|
+
return /* @__PURE__ */ jsxs32("form", { onSubmit, className: cn32("flex flex-col gap-4", className), noValidate: true, children: [
|
|
4414
|
+
/* @__PURE__ */ jsx35("h2", { className: "text-sm font-semibold text-foreground", children: "Tracking configuration" }),
|
|
4415
|
+
/* @__PURE__ */ jsxs32("label", { className: "flex items-center gap-2 text-sm text-foreground", children: [
|
|
4416
|
+
/* @__PURE__ */ jsx35(
|
|
4276
4417
|
"input",
|
|
4277
4418
|
{
|
|
4278
4419
|
type: "checkbox",
|
|
@@ -4283,8 +4424,8 @@ function TrackingConfigForm({ basePath = "/api", className }) {
|
|
|
4283
4424
|
),
|
|
4284
4425
|
"Open tracking"
|
|
4285
4426
|
] }),
|
|
4286
|
-
/* @__PURE__ */
|
|
4287
|
-
/* @__PURE__ */
|
|
4427
|
+
/* @__PURE__ */ jsxs32("label", { className: "flex items-center gap-2 text-sm text-foreground", children: [
|
|
4428
|
+
/* @__PURE__ */ jsx35(
|
|
4288
4429
|
"input",
|
|
4289
4430
|
{
|
|
4290
4431
|
type: "checkbox",
|
|
@@ -4295,7 +4436,7 @@ function TrackingConfigForm({ basePath = "/api", className }) {
|
|
|
4295
4436
|
),
|
|
4296
4437
|
"Click tracking"
|
|
4297
4438
|
] }),
|
|
4298
|
-
/* @__PURE__ */
|
|
4439
|
+
/* @__PURE__ */ jsx35("div", { children: /* @__PURE__ */ jsx35(
|
|
4299
4440
|
"button",
|
|
4300
4441
|
{
|
|
4301
4442
|
type: "submit",
|
|
@@ -4309,9 +4450,9 @@ function TrackingConfigForm({ basePath = "/api", className }) {
|
|
|
4309
4450
|
|
|
4310
4451
|
// src/api-key-manager.tsx
|
|
4311
4452
|
import { useState as useState20 } from "react";
|
|
4312
|
-
import {
|
|
4453
|
+
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
4454
|
import { useApiMutation as useApiMutation18, useApiQuery as useApiQuery27 } from "@quanticjs/react-query";
|
|
4314
|
-
import { jsx as
|
|
4455
|
+
import { jsx as jsx36, jsxs as jsxs33 } from "react/jsx-runtime";
|
|
4315
4456
|
function normalize9(raw) {
|
|
4316
4457
|
const list = Array.isArray(raw) ? raw : Array.isArray(raw?.items) ? raw.items : [];
|
|
4317
4458
|
return list;
|
|
@@ -4369,102 +4510,69 @@ function ApiKeyManager({ basePath = "/api", className }) {
|
|
|
4369
4510
|
revoke.mutate(id);
|
|
4370
4511
|
}
|
|
4371
4512
|
};
|
|
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" }) })
|
|
4513
|
+
const rows = normalize9(data);
|
|
4514
|
+
return /* @__PURE__ */ jsxs33("section", { "aria-label": "API key management", className: cn33("flex flex-col gap-4", className), children: [
|
|
4515
|
+
/* @__PURE__ */ jsx36(Card7, { children: /* @__PURE__ */ jsxs33("form", { onSubmit: onCreate, className: "flex flex-wrap items-end gap-3 p-4", noValidate: true, children: [
|
|
4516
|
+
/* @__PURE__ */ jsxs33("label", { className: "flex flex-1 flex-col gap-1 text-sm", children: [
|
|
4517
|
+
/* @__PURE__ */ jsx36("span", { className: "font-medium text-foreground", children: "New key name" }),
|
|
4518
|
+
/* @__PURE__ */ jsx36("input", { type: "text", value: name, onChange: (e) => setName(e.target.value), className: FIELD_CLASS })
|
|
4519
|
+
] }),
|
|
4520
|
+
/* @__PURE__ */ jsxs33("label", { className: "flex flex-1 flex-col gap-1 text-sm", children: [
|
|
4521
|
+
/* @__PURE__ */ jsx36("span", { className: "font-medium text-foreground", children: "Application (optional)" }),
|
|
4522
|
+
/* @__PURE__ */ jsx36(
|
|
4523
|
+
"input",
|
|
4524
|
+
{
|
|
4525
|
+
type: "text",
|
|
4526
|
+
value: applicationKey,
|
|
4527
|
+
onChange: (e) => setApplicationKey(e.target.value),
|
|
4528
|
+
placeholder: "delivery-hub",
|
|
4529
|
+
className: FIELD_CLASS
|
|
4530
|
+
}
|
|
4531
|
+
)
|
|
4532
|
+
] }),
|
|
4533
|
+
/* @__PURE__ */ jsx36(Button8, { type: "submit", disabled: create.isPending, children: create.isPending ? "Creating\u2026" : "Create key" })
|
|
4534
|
+
] }) }),
|
|
4535
|
+
/* @__PURE__ */ jsxs33(Card7, { children: [
|
|
4536
|
+
/* @__PURE__ */ jsx36(PanelHeader, { title: "Keys", subtitle: !isLoading && !isError ? `${rows.length} keys` : void 0 }),
|
|
4537
|
+
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: [
|
|
4538
|
+
/* @__PURE__ */ jsx36("thead", { children: /* @__PURE__ */ jsxs33("tr", { className: "border-b border-border text-start text-muted-foreground", children: [
|
|
4539
|
+
/* @__PURE__ */ jsx36("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Name" }),
|
|
4540
|
+
/* @__PURE__ */ jsx36("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Prefix" }),
|
|
4541
|
+
/* @__PURE__ */ jsx36("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Application" }),
|
|
4542
|
+
/* @__PURE__ */ jsx36("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Status" }),
|
|
4543
|
+
/* @__PURE__ */ jsx36("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Created" }),
|
|
4544
|
+
/* @__PURE__ */ jsx36("th", { scope: "col", className: "px-4 py-2 font-medium", children: "Last used" }),
|
|
4545
|
+
/* @__PURE__ */ jsx36("th", { scope: "col", className: "px-4 py-2 font-medium", children: /* @__PURE__ */ jsx36("span", { className: "sr-only", children: "Actions" }) })
|
|
4443
4546
|
] }) }),
|
|
4444
|
-
/* @__PURE__ */
|
|
4445
|
-
/* @__PURE__ */
|
|
4446
|
-
/* @__PURE__ */
|
|
4447
|
-
/* @__PURE__ */
|
|
4448
|
-
/* @__PURE__ */
|
|
4449
|
-
/* @__PURE__ */
|
|
4450
|
-
/* @__PURE__ */
|
|
4451
|
-
/* @__PURE__ */
|
|
4452
|
-
|
|
4547
|
+
/* @__PURE__ */ jsx36("tbody", { children: rows.map((row) => /* @__PURE__ */ jsxs33("tr", { className: "border-b border-border last:border-0 hover:bg-muted/40", children: [
|
|
4548
|
+
/* @__PURE__ */ jsx36("td", { className: "px-4 py-3 text-foreground", children: row.name }),
|
|
4549
|
+
/* @__PURE__ */ jsx36("td", { className: "px-4 py-3 font-mono text-muted-foreground", children: row.prefix ?? "\u2014" }),
|
|
4550
|
+
/* @__PURE__ */ jsx36("td", { className: "px-4 py-3 font-mono text-muted-foreground", children: row.applicationKey ?? "\u2014" }),
|
|
4551
|
+
/* @__PURE__ */ jsx36("td", { className: "px-4 py-3", children: /* @__PURE__ */ jsx36(StatusBadge8, { variant: row.revoked ? "destructive" : "success", children: row.revoked ? "Revoked" : "Active" }) }),
|
|
4552
|
+
/* @__PURE__ */ jsx36("td", { className: "px-4 py-3 text-muted-foreground", children: formatDateTime9(row.createdAt) }),
|
|
4553
|
+
/* @__PURE__ */ jsx36("td", { className: "px-4 py-3 text-muted-foreground", children: row.lastUsedAt ? formatDateTime9(row.lastUsedAt) : "\u2014" }),
|
|
4554
|
+
/* @__PURE__ */ jsx36("td", { className: "px-4 py-3 text-end", children: /* @__PURE__ */ jsx36(
|
|
4555
|
+
Button8,
|
|
4453
4556
|
{
|
|
4454
4557
|
type: "button",
|
|
4558
|
+
variant: "ghost",
|
|
4559
|
+
size: "sm",
|
|
4560
|
+
className: "text-destructive",
|
|
4455
4561
|
disabled: revoke.isPending || row.revoked,
|
|
4456
4562
|
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
4563
|
children: "Revoke"
|
|
4459
4564
|
}
|
|
4460
4565
|
) })
|
|
4461
4566
|
] }, row.id)) })
|
|
4462
|
-
] })
|
|
4463
|
-
}
|
|
4464
|
-
}
|
|
4465
|
-
|
|
4466
|
-
|
|
4467
|
-
|
|
4567
|
+
] })
|
|
4568
|
+
] })
|
|
4569
|
+
] });
|
|
4570
|
+
}
|
|
4571
|
+
function KeyIcon() {
|
|
4572
|
+
return /* @__PURE__ */ jsxs33("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
4573
|
+
/* @__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" }),
|
|
4574
|
+
/* @__PURE__ */ jsx36("path", { d: "m21 2-9.6 9.6" }),
|
|
4575
|
+
/* @__PURE__ */ jsx36("circle", { cx: "7.5", cy: "15.5", r: "5.5" })
|
|
4468
4576
|
] });
|
|
4469
4577
|
}
|
|
4470
4578
|
|
|
@@ -4472,7 +4580,7 @@ function ApiKeyManager({ basePath = "/api", className }) {
|
|
|
4472
4580
|
import { useState as useState21 } from "react";
|
|
4473
4581
|
import { cn as cn34, formatDateTime as formatDateTime10, StatusBadge as StatusBadge9, useToast as useToast18 } from "@quanticjs/react-ui";
|
|
4474
4582
|
import { useApiMutation as useApiMutation19, useApiQuery as useApiQuery28 } from "@quanticjs/react-query";
|
|
4475
|
-
import { jsx as
|
|
4583
|
+
import { jsx as jsx37, jsxs as jsxs34 } from "react/jsx-runtime";
|
|
4476
4584
|
function normalize10(raw) {
|
|
4477
4585
|
const list = Array.isArray(raw) ? raw : Array.isArray(raw?.items) ? raw.items : [];
|
|
4478
4586
|
return list;
|
|
@@ -4518,10 +4626,10 @@ function ApplicationRegistryPanel({
|
|
|
4518
4626
|
if (!k || !name) return;
|
|
4519
4627
|
register.mutate({ key: k, displayName: name, description: description.trim() || void 0 });
|
|
4520
4628
|
};
|
|
4521
|
-
const registerForm = /* @__PURE__ */
|
|
4522
|
-
/* @__PURE__ */
|
|
4523
|
-
/* @__PURE__ */
|
|
4524
|
-
/* @__PURE__ */
|
|
4629
|
+
const registerForm = /* @__PURE__ */ jsxs34("form", { onSubmit: onRegister, className: "flex flex-wrap items-end gap-3", noValidate: true, children: [
|
|
4630
|
+
/* @__PURE__ */ jsxs34("div", { className: "flex flex-col gap-1", children: [
|
|
4631
|
+
/* @__PURE__ */ jsx37("label", { htmlFor: "application-key", className: "text-sm font-medium text-foreground", children: "Key (slug)" }),
|
|
4632
|
+
/* @__PURE__ */ jsx37(
|
|
4525
4633
|
"input",
|
|
4526
4634
|
{
|
|
4527
4635
|
id: "application-key",
|
|
@@ -4533,9 +4641,9 @@ function ApplicationRegistryPanel({
|
|
|
4533
4641
|
}
|
|
4534
4642
|
)
|
|
4535
4643
|
] }),
|
|
4536
|
-
/* @__PURE__ */
|
|
4537
|
-
/* @__PURE__ */
|
|
4538
|
-
/* @__PURE__ */
|
|
4644
|
+
/* @__PURE__ */ jsxs34("div", { className: "flex flex-col gap-1", children: [
|
|
4645
|
+
/* @__PURE__ */ jsx37("label", { htmlFor: "application-name", className: "text-sm font-medium text-foreground", children: "Display name" }),
|
|
4646
|
+
/* @__PURE__ */ jsx37(
|
|
4539
4647
|
"input",
|
|
4540
4648
|
{
|
|
4541
4649
|
id: "application-name",
|
|
@@ -4547,9 +4655,9 @@ function ApplicationRegistryPanel({
|
|
|
4547
4655
|
}
|
|
4548
4656
|
)
|
|
4549
4657
|
] }),
|
|
4550
|
-
/* @__PURE__ */
|
|
4551
|
-
/* @__PURE__ */
|
|
4552
|
-
/* @__PURE__ */
|
|
4658
|
+
/* @__PURE__ */ jsxs34("div", { className: "flex flex-col gap-1", children: [
|
|
4659
|
+
/* @__PURE__ */ jsx37("label", { htmlFor: "application-description", className: "text-sm font-medium text-foreground", children: "Description (optional)" }),
|
|
4660
|
+
/* @__PURE__ */ jsx37(
|
|
4553
4661
|
"input",
|
|
4554
4662
|
{
|
|
4555
4663
|
id: "application-description",
|
|
@@ -4560,7 +4668,7 @@ function ApplicationRegistryPanel({
|
|
|
4560
4668
|
}
|
|
4561
4669
|
)
|
|
4562
4670
|
] }),
|
|
4563
|
-
/* @__PURE__ */
|
|
4671
|
+
/* @__PURE__ */ jsx37(
|
|
4564
4672
|
"button",
|
|
4565
4673
|
{
|
|
4566
4674
|
type: "submit",
|
|
@@ -4571,23 +4679,23 @@ function ApplicationRegistryPanel({
|
|
|
4571
4679
|
)
|
|
4572
4680
|
] });
|
|
4573
4681
|
if (isLoading) {
|
|
4574
|
-
return /* @__PURE__ */
|
|
4682
|
+
return /* @__PURE__ */ jsxs34(
|
|
4575
4683
|
"div",
|
|
4576
4684
|
{
|
|
4577
4685
|
role: "status",
|
|
4578
4686
|
"aria-label": "Loading applications",
|
|
4579
4687
|
className: cn34("flex flex-col gap-2 p-4", className),
|
|
4580
4688
|
children: [
|
|
4581
|
-
/* @__PURE__ */
|
|
4582
|
-
[0, 1, 2].map((i) => /* @__PURE__ */
|
|
4689
|
+
/* @__PURE__ */ jsx37("span", { className: "sr-only", children: "Loading applications" }),
|
|
4690
|
+
[0, 1, 2].map((i) => /* @__PURE__ */ jsx37("div", { "aria-hidden": "true", className: "h-10 animate-pulse rounded bg-muted" }, i))
|
|
4583
4691
|
]
|
|
4584
4692
|
}
|
|
4585
4693
|
);
|
|
4586
4694
|
}
|
|
4587
4695
|
if (isError) {
|
|
4588
|
-
return /* @__PURE__ */
|
|
4589
|
-
/* @__PURE__ */
|
|
4590
|
-
/* @__PURE__ */
|
|
4696
|
+
return /* @__PURE__ */ jsxs34("div", { className: cn34("flex flex-col items-start gap-3 p-4", className), children: [
|
|
4697
|
+
/* @__PURE__ */ jsx37("p", { className: "text-sm text-foreground", children: "Failed to load applications" }),
|
|
4698
|
+
/* @__PURE__ */ jsx37(
|
|
4591
4699
|
"button",
|
|
4592
4700
|
{
|
|
4593
4701
|
type: "button",
|
|
@@ -4599,22 +4707,22 @@ function ApplicationRegistryPanel({
|
|
|
4599
4707
|
] });
|
|
4600
4708
|
}
|
|
4601
4709
|
const apps = normalize10(data);
|
|
4602
|
-
return /* @__PURE__ */
|
|
4710
|
+
return /* @__PURE__ */ jsxs34("section", { "aria-label": "Applications", className: cn34("flex flex-col gap-4 p-4", className), children: [
|
|
4603
4711
|
registerForm,
|
|
4604
|
-
apps.length === 0 ? /* @__PURE__ */
|
|
4605
|
-
/* @__PURE__ */
|
|
4606
|
-
/* @__PURE__ */
|
|
4607
|
-
/* @__PURE__ */
|
|
4608
|
-
/* @__PURE__ */
|
|
4609
|
-
/* @__PURE__ */
|
|
4610
|
-
/* @__PURE__ */
|
|
4712
|
+
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: [
|
|
4713
|
+
/* @__PURE__ */ jsx37("thead", { children: /* @__PURE__ */ jsxs34("tr", { className: "border-b border-border text-start text-muted-foreground", children: [
|
|
4714
|
+
/* @__PURE__ */ jsx37("th", { className: "py-2 font-medium", children: "Key" }),
|
|
4715
|
+
/* @__PURE__ */ jsx37("th", { className: "py-2 font-medium", children: "Name" }),
|
|
4716
|
+
/* @__PURE__ */ jsx37("th", { className: "py-2 font-medium", children: "Status" }),
|
|
4717
|
+
/* @__PURE__ */ jsx37("th", { className: "py-2 font-medium", children: "Created" }),
|
|
4718
|
+
/* @__PURE__ */ jsx37("th", { className: "py-2 font-medium", children: "Actions" })
|
|
4611
4719
|
] }) }),
|
|
4612
|
-
/* @__PURE__ */
|
|
4613
|
-
/* @__PURE__ */
|
|
4614
|
-
/* @__PURE__ */
|
|
4615
|
-
/* @__PURE__ */
|
|
4616
|
-
/* @__PURE__ */
|
|
4617
|
-
/* @__PURE__ */
|
|
4720
|
+
/* @__PURE__ */ jsx37("tbody", { children: apps.map((app) => /* @__PURE__ */ jsxs34("tr", { className: "border-b border-border", children: [
|
|
4721
|
+
/* @__PURE__ */ jsx37("td", { className: "py-2 font-mono text-foreground", children: app.key }),
|
|
4722
|
+
/* @__PURE__ */ jsx37("td", { className: "py-2 text-foreground", children: app.displayName }),
|
|
4723
|
+
/* @__PURE__ */ jsx37("td", { className: "py-2", children: /* @__PURE__ */ jsx37(StatusBadge9, { variant: app.status === "active" ? "success" : "neutral", children: app.status }) }),
|
|
4724
|
+
/* @__PURE__ */ jsx37("td", { className: "py-2 text-muted-foreground", children: formatDateTime10(app.createdAt) }),
|
|
4725
|
+
/* @__PURE__ */ jsx37("td", { className: "py-2", children: /* @__PURE__ */ jsx37(
|
|
4618
4726
|
"button",
|
|
4619
4727
|
{
|
|
4620
4728
|
type: "button",
|