@fonderie/react-admin-screens 1.4.0 → 1.6.0
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 +663 -474
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +32 -16
- package/dist/index.d.ts +32 -16
- package/dist/index.js +696 -472
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
// src/screens/AdminShell.tsx
|
|
2
|
+
import {
|
|
3
|
+
createAdminT as createAdminT16
|
|
4
|
+
} from "@fonderie/client";
|
|
2
5
|
import { ConfigEditorScreen, ConfigListScreen } from "@fonderie/react-config-admin-screens";
|
|
3
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
TemplateCreateScreen,
|
|
8
|
+
TemplateEditorScreen,
|
|
9
|
+
TemplateListScreen
|
|
10
|
+
} from "@fonderie/react-courier-admin-screens";
|
|
4
11
|
import { useEffect as useEffect2, useState as useState9 } from "react";
|
|
5
12
|
|
|
6
13
|
// src/styles.ts
|
|
@@ -552,11 +559,12 @@ function Empty({
|
|
|
552
559
|
function RefreshButton({
|
|
553
560
|
onClick,
|
|
554
561
|
busy,
|
|
555
|
-
label = "Refresh"
|
|
562
|
+
label = "Refresh",
|
|
563
|
+
busyLabel = "Working\u2026"
|
|
556
564
|
}) {
|
|
557
565
|
return /* @__PURE__ */ jsxs("button", { type: "button", style: styles.button, onClick, disabled: busy, children: [
|
|
558
566
|
/* @__PURE__ */ jsx(Icon, { name: "refresh", size: 14 }),
|
|
559
|
-
busy ?
|
|
567
|
+
busy ? busyLabel : label
|
|
560
568
|
] });
|
|
561
569
|
}
|
|
562
570
|
function MethodChip({ method }) {
|
|
@@ -583,9 +591,14 @@ function MethodChip({ method }) {
|
|
|
583
591
|
}
|
|
584
592
|
|
|
585
593
|
// src/screens/AdminLogScreen.tsx
|
|
594
|
+
import {
|
|
595
|
+
createAdminT,
|
|
596
|
+
formatAdminDate
|
|
597
|
+
} from "@fonderie/client";
|
|
586
598
|
import { useAdminLog } from "@fonderie/react-admin";
|
|
587
599
|
import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
588
|
-
function AdminLogScreen({ client, pageSize = 50 }) {
|
|
600
|
+
function AdminLogScreen({ client, pageSize = 50, locale }) {
|
|
601
|
+
const t2 = createAdminT(locale);
|
|
589
602
|
const { entries, hasMore, isLoading, error, refresh, loadMore } = useAdminLog(client, {
|
|
590
603
|
limit: pageSize
|
|
591
604
|
});
|
|
@@ -593,22 +606,30 @@ function AdminLogScreen({ client, pageSize = 50 }) {
|
|
|
593
606
|
/* @__PURE__ */ jsx2(
|
|
594
607
|
PageHeader,
|
|
595
608
|
{
|
|
596
|
-
title: "
|
|
597
|
-
lead: "
|
|
598
|
-
actions: /* @__PURE__ */ jsx2(
|
|
609
|
+
title: t2("log.title"),
|
|
610
|
+
lead: t2("log.lead"),
|
|
611
|
+
actions: /* @__PURE__ */ jsx2(
|
|
612
|
+
RefreshButton,
|
|
613
|
+
{
|
|
614
|
+
onClick: () => void refresh(),
|
|
615
|
+
busy: isLoading,
|
|
616
|
+
label: t2("common.refresh"),
|
|
617
|
+
busyLabel: t2("common.working")
|
|
618
|
+
}
|
|
619
|
+
)
|
|
599
620
|
}
|
|
600
621
|
),
|
|
601
|
-
error ? /* @__PURE__ */ jsx2("p", { style: styles.error, role: "alert", children: error.status === 404 ? "
|
|
622
|
+
error ? /* @__PURE__ */ jsx2("p", { style: styles.error, role: "alert", children: error.status === 404 ? t2("log.off") : error.explanation }) : entries.length === 0 && !isLoading ? /* @__PURE__ */ jsx2(Empty, { icon: "log", title: t2("log.empty") }) : /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
602
623
|
/* @__PURE__ */ jsxs2("table", { style: styles.table, children: [
|
|
603
624
|
/* @__PURE__ */ jsx2("thead", { children: /* @__PURE__ */ jsxs2("tr", { children: [
|
|
604
|
-
/* @__PURE__ */ jsx2("th", { style: styles.th, children: "
|
|
605
|
-
/* @__PURE__ */ jsx2("th", { style: styles.th, children: "
|
|
606
|
-
/* @__PURE__ */ jsx2("th", { style: styles.th, children: "
|
|
607
|
-
/* @__PURE__ */ jsx2("th", { style: styles.th, children: "
|
|
608
|
-
/* @__PURE__ */ jsx2("th", { style: styles.th, children: "
|
|
625
|
+
/* @__PURE__ */ jsx2("th", { style: styles.th, children: t2("log.colWhen") }),
|
|
626
|
+
/* @__PURE__ */ jsx2("th", { style: styles.th, children: t2("log.colActor") }),
|
|
627
|
+
/* @__PURE__ */ jsx2("th", { style: styles.th, children: t2("log.colRequest") }),
|
|
628
|
+
/* @__PURE__ */ jsx2("th", { style: styles.th, children: t2("log.colStatus") }),
|
|
629
|
+
/* @__PURE__ */ jsx2("th", { style: styles.th, children: t2("log.colModule") })
|
|
609
630
|
] }) }),
|
|
610
631
|
/* @__PURE__ */ jsx2("tbody", { children: entries.map((e) => /* @__PURE__ */ jsxs2("tr", { children: [
|
|
611
|
-
/* @__PURE__ */ jsx2("td", { style: { ...styles.td, ...styles.muted, whiteSpace: "nowrap" }, children:
|
|
632
|
+
/* @__PURE__ */ jsx2("td", { style: { ...styles.td, ...styles.muted, whiteSpace: "nowrap" }, children: formatAdminDate(e.at, locale, "datetime") }),
|
|
612
633
|
/* @__PURE__ */ jsx2("td", { style: styles.td, children: e.actor }),
|
|
613
634
|
/* @__PURE__ */ jsxs2("td", { style: styles.td, children: [
|
|
614
635
|
/* @__PURE__ */ jsx2(MethodChip, { method: e.method }),
|
|
@@ -626,14 +647,14 @@ function AdminLogScreen({ client, pageSize = 50 }) {
|
|
|
626
647
|
/* @__PURE__ */ jsx2("td", { style: { ...styles.td, ...styles.muted }, children: e.module })
|
|
627
648
|
] }, e.id)) })
|
|
628
649
|
] }),
|
|
629
|
-
isLoading ? /* @__PURE__ */ jsx2("p", { style: styles.status, children: "
|
|
650
|
+
isLoading ? /* @__PURE__ */ jsx2("p", { style: styles.status, children: t2("common.loading") }) : null,
|
|
630
651
|
hasMore && !isLoading ? /* @__PURE__ */ jsx2(
|
|
631
652
|
"button",
|
|
632
653
|
{
|
|
633
654
|
type: "button",
|
|
634
655
|
style: { ...styles.button, marginTop: 12 },
|
|
635
656
|
onClick: () => void loadMore(),
|
|
636
|
-
children: "
|
|
657
|
+
children: t2("common.loadMore")
|
|
637
658
|
}
|
|
638
659
|
) : null
|
|
639
660
|
] })
|
|
@@ -641,9 +662,14 @@ function AdminLogScreen({ client, pageSize = 50 }) {
|
|
|
641
662
|
}
|
|
642
663
|
|
|
643
664
|
// src/screens/AttentionScreen.tsx
|
|
665
|
+
import {
|
|
666
|
+
createAdminT as createAdminT2,
|
|
667
|
+
formatAdminDate as formatAdminDate2
|
|
668
|
+
} from "@fonderie/client";
|
|
644
669
|
import { useAttention, useManifest } from "@fonderie/react-admin";
|
|
645
670
|
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
646
|
-
function AttentionScreen({ client }) {
|
|
671
|
+
function AttentionScreen({ client, locale }) {
|
|
672
|
+
const t2 = createAdminT2(locale);
|
|
647
673
|
const { attention, isLoading, error, refresh } = useAttention(client);
|
|
648
674
|
const { manifest } = useManifest(client);
|
|
649
675
|
const errors = attention?.items.filter((i) => i.severity === "error") ?? [];
|
|
@@ -654,9 +680,19 @@ function AttentionScreen({ client }) {
|
|
|
654
680
|
/* @__PURE__ */ jsx3(
|
|
655
681
|
PageHeader,
|
|
656
682
|
{
|
|
657
|
-
title: "
|
|
658
|
-
lead: attention ?
|
|
659
|
-
|
|
683
|
+
title: t2("attention.title"),
|
|
684
|
+
lead: attention ? t2("attention.leadChecked", {
|
|
685
|
+
time: formatAdminDate2(attention.generatedAt, locale, "time")
|
|
686
|
+
}) : t2("attention.lead"),
|
|
687
|
+
actions: /* @__PURE__ */ jsx3(
|
|
688
|
+
RefreshButton,
|
|
689
|
+
{
|
|
690
|
+
onClick: () => void refresh(),
|
|
691
|
+
busy: isLoading,
|
|
692
|
+
label: t2("common.refresh"),
|
|
693
|
+
busyLabel: t2("common.working")
|
|
694
|
+
}
|
|
695
|
+
)
|
|
660
696
|
}
|
|
661
697
|
),
|
|
662
698
|
error ? /* @__PURE__ */ jsx3("p", { style: styles.error, role: "alert", children: error.explanation }) : null,
|
|
@@ -664,44 +700,42 @@ function AttentionScreen({ client }) {
|
|
|
664
700
|
/* @__PURE__ */ jsx3(
|
|
665
701
|
Stat,
|
|
666
702
|
{
|
|
667
|
-
label: "
|
|
703
|
+
label: t2("attention.needsAction"),
|
|
668
704
|
value: attention ? errors.length : "\u2014",
|
|
669
705
|
tone: errors.length ? "bad" : attention ? "ok" : void 0,
|
|
670
|
-
hint: "
|
|
706
|
+
hint: t2("attention.needsActionHint")
|
|
671
707
|
}
|
|
672
708
|
),
|
|
673
709
|
/* @__PURE__ */ jsx3(
|
|
674
710
|
Stat,
|
|
675
711
|
{
|
|
676
|
-
label: "
|
|
712
|
+
label: t2("attention.advice"),
|
|
677
713
|
value: attention ? advice.length : "\u2014",
|
|
678
714
|
tone: advice.length ? "warn" : void 0,
|
|
679
|
-
hint: "
|
|
715
|
+
hint: t2("attention.adviceHint")
|
|
680
716
|
}
|
|
681
717
|
),
|
|
682
718
|
/* @__PURE__ */ jsx3(
|
|
683
719
|
Stat,
|
|
684
720
|
{
|
|
685
|
-
label: "
|
|
721
|
+
label: t2("attention.modulesReady"),
|
|
686
722
|
value: manifest ? `${ready}/${total}` : "\u2014",
|
|
687
723
|
tone: manifest && ready < total ? "warn" : manifest ? "ok" : void 0,
|
|
688
|
-
hint: manifest ?
|
|
724
|
+
hint: manifest ? t2("attention.modulesReadyHint", { version: manifest.admin.version }) : void 0
|
|
689
725
|
}
|
|
690
726
|
),
|
|
691
727
|
/* @__PURE__ */ jsx3(
|
|
692
728
|
Stat,
|
|
693
729
|
{
|
|
694
|
-
label: "
|
|
730
|
+
label: t2("attention.routes"),
|
|
695
731
|
value: manifest ? manifest.routes.length : "\u2014",
|
|
696
732
|
hint: manifest ? manifest.env : void 0
|
|
697
733
|
}
|
|
698
734
|
)
|
|
699
735
|
] }),
|
|
700
|
-
isLoading && !attention ? /* @__PURE__ */ jsx3("p", { style: styles.status, children: "
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
"."
|
|
704
|
-
] }) : /* @__PURE__ */ jsx3("ul", { style: styles.list, children: [...errors, ...advice].map((item) => /* @__PURE__ */ jsxs3(
|
|
736
|
+
isLoading && !attention ? /* @__PURE__ */ jsx3("p", { style: styles.status, children: t2("attention.running") }) : attention && attention.items.length === 0 ? /* @__PURE__ */ jsx3(Empty, { title: t2("attention.emptyTitle"), children: t2("attention.emptyBody", {
|
|
737
|
+
time: formatAdminDate2(attention.generatedAt, locale, "datetime")
|
|
738
|
+
}) }) : /* @__PURE__ */ jsx3("ul", { style: styles.list, children: [...errors, ...advice].map((item) => /* @__PURE__ */ jsxs3(
|
|
705
739
|
"li",
|
|
706
740
|
{
|
|
707
741
|
style: { ...styles.row, display: "flex", gap: 12, alignItems: "flex-start" },
|
|
@@ -729,7 +763,7 @@ function AttentionScreen({ client }) {
|
|
|
729
763
|
marginBottom: 2
|
|
730
764
|
},
|
|
731
765
|
children: [
|
|
732
|
-
/* @__PURE__ */ jsx3(Pill, { tone: item.severity === "error" ? "bad" : "warn", children: item.severity === "error" ? "error" : "advice" }),
|
|
766
|
+
/* @__PURE__ */ jsx3(Pill, { tone: item.severity === "error" ? "bad" : "warn", children: item.severity === "error" ? t2("common.status.error") : t2("common.status.advice") }),
|
|
733
767
|
/* @__PURE__ */ jsx3("span", { style: styles.mono, children: item.source })
|
|
734
768
|
]
|
|
735
769
|
}
|
|
@@ -744,23 +778,25 @@ function AttentionScreen({ client }) {
|
|
|
744
778
|
}
|
|
745
779
|
|
|
746
780
|
// src/screens/EnvironmentScreen.tsx
|
|
781
|
+
import { createAdminT as createAdminT3 } from "@fonderie/client";
|
|
747
782
|
import { useAdminEnvironment } from "@fonderie/react-admin";
|
|
748
783
|
import { Fragment as Fragment2, jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
749
|
-
function EnvironmentScreen({ client }) {
|
|
784
|
+
function EnvironmentScreen({ client, locale }) {
|
|
785
|
+
const t2 = createAdminT3(locale);
|
|
750
786
|
const { report, isLoading, error } = useAdminEnvironment(client);
|
|
751
787
|
const missing = report?.env.filter((e) => !e.set).length ?? 0;
|
|
752
788
|
return /* @__PURE__ */ jsxs4("div", { style: styles.container, children: [
|
|
753
789
|
/* @__PURE__ */ jsx4(
|
|
754
790
|
PageHeader,
|
|
755
791
|
{
|
|
756
|
-
title: "
|
|
757
|
-
lead: "
|
|
758
|
-
actions: report && report.env.length > 0 ? /* @__PURE__ */ jsx4(Pill, { tone: missing ? "bad" : "ok", children: missing ?
|
|
792
|
+
title: t2("environment.title"),
|
|
793
|
+
lead: t2("environment.lead"),
|
|
794
|
+
actions: report && report.env.length > 0 ? /* @__PURE__ */ jsx4(Pill, { tone: missing ? "bad" : "ok", children: missing ? t2("environment.missingCount", { n: missing }) : t2("environment.allSet") }) : null
|
|
759
795
|
}
|
|
760
796
|
),
|
|
761
|
-
isLoading ? /* @__PURE__ */ jsx4("p", { style: styles.status, children: "
|
|
762
|
-
/* @__PURE__ */ jsx4("h2", { style: { ...styles.subtitle, marginTop: 0 }, children: "
|
|
763
|
-
report.env.length === 0 ? /* @__PURE__ */ jsx4("p", { style: styles.muted, children: "
|
|
797
|
+
isLoading ? /* @__PURE__ */ jsx4("p", { style: styles.status, children: t2("common.loading") }) : error ? /* @__PURE__ */ jsx4("p", { style: styles.error, role: "alert", children: error.explanation }) : report ? /* @__PURE__ */ jsxs4(Fragment2, { children: [
|
|
798
|
+
/* @__PURE__ */ jsx4("h2", { style: { ...styles.subtitle, marginTop: 0 }, children: t2("environment.variables") }),
|
|
799
|
+
report.env.length === 0 ? /* @__PURE__ */ jsx4("p", { style: styles.muted, children: t2("environment.noVariables") }) : /* @__PURE__ */ jsx4(
|
|
764
800
|
"div",
|
|
765
801
|
{
|
|
766
802
|
style: {
|
|
@@ -781,14 +817,14 @@ function EnvironmentScreen({ client }) {
|
|
|
781
817
|
},
|
|
782
818
|
children: [
|
|
783
819
|
/* @__PURE__ */ jsx4("span", { style: { ...styles.mono, wordBreak: "break-all" }, children: e.name }),
|
|
784
|
-
/* @__PURE__ */ jsx4(Pill, { tone: e.set ? "ok" : "bad", children: e.set ? "set" : "missing" })
|
|
820
|
+
/* @__PURE__ */ jsx4(Pill, { tone: e.set ? "ok" : "bad", children: e.set ? t2("common.status.set") : t2("common.status.missing") })
|
|
785
821
|
]
|
|
786
822
|
},
|
|
787
823
|
e.name
|
|
788
824
|
))
|
|
789
825
|
}
|
|
790
826
|
),
|
|
791
|
-
/* @__PURE__ */ jsx4("h2", { style: styles.subtitle, children: "
|
|
827
|
+
/* @__PURE__ */ jsx4("h2", { style: styles.subtitle, children: t2("environment.moduleReadiness") }),
|
|
792
828
|
/* @__PURE__ */ jsx4("ul", { style: styles.list, children: report.modules.map((m) => /* @__PURE__ */ jsxs4("li", { style: styles.row, children: [
|
|
793
829
|
/* @__PURE__ */ jsxs4(
|
|
794
830
|
"div",
|
|
@@ -805,7 +841,7 @@ function EnvironmentScreen({ client }) {
|
|
|
805
841
|
Pill,
|
|
806
842
|
{
|
|
807
843
|
tone: m.problems.length === 0 ? "ok" : m.problems.some((p) => p.severity === "error") ? "bad" : "warn",
|
|
808
|
-
children: m.problems.length === 0 ? "ready" :
|
|
844
|
+
children: m.problems.length === 0 ? t2("common.status.ready") : m.problems.length === 1 ? t2("environment.problemOne") : t2("environment.problemMany", { n: m.problems.length })
|
|
809
845
|
}
|
|
810
846
|
)
|
|
811
847
|
]
|
|
@@ -829,34 +865,44 @@ function EnvironmentScreen({ client }) {
|
|
|
829
865
|
}
|
|
830
866
|
|
|
831
867
|
// src/screens/DoctorScreen.tsx
|
|
868
|
+
import { createAdminT as createAdminT4 } from "@fonderie/client";
|
|
832
869
|
import { useDoctor } from "@fonderie/react-admin";
|
|
833
870
|
import { Fragment as Fragment3, jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
834
|
-
function DoctorScreen({ client }) {
|
|
871
|
+
function DoctorScreen({ client, locale }) {
|
|
872
|
+
const t2 = createAdminT4(locale);
|
|
835
873
|
const { report, isLoading, error, refresh } = useDoctor(client);
|
|
836
874
|
return /* @__PURE__ */ jsxs5("div", { style: styles.container, children: [
|
|
837
875
|
/* @__PURE__ */ jsx5(
|
|
838
876
|
PageHeader,
|
|
839
877
|
{
|
|
840
|
-
title: "
|
|
841
|
-
lead: "
|
|
878
|
+
title: t2("doctor.title"),
|
|
879
|
+
lead: t2("doctor.lead"),
|
|
842
880
|
actions: /* @__PURE__ */ jsxs5(Fragment3, { children: [
|
|
843
|
-
report && !isLoading ? /* @__PURE__ */ jsx5(Pill, { tone: report.ok ? "ok" : "bad", children: report.ok ? "
|
|
844
|
-
/* @__PURE__ */ jsx5(
|
|
881
|
+
report && !isLoading ? /* @__PURE__ */ jsx5(Pill, { tone: report.ok ? "ok" : "bad", children: report.ok ? t2("doctor.allPass") : t2("doctor.oneFailed") }) : null,
|
|
882
|
+
/* @__PURE__ */ jsx5(
|
|
883
|
+
RefreshButton,
|
|
884
|
+
{
|
|
885
|
+
onClick: () => void refresh(),
|
|
886
|
+
busy: isLoading,
|
|
887
|
+
label: t2("doctor.runAgain"),
|
|
888
|
+
busyLabel: t2("common.working")
|
|
889
|
+
}
|
|
890
|
+
)
|
|
845
891
|
] })
|
|
846
892
|
}
|
|
847
893
|
),
|
|
848
|
-
isLoading && !report ? /* @__PURE__ */ jsx5("p", { style: styles.status, children: "
|
|
894
|
+
isLoading && !report ? /* @__PURE__ */ jsx5("p", { style: styles.status, children: t2("doctor.running") }) : error ? /* @__PURE__ */ jsx5("p", { style: styles.error, role: "alert", children: error.explanation }) : /* @__PURE__ */ jsxs5("table", { style: styles.table, children: [
|
|
849
895
|
/* @__PURE__ */ jsx5("thead", { children: /* @__PURE__ */ jsxs5("tr", { children: [
|
|
850
|
-
/* @__PURE__ */ jsx5("th", { style: { ...styles.th, width: 110 }, children: "
|
|
851
|
-
/* @__PURE__ */ jsx5("th", { style: styles.th, children: "
|
|
852
|
-
/* @__PURE__ */ jsx5("th", { style: { ...styles.th, textAlign: "right", width: 90 }, children: "
|
|
896
|
+
/* @__PURE__ */ jsx5("th", { style: { ...styles.th, width: 110 }, children: t2("doctor.colResult") }),
|
|
897
|
+
/* @__PURE__ */ jsx5("th", { style: styles.th, children: t2("doctor.colCheck") }),
|
|
898
|
+
/* @__PURE__ */ jsx5("th", { style: { ...styles.th, textAlign: "right", width: 90 }, children: t2("doctor.colTime") })
|
|
853
899
|
] }) }),
|
|
854
900
|
/* @__PURE__ */ jsx5("tbody", { children: report?.checks.map((c) => /* @__PURE__ */ jsxs5("tr", { children: [
|
|
855
901
|
/* @__PURE__ */ jsx5("td", { style: styles.td, children: /* @__PURE__ */ jsx5(
|
|
856
902
|
Pill,
|
|
857
903
|
{
|
|
858
904
|
tone: c.skipped ? "neutral" : c.ok ? c.findings.length ? "warn" : "ok" : "bad",
|
|
859
|
-
children: c.skipped ? "skipped" : c.ok ? c.findings.length ? "advice" : "ok" : "failed"
|
|
905
|
+
children: c.skipped ? t2("common.status.skipped") : c.ok ? c.findings.length ? t2("common.status.advice") : t2("common.status.ok") : t2("common.status.failed")
|
|
860
906
|
}
|
|
861
907
|
) }),
|
|
862
908
|
/* @__PURE__ */ jsxs5("td", { style: styles.td, children: [
|
|
@@ -901,30 +947,37 @@ function DoctorScreen({ client }) {
|
|
|
901
947
|
}
|
|
902
948
|
|
|
903
949
|
// src/screens/ModulesScreen.tsx
|
|
950
|
+
import { createAdminT as createAdminT5 } from "@fonderie/client";
|
|
904
951
|
import { useManifest as useManifest2 } from "@fonderie/react-admin";
|
|
905
952
|
import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
906
|
-
function ModulesScreen({ client }) {
|
|
953
|
+
function ModulesScreen({ client, locale }) {
|
|
954
|
+
const t2 = createAdminT5(locale);
|
|
907
955
|
const { manifest, isLoading, error } = useManifest2(client);
|
|
908
956
|
return /* @__PURE__ */ jsxs6("div", { style: styles.container, children: [
|
|
909
957
|
/* @__PURE__ */ jsx6(
|
|
910
958
|
PageHeader,
|
|
911
959
|
{
|
|
912
|
-
title: "
|
|
913
|
-
lead: manifest ?
|
|
960
|
+
title: t2("modules.title"),
|
|
961
|
+
lead: manifest ? t2("modules.leadSummary", {
|
|
962
|
+
env: manifest.env,
|
|
963
|
+
version: manifest.admin.version,
|
|
964
|
+
log: manifest.admin.log ? t2("modules.logOn") : t2("modules.logOff"),
|
|
965
|
+
routes: manifest.routes.length
|
|
966
|
+
}) : t2("modules.lead")
|
|
914
967
|
}
|
|
915
968
|
),
|
|
916
|
-
isLoading ? /* @__PURE__ */ jsx6("p", { style: styles.status, children: "
|
|
969
|
+
isLoading ? /* @__PURE__ */ jsx6("p", { style: styles.status, children: t2("common.loading") }) : error ? /* @__PURE__ */ jsx6("p", { style: styles.error, role: "alert", children: error.explanation }) : manifest ? /* @__PURE__ */ jsxs6("table", { style: styles.table, children: [
|
|
917
970
|
/* @__PURE__ */ jsx6("thead", { children: /* @__PURE__ */ jsxs6("tr", { children: [
|
|
918
|
-
/* @__PURE__ */ jsx6("th", { style: styles.th, children: "
|
|
919
|
-
/* @__PURE__ */ jsx6("th", { style: styles.th, children: "
|
|
920
|
-
/* @__PURE__ */ jsx6("th", { style: styles.th, children: "
|
|
921
|
-
/* @__PURE__ */ jsx6("th", { style: styles.th, children: "
|
|
971
|
+
/* @__PURE__ */ jsx6("th", { style: styles.th, children: t2("modules.colModule") }),
|
|
972
|
+
/* @__PURE__ */ jsx6("th", { style: styles.th, children: t2("modules.colVersion") }),
|
|
973
|
+
/* @__PURE__ */ jsx6("th", { style: styles.th, children: t2("modules.colReadiness") }),
|
|
974
|
+
/* @__PURE__ */ jsx6("th", { style: styles.th, children: t2("modules.colAdmin") })
|
|
922
975
|
] }) }),
|
|
923
976
|
/* @__PURE__ */ jsx6("tbody", { children: manifest.modules.map((m) => /* @__PURE__ */ jsxs6("tr", { children: [
|
|
924
977
|
/* @__PURE__ */ jsx6("td", { style: { ...styles.td, ...styles.mono, fontWeight: 600 }, children: m.name }),
|
|
925
|
-
/* @__PURE__ */ jsx6("td", { style: { ...styles.td, ...styles.mono }, children: m.version ?? /* @__PURE__ */ jsx6("span", { style: styles.muted, children: "
|
|
978
|
+
/* @__PURE__ */ jsx6("td", { style: { ...styles.td, ...styles.mono }, children: m.version ?? /* @__PURE__ */ jsx6("span", { style: styles.muted, children: t2("modules.notReported") }) }),
|
|
926
979
|
/* @__PURE__ */ jsxs6("td", { style: styles.td, children: [
|
|
927
|
-
/* @__PURE__ */ jsx6(Pill, { tone: m.readiness.ok ? "ok" : "bad", children: m.readiness.ok ? "ready" : "error" }),
|
|
980
|
+
/* @__PURE__ */ jsx6(Pill, { tone: m.readiness.ok ? "ok" : "bad", children: m.readiness.ok ? t2("common.status.ready") : t2("common.status.error") }),
|
|
928
981
|
m.readiness.problems.map((p) => /* @__PURE__ */ jsx6(
|
|
929
982
|
"div",
|
|
930
983
|
{
|
|
@@ -938,17 +991,19 @@ function ModulesScreen({ client }) {
|
|
|
938
991
|
p.message
|
|
939
992
|
))
|
|
940
993
|
] }),
|
|
941
|
-
/* @__PURE__ */ jsx6("td", { style: styles.td, children: m.describesAdmin ? /* @__PURE__ */ jsx6("span", { style: styles.badge, children: "
|
|
994
|
+
/* @__PURE__ */ jsx6("td", { style: styles.td, children: m.describesAdmin ? /* @__PURE__ */ jsx6("span", { style: styles.badge, children: t2("modules.describesAdmin") }) : /* @__PURE__ */ jsx6("span", { style: styles.muted, children: "\u2014" }) })
|
|
942
995
|
] }, m.name)) })
|
|
943
996
|
] }) : null
|
|
944
997
|
] });
|
|
945
998
|
}
|
|
946
999
|
|
|
947
1000
|
// src/screens/RoutesScreen.tsx
|
|
1001
|
+
import { createAdminT as createAdminT6 } from "@fonderie/client";
|
|
948
1002
|
import { useAdminRoutes } from "@fonderie/react-admin";
|
|
949
1003
|
import { useState } from "react";
|
|
950
1004
|
import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
951
|
-
function RoutesScreen({ client }) {
|
|
1005
|
+
function RoutesScreen({ client, locale }) {
|
|
1006
|
+
const t2 = createAdminT6(locale);
|
|
952
1007
|
const { report, isLoading, error } = useAdminRoutes(client);
|
|
953
1008
|
const [q, setQ] = useState("");
|
|
954
1009
|
const needle = q.trim().toLowerCase();
|
|
@@ -959,27 +1014,27 @@ function RoutesScreen({ client }) {
|
|
|
959
1014
|
/* @__PURE__ */ jsx7(
|
|
960
1015
|
PageHeader,
|
|
961
1016
|
{
|
|
962
|
-
title: "
|
|
963
|
-
lead: report ?
|
|
1017
|
+
title: t2("routes.title"),
|
|
1018
|
+
lead: report ? t2("routes.leadCount", { n: report.routes.length }) : t2("routes.lead"),
|
|
964
1019
|
actions: /* @__PURE__ */ jsx7(
|
|
965
1020
|
"input",
|
|
966
1021
|
{
|
|
967
1022
|
type: "search",
|
|
968
1023
|
value: q,
|
|
969
1024
|
onChange: (e) => setQ(e.target.value),
|
|
970
|
-
placeholder: "
|
|
1025
|
+
placeholder: t2("routes.filterPlaceholder"),
|
|
971
1026
|
style: { ...styles.input, width: 280 },
|
|
972
|
-
"aria-label": "
|
|
1027
|
+
"aria-label": t2("routes.filterLabel")
|
|
973
1028
|
}
|
|
974
1029
|
)
|
|
975
1030
|
}
|
|
976
1031
|
),
|
|
977
|
-
isLoading ? /* @__PURE__ */ jsx7("p", { style: styles.status, children: "
|
|
1032
|
+
isLoading ? /* @__PURE__ */ jsx7("p", { style: styles.status, children: t2("common.loading") }) : error ? /* @__PURE__ */ jsx7("p", { style: styles.error, role: "alert", children: error.explanation }) : /* @__PURE__ */ jsxs7("table", { style: styles.table, children: [
|
|
978
1033
|
/* @__PURE__ */ jsx7("thead", { children: /* @__PURE__ */ jsxs7("tr", { children: [
|
|
979
|
-
/* @__PURE__ */ jsx7("th", { style: { ...styles.th, width: 80 }, children: "
|
|
980
|
-
/* @__PURE__ */ jsx7("th", { style: styles.th, children: "
|
|
981
|
-
/* @__PURE__ */ jsx7("th", { style: styles.th, children: "
|
|
982
|
-
/* @__PURE__ */ jsx7("th", { style: styles.th, children: "
|
|
1034
|
+
/* @__PURE__ */ jsx7("th", { style: { ...styles.th, width: 80 }, children: t2("routes.colMethod") }),
|
|
1035
|
+
/* @__PURE__ */ jsx7("th", { style: styles.th, children: t2("routes.colPath") }),
|
|
1036
|
+
/* @__PURE__ */ jsx7("th", { style: styles.th, children: t2("routes.colGuard") }),
|
|
1037
|
+
/* @__PURE__ */ jsx7("th", { style: styles.th, children: t2("routes.colModule") })
|
|
983
1038
|
] }) }),
|
|
984
1039
|
/* @__PURE__ */ jsxs7("tbody", { children: [
|
|
985
1040
|
routes.map((r) => /* @__PURE__ */ jsxs7("tr", { children: [
|
|
@@ -993,61 +1048,66 @@ function RoutesScreen({ client }) {
|
|
|
993
1048
|
children: r.guard
|
|
994
1049
|
}
|
|
995
1050
|
) }),
|
|
996
|
-
/* @__PURE__ */ jsx7("td", { style: { ...styles.td, ...styles.muted }, children: r.module ?? "application" })
|
|
1051
|
+
/* @__PURE__ */ jsx7("td", { style: { ...styles.td, ...styles.muted }, children: r.module ?? t2("routes.application") })
|
|
997
1052
|
] }, `${r.method} ${r.path}`)),
|
|
998
|
-
routes.length === 0 ? /* @__PURE__ */ jsx7("tr", { children: /* @__PURE__ */
|
|
999
|
-
"No route matches \u201C",
|
|
1000
|
-
q,
|
|
1001
|
-
"\u201D."
|
|
1002
|
-
] }) }) : null
|
|
1053
|
+
routes.length === 0 ? /* @__PURE__ */ jsx7("tr", { children: /* @__PURE__ */ jsx7("td", { style: { ...styles.td, ...styles.muted }, colSpan: 4, children: t2("routes.noMatch", { q }) }) }) : null
|
|
1003
1054
|
] })
|
|
1004
1055
|
] })
|
|
1005
1056
|
] });
|
|
1006
1057
|
}
|
|
1007
1058
|
|
|
1008
1059
|
// src/screens/MigrationsScreen.tsx
|
|
1060
|
+
import {
|
|
1061
|
+
createAdminT as createAdminT7
|
|
1062
|
+
} from "@fonderie/client";
|
|
1009
1063
|
import { useAdminMigrations } from "@fonderie/react-admin";
|
|
1010
1064
|
import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
1011
|
-
function why(m, everApplied) {
|
|
1065
|
+
function why(m, everApplied, t2) {
|
|
1012
1066
|
if (m.pending.length === 0) return null;
|
|
1013
|
-
if (m.blockedBy) return
|
|
1067
|
+
if (m.blockedBy) return t2("migrations.blockedBy", { module: m.blockedBy });
|
|
1014
1068
|
if (everApplied && m.pending.some((p) => p.impact === "destructive"))
|
|
1015
|
-
return "
|
|
1069
|
+
return t2("migrations.destructiveBlocked");
|
|
1016
1070
|
return null;
|
|
1017
1071
|
}
|
|
1018
|
-
function MigrationsScreen({ client }) {
|
|
1072
|
+
function MigrationsScreen({ client, locale }) {
|
|
1073
|
+
const t2 = createAdminT7(locale);
|
|
1019
1074
|
const { report, isLoading, error, refresh, apply } = useAdminMigrations(client);
|
|
1020
1075
|
const behind = report?.modules.filter((m) => m.pending.length > 0) ?? [];
|
|
1021
1076
|
return /* @__PURE__ */ jsxs8("div", { style: styles.container, children: [
|
|
1022
1077
|
/* @__PURE__ */ jsx8(
|
|
1023
1078
|
PageHeader,
|
|
1024
1079
|
{
|
|
1025
|
-
title: "
|
|
1026
|
-
lead: "
|
|
1027
|
-
actions: /* @__PURE__ */ jsx8(
|
|
1080
|
+
title: t2("migrations.title"),
|
|
1081
|
+
lead: t2("migrations.lead"),
|
|
1082
|
+
actions: /* @__PURE__ */ jsx8(
|
|
1083
|
+
RefreshButton,
|
|
1084
|
+
{
|
|
1085
|
+
onClick: () => void refresh(),
|
|
1086
|
+
busy: isLoading,
|
|
1087
|
+
label: t2("common.refresh"),
|
|
1088
|
+
busyLabel: t2("common.working")
|
|
1089
|
+
}
|
|
1090
|
+
)
|
|
1028
1091
|
}
|
|
1029
1092
|
),
|
|
1030
|
-
error ? /* @__PURE__ */ jsx8("p", { style: styles.error, role: "alert", children: error.status === 403 ? "
|
|
1031
|
-
report && !report.everApplied ? /* @__PURE__ */ jsx8("p", { style: styles.notice, children: "
|
|
1032
|
-
report && behind.length === 0 ? /* @__PURE__ */ jsx8(Empty, { icon: "migrations", title: "
|
|
1093
|
+
error ? /* @__PURE__ */ jsx8("p", { style: styles.error, role: "alert", children: error.status === 403 ? t2("migrations.needsWrite") : error.explanation }) : null,
|
|
1094
|
+
report && !report.everApplied ? /* @__PURE__ */ jsx8("p", { style: styles.notice, children: t2("migrations.firstInstall") }) : null,
|
|
1095
|
+
report && behind.length === 0 ? /* @__PURE__ */ jsx8(Empty, { icon: "migrations", title: t2("migrations.upToDate"), children: t2("migrations.noPending") }) : null,
|
|
1033
1096
|
behind.map((m) => {
|
|
1034
|
-
const blocked = why(m, report?.everApplied ?? false);
|
|
1097
|
+
const blocked = why(m, report?.everApplied ?? false, t2);
|
|
1035
1098
|
const files = m.pending.map((p) => p.file);
|
|
1036
1099
|
return /* @__PURE__ */ jsxs8("section", { style: { ...styles.card, marginBottom: 16 }, children: [
|
|
1037
1100
|
/* @__PURE__ */ jsxs8("h2", { style: { ...styles.subtitle, marginTop: 0 }, children: [
|
|
1038
1101
|
/* @__PURE__ */ jsx8("span", { style: styles.mono, children: m.name }),
|
|
1039
|
-
/* @__PURE__ */
|
|
1040
|
-
m.pending.length,
|
|
1041
|
-
" pending"
|
|
1042
|
-
] })
|
|
1102
|
+
/* @__PURE__ */ jsx8(Pill, { tone: "warn", children: t2("migrations.pendingCount", { n: m.pending.length }) })
|
|
1043
1103
|
] }),
|
|
1044
1104
|
/* @__PURE__ */ jsx8("ul", { style: { margin: "0 0 12px", paddingLeft: 18, lineHeight: 1.9 }, children: m.pending.map((p) => /* @__PURE__ */ jsxs8("li", { children: [
|
|
1045
1105
|
/* @__PURE__ */ jsx8("code", { style: styles.code, children: p.file }),
|
|
1046
1106
|
" ",
|
|
1047
|
-
p.impact === "destructive" ? /* @__PURE__ */ jsx8(Pill, { tone: "bad", children: "destructive" }) : /* @__PURE__ */ jsx8(Pill, { tone: "neutral", children: "additive" }),
|
|
1107
|
+
p.impact === "destructive" ? /* @__PURE__ */ jsx8(Pill, { tone: "bad", children: t2("migrations.destructive") }) : /* @__PURE__ */ jsx8(Pill, { tone: "neutral", children: t2("migrations.additive") }),
|
|
1048
1108
|
p.destructive.length > 0 ? /* @__PURE__ */ jsx8("ul", { children: p.destructive.map((s) => /* @__PURE__ */ jsx8("li", { children: /* @__PURE__ */ jsx8("code", { children: s.slice(0, 120) }) }, s)) }) : null
|
|
1049
1109
|
] }, p.file)) }),
|
|
1050
|
-
blocked ? /* @__PURE__ */ jsx8("p", { style: { ...styles.notice, marginBottom: 0 }, children: blocked }) : /* @__PURE__ */
|
|
1110
|
+
blocked ? /* @__PURE__ */ jsx8("p", { style: { ...styles.notice, marginBottom: 0 }, children: blocked }) : /* @__PURE__ */ jsx8(
|
|
1051
1111
|
"button",
|
|
1052
1112
|
{
|
|
1053
1113
|
type: "button",
|
|
@@ -1055,17 +1115,12 @@ function MigrationsScreen({ client }) {
|
|
|
1055
1115
|
disabled: isLoading || !m.appliable,
|
|
1056
1116
|
onClick: () => {
|
|
1057
1117
|
if (window.confirm(
|
|
1058
|
-
|
|
1118
|
+
t2("migrations.confirmApply", { n: m.pending.length, module: m.name })
|
|
1059
1119
|
))
|
|
1060
1120
|
void apply(m.name, files).catch(() => {
|
|
1061
1121
|
});
|
|
1062
1122
|
},
|
|
1063
|
-
children:
|
|
1064
|
-
"Apply ",
|
|
1065
|
-
m.pending.length,
|
|
1066
|
-
" migration",
|
|
1067
|
-
m.pending.length === 1 ? "" : "s"
|
|
1068
|
-
]
|
|
1123
|
+
children: m.pending.length === 1 ? t2("migrations.applyOne") : t2("migrations.applyMany", { n: m.pending.length })
|
|
1069
1124
|
}
|
|
1070
1125
|
)
|
|
1071
1126
|
] }, m.name);
|
|
@@ -1074,20 +1129,25 @@ function MigrationsScreen({ client }) {
|
|
|
1074
1129
|
}
|
|
1075
1130
|
|
|
1076
1131
|
// src/screens/OperatorsScreen.tsx
|
|
1132
|
+
import {
|
|
1133
|
+
createAdminT as createAdminT8,
|
|
1134
|
+
formatAdminDate as formatAdminDate3
|
|
1135
|
+
} from "@fonderie/client";
|
|
1077
1136
|
import { useAdminOperators } from "@fonderie/react-admin";
|
|
1078
1137
|
import { useState as useState2 } from "react";
|
|
1079
1138
|
import { Fragment as Fragment4, jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
1080
1139
|
var LEVELS = [
|
|
1081
|
-
{
|
|
1082
|
-
{
|
|
1083
|
-
{
|
|
1084
|
-
label: "Owner",
|
|
1085
|
-
scopes: ["read", "write", "secrets"],
|
|
1086
|
-
hint: "secrets, tokens and operators too"
|
|
1087
|
-
}
|
|
1140
|
+
{ id: "read", scopes: ["read"] },
|
|
1141
|
+
{ id: "editor", scopes: ["read", "write"] },
|
|
1142
|
+
{ id: "owner", scopes: ["read", "write", "secrets"] }
|
|
1088
1143
|
];
|
|
1089
|
-
var levelOf = (scopes) => scopes.includes("secrets") ? "
|
|
1090
|
-
function Minted({
|
|
1144
|
+
var levelOf = (scopes) => scopes.includes("secrets") ? "owner" : scopes.includes("write") ? "editor" : "read";
|
|
1145
|
+
function Minted({
|
|
1146
|
+
link,
|
|
1147
|
+
onClose,
|
|
1148
|
+
t: t2,
|
|
1149
|
+
locale
|
|
1150
|
+
}) {
|
|
1091
1151
|
const [copied, setCopied] = useState2(false);
|
|
1092
1152
|
const url = `${window.location.origin}${link.url}`;
|
|
1093
1153
|
return /* @__PURE__ */ jsxs9(
|
|
@@ -1099,15 +1159,9 @@ function Minted({ link, onClose }) {
|
|
|
1099
1159
|
borderColor: "color-mix(in srgb, var(--fonderie-accent,#00d294) 35%, transparent)"
|
|
1100
1160
|
},
|
|
1101
1161
|
children: [
|
|
1102
|
-
/* @__PURE__ */
|
|
1103
|
-
"Send this link to ",
|
|
1104
|
-
link.email,
|
|
1105
|
-
". It is shown once."
|
|
1106
|
-
] }),
|
|
1107
|
-
" It works once and expires",
|
|
1162
|
+
/* @__PURE__ */ jsx9("strong", { children: t2("operators.mintedTitle", { email: link.email }) }),
|
|
1108
1163
|
" ",
|
|
1109
|
-
|
|
1110
|
-
".",
|
|
1164
|
+
t2("operators.mintedBody", { date: formatAdminDate3(link.expiresAt, locale) }),
|
|
1111
1165
|
/* @__PURE__ */ jsxs9("div", { style: { display: "flex", gap: 8, marginTop: 8, alignItems: "center" }, children: [
|
|
1112
1166
|
/* @__PURE__ */ jsx9("code", { style: { ...styles.code, flex: 1, padding: "7px 10px", wordBreak: "break-all" }, children: url }),
|
|
1113
1167
|
/* @__PURE__ */ jsx9(
|
|
@@ -1119,32 +1173,36 @@ function Minted({ link, onClose }) {
|
|
|
1119
1173
|
void navigator.clipboard?.writeText(url);
|
|
1120
1174
|
setCopied(true);
|
|
1121
1175
|
},
|
|
1122
|
-
children: copied ? "
|
|
1176
|
+
children: copied ? t2("common.copied") : t2("common.copy")
|
|
1123
1177
|
}
|
|
1124
1178
|
),
|
|
1125
|
-
/* @__PURE__ */ jsx9(
|
|
1179
|
+
/* @__PURE__ */ jsx9(
|
|
1180
|
+
"button",
|
|
1181
|
+
{
|
|
1182
|
+
type: "button",
|
|
1183
|
+
style: styles.buttonGhost,
|
|
1184
|
+
onClick: onClose,
|
|
1185
|
+
"aria-label": t2("common.dismiss"),
|
|
1186
|
+
children: /* @__PURE__ */ jsx9(Icon, { name: "close", size: 14 })
|
|
1187
|
+
}
|
|
1188
|
+
)
|
|
1126
1189
|
] })
|
|
1127
1190
|
]
|
|
1128
1191
|
}
|
|
1129
1192
|
);
|
|
1130
1193
|
}
|
|
1131
|
-
function OperatorsScreen({ client, me }) {
|
|
1194
|
+
function OperatorsScreen({ client, me, locale }) {
|
|
1195
|
+
const t2 = createAdminT8(locale);
|
|
1132
1196
|
const { report, isLoading, error, invite, recover, update, revokeLink } = useAdminOperators(client);
|
|
1133
1197
|
const [email, setEmail] = useState2("");
|
|
1134
|
-
const [level, setLevel] = useState2("
|
|
1198
|
+
const [level, setLevel] = useState2("editor");
|
|
1135
1199
|
const [minted, setMinted] = useState2(null);
|
|
1136
|
-
const scopesFor = (
|
|
1137
|
-
const status = (o) => o.disabledAt ? /* @__PURE__ */ jsx9(Pill, { tone: "neutral", children: "disabled" }) : o.locked ? /* @__PURE__ */ jsx9(Pill, { tone: "warn", children: "locked" }) : !o.enrolled ? /* @__PURE__ */ jsx9(Pill, { tone: "warn", children: "
|
|
1200
|
+
const scopesFor = (id) => LEVELS.find((l) => l.id === id)?.scopes ?? ["read"];
|
|
1201
|
+
const status = (o) => o.disabledAt ? /* @__PURE__ */ jsx9(Pill, { tone: "neutral", children: t2("common.status.disabled") }) : o.locked ? /* @__PURE__ */ jsx9(Pill, { tone: "warn", children: t2("common.status.locked") }) : !o.enrolled ? /* @__PURE__ */ jsx9(Pill, { tone: "warn", children: t2("operators.settingUp") }) : /* @__PURE__ */ jsx9(Pill, { tone: "ok", children: t2("common.status.active") });
|
|
1138
1202
|
return /* @__PURE__ */ jsxs9("div", { style: styles.container, children: [
|
|
1139
|
-
/* @__PURE__ */ jsx9(
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
title: "Operators",
|
|
1143
|
-
lead: "The people who can sign in to this console. Each one uses a password and an authenticator app; there is no sign-up."
|
|
1144
|
-
}
|
|
1145
|
-
),
|
|
1146
|
-
error ? /* @__PURE__ */ jsx9("p", { style: styles.error, role: "alert", children: error.status === 403 && error.reason === "FORBIDDEN" ? "Managing operators needs the Owner level." : error.explanation }) : null,
|
|
1147
|
-
minted ? /* @__PURE__ */ jsx9(Minted, { link: minted, onClose: () => setMinted(null) }) : null,
|
|
1203
|
+
/* @__PURE__ */ jsx9(PageHeader, { title: t2("operators.title"), lead: t2("operators.lead") }),
|
|
1204
|
+
error ? /* @__PURE__ */ jsx9("p", { style: styles.error, role: "alert", children: error.status === 403 && error.reason === "FORBIDDEN" ? t2("operators.needsOwner") : error.explanation }) : null,
|
|
1205
|
+
minted ? /* @__PURE__ */ jsx9(Minted, { link: minted, onClose: () => setMinted(null), t: t2, locale }) : null,
|
|
1148
1206
|
/* @__PURE__ */ jsxs9(
|
|
1149
1207
|
"form",
|
|
1150
1208
|
{
|
|
@@ -1166,7 +1224,7 @@ function OperatorsScreen({ client, me }) {
|
|
|
1166
1224
|
},
|
|
1167
1225
|
children: [
|
|
1168
1226
|
/* @__PURE__ */ jsx9(Icon, { name: "users", size: 16 }),
|
|
1169
|
-
/* @__PURE__ */ jsx9("strong", { style: { fontSize: 13.5, marginRight: 4 }, children: "
|
|
1227
|
+
/* @__PURE__ */ jsx9("strong", { style: { fontSize: 13.5, marginRight: 4 }, children: t2("operators.invite") }),
|
|
1170
1228
|
/* @__PURE__ */ jsx9(
|
|
1171
1229
|
"input",
|
|
1172
1230
|
{
|
|
@@ -1174,9 +1232,9 @@ function OperatorsScreen({ client, me }) {
|
|
|
1174
1232
|
required: true,
|
|
1175
1233
|
value: email,
|
|
1176
1234
|
onChange: (e) => setEmail(e.target.value),
|
|
1177
|
-
placeholder: "
|
|
1235
|
+
placeholder: t2("operators.invitePlaceholder"),
|
|
1178
1236
|
style: { ...styles.input, flex: 1, minWidth: 220 },
|
|
1179
|
-
"aria-label": "
|
|
1237
|
+
"aria-label": t2("operators.inviteLabel")
|
|
1180
1238
|
}
|
|
1181
1239
|
),
|
|
1182
1240
|
/* @__PURE__ */ jsx9(
|
|
@@ -1185,27 +1243,27 @@ function OperatorsScreen({ client, me }) {
|
|
|
1185
1243
|
value: level,
|
|
1186
1244
|
onChange: (e) => setLevel(e.target.value),
|
|
1187
1245
|
style: styles.input,
|
|
1188
|
-
"aria-label": "
|
|
1189
|
-
children: LEVELS.map((l) => /* @__PURE__ */ jsxs9("option", { value: l.
|
|
1190
|
-
l.
|
|
1246
|
+
"aria-label": t2("operators.accessLevelLabel"),
|
|
1247
|
+
children: LEVELS.map((l) => /* @__PURE__ */ jsxs9("option", { value: l.id, children: [
|
|
1248
|
+
t2(`operators.level.${l.id}`),
|
|
1191
1249
|
" \u2014 ",
|
|
1192
|
-
l.
|
|
1193
|
-
] }, l.
|
|
1250
|
+
t2(`operators.levelHint.${l.id}`)
|
|
1251
|
+
] }, l.id))
|
|
1194
1252
|
}
|
|
1195
1253
|
),
|
|
1196
1254
|
/* @__PURE__ */ jsxs9("button", { type: "submit", style: styles.buttonPrimary, disabled: !email.trim(), children: [
|
|
1197
1255
|
/* @__PURE__ */ jsx9(Icon, { name: "plus", size: 14 }),
|
|
1198
|
-
"
|
|
1256
|
+
t2("operators.createInvite")
|
|
1199
1257
|
] })
|
|
1200
1258
|
]
|
|
1201
1259
|
}
|
|
1202
1260
|
),
|
|
1203
|
-
isLoading && !report ? /* @__PURE__ */ jsx9("p", { style: styles.status, children: "
|
|
1261
|
+
isLoading && !report ? /* @__PURE__ */ jsx9("p", { style: styles.status, children: t2("common.loading") }) : report && report.operators.length === 0 ? /* @__PURE__ */ jsx9(Empty, { icon: "users", title: t2("operators.emptyTitle") }) : report ? /* @__PURE__ */ jsxs9("table", { style: styles.table, children: [
|
|
1204
1262
|
/* @__PURE__ */ jsx9("thead", { children: /* @__PURE__ */ jsxs9("tr", { children: [
|
|
1205
|
-
/* @__PURE__ */ jsx9("th", { style: styles.th, children: "
|
|
1206
|
-
/* @__PURE__ */ jsx9("th", { style: styles.th, children: "
|
|
1207
|
-
/* @__PURE__ */ jsx9("th", { style: styles.th, children: "
|
|
1208
|
-
/* @__PURE__ */ jsx9("th", { style: styles.th, children: "
|
|
1263
|
+
/* @__PURE__ */ jsx9("th", { style: styles.th, children: t2("operators.col.operator") }),
|
|
1264
|
+
/* @__PURE__ */ jsx9("th", { style: styles.th, children: t2("operators.col.access") }),
|
|
1265
|
+
/* @__PURE__ */ jsx9("th", { style: styles.th, children: t2("operators.col.status") }),
|
|
1266
|
+
/* @__PURE__ */ jsx9("th", { style: styles.th, children: t2("operators.col.lastSignIn") }),
|
|
1209
1267
|
/* @__PURE__ */ jsx9("th", { style: styles.th })
|
|
1210
1268
|
] }) }),
|
|
1211
1269
|
/* @__PURE__ */ jsx9("tbody", { children: report.operators.map((o) => /* @__PURE__ */ jsxs9("tr", { children: [
|
|
@@ -1221,32 +1279,30 @@ function OperatorsScreen({ client, me }) {
|
|
|
1221
1279
|
}),
|
|
1222
1280
|
style: { ...styles.input, height: 28, fontSize: 12.5 },
|
|
1223
1281
|
disabled: o.email === me,
|
|
1224
|
-
"aria-label":
|
|
1225
|
-
children: LEVELS.map((l) => /* @__PURE__ */ jsx9("option", { value: l.
|
|
1282
|
+
"aria-label": t2("operators.accessLevelFor", { email: o.email }),
|
|
1283
|
+
children: LEVELS.map((l) => /* @__PURE__ */ jsx9("option", { value: l.id, children: t2(`operators.level.${l.id}`) }, l.id))
|
|
1226
1284
|
}
|
|
1227
1285
|
) }),
|
|
1228
1286
|
/* @__PURE__ */ jsxs9("td", { style: styles.td, children: [
|
|
1229
1287
|
status(o),
|
|
1230
|
-
o.enrolled && o.backupCodesLeft <= 2 && !o.disabledAt ? /* @__PURE__ */
|
|
1231
|
-
o.backupCodesLeft,
|
|
1232
|
-
|
|
1233
|
-
|
|
1288
|
+
o.enrolled && o.backupCodesLeft <= 2 && !o.disabledAt ? /* @__PURE__ */ jsx9("div", { style: { ...styles.muted, marginTop: 4 }, children: t2(
|
|
1289
|
+
o.backupCodesLeft === 1 ? "operators.backupCodesLeftOne" : "operators.backupCodesLeftMany",
|
|
1290
|
+
{ n: o.backupCodesLeft }
|
|
1291
|
+
) }) : null
|
|
1234
1292
|
] }),
|
|
1235
|
-
/* @__PURE__ */ jsx9("td", { style: { ...styles.td, ...styles.muted, whiteSpace: "nowrap" }, children: o.lastLoginAt ?
|
|
1236
|
-
/* @__PURE__ */ jsx9("td", { style: { ...styles.td, textAlign: "right", whiteSpace: "nowrap" }, children: o.email === me ? /* @__PURE__ */ jsx9("span", { style: styles.muted, children: "you" }) : /* @__PURE__ */ jsxs9(Fragment4, { children: [
|
|
1293
|
+
/* @__PURE__ */ jsx9("td", { style: { ...styles.td, ...styles.muted, whiteSpace: "nowrap" }, children: o.lastLoginAt ? formatAdminDate3(o.lastLoginAt, locale) : t2("common.never") }),
|
|
1294
|
+
/* @__PURE__ */ jsx9("td", { style: { ...styles.td, textAlign: "right", whiteSpace: "nowrap" }, children: o.email === me ? /* @__PURE__ */ jsx9("span", { style: styles.muted, children: t2("common.you") }) : /* @__PURE__ */ jsxs9(Fragment4, { children: [
|
|
1237
1295
|
/* @__PURE__ */ jsx9(
|
|
1238
1296
|
"button",
|
|
1239
1297
|
{
|
|
1240
1298
|
type: "button",
|
|
1241
1299
|
style: { ...styles.button, height: 28, marginRight: 6 },
|
|
1242
1300
|
onClick: () => {
|
|
1243
|
-
if (window.confirm(
|
|
1244
|
-
`Create a recovery link for ${o.email}? It signs them out everywhere; the link sets a new password and a new authenticator.`
|
|
1245
|
-
))
|
|
1301
|
+
if (window.confirm(t2("operators.recoveryConfirm", { email: o.email })))
|
|
1246
1302
|
void recover(o.id).then(setMinted).catch(() => {
|
|
1247
1303
|
});
|
|
1248
1304
|
},
|
|
1249
|
-
children: "
|
|
1305
|
+
children: t2("operators.recoveryLink")
|
|
1250
1306
|
}
|
|
1251
1307
|
),
|
|
1252
1308
|
/* @__PURE__ */ jsx9(
|
|
@@ -1258,35 +1314,32 @@ function OperatorsScreen({ client, me }) {
|
|
|
1258
1314
|
height: 28
|
|
1259
1315
|
},
|
|
1260
1316
|
onClick: () => {
|
|
1261
|
-
if (o.disabledAt || window.confirm(
|
|
1317
|
+
if (o.disabledAt || window.confirm(t2("operators.disableConfirm", { email: o.email })))
|
|
1262
1318
|
void update(o.id, { disabled: !o.disabledAt }).catch(() => {
|
|
1263
1319
|
});
|
|
1264
1320
|
},
|
|
1265
|
-
children: o.disabledAt ? "
|
|
1321
|
+
children: o.disabledAt ? t2("operators.enable") : t2("operators.disable")
|
|
1266
1322
|
}
|
|
1267
1323
|
)
|
|
1268
1324
|
] }) })
|
|
1269
1325
|
] }, o.id)) })
|
|
1270
1326
|
] }) : null,
|
|
1271
1327
|
report && report.links.length > 0 ? /* @__PURE__ */ jsxs9(Fragment4, { children: [
|
|
1272
|
-
/* @__PURE__ */ jsx9("h2", { style: styles.subtitle, children: "
|
|
1328
|
+
/* @__PURE__ */ jsx9("h2", { style: styles.subtitle, children: t2("operators.pendingLinks") }),
|
|
1273
1329
|
/* @__PURE__ */ jsx9("ul", { style: styles.list, children: report.links.map((l) => /* @__PURE__ */ jsxs9(
|
|
1274
1330
|
"li",
|
|
1275
1331
|
{
|
|
1276
1332
|
style: { ...styles.row, display: "flex", gap: 12, alignItems: "center" },
|
|
1277
1333
|
children: [
|
|
1278
|
-
/* @__PURE__ */ jsx9(Pill, { tone: l.kind === "invite" ? "info" : "warn", dot: false, children: l.kind }),
|
|
1334
|
+
/* @__PURE__ */ jsx9(Pill, { tone: l.kind === "invite" ? "info" : "warn", dot: false, children: l.kind === "invite" ? t2("operators.linkKind.invite") : t2("operators.linkKind.recovery") }),
|
|
1279
1335
|
/* @__PURE__ */ jsxs9("span", { style: { flex: 1 }, children: [
|
|
1280
1336
|
l.email,
|
|
1281
1337
|
l.kind === "invite" ? /* @__PURE__ */ jsxs9("span", { style: styles.muted, children: [
|
|
1282
1338
|
" \xB7 ",
|
|
1283
|
-
levelOf(l.scopes)
|
|
1339
|
+
t2(`operators.level.${levelOf(l.scopes)}`)
|
|
1284
1340
|
] }) : null
|
|
1285
1341
|
] }),
|
|
1286
|
-
/* @__PURE__ */
|
|
1287
|
-
"expires ",
|
|
1288
|
-
new Date(l.expiresAt).toLocaleString()
|
|
1289
|
-
] }),
|
|
1342
|
+
/* @__PURE__ */ jsx9("span", { style: styles.muted, children: t2("operators.expiresOn", { date: formatAdminDate3(l.expiresAt, locale) }) }),
|
|
1290
1343
|
/* @__PURE__ */ jsx9(
|
|
1291
1344
|
"button",
|
|
1292
1345
|
{
|
|
@@ -1294,7 +1347,7 @@ function OperatorsScreen({ client, me }) {
|
|
|
1294
1347
|
style: { ...styles.buttonDanger, height: 28 },
|
|
1295
1348
|
onClick: () => void revokeLink(l.id).catch(() => {
|
|
1296
1349
|
}),
|
|
1297
|
-
children: "
|
|
1350
|
+
children: t2("operators.revoke")
|
|
1298
1351
|
}
|
|
1299
1352
|
)
|
|
1300
1353
|
]
|
|
@@ -1306,11 +1359,16 @@ function OperatorsScreen({ client, me }) {
|
|
|
1306
1359
|
}
|
|
1307
1360
|
|
|
1308
1361
|
// src/screens/TokensScreen.tsx
|
|
1362
|
+
import {
|
|
1363
|
+
createAdminT as createAdminT9,
|
|
1364
|
+
formatAdminDate as formatAdminDate4
|
|
1365
|
+
} from "@fonderie/client";
|
|
1309
1366
|
import { useAdminTokens } from "@fonderie/react-admin";
|
|
1310
1367
|
import { useState as useState3 } from "react";
|
|
1311
1368
|
import { Fragment as Fragment5, jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
1312
1369
|
var ALL = ["read", "write", "secrets"];
|
|
1313
|
-
function TokensScreen({ client }) {
|
|
1370
|
+
function TokensScreen({ client, locale }) {
|
|
1371
|
+
const t2 = createAdminT9(locale);
|
|
1314
1372
|
const { report, isLoading, error, issue, revoke } = useAdminTokens(client);
|
|
1315
1373
|
const [name, setName] = useState3("");
|
|
1316
1374
|
const [scopes, setScopes] = useState3(["read"]);
|
|
@@ -1318,19 +1376,13 @@ function TokensScreen({ client }) {
|
|
|
1318
1376
|
const [minted, setMinted] = useState3(null);
|
|
1319
1377
|
const toggle = (s) => setScopes((prev) => prev.includes(s) ? prev.filter((x) => x !== s) : [...prev, s]);
|
|
1320
1378
|
return /* @__PURE__ */ jsxs10("div", { style: styles.container, children: [
|
|
1321
|
-
/* @__PURE__ */ jsx10(
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
title: "Tokens",
|
|
1325
|
-
lead: "Credentials for machines: the root token's strength, scoped tokens for the CLI and CI, and any legacy per-module tokens. People sign in as operators."
|
|
1326
|
-
}
|
|
1327
|
-
),
|
|
1328
|
-
error ? /* @__PURE__ */ jsx10("p", { style: styles.error, role: "alert", children: error.status === 401 ? "Issuing and revoking need the root token (the one in your deployment config)." : error.explanation }) : null,
|
|
1329
|
-
/* @__PURE__ */ jsx10("h2", { style: { ...styles.subtitle, marginTop: 0 }, children: "Root token" }),
|
|
1379
|
+
/* @__PURE__ */ jsx10(PageHeader, { title: t2("tokens.title"), lead: t2("tokens.lead") }),
|
|
1380
|
+
error ? /* @__PURE__ */ jsx10("p", { style: styles.error, role: "alert", children: error.status === 401 ? t2("tokens.needsRoot") : error.explanation }) : null,
|
|
1381
|
+
/* @__PURE__ */ jsx10("h2", { style: { ...styles.subtitle, marginTop: 0 }, children: t2("tokens.rootToken") }),
|
|
1330
1382
|
report ? /* @__PURE__ */ jsxs10("div", { style: { ...styles.card, display: "flex", gap: 12, alignItems: "flex-start" }, children: [
|
|
1331
1383
|
/* @__PURE__ */ jsx10(Icon, { name: "lock", size: 18, style: { marginTop: 2 } }),
|
|
1332
1384
|
/* @__PURE__ */ jsxs10("div", { children: [
|
|
1333
|
-
/* @__PURE__ */ jsx10(Pill, { tone: report.admin.ok ? "ok" : "bad", children: report.admin.ok ? "strong" : "weak" }),
|
|
1385
|
+
/* @__PURE__ */ jsx10(Pill, { tone: report.admin.ok ? "ok" : "bad", children: report.admin.ok ? t2("tokens.strong") : t2("tokens.weak") }),
|
|
1334
1386
|
report.admin.problems.map((p) => /* @__PURE__ */ jsx10(
|
|
1335
1387
|
"div",
|
|
1336
1388
|
{
|
|
@@ -1341,8 +1393,8 @@ function TokensScreen({ client }) {
|
|
|
1341
1393
|
))
|
|
1342
1394
|
] })
|
|
1343
1395
|
] }) : null,
|
|
1344
|
-
/* @__PURE__ */ jsx10("h2", { style: styles.subtitle, children: "
|
|
1345
|
-
report?.issued === null ? /* @__PURE__ */ jsx10("p", { style: styles.muted, children: "
|
|
1396
|
+
/* @__PURE__ */ jsx10("h2", { style: styles.subtitle, children: t2("tokens.issuedTokens") }),
|
|
1397
|
+
report?.issued === null ? /* @__PURE__ */ jsx10("p", { style: styles.muted, children: t2("tokens.issuingOff") }) : /* @__PURE__ */ jsxs10(Fragment5, { children: [
|
|
1346
1398
|
minted ? /* @__PURE__ */ jsxs10(
|
|
1347
1399
|
"div",
|
|
1348
1400
|
{
|
|
@@ -1352,7 +1404,7 @@ function TokensScreen({ client }) {
|
|
|
1352
1404
|
borderColor: "color-mix(in srgb, var(--fonderie-accent,#00d294) 35%, transparent)"
|
|
1353
1405
|
},
|
|
1354
1406
|
children: [
|
|
1355
|
-
/* @__PURE__ */ jsx10("strong", { children: "
|
|
1407
|
+
/* @__PURE__ */ jsx10("strong", { children: t2("tokens.copyNow") }),
|
|
1356
1408
|
" (",
|
|
1357
1409
|
minted.name,
|
|
1358
1410
|
")",
|
|
@@ -1383,8 +1435,8 @@ function TokensScreen({ client }) {
|
|
|
1383
1435
|
name: name.trim(),
|
|
1384
1436
|
scopes,
|
|
1385
1437
|
...days && Number.isInteger(d) && d > 0 ? { expiresInDays: d } : {}
|
|
1386
|
-
}).then((
|
|
1387
|
-
setMinted({ name:
|
|
1438
|
+
}).then((t3) => {
|
|
1439
|
+
setMinted({ name: t3.name, token: t3.token });
|
|
1388
1440
|
setName("");
|
|
1389
1441
|
setDays("");
|
|
1390
1442
|
}).catch(() => {
|
|
@@ -1396,9 +1448,9 @@ function TokensScreen({ client }) {
|
|
|
1396
1448
|
{
|
|
1397
1449
|
value: name,
|
|
1398
1450
|
onChange: (e) => setName(e.target.value),
|
|
1399
|
-
placeholder: "
|
|
1451
|
+
placeholder: t2("tokens.namePlaceholder"),
|
|
1400
1452
|
style: styles.input,
|
|
1401
|
-
"aria-label": "
|
|
1453
|
+
"aria-label": t2("tokens.nameLabel")
|
|
1402
1454
|
}
|
|
1403
1455
|
),
|
|
1404
1456
|
ALL.map((s) => /* @__PURE__ */ jsxs10(
|
|
@@ -1415,7 +1467,7 @@ function TokensScreen({ client }) {
|
|
|
1415
1467
|
children: [
|
|
1416
1468
|
/* @__PURE__ */ jsx10("input", { type: "checkbox", checked: scopes.includes(s), onChange: () => toggle(s) }),
|
|
1417
1469
|
" ",
|
|
1418
|
-
s
|
|
1470
|
+
t2(`tokens.scope.${s}`)
|
|
1419
1471
|
]
|
|
1420
1472
|
},
|
|
1421
1473
|
s
|
|
@@ -1425,9 +1477,9 @@ function TokensScreen({ client }) {
|
|
|
1425
1477
|
{
|
|
1426
1478
|
value: days,
|
|
1427
1479
|
onChange: (e) => setDays(e.target.value),
|
|
1428
|
-
placeholder: "
|
|
1480
|
+
placeholder: t2("tokens.daysPlaceholder"),
|
|
1429
1481
|
style: { ...styles.input, width: 140 },
|
|
1430
|
-
"aria-label": "
|
|
1482
|
+
"aria-label": t2("tokens.daysLabel")
|
|
1431
1483
|
}
|
|
1432
1484
|
),
|
|
1433
1485
|
/* @__PURE__ */ jsxs10(
|
|
@@ -1438,7 +1490,7 @@ function TokensScreen({ client }) {
|
|
|
1438
1490
|
disabled: !name.trim() || scopes.length === 0 || isLoading,
|
|
1439
1491
|
children: [
|
|
1440
1492
|
/* @__PURE__ */ jsx10(Icon, { name: "plus", size: 14 }),
|
|
1441
|
-
"
|
|
1493
|
+
t2("tokens.issue")
|
|
1442
1494
|
]
|
|
1443
1495
|
}
|
|
1444
1496
|
)
|
|
@@ -1447,58 +1499,60 @@ function TokensScreen({ client }) {
|
|
|
1447
1499
|
),
|
|
1448
1500
|
report?.issued && report.issued.length > 0 ? /* @__PURE__ */ jsxs10("table", { style: styles.table, children: [
|
|
1449
1501
|
/* @__PURE__ */ jsx10("thead", { children: /* @__PURE__ */ jsxs10("tr", { children: [
|
|
1450
|
-
/* @__PURE__ */ jsx10("th", { style: styles.th, children: "
|
|
1451
|
-
/* @__PURE__ */ jsx10("th", { style: styles.th, children: "
|
|
1452
|
-
/* @__PURE__ */ jsx10("th", { style: styles.th, children: "
|
|
1453
|
-
/* @__PURE__ */ jsx10("th", { style: styles.th, children: "
|
|
1454
|
-
/* @__PURE__ */ jsx10("th", { style: styles.th, children: "
|
|
1502
|
+
/* @__PURE__ */ jsx10("th", { style: styles.th, children: t2("tokens.col.name") }),
|
|
1503
|
+
/* @__PURE__ */ jsx10("th", { style: styles.th, children: t2("tokens.col.scopes") }),
|
|
1504
|
+
/* @__PURE__ */ jsx10("th", { style: styles.th, children: t2("tokens.col.created") }),
|
|
1505
|
+
/* @__PURE__ */ jsx10("th", { style: styles.th, children: t2("tokens.col.expires") }),
|
|
1506
|
+
/* @__PURE__ */ jsx10("th", { style: styles.th, children: t2("tokens.col.lastUsed") }),
|
|
1455
1507
|
/* @__PURE__ */ jsx10("th", { style: styles.th })
|
|
1456
1508
|
] }) }),
|
|
1457
|
-
/* @__PURE__ */ jsx10("tbody", { children: report.issued.map((
|
|
1509
|
+
/* @__PURE__ */ jsx10("tbody", { children: report.issued.map((tk) => /* @__PURE__ */ jsxs10("tr", { children: [
|
|
1458
1510
|
/* @__PURE__ */ jsxs10("td", { style: styles.td, children: [
|
|
1459
|
-
|
|
1460
|
-
|
|
1511
|
+
tk.name,
|
|
1512
|
+
tk.revokedAt ? /* @__PURE__ */ jsxs10(Fragment5, { children: [
|
|
1461
1513
|
" ",
|
|
1462
|
-
/* @__PURE__ */ jsx10(Pill, { tone: "neutral", children: "revoked" })
|
|
1514
|
+
/* @__PURE__ */ jsx10(Pill, { tone: "neutral", children: t2("tokens.revoked") })
|
|
1463
1515
|
] }) : null
|
|
1464
1516
|
] }),
|
|
1465
|
-
/* @__PURE__ */ jsx10("td", { style: { ...styles.td, ...styles.mono }, children:
|
|
1517
|
+
/* @__PURE__ */ jsx10("td", { style: { ...styles.td, ...styles.mono }, children: tk.scopes.map((s) => t2(`tokens.scope.${s}`)).join(", ") }),
|
|
1466
1518
|
/* @__PURE__ */ jsxs10("td", { style: { ...styles.td, ...styles.muted }, children: [
|
|
1467
|
-
|
|
1519
|
+
formatAdminDate4(tk.createdAt, locale, "date"),
|
|
1468
1520
|
" \xB7 ",
|
|
1469
|
-
|
|
1521
|
+
tk.createdBy
|
|
1470
1522
|
] }),
|
|
1471
|
-
/* @__PURE__ */ jsx10("td", { style: { ...styles.td, ...styles.muted }, children:
|
|
1472
|
-
/* @__PURE__ */ jsx10("td", { style: { ...styles.td, ...styles.muted }, children:
|
|
1473
|
-
/* @__PURE__ */ jsx10("td", { style: styles.td, children:
|
|
1523
|
+
/* @__PURE__ */ jsx10("td", { style: { ...styles.td, ...styles.muted }, children: tk.expiresAt ? formatAdminDate4(tk.expiresAt, locale, "date") : t2("common.never") }),
|
|
1524
|
+
/* @__PURE__ */ jsx10("td", { style: { ...styles.td, ...styles.muted }, children: tk.lastUsedAt ? formatAdminDate4(tk.lastUsedAt, locale) : t2("common.never") }),
|
|
1525
|
+
/* @__PURE__ */ jsx10("td", { style: styles.td, children: tk.revokedAt ? null : /* @__PURE__ */ jsx10(
|
|
1474
1526
|
"button",
|
|
1475
1527
|
{
|
|
1476
1528
|
type: "button",
|
|
1477
1529
|
style: styles.buttonDanger,
|
|
1478
1530
|
onClick: () => {
|
|
1479
|
-
if (window.confirm(
|
|
1480
|
-
|
|
1481
|
-
))
|
|
1482
|
-
void revoke(t2.id).catch(() => {
|
|
1531
|
+
if (window.confirm(t2("tokens.revokeConfirm", { name: tk.name })))
|
|
1532
|
+
void revoke(tk.id).catch(() => {
|
|
1483
1533
|
});
|
|
1484
1534
|
},
|
|
1485
|
-
children: "
|
|
1535
|
+
children: t2("tokens.revoke")
|
|
1486
1536
|
}
|
|
1487
1537
|
) })
|
|
1488
|
-
] },
|
|
1489
|
-
] }) : /* @__PURE__ */ jsx10(Empty, { icon: "tokens", title: "
|
|
1538
|
+
] }, tk.id)) })
|
|
1539
|
+
] }) : /* @__PURE__ */ jsx10(Empty, { icon: "tokens", title: t2("tokens.emptyTitle"), children: t2("tokens.emptyBody") })
|
|
1490
1540
|
] }),
|
|
1491
|
-
/* @__PURE__ */ jsx10("h2", { style: styles.subtitle, children: "
|
|
1492
|
-
report && report.legacy.length === 0 ? /* @__PURE__ */ jsx10("p", { style: styles.muted, children: "
|
|
1541
|
+
/* @__PURE__ */ jsx10("h2", { style: styles.subtitle, children: t2("tokens.legacyTitle") }),
|
|
1542
|
+
report && report.legacy.length === 0 ? /* @__PURE__ */ jsx10("p", { style: styles.muted, children: t2("tokens.legacyNone") }) : /* @__PURE__ */ jsx10("ul", { style: styles.list, children: report?.legacy.map((l) => /* @__PURE__ */ jsxs10("li", { style: styles.row, children: [
|
|
1493
1543
|
/* @__PURE__ */ jsx10("span", { style: styles.mono, children: l.module }),
|
|
1494
1544
|
" ",
|
|
1495
|
-
/* @__PURE__ */ jsx10("span", { style: styles.muted, children: "
|
|
1545
|
+
/* @__PURE__ */ jsx10("span", { style: styles.muted, children: t2("tokens.legacyRow") })
|
|
1496
1546
|
] }, l.module)) })
|
|
1497
1547
|
] });
|
|
1498
1548
|
}
|
|
1499
1549
|
|
|
1500
1550
|
// src/screens/UsersScreen.tsx
|
|
1501
|
-
import {
|
|
1551
|
+
import {
|
|
1552
|
+
createAdminT as createAdminT12,
|
|
1553
|
+
describeLocation,
|
|
1554
|
+
formatAdminDate as formatAdminDate7
|
|
1555
|
+
} from "@fonderie/client";
|
|
1502
1556
|
import {
|
|
1503
1557
|
useAdminLoginHistory,
|
|
1504
1558
|
useAdminUser,
|
|
@@ -1508,14 +1562,38 @@ import {
|
|
|
1508
1562
|
import { useState as useState6 } from "react";
|
|
1509
1563
|
|
|
1510
1564
|
// src/billing.ts
|
|
1565
|
+
import {
|
|
1566
|
+
createAdminT as createAdminT10,
|
|
1567
|
+
formatAdminDate as formatAdminDate5
|
|
1568
|
+
} from "@fonderie/client";
|
|
1511
1569
|
import { useEffect, useState as useState4 } from "react";
|
|
1512
|
-
function periodEnd(s) {
|
|
1570
|
+
function periodEnd(s, locale) {
|
|
1513
1571
|
if (!s.currentPeriodEnd) return null;
|
|
1514
|
-
const
|
|
1572
|
+
const t2 = createAdminT10(locale);
|
|
1573
|
+
const date = formatAdminDate5(s.currentPeriodEnd, locale, "date");
|
|
1515
1574
|
if (s.status === "canceled")
|
|
1516
|
-
return {
|
|
1517
|
-
|
|
1518
|
-
|
|
1575
|
+
return {
|
|
1576
|
+
label: new Date(s.currentPeriodEnd) < /* @__PURE__ */ new Date() ? t2("billing.ended") : t2("billing.ends"),
|
|
1577
|
+
date
|
|
1578
|
+
};
|
|
1579
|
+
if (s.cancelAtPeriodEnd) return { label: t2("billing.ends"), date };
|
|
1580
|
+
return { label: t2("billing.renews"), date };
|
|
1581
|
+
}
|
|
1582
|
+
var STATUS_KEYS = [
|
|
1583
|
+
"active",
|
|
1584
|
+
"trialing",
|
|
1585
|
+
"past_due",
|
|
1586
|
+
"unpaid",
|
|
1587
|
+
"canceled",
|
|
1588
|
+
"incomplete",
|
|
1589
|
+
"incomplete_expired",
|
|
1590
|
+
"paused"
|
|
1591
|
+
];
|
|
1592
|
+
function statusLabel(t2, status) {
|
|
1593
|
+
return STATUS_KEYS.includes(status) ? t2(`billing.statusLabel.${status}`) : status;
|
|
1594
|
+
}
|
|
1595
|
+
function intervalLabel(t2, interval) {
|
|
1596
|
+
return interval === "month" || interval === "year" ? t2(`billing.intervalLabel.${interval}`) : interval;
|
|
1519
1597
|
}
|
|
1520
1598
|
var statusTone = (status) => status === "active" ? "ok" : status === "trialing" ? "info" : status === "past_due" || status === "unpaid" ? "warn" : "neutral";
|
|
1521
1599
|
function useSubscriptionIndex(client) {
|
|
@@ -1550,21 +1628,31 @@ function useSubscriptionIndex(client) {
|
|
|
1550
1628
|
}
|
|
1551
1629
|
|
|
1552
1630
|
// src/screens/SubscriberBilling.tsx
|
|
1631
|
+
import {
|
|
1632
|
+
createAdminT as createAdminT11,
|
|
1633
|
+
formatAdminDate as formatAdminDate6
|
|
1634
|
+
} from "@fonderie/client";
|
|
1553
1635
|
import { useAdminSubscriber } from "@fonderie/react-admin";
|
|
1554
1636
|
import { useState as useState5 } from "react";
|
|
1555
1637
|
import { Fragment as Fragment6, jsx as jsx11, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
1556
|
-
function SubscriberBilling({ client, subscriber }) {
|
|
1557
|
-
const
|
|
1638
|
+
function SubscriberBilling({ client, subscriber, locale }) {
|
|
1639
|
+
const t2 = createAdminT11(locale);
|
|
1640
|
+
const LEDGER_KINDS = ["purchase", "grant", "usage", "refund", "adjustment", "expiry"];
|
|
1641
|
+
const ledgerKind = (kind) => LEDGER_KINDS.includes(kind) ? t2(`billing.ledgerKind.${kind}`) : kind;
|
|
1642
|
+
const [currency, setCurrency] = useState5("");
|
|
1643
|
+
const [currencyDraft, setCurrencyDraft] = useState5("");
|
|
1644
|
+
const { subscription, wallet, ledger, hasMoreLedger, isLoading, error, loadMoreLedger, grant } = useAdminSubscriber(client, subscriber, { limit: 20, ...currency ? { currency } : {} });
|
|
1558
1645
|
const [amount, setAmount] = useState5("");
|
|
1559
1646
|
const [note, setNote] = useState5("");
|
|
1560
1647
|
const [granted, setGranted] = useState5(null);
|
|
1561
|
-
if (isLoading && !wallet && !subscription)
|
|
1562
|
-
|
|
1648
|
+
if (isLoading && !wallet && !subscription)
|
|
1649
|
+
return /* @__PURE__ */ jsx11("p", { style: styles.status, children: t2("billing.loading") });
|
|
1650
|
+
const end = subscription ? periodEnd(subscription, locale) : null;
|
|
1563
1651
|
return /* @__PURE__ */ jsxs11(Fragment6, { children: [
|
|
1564
1652
|
error ? /* @__PURE__ */ jsx11("p", { style: styles.error, role: "alert", children: error.explanation }) : null,
|
|
1565
1653
|
/* @__PURE__ */ jsxs11("div", { style: { ...styles.grid, marginBottom: 16 }, children: [
|
|
1566
1654
|
/* @__PURE__ */ jsxs11("div", { style: styles.card, children: [
|
|
1567
|
-
/* @__PURE__ */ jsx11("div", { style: styles.statLabel, children: "
|
|
1655
|
+
/* @__PURE__ */ jsx11("div", { style: styles.statLabel, children: t2("billing.plan") }),
|
|
1568
1656
|
/* @__PURE__ */ jsxs11(
|
|
1569
1657
|
"div",
|
|
1570
1658
|
{
|
|
@@ -1576,14 +1664,14 @@ function SubscriberBilling({ client, subscriber }) {
|
|
|
1576
1664
|
flexWrap: "wrap"
|
|
1577
1665
|
},
|
|
1578
1666
|
children: [
|
|
1579
|
-
/* @__PURE__ */ jsx11("strong", { style: { fontSize: 18 }, children: subscription ? subscription.plan : "
|
|
1667
|
+
/* @__PURE__ */ jsx11("strong", { style: { fontSize: 18 }, children: subscription ? subscription.plan : t2("billing.free") }),
|
|
1580
1668
|
subscription ? /* @__PURE__ */ jsxs11(Fragment6, { children: [
|
|
1581
1669
|
/* @__PURE__ */ jsxs11("span", { style: styles.muted, children: [
|
|
1582
1670
|
"\xB7 ",
|
|
1583
|
-
subscription.interval
|
|
1671
|
+
intervalLabel(t2, subscription.interval)
|
|
1584
1672
|
] }),
|
|
1585
|
-
/* @__PURE__ */ jsx11(Pill, { tone: statusTone(subscription.status), children: subscription.status })
|
|
1586
|
-
] }) : /* @__PURE__ */ jsx11("span", { style: styles.muted, children: "
|
|
1673
|
+
/* @__PURE__ */ jsx11(Pill, { tone: statusTone(subscription.status), children: statusLabel(t2, subscription.status) })
|
|
1674
|
+
] }) : /* @__PURE__ */ jsx11("span", { style: styles.muted, children: t2("billing.noSubscription") })
|
|
1587
1675
|
]
|
|
1588
1676
|
}
|
|
1589
1677
|
),
|
|
@@ -1595,7 +1683,42 @@ function SubscriberBilling({ client, subscriber }) {
|
|
|
1595
1683
|
subscription?.providerSubscriptionId ? /* @__PURE__ */ jsx11("div", { style: { ...styles.statHint, fontFamily: "var(--fonderie-mono,monospace)" }, children: subscription.providerSubscriptionId }) : null
|
|
1596
1684
|
] }),
|
|
1597
1685
|
/* @__PURE__ */ jsxs11("div", { style: styles.card, children: [
|
|
1598
|
-
/* @__PURE__ */
|
|
1686
|
+
/* @__PURE__ */ jsxs11(
|
|
1687
|
+
"div",
|
|
1688
|
+
{
|
|
1689
|
+
style: {
|
|
1690
|
+
display: "flex",
|
|
1691
|
+
justifyContent: "space-between",
|
|
1692
|
+
alignItems: "center",
|
|
1693
|
+
gap: 8
|
|
1694
|
+
},
|
|
1695
|
+
children: [
|
|
1696
|
+
/* @__PURE__ */ jsx11("div", { style: styles.statLabel, children: t2("billing.credits") }),
|
|
1697
|
+
/* @__PURE__ */ jsx11(
|
|
1698
|
+
"form",
|
|
1699
|
+
{
|
|
1700
|
+
style: { display: "flex", gap: 4 },
|
|
1701
|
+
onSubmit: (e) => {
|
|
1702
|
+
e.preventDefault();
|
|
1703
|
+
setCurrency(currencyDraft.trim().toUpperCase());
|
|
1704
|
+
},
|
|
1705
|
+
children: /* @__PURE__ */ jsx11(
|
|
1706
|
+
"input",
|
|
1707
|
+
{
|
|
1708
|
+
value: currencyDraft,
|
|
1709
|
+
onChange: (e) => setCurrencyDraft(e.target.value),
|
|
1710
|
+
placeholder: wallet?.currency ?? t2("billing.currencyPlaceholder"),
|
|
1711
|
+
maxLength: 8,
|
|
1712
|
+
style: { ...styles.input, height: 26, width: 84, fontSize: 12 },
|
|
1713
|
+
"aria-label": t2("billing.currencyLabel"),
|
|
1714
|
+
title: t2("billing.currencyTitle")
|
|
1715
|
+
}
|
|
1716
|
+
)
|
|
1717
|
+
}
|
|
1718
|
+
)
|
|
1719
|
+
]
|
|
1720
|
+
}
|
|
1721
|
+
),
|
|
1599
1722
|
wallet ? /* @__PURE__ */ jsxs11(Fragment6, { children: [
|
|
1600
1723
|
/* @__PURE__ */ jsxs11("div", { style: styles.statValue, children: [
|
|
1601
1724
|
wallet.balance,
|
|
@@ -1603,13 +1726,15 @@ function SubscriberBilling({ client, subscriber }) {
|
|
|
1603
1726
|
/* @__PURE__ */ jsx11("span", { style: { fontSize: 14, fontWeight: 500 }, children: wallet.currency })
|
|
1604
1727
|
] }),
|
|
1605
1728
|
/* @__PURE__ */ jsxs11("div", { style: styles.statHint, children: [
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
wallet.grantedExpiresAt ?
|
|
1729
|
+
t2("billing.breakdown", {
|
|
1730
|
+
permanent: wallet.purchased ?? "0",
|
|
1731
|
+
allowance: wallet.granted ?? "0"
|
|
1732
|
+
}),
|
|
1733
|
+
wallet.grantedExpiresAt ? t2("billing.expires", {
|
|
1734
|
+
date: formatAdminDate6(wallet.grantedExpiresAt, locale, "date")
|
|
1735
|
+
}) : ""
|
|
1611
1736
|
] })
|
|
1612
|
-
] }) : /* @__PURE__ */ jsx11("div", { style: styles.statHint, children: "
|
|
1737
|
+
] }) : /* @__PURE__ */ jsx11("div", { style: styles.statHint, children: t2("billing.noWallet") })
|
|
1613
1738
|
] })
|
|
1614
1739
|
] }),
|
|
1615
1740
|
wallet ? /* @__PURE__ */ jsxs11(
|
|
@@ -1631,23 +1756,25 @@ function SubscriberBilling({ client, subscriber }) {
|
|
|
1631
1756
|
...note ? { description: note } : {},
|
|
1632
1757
|
idempotencyKey: key
|
|
1633
1758
|
}).then(() => {
|
|
1634
|
-
setGranted(
|
|
1759
|
+
setGranted(
|
|
1760
|
+
t2("billing.granted", { amount: amount.trim(), currency: wallet.currency })
|
|
1761
|
+
);
|
|
1635
1762
|
setAmount("");
|
|
1636
1763
|
setNote("");
|
|
1637
1764
|
}).catch(() => {
|
|
1638
1765
|
});
|
|
1639
1766
|
},
|
|
1640
1767
|
children: [
|
|
1641
|
-
/* @__PURE__ */ jsx11("strong", { style: { fontSize: 13.5, marginRight: 4 }, children: "
|
|
1768
|
+
/* @__PURE__ */ jsx11("strong", { style: { fontSize: 13.5, marginRight: 4 }, children: t2("billing.grantCredits") }),
|
|
1642
1769
|
/* @__PURE__ */ jsx11(
|
|
1643
1770
|
"input",
|
|
1644
1771
|
{
|
|
1645
1772
|
value: amount,
|
|
1646
1773
|
onChange: (e) => setAmount(e.target.value),
|
|
1647
|
-
placeholder:
|
|
1774
|
+
placeholder: t2("billing.amountPlaceholder", { currency: wallet.currency }),
|
|
1648
1775
|
inputMode: "numeric",
|
|
1649
1776
|
style: { ...styles.input, width: 150 },
|
|
1650
|
-
"aria-label": "
|
|
1777
|
+
"aria-label": t2("billing.amountLabel")
|
|
1651
1778
|
}
|
|
1652
1779
|
),
|
|
1653
1780
|
/* @__PURE__ */ jsx11(
|
|
@@ -1655,9 +1782,9 @@ function SubscriberBilling({ client, subscriber }) {
|
|
|
1655
1782
|
{
|
|
1656
1783
|
value: note,
|
|
1657
1784
|
onChange: (e) => setNote(e.target.value),
|
|
1658
|
-
placeholder: "
|
|
1785
|
+
placeholder: t2("billing.reasonPlaceholder"),
|
|
1659
1786
|
style: { ...styles.input, flex: 1, minWidth: 180 },
|
|
1660
|
-
"aria-label": "
|
|
1787
|
+
"aria-label": t2("billing.reasonLabel")
|
|
1661
1788
|
}
|
|
1662
1789
|
),
|
|
1663
1790
|
/* @__PURE__ */ jsxs11(
|
|
@@ -1668,7 +1795,7 @@ function SubscriberBilling({ client, subscriber }) {
|
|
|
1668
1795
|
disabled: !/^\d+$/.test(amount.trim()),
|
|
1669
1796
|
children: [
|
|
1670
1797
|
/* @__PURE__ */ jsx11(Icon, { name: "plus", size: 14 }),
|
|
1671
|
-
"
|
|
1798
|
+
t2("billing.grant")
|
|
1672
1799
|
]
|
|
1673
1800
|
}
|
|
1674
1801
|
),
|
|
@@ -1676,20 +1803,20 @@ function SubscriberBilling({ client, subscriber }) {
|
|
|
1676
1803
|
]
|
|
1677
1804
|
}
|
|
1678
1805
|
) : null,
|
|
1679
|
-
wallet ? ledger.length === 0 ? /* @__PURE__ */ jsx11(Empty, { icon: "subscriber", title: "
|
|
1806
|
+
wallet ? ledger.length === 0 ? /* @__PURE__ */ jsx11(Empty, { icon: "subscriber", title: t2("billing.noMovements") }) : /* @__PURE__ */ jsxs11(Fragment6, { children: [
|
|
1680
1807
|
/* @__PURE__ */ jsxs11("table", { style: styles.table, children: [
|
|
1681
1808
|
/* @__PURE__ */ jsx11("thead", { children: /* @__PURE__ */ jsxs11("tr", { children: [
|
|
1682
|
-
/* @__PURE__ */ jsx11("th", { style: styles.th, children: "
|
|
1683
|
-
/* @__PURE__ */ jsx11("th", { style: styles.th, children: "
|
|
1684
|
-
/* @__PURE__ */ jsx11("th", { style: styles.th, children: "
|
|
1685
|
-
/* @__PURE__ */ jsx11("th", { style: styles.th, children: "
|
|
1809
|
+
/* @__PURE__ */ jsx11("th", { style: styles.th, children: t2("billing.col.when") }),
|
|
1810
|
+
/* @__PURE__ */ jsx11("th", { style: styles.th, children: t2("billing.col.kind") }),
|
|
1811
|
+
/* @__PURE__ */ jsx11("th", { style: styles.th, children: t2("billing.col.amount") }),
|
|
1812
|
+
/* @__PURE__ */ jsx11("th", { style: styles.th, children: t2("billing.col.note") })
|
|
1686
1813
|
] }) }),
|
|
1687
|
-
/* @__PURE__ */ jsx11("tbody", { children: ledger.map((
|
|
1688
|
-
/* @__PURE__ */ jsx11("td", { style: { ...styles.td, ...styles.muted, whiteSpace: "nowrap" }, children:
|
|
1689
|
-
/* @__PURE__ */ jsx11("td", { style: styles.td, children:
|
|
1690
|
-
/* @__PURE__ */ jsx11("td", { style: { ...styles.td, ...styles.mono }, children:
|
|
1691
|
-
/* @__PURE__ */ jsx11("td", { style: { ...styles.td, ...styles.muted }, children:
|
|
1692
|
-
] },
|
|
1814
|
+
/* @__PURE__ */ jsx11("tbody", { children: ledger.map((tx) => /* @__PURE__ */ jsxs11("tr", { children: [
|
|
1815
|
+
/* @__PURE__ */ jsx11("td", { style: { ...styles.td, ...styles.muted, whiteSpace: "nowrap" }, children: formatAdminDate6(tx.createdAt, locale) }),
|
|
1816
|
+
/* @__PURE__ */ jsx11("td", { style: styles.td, children: ledgerKind(tx.type) }),
|
|
1817
|
+
/* @__PURE__ */ jsx11("td", { style: { ...styles.td, ...styles.mono }, children: tx.amount }),
|
|
1818
|
+
/* @__PURE__ */ jsx11("td", { style: { ...styles.td, ...styles.muted }, children: tx.description ?? "" })
|
|
1819
|
+
] }, tx.id)) })
|
|
1693
1820
|
] }),
|
|
1694
1821
|
hasMoreLedger ? /* @__PURE__ */ jsx11(
|
|
1695
1822
|
"button",
|
|
@@ -1697,7 +1824,7 @@ function SubscriberBilling({ client, subscriber }) {
|
|
|
1697
1824
|
type: "button",
|
|
1698
1825
|
style: { ...styles.button, marginTop: 8 },
|
|
1699
1826
|
onClick: () => void loadMoreLedger(),
|
|
1700
|
-
children: "
|
|
1827
|
+
children: t2("common.loadMore")
|
|
1701
1828
|
}
|
|
1702
1829
|
) : null
|
|
1703
1830
|
] }) : null
|
|
@@ -1710,8 +1837,10 @@ function UsersScreen({
|
|
|
1710
1837
|
client,
|
|
1711
1838
|
pageSize = 50,
|
|
1712
1839
|
billingClient,
|
|
1713
|
-
openUserId
|
|
1840
|
+
openUserId,
|
|
1841
|
+
locale
|
|
1714
1842
|
}) {
|
|
1843
|
+
const t2 = createAdminT12(locale);
|
|
1715
1844
|
const [input, setInput] = useState6("");
|
|
1716
1845
|
const [selected, setSelected] = useState6(
|
|
1717
1846
|
openUserId ? { id: openUserId } : null
|
|
@@ -1729,19 +1858,13 @@ function UsersScreen({
|
|
|
1729
1858
|
const userId = user?.id ?? null;
|
|
1730
1859
|
const sessions = useAdminUserSessions(client, userId);
|
|
1731
1860
|
const history = useAdminLoginHistory(client, userId, { limit: 20 });
|
|
1732
|
-
const yesNo = (v) => v ? /* @__PURE__ */ jsx12(Pill, { tone: "ok", children: "yes" }) : /* @__PURE__ */ jsx12(Pill, { tone: "neutral", children: "no" });
|
|
1861
|
+
const yesNo = (v) => v ? /* @__PURE__ */ jsx12(Pill, { tone: "ok", children: t2("common.yes") }) : /* @__PURE__ */ jsx12(Pill, { tone: "neutral", children: t2("common.no") });
|
|
1733
1862
|
const clear = () => {
|
|
1734
1863
|
setSelected(null);
|
|
1735
1864
|
setInput("");
|
|
1736
1865
|
};
|
|
1737
1866
|
return /* @__PURE__ */ jsxs12("div", { style: styles.container, children: [
|
|
1738
|
-
/* @__PURE__ */ jsx12(
|
|
1739
|
-
PageHeader,
|
|
1740
|
-
{
|
|
1741
|
-
title: "Users",
|
|
1742
|
-
lead: "Everyone signed up. Open an account for its sessions, sign-ins and the suspend and sign-out controls."
|
|
1743
|
-
}
|
|
1744
|
-
),
|
|
1867
|
+
/* @__PURE__ */ jsx12(PageHeader, { title: t2("users.title"), lead: t2("users.lead") }),
|
|
1745
1868
|
/* @__PURE__ */ jsxs12(
|
|
1746
1869
|
"form",
|
|
1747
1870
|
{
|
|
@@ -1758,18 +1881,18 @@ function UsersScreen({
|
|
|
1758
1881
|
type: "email",
|
|
1759
1882
|
value: input,
|
|
1760
1883
|
onChange: (e) => setInput(e.target.value),
|
|
1761
|
-
placeholder: "
|
|
1884
|
+
placeholder: t2("users.emailPlaceholder"),
|
|
1762
1885
|
style: { ...styles.input, minWidth: 280 },
|
|
1763
|
-
"aria-label": "
|
|
1886
|
+
"aria-label": t2("users.emailLabel")
|
|
1764
1887
|
}
|
|
1765
1888
|
),
|
|
1766
1889
|
/* @__PURE__ */ jsxs12("button", { type: "submit", style: styles.buttonPrimary, disabled: isLoading, children: [
|
|
1767
1890
|
/* @__PURE__ */ jsx12(Icon, { name: "search", size: 14 }),
|
|
1768
|
-
"
|
|
1891
|
+
t2("common.lookUp")
|
|
1769
1892
|
] }),
|
|
1770
1893
|
selected ? /* @__PURE__ */ jsxs12("button", { type: "button", style: styles.buttonGhost, onClick: clear, children: [
|
|
1771
1894
|
/* @__PURE__ */ jsx12(Icon, { name: "back", size: 14 }),
|
|
1772
|
-
"
|
|
1895
|
+
t2("users.allUsers")
|
|
1773
1896
|
] }) : /* @__PURE__ */ jsx12(
|
|
1774
1897
|
"button",
|
|
1775
1898
|
{
|
|
@@ -1777,7 +1900,7 @@ function UsersScreen({
|
|
|
1777
1900
|
style: styles.button,
|
|
1778
1901
|
onClick: () => void list.refresh(),
|
|
1779
1902
|
disabled: list.isLoading,
|
|
1780
|
-
children: "
|
|
1903
|
+
children: t2("common.refresh")
|
|
1781
1904
|
}
|
|
1782
1905
|
),
|
|
1783
1906
|
!selected ? /* @__PURE__ */ jsx12(
|
|
@@ -1791,7 +1914,7 @@ function UsersScreen({
|
|
|
1791
1914
|
padding: 0,
|
|
1792
1915
|
minWidth: 0
|
|
1793
1916
|
},
|
|
1794
|
-
"aria-label": "
|
|
1917
|
+
"aria-label": t2("users.whichAccounts"),
|
|
1795
1918
|
children: [false, true].map((d) => /* @__PURE__ */ jsx12(
|
|
1796
1919
|
"button",
|
|
1797
1920
|
{
|
|
@@ -1802,7 +1925,7 @@ function UsersScreen({
|
|
|
1802
1925
|
...showDeleted === d ? styles.buttonPrimary : styles.button,
|
|
1803
1926
|
height: 28
|
|
1804
1927
|
},
|
|
1805
|
-
children: d ? "
|
|
1928
|
+
children: d ? t2("users.deletedAccounts") : t2("users.activeAccounts")
|
|
1806
1929
|
},
|
|
1807
1930
|
String(d)
|
|
1808
1931
|
))
|
|
@@ -1811,34 +1934,39 @@ function UsersScreen({
|
|
|
1811
1934
|
]
|
|
1812
1935
|
}
|
|
1813
1936
|
),
|
|
1814
|
-
error && !(error.status === 404 && selected?.id) ? /* @__PURE__ */ jsx12("p", { style: styles.error, role: "alert", children: error.status === 404 ? "
|
|
1937
|
+
error && !(error.status === 404 && selected?.id) ? /* @__PURE__ */ jsx12("p", { style: styles.error, role: "alert", children: error.status === 404 ? t2("users.noUserWithEmail") : error.explanation }) : null,
|
|
1815
1938
|
error?.status === 404 && selected?.id ? /* @__PURE__ */ jsxs12(Fragment7, { children: [
|
|
1816
1939
|
/* @__PURE__ */ jsxs12("div", { style: styles.notice, role: "status", children: [
|
|
1817
|
-
/* @__PURE__ */
|
|
1940
|
+
/* @__PURE__ */ jsxs12("strong", { children: [
|
|
1941
|
+
t2("users.missingIdPrefix"),
|
|
1942
|
+
" "
|
|
1943
|
+
] }),
|
|
1818
1944
|
/* @__PURE__ */ jsx12("code", { style: styles.code, children: selected.id }),
|
|
1819
1945
|
/* @__PURE__ */ jsx12("strong", { children: "." }),
|
|
1820
|
-
"
|
|
1946
|
+
" ",
|
|
1947
|
+
t2("users.missingIdBody")
|
|
1821
1948
|
] }),
|
|
1822
1949
|
billingClient ? /* @__PURE__ */ jsxs12(Fragment7, { children: [
|
|
1823
|
-
/* @__PURE__ */ jsx12("h2", { style: styles.subtitle, children: "
|
|
1950
|
+
/* @__PURE__ */ jsx12("h2", { style: styles.subtitle, children: t2("users.planCredits") }),
|
|
1824
1951
|
/* @__PURE__ */ jsx12(
|
|
1825
1952
|
SubscriberBilling,
|
|
1826
1953
|
{
|
|
1827
1954
|
client: billingClient,
|
|
1828
|
-
subscriber: { type: "user", id: selected.id }
|
|
1955
|
+
subscriber: { type: "user", id: selected.id },
|
|
1956
|
+
locale
|
|
1829
1957
|
}
|
|
1830
1958
|
)
|
|
1831
1959
|
] }) : null
|
|
1832
1960
|
] }) : null,
|
|
1833
1961
|
!selected ? /* @__PURE__ */ jsxs12(Fragment7, { children: [
|
|
1834
1962
|
list.error ? /* @__PURE__ */ jsx12("p", { style: styles.error, role: "alert", children: list.error.explanation }) : null,
|
|
1835
|
-
list.users.length === 0 && !list.isLoading ? /* @__PURE__ */ jsx12(Empty, { icon: "users", title: "
|
|
1963
|
+
list.users.length === 0 && !list.isLoading ? /* @__PURE__ */ jsx12(Empty, { icon: "users", title: t2("users.emptyTitle"), children: t2("users.emptyBody") }) : /* @__PURE__ */ jsxs12("table", { style: styles.table, children: [
|
|
1836
1964
|
/* @__PURE__ */ jsx12("thead", { children: /* @__PURE__ */ jsxs12("tr", { children: [
|
|
1837
|
-
/* @__PURE__ */ jsx12("th", { style: styles.th, children: "
|
|
1838
|
-
/* @__PURE__ */ jsx12("th", { style: styles.th, children: "
|
|
1839
|
-
billingClient ? /* @__PURE__ */ jsx12("th", { style: styles.th, children: "
|
|
1840
|
-
/* @__PURE__ */ jsx12("th", { style: styles.th, children: "
|
|
1841
|
-
/* @__PURE__ */ jsx12("th", { style: styles.th, children: "
|
|
1965
|
+
/* @__PURE__ */ jsx12("th", { style: styles.th, children: t2("users.col.email") }),
|
|
1966
|
+
/* @__PURE__ */ jsx12("th", { style: styles.th, children: t2("users.col.name") }),
|
|
1967
|
+
billingClient ? /* @__PURE__ */ jsx12("th", { style: styles.th, children: t2("users.col.plan") }) : null,
|
|
1968
|
+
/* @__PURE__ */ jsx12("th", { style: styles.th, children: t2("users.col.created") }),
|
|
1969
|
+
/* @__PURE__ */ jsx12("th", { style: styles.th, children: t2("users.col.status") })
|
|
1842
1970
|
] }) }),
|
|
1843
1971
|
/* @__PURE__ */ jsx12("tbody", { children: list.users.map((u) => /* @__PURE__ */ jsxs12("tr", { children: [
|
|
1844
1972
|
/* @__PURE__ */ jsx12("td", { style: styles.td, children: /* @__PURE__ */ jsx12(
|
|
@@ -1855,29 +1983,29 @@ function UsersScreen({
|
|
|
1855
1983
|
const sub = plans?.get(`user/${u.id}`);
|
|
1856
1984
|
if (!plans) return /* @__PURE__ */ jsx12("span", { style: styles.muted, children: "\u2026" });
|
|
1857
1985
|
if (!sub || sub.status === "canceled")
|
|
1858
|
-
return /* @__PURE__ */ jsx12("span", { style: styles.muted, children: "free" });
|
|
1986
|
+
return /* @__PURE__ */ jsx12("span", { style: styles.muted, children: t2("common.status.free") });
|
|
1859
1987
|
return /* @__PURE__ */ jsxs12(Fragment7, { children: [
|
|
1860
1988
|
/* @__PURE__ */ jsx12("strong", { children: sub.plan }),
|
|
1861
1989
|
" ",
|
|
1862
|
-
sub.status !== "active" ? /* @__PURE__ */ jsx12(Pill, { tone: statusTone(sub.status), children: sub.status }) : null
|
|
1990
|
+
sub.status !== "active" ? /* @__PURE__ */ jsx12(Pill, { tone: statusTone(sub.status), children: statusLabel(t2, sub.status) }) : null
|
|
1863
1991
|
] });
|
|
1864
1992
|
})() }) : null,
|
|
1865
|
-
/* @__PURE__ */ jsx12("td", { style: styles.td, children:
|
|
1993
|
+
/* @__PURE__ */ jsx12("td", { style: styles.td, children: formatAdminDate7(u.createdAt, locale, "date") }),
|
|
1866
1994
|
/* @__PURE__ */ jsxs12("td", { style: styles.td, children: [
|
|
1867
|
-
u.suspended ? /* @__PURE__ */ jsx12(Pill, { tone: "warn", children: "suspended" }) : null,
|
|
1868
|
-
u.deletedAt ? /* @__PURE__ */ jsx12(Pill, { tone: "neutral", children: "deleted" }) : null,
|
|
1869
|
-
!u.suspended && !u.deletedAt ? /* @__PURE__ */ jsx12(Pill, { tone: "ok", children: "active" }) : null
|
|
1995
|
+
u.suspended ? /* @__PURE__ */ jsx12(Pill, { tone: "warn", children: t2("common.status.suspended") }) : null,
|
|
1996
|
+
u.deletedAt ? /* @__PURE__ */ jsx12(Pill, { tone: "neutral", children: t2("common.status.deleted") }) : null,
|
|
1997
|
+
!u.suspended && !u.deletedAt ? /* @__PURE__ */ jsx12(Pill, { tone: "ok", children: t2("common.status.active") }) : null
|
|
1870
1998
|
] })
|
|
1871
1999
|
] }, u.id)) })
|
|
1872
2000
|
] }),
|
|
1873
|
-
list.isLoading ? /* @__PURE__ */ jsx12("p", { style: styles.status, children: "
|
|
2001
|
+
list.isLoading ? /* @__PURE__ */ jsx12("p", { style: styles.status, children: t2("common.loading") }) : null,
|
|
1874
2002
|
list.hasMore && !list.isLoading ? /* @__PURE__ */ jsx12(
|
|
1875
2003
|
"button",
|
|
1876
2004
|
{
|
|
1877
2005
|
type: "button",
|
|
1878
2006
|
style: { ...styles.button, marginTop: 8 },
|
|
1879
2007
|
onClick: () => void list.loadMore(),
|
|
1880
|
-
children: "
|
|
2008
|
+
children: t2("common.loadMore")
|
|
1881
2009
|
}
|
|
1882
2010
|
) : null
|
|
1883
2011
|
] }) : null,
|
|
@@ -1885,49 +2013,48 @@ function UsersScreen({
|
|
|
1885
2013
|
/* @__PURE__ */ jsxs12("h2", { style: styles.subtitle, children: [
|
|
1886
2014
|
user.firstName || user.lastName ? `${user.firstName} ${user.lastName}`.trim() : user.email,
|
|
1887
2015
|
" ",
|
|
1888
|
-
user.suspended ? /* @__PURE__ */ jsx12(Pill, { tone: "warn", children: "suspended" }) : null,
|
|
1889
|
-
user.deletedAt ? /* @__PURE__ */ jsx12(Pill, { tone: "neutral", children: "deleted" }) : null
|
|
2016
|
+
user.suspended ? /* @__PURE__ */ jsx12(Pill, { tone: "warn", children: t2("common.status.suspended") }) : null,
|
|
2017
|
+
user.deletedAt ? /* @__PURE__ */ jsx12(Pill, { tone: "neutral", children: t2("common.status.deleted") }) : null
|
|
1890
2018
|
] }),
|
|
1891
2019
|
/* @__PURE__ */ jsx12("table", { style: styles.table, children: /* @__PURE__ */ jsxs12("tbody", { children: [
|
|
1892
2020
|
/* @__PURE__ */ jsxs12("tr", { children: [
|
|
1893
|
-
/* @__PURE__ */ jsx12("td", { style: styles.td, children: "id" }),
|
|
2021
|
+
/* @__PURE__ */ jsx12("td", { style: styles.td, children: t2("users.field.id") }),
|
|
1894
2022
|
/* @__PURE__ */ jsx12("td", { style: { ...styles.td, ...styles.mono }, children: user.id })
|
|
1895
2023
|
] }),
|
|
1896
2024
|
/* @__PURE__ */ jsxs12("tr", { children: [
|
|
1897
|
-
/* @__PURE__ */ jsx12("td", { style: styles.td, children: "email" }),
|
|
2025
|
+
/* @__PURE__ */ jsx12("td", { style: styles.td, children: t2("users.field.email") }),
|
|
1898
2026
|
/* @__PURE__ */ jsxs12("td", { style: styles.td, children: [
|
|
1899
2027
|
user.email,
|
|
1900
|
-
" \xB7
|
|
2028
|
+
" \xB7 ",
|
|
2029
|
+
t2("users.field.verified"),
|
|
2030
|
+
" ",
|
|
1901
2031
|
yesNo(user.isEmailVerified)
|
|
1902
2032
|
] })
|
|
1903
2033
|
] }),
|
|
1904
2034
|
/* @__PURE__ */ jsxs12("tr", { children: [
|
|
1905
|
-
/* @__PURE__ */ jsx12("td", { style: styles.td, children: "
|
|
2035
|
+
/* @__PURE__ */ jsx12("td", { style: styles.td, children: t2("users.field.mfa") }),
|
|
1906
2036
|
/* @__PURE__ */ jsx12("td", { style: styles.td, children: yesNo(user.mfaEnabled) })
|
|
1907
2037
|
] }),
|
|
1908
2038
|
/* @__PURE__ */ jsxs12("tr", { children: [
|
|
1909
|
-
/* @__PURE__ */ jsx12("td", { style: styles.td, children: "provider" }),
|
|
2039
|
+
/* @__PURE__ */ jsx12("td", { style: styles.td, children: t2("users.field.provider") }),
|
|
1910
2040
|
/* @__PURE__ */ jsxs12("td", { style: styles.td, children: [
|
|
1911
|
-
user.provider || "
|
|
1912
|
-
user.hasPassword ? "" :
|
|
2041
|
+
user.provider || t2("users.passwordProvider"),
|
|
2042
|
+
user.hasPassword ? "" : ` \xB7 ${t2("users.noPasswordSet")}`
|
|
1913
2043
|
] })
|
|
1914
2044
|
] }),
|
|
1915
2045
|
/* @__PURE__ */ jsxs12("tr", { children: [
|
|
1916
|
-
/* @__PURE__ */ jsx12("td", { style: styles.td, children: "
|
|
1917
|
-
/* @__PURE__ */ jsx12("td", { style: styles.td, children: user.lastLogin ?
|
|
2046
|
+
/* @__PURE__ */ jsx12("td", { style: styles.td, children: t2("users.field.lastLogin") }),
|
|
2047
|
+
/* @__PURE__ */ jsx12("td", { style: styles.td, children: user.lastLogin ? formatAdminDate7(user.lastLogin, locale) : /* @__PURE__ */ jsx12("span", { style: styles.muted, children: t2("common.never") }) })
|
|
1918
2048
|
] }),
|
|
1919
2049
|
/* @__PURE__ */ jsxs12("tr", { children: [
|
|
1920
|
-
/* @__PURE__ */ jsx12("td", { style: styles.td, children: "created" }),
|
|
1921
|
-
/* @__PURE__ */ jsx12("td", { style: styles.td, children:
|
|
2050
|
+
/* @__PURE__ */ jsx12("td", { style: styles.td, children: t2("users.field.created") }),
|
|
2051
|
+
/* @__PURE__ */ jsx12("td", { style: styles.td, children: formatAdminDate7(user.createdAt, locale) })
|
|
1922
2052
|
] })
|
|
1923
2053
|
] }) }),
|
|
1924
2054
|
user.deletedAt ? /* @__PURE__ */ jsxs12("div", { style: { ...styles.notice, marginTop: 12 }, role: "status", children: [
|
|
1925
|
-
/* @__PURE__ */
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
"."
|
|
1929
|
-
] }),
|
|
1930
|
-
" The account cannot sign in, and it is erased when the retention purge runs. Its billing records stay."
|
|
2055
|
+
/* @__PURE__ */ jsx12("strong", { children: t2("users.deletedOn", { date: formatAdminDate7(user.deletedAt, locale) }) }),
|
|
2056
|
+
" ",
|
|
2057
|
+
t2("users.deletedBody")
|
|
1931
2058
|
] }) : /* @__PURE__ */ jsxs12("div", { style: { ...styles.toolbar, marginTop: 12 }, children: [
|
|
1932
2059
|
user.suspended ? /* @__PURE__ */ jsx12(
|
|
1933
2060
|
"button",
|
|
@@ -1936,7 +2063,7 @@ function UsersScreen({
|
|
|
1936
2063
|
style: styles.button,
|
|
1937
2064
|
onClick: () => void unsuspend(),
|
|
1938
2065
|
disabled: isLoading,
|
|
1939
|
-
children: "
|
|
2066
|
+
children: t2("users.unsuspend")
|
|
1940
2067
|
}
|
|
1941
2068
|
) : /* @__PURE__ */ jsx12(
|
|
1942
2069
|
"button",
|
|
@@ -1945,7 +2072,7 @@ function UsersScreen({
|
|
|
1945
2072
|
style: styles.buttonDanger,
|
|
1946
2073
|
onClick: () => void suspend(),
|
|
1947
2074
|
disabled: isLoading,
|
|
1948
|
-
children: "
|
|
2075
|
+
children: t2("users.suspend")
|
|
1949
2076
|
}
|
|
1950
2077
|
),
|
|
1951
2078
|
/* @__PURE__ */ jsx12(
|
|
@@ -1955,23 +2082,24 @@ function UsersScreen({
|
|
|
1955
2082
|
style: styles.button,
|
|
1956
2083
|
onClick: () => void revokeSessions().then(() => sessions.refresh()),
|
|
1957
2084
|
disabled: isLoading,
|
|
1958
|
-
children: "
|
|
2085
|
+
children: t2("users.signOutEverywhere")
|
|
1959
2086
|
}
|
|
1960
2087
|
)
|
|
1961
2088
|
] }),
|
|
1962
2089
|
billingClient ? /* @__PURE__ */ jsxs12(Fragment7, { children: [
|
|
1963
|
-
/* @__PURE__ */ jsx12("h2", { style: styles.subtitle, children: "
|
|
2090
|
+
/* @__PURE__ */ jsx12("h2", { style: styles.subtitle, children: t2("users.planCredits") }),
|
|
1964
2091
|
/* @__PURE__ */ jsx12(
|
|
1965
2092
|
SubscriberBilling,
|
|
1966
2093
|
{
|
|
1967
2094
|
client: billingClient,
|
|
1968
|
-
subscriber: { type: "user", id: user.id }
|
|
2095
|
+
subscriber: { type: "user", id: user.id },
|
|
2096
|
+
locale
|
|
1969
2097
|
}
|
|
1970
2098
|
)
|
|
1971
2099
|
] }) : null,
|
|
1972
2100
|
!user.deletedAt ? /* @__PURE__ */ jsxs12(Fragment7, { children: [
|
|
1973
|
-
/* @__PURE__ */ jsx12("h2", { style: styles.subtitle, children: "
|
|
1974
|
-
sessions.sessions.length === 0 ? /* @__PURE__ */ jsx12("p", { style: styles.muted, children: "
|
|
2101
|
+
/* @__PURE__ */ jsx12("h2", { style: styles.subtitle, children: t2("users.liveSessions") }),
|
|
2102
|
+
sessions.sessions.length === 0 ? /* @__PURE__ */ jsx12("p", { style: styles.muted, children: t2("common.none") }) : /* @__PURE__ */ jsx12("ul", { style: styles.list, children: sessions.sessions.map((s) => /* @__PURE__ */ jsxs12("li", { style: styles.row, children: [
|
|
1975
2103
|
/* @__PURE__ */ jsx12("span", { style: styles.mono, children: s.ipAddress ?? "\u2014" }),
|
|
1976
2104
|
" ",
|
|
1977
2105
|
describeLocation(s.location) ? /* @__PURE__ */ jsxs12("span", { style: styles.muted, children: [
|
|
@@ -1980,14 +2108,11 @@ function UsersScreen({
|
|
|
1980
2108
|
] }) : null,
|
|
1981
2109
|
/* @__PURE__ */ jsx12("span", { style: styles.muted, children: s.userAgent ?? "" }),
|
|
1982
2110
|
" ",
|
|
1983
|
-
/* @__PURE__ */
|
|
1984
|
-
"since ",
|
|
1985
|
-
new Date(s.createdAt).toLocaleString()
|
|
1986
|
-
] })
|
|
2111
|
+
/* @__PURE__ */ jsx12("span", { style: styles.muted, children: t2("users.since", { date: formatAdminDate7(s.createdAt, locale) }) })
|
|
1987
2112
|
] }, s.id)) }),
|
|
1988
|
-
/* @__PURE__ */ jsx12("h2", { style: styles.subtitle, children: "
|
|
1989
|
-
history.events.length === 0 && !history.isLoading ? /* @__PURE__ */ jsx12("p", { style: styles.muted, children: "
|
|
1990
|
-
/* @__PURE__ */ jsx12(Pill, { tone: e.outcome === "success" ? "ok" : "bad", children: e.outcome }),
|
|
2113
|
+
/* @__PURE__ */ jsx12("h2", { style: styles.subtitle, children: t2("users.recentSignIns") }),
|
|
2114
|
+
history.events.length === 0 && !history.isLoading ? /* @__PURE__ */ jsx12("p", { style: styles.muted, children: t2("users.noneRecorded") }) : /* @__PURE__ */ jsx12("ul", { style: styles.list, children: history.events.map((e) => /* @__PURE__ */ jsxs12("li", { style: styles.row, children: [
|
|
2115
|
+
/* @__PURE__ */ jsx12(Pill, { tone: e.outcome === "success" ? "ok" : "bad", children: e.outcome === "success" ? t2("users.outcome.success") : e.outcome === "failure" ? t2("users.outcome.failure") : e.outcome }),
|
|
1991
2116
|
" ",
|
|
1992
2117
|
/* @__PURE__ */ jsx12("span", { style: styles.muted, children: e.method }),
|
|
1993
2118
|
" ",
|
|
@@ -1996,10 +2121,10 @@ function UsersScreen({
|
|
|
1996
2121
|
describeLocation(e.location) ? /* @__PURE__ */ jsx12("span", { style: styles.muted, children: describeLocation(e.location) }) : null,
|
|
1997
2122
|
e.location?.proxy || e.location?.hosting ? /* @__PURE__ */ jsxs12(Fragment7, { children: [
|
|
1998
2123
|
" ",
|
|
1999
|
-
/* @__PURE__ */ jsx12(Pill, { tone: "warn", children: e.location.proxy ? "
|
|
2124
|
+
/* @__PURE__ */ jsx12(Pill, { tone: "warn", children: e.location.proxy ? t2("users.proxyVpn") : t2("users.hosting") })
|
|
2000
2125
|
] }) : null,
|
|
2001
2126
|
" ",
|
|
2002
|
-
/* @__PURE__ */ jsx12("span", { style: styles.muted, children:
|
|
2127
|
+
/* @__PURE__ */ jsx12("span", { style: styles.muted, children: formatAdminDate7(e.createdAt, locale) })
|
|
2003
2128
|
] }, e.id)) }),
|
|
2004
2129
|
history.hasMore && !history.isLoading ? /* @__PURE__ */ jsx12(
|
|
2005
2130
|
"button",
|
|
@@ -2007,7 +2132,7 @@ function UsersScreen({
|
|
|
2007
2132
|
type: "button",
|
|
2008
2133
|
style: { ...styles.button, marginTop: 8 },
|
|
2009
2134
|
onClick: () => void history.loadMore(),
|
|
2010
|
-
children: "
|
|
2135
|
+
children: t2("common.loadMore")
|
|
2011
2136
|
}
|
|
2012
2137
|
) : null
|
|
2013
2138
|
] }) : null
|
|
@@ -2016,24 +2141,33 @@ function UsersScreen({
|
|
|
2016
2141
|
}
|
|
2017
2142
|
|
|
2018
2143
|
// src/screens/CatalogScreen.tsx
|
|
2144
|
+
import { createAdminT as createAdminT13 } from "@fonderie/client";
|
|
2019
2145
|
import { useAdminCatalog } from "@fonderie/react-admin";
|
|
2020
2146
|
import { Fragment as Fragment8, jsx as jsx13, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
2021
|
-
function CatalogScreen({ client }) {
|
|
2147
|
+
function CatalogScreen({ client, locale }) {
|
|
2148
|
+
const t2 = createAdminT13(locale);
|
|
2022
2149
|
const { catalog, isLoading, error, refresh, deletePlan } = useAdminCatalog(client);
|
|
2023
2150
|
const money = (v) => v == null ? "\u2014" : (v / 100).toFixed(2);
|
|
2024
2151
|
return /* @__PURE__ */ jsxs13("div", { style: styles.container, children: [
|
|
2025
2152
|
/* @__PURE__ */ jsx13(
|
|
2026
2153
|
PageHeader,
|
|
2027
2154
|
{
|
|
2028
|
-
title: "
|
|
2029
|
-
lead: "
|
|
2030
|
-
actions: /* @__PURE__ */ jsx13(
|
|
2155
|
+
title: t2("catalog.title"),
|
|
2156
|
+
lead: t2("catalog.lead"),
|
|
2157
|
+
actions: /* @__PURE__ */ jsx13(
|
|
2158
|
+
RefreshButton,
|
|
2159
|
+
{
|
|
2160
|
+
onClick: () => void refresh(),
|
|
2161
|
+
busy: isLoading,
|
|
2162
|
+
label: t2("common.refresh")
|
|
2163
|
+
}
|
|
2164
|
+
)
|
|
2031
2165
|
}
|
|
2032
2166
|
),
|
|
2033
2167
|
error ? /* @__PURE__ */ jsx13("p", { style: styles.error, role: "alert", children: error.explanation }) : null,
|
|
2034
|
-
isLoading && !catalog ? /* @__PURE__ */ jsx13("p", { style: styles.status, children: "
|
|
2168
|
+
isLoading && !catalog ? /* @__PURE__ */ jsx13("p", { style: styles.status, children: t2("common.loading") }) : null,
|
|
2035
2169
|
catalog ? /* @__PURE__ */ jsxs13(Fragment8, { children: [
|
|
2036
|
-
/* @__PURE__ */ jsx13("h2", { style: { ...styles.subtitle, marginTop: 0 }, children: "
|
|
2170
|
+
/* @__PURE__ */ jsx13("h2", { style: { ...styles.subtitle, marginTop: 0 }, children: t2("catalog.configured") }),
|
|
2037
2171
|
/* @__PURE__ */ jsx13(
|
|
2038
2172
|
"pre",
|
|
2039
2173
|
{
|
|
@@ -2048,15 +2182,15 @@ function CatalogScreen({ client }) {
|
|
|
2048
2182
|
children: JSON.stringify(catalog.configured, null, 2)
|
|
2049
2183
|
}
|
|
2050
2184
|
),
|
|
2051
|
-
/* @__PURE__ */ jsx13("h2", { style: styles.subtitle, children: "
|
|
2052
|
-
catalog.stored.length === 0 ? /* @__PURE__ */ jsx13(Empty, { icon: "catalog", title: "
|
|
2185
|
+
/* @__PURE__ */ jsx13("h2", { style: styles.subtitle, children: t2("catalog.stored") }),
|
|
2186
|
+
catalog.stored.length === 0 ? /* @__PURE__ */ jsx13(Empty, { icon: "catalog", title: t2("catalog.emptyTitle"), children: t2("catalog.emptyBody") }) : /* @__PURE__ */ jsxs13("table", { style: styles.table, children: [
|
|
2053
2187
|
/* @__PURE__ */ jsx13("thead", { children: /* @__PURE__ */ jsxs13("tr", { children: [
|
|
2054
|
-
/* @__PURE__ */ jsx13("th", { style: styles.th, children: "
|
|
2055
|
-
/* @__PURE__ */ jsx13("th", { style: styles.th, children: "
|
|
2056
|
-
/* @__PURE__ */ jsx13("th", { style: styles.th, children: "
|
|
2057
|
-
/* @__PURE__ */ jsx13("th", { style: styles.th, children: "
|
|
2058
|
-
/* @__PURE__ */ jsx13("th", { style: styles.th, children: "
|
|
2059
|
-
/* @__PURE__ */ jsx13("th", { style: styles.th, children: "
|
|
2188
|
+
/* @__PURE__ */ jsx13("th", { style: styles.th, children: t2("catalog.col.plan") }),
|
|
2189
|
+
/* @__PURE__ */ jsx13("th", { style: styles.th, children: t2("catalog.col.tier") }),
|
|
2190
|
+
/* @__PURE__ */ jsx13("th", { style: styles.th, children: t2("catalog.col.seats") }),
|
|
2191
|
+
/* @__PURE__ */ jsx13("th", { style: styles.th, children: t2("catalog.col.monthly") }),
|
|
2192
|
+
/* @__PURE__ */ jsx13("th", { style: styles.th, children: t2("catalog.col.yearly") }),
|
|
2193
|
+
/* @__PURE__ */ jsx13("th", { style: styles.th, children: t2("catalog.col.trial") }),
|
|
2060
2194
|
/* @__PURE__ */ jsx13("th", { style: styles.th })
|
|
2061
2195
|
] }) }),
|
|
2062
2196
|
/* @__PURE__ */ jsx13("tbody", { children: catalog.stored.map((p) => /* @__PURE__ */ jsxs13("tr", { children: [
|
|
@@ -2072,18 +2206,18 @@ function CatalogScreen({ client }) {
|
|
|
2072
2206
|
p.pricing?.currency ?? ""
|
|
2073
2207
|
] }),
|
|
2074
2208
|
/* @__PURE__ */ jsx13("td", { style: styles.td, children: money(p.pricing?.yearly) }),
|
|
2075
|
-
/* @__PURE__ */ jsx13("td", { style: styles.td, children: p.trialDays ?
|
|
2209
|
+
/* @__PURE__ */ jsx13("td", { style: styles.td, children: p.trialDays ? t2("catalog.trialDays", { n: p.trialDays }) : "\u2014" }),
|
|
2076
2210
|
/* @__PURE__ */ jsx13("td", { style: styles.td, children: /* @__PURE__ */ jsx13(
|
|
2077
2211
|
"button",
|
|
2078
2212
|
{
|
|
2079
2213
|
type: "button",
|
|
2080
2214
|
style: styles.buttonDanger,
|
|
2081
2215
|
onClick: () => {
|
|
2082
|
-
if (window.confirm(
|
|
2216
|
+
if (window.confirm(t2("catalog.deleteConfirm", { name: p.name })))
|
|
2083
2217
|
void deletePlan(p.id).catch(() => {
|
|
2084
2218
|
});
|
|
2085
2219
|
},
|
|
2086
|
-
children: "
|
|
2220
|
+
children: t2("common.delete")
|
|
2087
2221
|
}
|
|
2088
2222
|
) })
|
|
2089
2223
|
] }, p.id)) })
|
|
@@ -2093,19 +2227,28 @@ function CatalogScreen({ client }) {
|
|
|
2093
2227
|
}
|
|
2094
2228
|
|
|
2095
2229
|
// src/screens/SubscriberScreen.tsx
|
|
2230
|
+
import {
|
|
2231
|
+
createAdminT as createAdminT14
|
|
2232
|
+
} from "@fonderie/client";
|
|
2096
2233
|
import { useAdminSubscribers } from "@fonderie/react-admin";
|
|
2097
2234
|
import { useState as useState7 } from "react";
|
|
2098
2235
|
import { Fragment as Fragment9, jsx as jsx14, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
2099
2236
|
var FILTERS = [
|
|
2100
|
-
{
|
|
2101
|
-
{
|
|
2102
|
-
{
|
|
2103
|
-
{
|
|
2104
|
-
{
|
|
2237
|
+
{ id: "all", match: () => true },
|
|
2238
|
+
{ id: "active", match: (s) => s === "active" },
|
|
2239
|
+
{ id: "trialing", match: (s) => s === "trialing" },
|
|
2240
|
+
{ id: "pastDue", match: (s) => s === "past_due" || s === "unpaid" },
|
|
2241
|
+
{ id: "canceled", match: (s) => s === "canceled" }
|
|
2105
2242
|
];
|
|
2106
|
-
function SubscriberScreen({
|
|
2243
|
+
function SubscriberScreen({
|
|
2244
|
+
client,
|
|
2245
|
+
pageSize = 50,
|
|
2246
|
+
onOpenUser,
|
|
2247
|
+
locale
|
|
2248
|
+
}) {
|
|
2249
|
+
const t2 = createAdminT14(locale);
|
|
2107
2250
|
const list = useAdminSubscribers(client, { limit: pageSize });
|
|
2108
|
-
const [filter, setFilter] = useState7("
|
|
2251
|
+
const [filter, setFilter] = useState7("all");
|
|
2109
2252
|
const [open, setOpen] = useState7(null);
|
|
2110
2253
|
const [type, setType] = useState7("workspace");
|
|
2111
2254
|
const [idInput, setIdInput] = useState7("");
|
|
@@ -2115,26 +2258,33 @@ function SubscriberScreen({ client, pageSize = 50, onOpenUser }) {
|
|
|
2115
2258
|
PageHeader,
|
|
2116
2259
|
{
|
|
2117
2260
|
title: `${open.type}/${open.id}`,
|
|
2118
|
-
lead: "
|
|
2261
|
+
lead: t2("billing.subscriptions.detailLead"),
|
|
2119
2262
|
actions: /* @__PURE__ */ jsxs14("button", { type: "button", style: styles.buttonGhost, onClick: () => setOpen(null), children: [
|
|
2120
2263
|
/* @__PURE__ */ jsx14(Icon, { name: "back", size: 14 }),
|
|
2121
|
-
"
|
|
2264
|
+
t2("billing.subscriptions.back")
|
|
2122
2265
|
] })
|
|
2123
2266
|
}
|
|
2124
2267
|
),
|
|
2125
|
-
/* @__PURE__ */ jsx14(SubscriberBilling, { client, subscriber: open })
|
|
2268
|
+
/* @__PURE__ */ jsx14(SubscriberBilling, { client, subscriber: open, locale })
|
|
2126
2269
|
] });
|
|
2127
2270
|
}
|
|
2128
|
-
const match = FILTERS.find((f) => f.
|
|
2271
|
+
const match = FILTERS.find((f) => f.id === filter)?.match ?? (() => true);
|
|
2129
2272
|
const rows = list.subscriptions.filter((s) => match(s.status));
|
|
2130
|
-
const openRow = (
|
|
2273
|
+
const openRow = (t3, id) => t3 === "user" && onOpenUser ? onOpenUser(id) : setOpen({ type: t3, id });
|
|
2131
2274
|
return /* @__PURE__ */ jsxs14("div", { style: styles.container, children: [
|
|
2132
2275
|
/* @__PURE__ */ jsx14(
|
|
2133
2276
|
PageHeader,
|
|
2134
2277
|
{
|
|
2135
|
-
title: "
|
|
2136
|
-
lead: "
|
|
2137
|
-
actions: /* @__PURE__ */ jsx14(
|
|
2278
|
+
title: t2("billing.subscriptions.title"),
|
|
2279
|
+
lead: t2("billing.subscriptions.lead"),
|
|
2280
|
+
actions: /* @__PURE__ */ jsx14(
|
|
2281
|
+
RefreshButton,
|
|
2282
|
+
{
|
|
2283
|
+
onClick: () => void list.refresh(),
|
|
2284
|
+
busy: list.isLoading,
|
|
2285
|
+
label: t2("common.refresh")
|
|
2286
|
+
}
|
|
2287
|
+
)
|
|
2138
2288
|
}
|
|
2139
2289
|
),
|
|
2140
2290
|
/* @__PURE__ */ jsxs14("div", { style: { ...styles.toolbar, justifyContent: "space-between" }, children: [
|
|
@@ -2150,23 +2300,23 @@ function SubscriberScreen({ client, pageSize = 50, onOpenUser }) {
|
|
|
2150
2300
|
padding: 0,
|
|
2151
2301
|
minWidth: 0
|
|
2152
2302
|
},
|
|
2153
|
-
"aria-label": "
|
|
2303
|
+
"aria-label": t2("billing.subscriptions.filterLabel"),
|
|
2154
2304
|
children: FILTERS.map((f) => {
|
|
2155
2305
|
const n = list.subscriptions.filter((s) => f.match(s.status)).length;
|
|
2156
|
-
const on = filter === f.
|
|
2306
|
+
const on = filter === f.id;
|
|
2157
2307
|
return /* @__PURE__ */ jsxs14(
|
|
2158
2308
|
"button",
|
|
2159
2309
|
{
|
|
2160
2310
|
type: "button",
|
|
2161
2311
|
"aria-pressed": on,
|
|
2162
|
-
onClick: () => setFilter(f.
|
|
2312
|
+
onClick: () => setFilter(f.id),
|
|
2163
2313
|
style: { ...on ? styles.buttonPrimary : styles.button, height: 28 },
|
|
2164
2314
|
children: [
|
|
2165
|
-
f.
|
|
2315
|
+
t2(`billing.subscriptions.filter.${f.id}`),
|
|
2166
2316
|
/* @__PURE__ */ jsx14("span", { style: { opacity: 0.7 }, children: n })
|
|
2167
2317
|
]
|
|
2168
2318
|
},
|
|
2169
|
-
f.
|
|
2319
|
+
f.id
|
|
2170
2320
|
);
|
|
2171
2321
|
})
|
|
2172
2322
|
}
|
|
@@ -2186,10 +2336,10 @@ function SubscriberScreen({ client, pageSize = 50, onOpenUser }) {
|
|
|
2186
2336
|
value: type,
|
|
2187
2337
|
onChange: (e) => setType(e.target.value),
|
|
2188
2338
|
style: styles.input,
|
|
2189
|
-
"aria-label": "
|
|
2339
|
+
"aria-label": t2("billing.subscriptions.typeLabel"),
|
|
2190
2340
|
children: [
|
|
2191
|
-
/* @__PURE__ */ jsx14("option", { value: "workspace", children: "
|
|
2192
|
-
/* @__PURE__ */ jsx14("option", { value: "user", children: "
|
|
2341
|
+
/* @__PURE__ */ jsx14("option", { value: "workspace", children: t2("billing.subscriptions.typeWorkspace") }),
|
|
2342
|
+
/* @__PURE__ */ jsx14("option", { value: "user", children: t2("billing.subscriptions.typeUser") })
|
|
2193
2343
|
]
|
|
2194
2344
|
}
|
|
2195
2345
|
),
|
|
@@ -2198,36 +2348,29 @@ function SubscriberScreen({ client, pageSize = 50, onOpenUser }) {
|
|
|
2198
2348
|
{
|
|
2199
2349
|
value: idInput,
|
|
2200
2350
|
onChange: (e) => setIdInput(e.target.value),
|
|
2201
|
-
placeholder: "
|
|
2351
|
+
placeholder: t2("billing.subscriptions.idPlaceholder"),
|
|
2202
2352
|
style: { ...styles.input, width: 220 },
|
|
2203
|
-
"aria-label": "
|
|
2353
|
+
"aria-label": t2("billing.subscriptions.idLabel")
|
|
2204
2354
|
}
|
|
2205
2355
|
),
|
|
2206
2356
|
/* @__PURE__ */ jsxs14("button", { type: "submit", style: styles.button, disabled: !idInput.trim(), children: [
|
|
2207
2357
|
/* @__PURE__ */ jsx14(Icon, { name: "search", size: 14 }),
|
|
2208
|
-
"
|
|
2358
|
+
t2("common.open")
|
|
2209
2359
|
] })
|
|
2210
2360
|
]
|
|
2211
2361
|
}
|
|
2212
2362
|
)
|
|
2213
2363
|
] }),
|
|
2214
2364
|
list.error ? /* @__PURE__ */ jsx14("p", { style: styles.error, role: "alert", children: list.error.explanation }) : null,
|
|
2215
|
-
rows.length === 0 && !list.isLoading ? /* @__PURE__ */ jsx14(
|
|
2216
|
-
Empty,
|
|
2217
|
-
{
|
|
2218
|
-
icon: "subscriber",
|
|
2219
|
-
title: filter === "All" ? "No subscriptions yet" : `No ${filter.toLowerCase()} subscriptions`,
|
|
2220
|
-
children: "Subscriptions appear here once someone checks out."
|
|
2221
|
-
}
|
|
2222
|
-
) : /* @__PURE__ */ jsxs14("table", { style: styles.table, children: [
|
|
2365
|
+
rows.length === 0 && !list.isLoading ? /* @__PURE__ */ jsx14(Empty, { icon: "subscriber", title: t2(`billing.subscriptions.empty.${filter}`), children: t2("billing.subscriptions.emptyHint") }) : /* @__PURE__ */ jsxs14("table", { style: styles.table, children: [
|
|
2223
2366
|
/* @__PURE__ */ jsx14("thead", { children: /* @__PURE__ */ jsxs14("tr", { children: [
|
|
2224
|
-
/* @__PURE__ */ jsx14("th", { style: styles.th, children: "
|
|
2225
|
-
/* @__PURE__ */ jsx14("th", { style: styles.th, children: "
|
|
2226
|
-
/* @__PURE__ */ jsx14("th", { style: styles.th, children: "
|
|
2227
|
-
/* @__PURE__ */ jsx14("th", { style: styles.th, children: "
|
|
2367
|
+
/* @__PURE__ */ jsx14("th", { style: styles.th, children: t2("billing.subscriptions.col.subscriber") }),
|
|
2368
|
+
/* @__PURE__ */ jsx14("th", { style: styles.th, children: t2("billing.subscriptions.col.plan") }),
|
|
2369
|
+
/* @__PURE__ */ jsx14("th", { style: styles.th, children: t2("billing.subscriptions.col.status") }),
|
|
2370
|
+
/* @__PURE__ */ jsx14("th", { style: styles.th, children: t2("billing.subscriptions.col.renewsEnds") })
|
|
2228
2371
|
] }) }),
|
|
2229
2372
|
/* @__PURE__ */ jsx14("tbody", { children: rows.map((s) => {
|
|
2230
|
-
const end = periodEnd(s);
|
|
2373
|
+
const end = periodEnd(s, locale);
|
|
2231
2374
|
return /* @__PURE__ */ jsxs14("tr", { children: [
|
|
2232
2375
|
/* @__PURE__ */ jsx14("td", { style: styles.td, children: /* @__PURE__ */ jsxs14(
|
|
2233
2376
|
"button",
|
|
@@ -2247,14 +2390,14 @@ function SubscriberScreen({ client, pageSize = 50, onOpenUser }) {
|
|
|
2247
2390
|
" ",
|
|
2248
2391
|
/* @__PURE__ */ jsxs14("span", { style: styles.muted, children: [
|
|
2249
2392
|
"\xB7 ",
|
|
2250
|
-
s.interval
|
|
2393
|
+
intervalLabel(t2, s.interval)
|
|
2251
2394
|
] })
|
|
2252
2395
|
] }),
|
|
2253
2396
|
/* @__PURE__ */ jsxs14("td", { style: styles.td, children: [
|
|
2254
|
-
/* @__PURE__ */ jsx14(Pill, { tone: statusTone(s.status), children: s.status }),
|
|
2397
|
+
/* @__PURE__ */ jsx14(Pill, { tone: statusTone(s.status), children: statusLabel(t2, s.status) }),
|
|
2255
2398
|
s.cancelAtPeriodEnd && s.status !== "canceled" ? /* @__PURE__ */ jsxs14(Fragment9, { children: [
|
|
2256
2399
|
" ",
|
|
2257
|
-
/* @__PURE__ */ jsx14(Pill, { tone: "warn", dot: false, children: "cancels" })
|
|
2400
|
+
/* @__PURE__ */ jsx14(Pill, { tone: "warn", dot: false, children: t2("billing.subscriptions.cancels") })
|
|
2258
2401
|
] }) : null
|
|
2259
2402
|
] }),
|
|
2260
2403
|
/* @__PURE__ */ jsx14("td", { style: { ...styles.td, whiteSpace: "nowrap" }, children: end ? /* @__PURE__ */ jsxs14(Fragment9, { children: [
|
|
@@ -2265,28 +2408,31 @@ function SubscriberScreen({ client, pageSize = 50, onOpenUser }) {
|
|
|
2265
2408
|
] }, s.id);
|
|
2266
2409
|
}) })
|
|
2267
2410
|
] }),
|
|
2268
|
-
list.isLoading ? /* @__PURE__ */ jsx14("p", { style: styles.status, children: "
|
|
2411
|
+
list.isLoading ? /* @__PURE__ */ jsx14("p", { style: styles.status, children: t2("common.loading") }) : null,
|
|
2269
2412
|
list.hasMore && !list.isLoading ? /* @__PURE__ */ jsx14(
|
|
2270
2413
|
"button",
|
|
2271
2414
|
{
|
|
2272
2415
|
type: "button",
|
|
2273
2416
|
style: { ...styles.button, marginTop: 8 },
|
|
2274
2417
|
onClick: () => void list.loadMore(),
|
|
2275
|
-
children: "
|
|
2418
|
+
children: t2("common.loadMore")
|
|
2276
2419
|
}
|
|
2277
2420
|
) : null
|
|
2278
2421
|
] });
|
|
2279
2422
|
}
|
|
2280
2423
|
|
|
2281
2424
|
// src/screens/AuditScreen.tsx
|
|
2425
|
+
import {
|
|
2426
|
+
createAdminT as createAdminT15,
|
|
2427
|
+
formatAdminDate as formatAdminDate8
|
|
2428
|
+
} from "@fonderie/client";
|
|
2282
2429
|
import { useAdminAudit } from "@fonderie/react-admin";
|
|
2283
2430
|
import { useState as useState8 } from "react";
|
|
2284
2431
|
import { jsx as jsx15, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
2285
|
-
function AuditScreen({ client, pageSize = 50 }) {
|
|
2286
|
-
const
|
|
2287
|
-
const [
|
|
2288
|
-
|
|
2289
|
-
);
|
|
2432
|
+
function AuditScreen({ client, pageSize = 50, locale }) {
|
|
2433
|
+
const t2 = createAdminT15(locale);
|
|
2434
|
+
const [draft, setDraft] = useState8({ workspaceId: "", type: "", actorId: "", from: "", to: "" });
|
|
2435
|
+
const [filter, setFilter] = useState8({});
|
|
2290
2436
|
const { events, hasMore, isLoading, error, refresh, loadMore } = useAdminAudit(client, {
|
|
2291
2437
|
...filter,
|
|
2292
2438
|
limit: pageSize
|
|
@@ -2302,13 +2448,7 @@ function AuditScreen({ client, pageSize = 50 }) {
|
|
|
2302
2448
|
}
|
|
2303
2449
|
);
|
|
2304
2450
|
return /* @__PURE__ */ jsxs15("div", { style: styles.container, children: [
|
|
2305
|
-
/* @__PURE__ */ jsx15(
|
|
2306
|
-
PageHeader,
|
|
2307
|
-
{
|
|
2308
|
-
title: "Audit",
|
|
2309
|
-
lead: "What happened, across every workspace unless you name one. The chain's integrity verdict is on the Doctor page."
|
|
2310
|
-
}
|
|
2311
|
-
),
|
|
2451
|
+
/* @__PURE__ */ jsx15(PageHeader, { title: t2("audit.title"), lead: t2("audit.lead") }),
|
|
2312
2452
|
/* @__PURE__ */ jsxs15(
|
|
2313
2453
|
"form",
|
|
2314
2454
|
{
|
|
@@ -2318,16 +2458,41 @@ function AuditScreen({ client, pageSize = 50 }) {
|
|
|
2318
2458
|
setFilter({
|
|
2319
2459
|
...draft.workspaceId.trim() ? { workspaceId: draft.workspaceId.trim() } : {},
|
|
2320
2460
|
...draft.type.trim() ? { type: draft.type.trim() } : {},
|
|
2321
|
-
...draft.actorId.trim() ? { actorId: draft.actorId.trim() } : {}
|
|
2461
|
+
...draft.actorId.trim() ? { actorId: draft.actorId.trim() } : {},
|
|
2462
|
+
// Dates are whole days in the operator's time zone: "to" includes that day.
|
|
2463
|
+
...draft.from ? { from: /* @__PURE__ */ new Date(`${draft.from}T00:00:00`) } : {},
|
|
2464
|
+
...draft.to ? { to: /* @__PURE__ */ new Date(`${draft.to}T23:59:59.999`) } : {}
|
|
2322
2465
|
});
|
|
2323
2466
|
},
|
|
2324
2467
|
children: [
|
|
2325
|
-
field("workspaceId",
|
|
2326
|
-
field("type", "
|
|
2327
|
-
field("actorId", "
|
|
2468
|
+
field("workspaceId", t2("audit.workspacePlaceholder")),
|
|
2469
|
+
field("type", t2("audit.typePlaceholder")),
|
|
2470
|
+
field("actorId", t2("audit.actorPlaceholder")),
|
|
2471
|
+
/* @__PURE__ */ jsx15(
|
|
2472
|
+
"input",
|
|
2473
|
+
{
|
|
2474
|
+
type: "date",
|
|
2475
|
+
value: draft.from,
|
|
2476
|
+
onChange: (e) => setDraft({ ...draft, from: e.target.value }),
|
|
2477
|
+
style: styles.input,
|
|
2478
|
+
"aria-label": t2("audit.fromLabel"),
|
|
2479
|
+
title: t2("audit.fromTitle")
|
|
2480
|
+
}
|
|
2481
|
+
),
|
|
2482
|
+
/* @__PURE__ */ jsx15(
|
|
2483
|
+
"input",
|
|
2484
|
+
{
|
|
2485
|
+
type: "date",
|
|
2486
|
+
value: draft.to,
|
|
2487
|
+
onChange: (e) => setDraft({ ...draft, to: e.target.value }),
|
|
2488
|
+
style: styles.input,
|
|
2489
|
+
"aria-label": t2("audit.toLabel"),
|
|
2490
|
+
title: t2("audit.toTitle")
|
|
2491
|
+
}
|
|
2492
|
+
),
|
|
2328
2493
|
/* @__PURE__ */ jsxs15("button", { type: "submit", style: styles.buttonPrimary, disabled: isLoading, children: [
|
|
2329
2494
|
/* @__PURE__ */ jsx15(Icon, { name: "search", size: 14 }),
|
|
2330
|
-
"
|
|
2495
|
+
t2("common.filter")
|
|
2331
2496
|
] }),
|
|
2332
2497
|
/* @__PURE__ */ jsx15(
|
|
2333
2498
|
"button",
|
|
@@ -2336,37 +2501,37 @@ function AuditScreen({ client, pageSize = 50 }) {
|
|
|
2336
2501
|
style: styles.button,
|
|
2337
2502
|
onClick: () => void refresh(),
|
|
2338
2503
|
disabled: isLoading,
|
|
2339
|
-
children: "
|
|
2504
|
+
children: t2("common.refresh")
|
|
2340
2505
|
}
|
|
2341
2506
|
)
|
|
2342
2507
|
]
|
|
2343
2508
|
}
|
|
2344
2509
|
),
|
|
2345
2510
|
error ? /* @__PURE__ */ jsx15("p", { style: styles.error, role: "alert", children: error.explanation }) : null,
|
|
2346
|
-
events.length === 0 && !isLoading ? /* @__PURE__ */ jsx15(Empty, { icon: "audit", title: "
|
|
2511
|
+
events.length === 0 && !isLoading ? /* @__PURE__ */ jsx15(Empty, { icon: "audit", title: t2("audit.empty") }) : /* @__PURE__ */ jsxs15("table", { style: styles.table, children: [
|
|
2347
2512
|
/* @__PURE__ */ jsx15("thead", { children: /* @__PURE__ */ jsxs15("tr", { children: [
|
|
2348
|
-
/* @__PURE__ */ jsx15("th", { style: styles.th, children: "
|
|
2349
|
-
/* @__PURE__ */ jsx15("th", { style: styles.th, children: "
|
|
2350
|
-
/* @__PURE__ */ jsx15("th", { style: styles.th, children: "
|
|
2351
|
-
/* @__PURE__ */ jsx15("th", { style: styles.th, children: "
|
|
2352
|
-
/* @__PURE__ */ jsx15("th", { style: styles.th, children: "
|
|
2513
|
+
/* @__PURE__ */ jsx15("th", { style: styles.th, children: t2("audit.col.when") }),
|
|
2514
|
+
/* @__PURE__ */ jsx15("th", { style: styles.th, children: t2("audit.col.type") }),
|
|
2515
|
+
/* @__PURE__ */ jsx15("th", { style: styles.th, children: t2("audit.col.workspace") }),
|
|
2516
|
+
/* @__PURE__ */ jsx15("th", { style: styles.th, children: t2("audit.col.actor") }),
|
|
2517
|
+
/* @__PURE__ */ jsx15("th", { style: styles.th, children: t2("audit.col.request") })
|
|
2353
2518
|
] }) }),
|
|
2354
2519
|
/* @__PURE__ */ jsx15("tbody", { children: events.map((e) => /* @__PURE__ */ jsxs15("tr", { children: [
|
|
2355
|
-
/* @__PURE__ */ jsx15("td", { style: { ...styles.td, ...styles.muted }, children:
|
|
2520
|
+
/* @__PURE__ */ jsx15("td", { style: { ...styles.td, ...styles.muted }, children: formatAdminDate8(e.createdAt, locale) }),
|
|
2356
2521
|
/* @__PURE__ */ jsx15("td", { style: { ...styles.td, ...styles.mono }, children: e.type }),
|
|
2357
2522
|
/* @__PURE__ */ jsx15("td", { style: { ...styles.td, ...styles.mono }, children: String(e.payload["workspaceId"] ?? "\u2014") }),
|
|
2358
2523
|
/* @__PURE__ */ jsx15("td", { style: { ...styles.td, ...styles.mono }, children: e.actorId ?? "\u2014" }),
|
|
2359
2524
|
/* @__PURE__ */ jsx15("td", { style: { ...styles.td, ...styles.muted }, children: e.requestId ?? "" })
|
|
2360
2525
|
] }, e.id)) })
|
|
2361
2526
|
] }),
|
|
2362
|
-
isLoading ? /* @__PURE__ */ jsx15("p", { style: styles.status, children: "
|
|
2527
|
+
isLoading ? /* @__PURE__ */ jsx15("p", { style: styles.status, children: t2("common.loading") }) : null,
|
|
2363
2528
|
hasMore && !isLoading ? /* @__PURE__ */ jsx15(
|
|
2364
2529
|
"button",
|
|
2365
2530
|
{
|
|
2366
2531
|
type: "button",
|
|
2367
2532
|
style: { ...styles.button, marginTop: 8 },
|
|
2368
2533
|
onClick: () => void loadMore(),
|
|
2369
|
-
children: "
|
|
2534
|
+
children: t2("common.loadMore")
|
|
2370
2535
|
}
|
|
2371
2536
|
) : null
|
|
2372
2537
|
] });
|
|
@@ -2404,34 +2569,43 @@ function useNarrow() {
|
|
|
2404
2569
|
return narrow;
|
|
2405
2570
|
}
|
|
2406
2571
|
var NAV = [
|
|
2407
|
-
{ group: "
|
|
2572
|
+
{ group: "nav.groups.today", items: [{ page: "attention", label: "nav.items.attention" }] },
|
|
2408
2573
|
{
|
|
2409
|
-
group: "
|
|
2574
|
+
group: "nav.groups.system",
|
|
2410
2575
|
items: [
|
|
2411
|
-
{ page: "modules", label: "
|
|
2412
|
-
{ page: "environment", label: "
|
|
2413
|
-
{ page: "doctor", label: "
|
|
2414
|
-
{ page: "routes", label: "
|
|
2576
|
+
{ page: "modules", label: "nav.items.modules" },
|
|
2577
|
+
{ page: "environment", label: "nav.items.environment" },
|
|
2578
|
+
{ page: "doctor", label: "nav.items.doctor" },
|
|
2579
|
+
{ page: "routes", label: "nav.items.routes" }
|
|
2415
2580
|
]
|
|
2416
2581
|
},
|
|
2417
|
-
{ group: "People", items: [{ page: "users", label: "Users", needs: "auth" }] },
|
|
2418
2582
|
{
|
|
2419
|
-
group: "
|
|
2583
|
+
group: "nav.groups.people",
|
|
2584
|
+
items: [{ page: "users", label: "nav.items.users", needs: "auth" }]
|
|
2585
|
+
},
|
|
2586
|
+
{
|
|
2587
|
+
group: "nav.groups.money",
|
|
2420
2588
|
items: [
|
|
2421
|
-
{ page: "catalog", label: "
|
|
2422
|
-
{ page: "subscriber", label: "
|
|
2589
|
+
{ page: "catalog", label: "nav.items.catalog", needs: "billing" },
|
|
2590
|
+
{ page: "subscriber", label: "nav.items.subscriptions", needs: "billing" }
|
|
2423
2591
|
]
|
|
2424
2592
|
},
|
|
2425
|
-
{ group: "Settings", items: [{ page: "settings", label: "Config & secrets", needs: "config" }] },
|
|
2426
|
-
{ group: "Messaging", items: [{ page: "templates", label: "Templates", needs: "courier" }] },
|
|
2427
2593
|
{
|
|
2428
|
-
group: "
|
|
2594
|
+
group: "nav.groups.settings",
|
|
2595
|
+
items: [{ page: "settings", label: "nav.items.settings", needs: "config" }]
|
|
2596
|
+
},
|
|
2597
|
+
{
|
|
2598
|
+
group: "nav.groups.messaging",
|
|
2599
|
+
items: [{ page: "templates", label: "nav.items.templates", needs: "courier" }]
|
|
2600
|
+
},
|
|
2601
|
+
{
|
|
2602
|
+
group: "nav.groups.activity",
|
|
2429
2603
|
items: [
|
|
2430
|
-
{ page: "audit", label: "
|
|
2431
|
-
{ page: "log", label: "
|
|
2432
|
-
{ page: "operators", label: "
|
|
2433
|
-
{ page: "tokens", label: "
|
|
2434
|
-
{ page: "migrations", label: "
|
|
2604
|
+
{ page: "audit", label: "nav.items.audit", needs: "audit" },
|
|
2605
|
+
{ page: "log", label: "nav.items.log" },
|
|
2606
|
+
{ page: "operators", label: "nav.items.operators", needs: "operators" },
|
|
2607
|
+
{ page: "tokens", label: "nav.items.tokens" },
|
|
2608
|
+
{ page: "migrations", label: "nav.items.migrations" }
|
|
2435
2609
|
]
|
|
2436
2610
|
}
|
|
2437
2611
|
];
|
|
@@ -2449,8 +2623,11 @@ function AdminShell({
|
|
|
2449
2623
|
envLabel,
|
|
2450
2624
|
footer,
|
|
2451
2625
|
operators = false,
|
|
2452
|
-
currentOperator
|
|
2626
|
+
currentOperator,
|
|
2627
|
+
publicConfigUrl,
|
|
2628
|
+
locale
|
|
2453
2629
|
}) {
|
|
2630
|
+
const t2 = createAdminT16(locale);
|
|
2454
2631
|
const narrow = useNarrow();
|
|
2455
2632
|
const [drawer, setDrawer] = useState9(false);
|
|
2456
2633
|
const [own, setOwn] = useState9("attention");
|
|
@@ -2473,40 +2650,41 @@ function AdminShell({
|
|
|
2473
2650
|
let body;
|
|
2474
2651
|
switch (current) {
|
|
2475
2652
|
case "attention":
|
|
2476
|
-
body = /* @__PURE__ */ jsx16(AttentionScreen, { client });
|
|
2653
|
+
body = /* @__PURE__ */ jsx16(AttentionScreen, { client, locale });
|
|
2477
2654
|
break;
|
|
2478
2655
|
case "modules":
|
|
2479
|
-
body = /* @__PURE__ */ jsx16(ModulesScreen, { client });
|
|
2656
|
+
body = /* @__PURE__ */ jsx16(ModulesScreen, { client, locale });
|
|
2480
2657
|
break;
|
|
2481
2658
|
case "doctor":
|
|
2482
|
-
body = /* @__PURE__ */ jsx16(DoctorScreen, { client });
|
|
2659
|
+
body = /* @__PURE__ */ jsx16(DoctorScreen, { client, locale });
|
|
2483
2660
|
break;
|
|
2484
2661
|
case "environment":
|
|
2485
|
-
body = /* @__PURE__ */ jsx16(EnvironmentScreen, { client });
|
|
2662
|
+
body = /* @__PURE__ */ jsx16(EnvironmentScreen, { client, locale });
|
|
2486
2663
|
break;
|
|
2487
2664
|
case "routes":
|
|
2488
|
-
body = /* @__PURE__ */ jsx16(RoutesScreen, { client });
|
|
2665
|
+
body = /* @__PURE__ */ jsx16(RoutesScreen, { client, locale });
|
|
2489
2666
|
break;
|
|
2490
2667
|
case "tokens":
|
|
2491
|
-
body = /* @__PURE__ */ jsx16(TokensScreen, { client });
|
|
2668
|
+
body = /* @__PURE__ */ jsx16(TokensScreen, { client, locale });
|
|
2492
2669
|
break;
|
|
2493
2670
|
case "operators":
|
|
2494
|
-
body = /* @__PURE__ */ jsx16(OperatorsScreen, { client, me: currentOperator });
|
|
2671
|
+
body = /* @__PURE__ */ jsx16(OperatorsScreen, { client, me: currentOperator, locale });
|
|
2495
2672
|
break;
|
|
2496
2673
|
case "migrations":
|
|
2497
|
-
body = /* @__PURE__ */ jsx16(MigrationsScreen, { client });
|
|
2674
|
+
body = /* @__PURE__ */ jsx16(MigrationsScreen, { client, locale });
|
|
2498
2675
|
break;
|
|
2499
2676
|
case "log":
|
|
2500
|
-
body = /* @__PURE__ */ jsx16(AdminLogScreen, { client });
|
|
2677
|
+
body = /* @__PURE__ */ jsx16(AdminLogScreen, { client, locale });
|
|
2501
2678
|
break;
|
|
2502
2679
|
case "catalog":
|
|
2503
|
-
body = billingClient ? /* @__PURE__ */ jsx16(CatalogScreen, { client: billingClient }) : /* @__PURE__ */ jsx16("p", { style: { ...styles.status, padding: "32px 40px" }, children: "
|
|
2680
|
+
body = billingClient ? /* @__PURE__ */ jsx16(CatalogScreen, { client: billingClient, locale }) : /* @__PURE__ */ jsx16("p", { style: { ...styles.status, padding: "32px 40px" }, children: t2("shell.missingClient", { client: "BillingAdminClient" }) });
|
|
2504
2681
|
break;
|
|
2505
2682
|
case "subscriber":
|
|
2506
2683
|
body = billingClient ? /* @__PURE__ */ jsx16(
|
|
2507
2684
|
SubscriberScreen,
|
|
2508
2685
|
{
|
|
2509
2686
|
client: billingClient,
|
|
2687
|
+
locale,
|
|
2510
2688
|
...authClient ? {
|
|
2511
2689
|
onOpenUser: (id) => {
|
|
2512
2690
|
setOpenUser(id);
|
|
@@ -2514,10 +2692,10 @@ function AdminShell({
|
|
|
2514
2692
|
}
|
|
2515
2693
|
} : {}
|
|
2516
2694
|
}
|
|
2517
|
-
) : /* @__PURE__ */ jsx16("p", { style: { ...styles.status, padding: "32px 40px" }, children: "
|
|
2695
|
+
) : /* @__PURE__ */ jsx16("p", { style: { ...styles.status, padding: "32px 40px" }, children: t2("shell.missingClient", { client: "BillingAdminClient" }) });
|
|
2518
2696
|
break;
|
|
2519
2697
|
case "audit":
|
|
2520
|
-
body = auditClient ? /* @__PURE__ */ jsx16(AuditScreen, { client: auditClient }) : /* @__PURE__ */ jsx16("p", { style: { ...styles.status, padding: "32px 40px" }, children: "
|
|
2698
|
+
body = auditClient ? /* @__PURE__ */ jsx16(AuditScreen, { client: auditClient, locale }) : /* @__PURE__ */ jsx16("p", { style: { ...styles.status, padding: "32px 40px" }, children: t2("shell.missingClient", { client: "AuditAdminClient" }) });
|
|
2521
2699
|
break;
|
|
2522
2700
|
case "users":
|
|
2523
2701
|
body = authClient ? /* @__PURE__ */ jsx16(
|
|
@@ -2525,16 +2703,17 @@ function AdminShell({
|
|
|
2525
2703
|
{
|
|
2526
2704
|
client: authClient,
|
|
2527
2705
|
billingClient,
|
|
2528
|
-
openUserId: openUser
|
|
2706
|
+
openUserId: openUser,
|
|
2707
|
+
locale
|
|
2529
2708
|
},
|
|
2530
2709
|
openUser ?? "list"
|
|
2531
|
-
) : /* @__PURE__ */ jsx16("p", { style: { ...styles.status, padding: "32px 40px" }, children: "
|
|
2710
|
+
) : /* @__PURE__ */ jsx16("p", { style: { ...styles.status, padding: "32px 40px" }, children: t2("shell.missingClient", { client: "AuthAdminClient" }) });
|
|
2532
2711
|
break;
|
|
2533
2712
|
case "settings":
|
|
2534
|
-
body = !configClient ? /* @__PURE__ */ jsx16("p", { style: { ...styles.status, padding: "32px 40px" }, children: "
|
|
2713
|
+
body = !configClient ? /* @__PURE__ */ jsx16("p", { style: { ...styles.status, padding: "32px 40px" }, children: t2("shell.missingClient", { client: "ConfigAdminClient" }) }) : editing && (editing.kind === "config" || editing.kind === "secret") ? /* @__PURE__ */ jsxs16(Fragment10, { children: [
|
|
2535
2714
|
/* @__PURE__ */ jsx16("div", { style: { padding: "24px 40px 0" }, children: /* @__PURE__ */ jsxs16("button", { type: "button", style: styles.buttonGhost, onClick: () => setEditing(null), children: [
|
|
2536
2715
|
/* @__PURE__ */ jsx16(Icon, { name: "back", size: 14 }),
|
|
2537
|
-
"
|
|
2716
|
+
t2("nav.items.settings")
|
|
2538
2717
|
] }) }),
|
|
2539
2718
|
/* @__PURE__ */ jsx16(
|
|
2540
2719
|
ConfigEditorScreen,
|
|
@@ -2542,41 +2721,85 @@ function AdminShell({
|
|
|
2542
2721
|
client: configClient,
|
|
2543
2722
|
kind: editing.kind,
|
|
2544
2723
|
configKey: editing.key,
|
|
2545
|
-
...environment !== void 0 ? { environment } : {},
|
|
2546
|
-
|
|
2547
|
-
|
|
2724
|
+
...editing.environment !== void 0 ? { environment: editing.environment } : environment !== void 0 ? { environment } : {},
|
|
2725
|
+
...editing.environments ? { environments: editing.environments } : {},
|
|
2726
|
+
onSaved: () => setEditing(null),
|
|
2727
|
+
onDeleted: () => setEditing(null),
|
|
2728
|
+
locale
|
|
2729
|
+
},
|
|
2730
|
+
`${editing.kind}:${editing.key}:${editing.environment ?? ""}`
|
|
2548
2731
|
)
|
|
2549
2732
|
] }) : /* @__PURE__ */ jsx16(
|
|
2550
2733
|
ConfigListScreen,
|
|
2551
2734
|
{
|
|
2552
2735
|
client: configClient,
|
|
2736
|
+
locale,
|
|
2553
2737
|
...environment !== void 0 ? { environment } : {},
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2738
|
+
...publicConfigUrl ? { publicConfigUrl } : {},
|
|
2739
|
+
onSelectConfig: (key, env) => setEditing({ kind: "config", key, environment: env }),
|
|
2740
|
+
onSelectSecret: (key, env) => setEditing({ kind: "secret", key, environment: env }),
|
|
2741
|
+
onCreateConfig: (c) => setEditing({
|
|
2742
|
+
kind: "config",
|
|
2743
|
+
key: "",
|
|
2744
|
+
environments: c.environments,
|
|
2745
|
+
...c.environment ? { environment: c.environment } : {}
|
|
2746
|
+
}),
|
|
2747
|
+
onCreateSecret: (c) => setEditing({
|
|
2748
|
+
kind: "secret",
|
|
2749
|
+
key: "",
|
|
2750
|
+
environments: c.environments,
|
|
2751
|
+
...c.environment ? { environment: c.environment } : {}
|
|
2752
|
+
})
|
|
2558
2753
|
}
|
|
2559
2754
|
);
|
|
2560
2755
|
break;
|
|
2561
2756
|
case "templates":
|
|
2562
|
-
body = !courierClient ? /* @__PURE__ */ jsx16("p", { style: { ...styles.status, padding: "32px 40px" }, children: "
|
|
2757
|
+
body = !courierClient ? /* @__PURE__ */ jsx16("p", { style: { ...styles.status, padding: "32px 40px" }, children: t2("shell.missingClient", { client: "CourierAdminClient" }) }) : editing?.kind === "template-new" ? /* @__PURE__ */ jsxs16(Fragment10, { children: [
|
|
2758
|
+
/* @__PURE__ */ jsx16("div", { style: { padding: "24px 40px 0" }, children: /* @__PURE__ */ jsxs16("button", { type: "button", style: styles.buttonGhost, onClick: () => setEditing(null), children: [
|
|
2759
|
+
/* @__PURE__ */ jsx16(Icon, { name: "back", size: 14 }),
|
|
2760
|
+
t2("nav.items.templates")
|
|
2761
|
+
] }) }),
|
|
2762
|
+
/* @__PURE__ */ jsx16(
|
|
2763
|
+
TemplateCreateScreen,
|
|
2764
|
+
{
|
|
2765
|
+
client: courierClient,
|
|
2766
|
+
locale,
|
|
2767
|
+
...editing.type ? { type: editing.type } : {},
|
|
2768
|
+
...editing.locales ? { locales: editing.locales } : {},
|
|
2769
|
+
onCreated: (c) => setEditing({ kind: "template", type: c.type, locale: c.locale, system: false })
|
|
2770
|
+
}
|
|
2771
|
+
)
|
|
2772
|
+
] }) : editing?.kind === "template" ? /* @__PURE__ */ jsxs16(Fragment10, { children: [
|
|
2563
2773
|
/* @__PURE__ */ jsx16("div", { style: { padding: "24px 40px 0" }, children: /* @__PURE__ */ jsxs16("button", { type: "button", style: styles.buttonGhost, onClick: () => setEditing(null), children: [
|
|
2564
2774
|
/* @__PURE__ */ jsx16(Icon, { name: "back", size: 14 }),
|
|
2565
|
-
"
|
|
2775
|
+
t2("nav.items.templates")
|
|
2566
2776
|
] }) }),
|
|
2567
2777
|
/* @__PURE__ */ jsx16(
|
|
2568
2778
|
TemplateEditorScreen,
|
|
2569
2779
|
{
|
|
2570
2780
|
client: courierClient,
|
|
2571
2781
|
type: editing.type,
|
|
2572
|
-
|
|
2573
|
-
|
|
2782
|
+
locale: editing.locale,
|
|
2783
|
+
system: editing.system,
|
|
2784
|
+
onSaved: () => setEditing(null),
|
|
2785
|
+
onDeleted: () => setEditing(null),
|
|
2786
|
+
onAddLocale: (type) => setEditing({ kind: "template-new", type }),
|
|
2787
|
+
uiLocale: locale
|
|
2788
|
+
},
|
|
2789
|
+
`${editing.type}:${editing.locale ?? ""}`
|
|
2574
2790
|
)
|
|
2575
2791
|
] }) : /* @__PURE__ */ jsx16(
|
|
2576
2792
|
TemplateListScreen,
|
|
2577
2793
|
{
|
|
2578
2794
|
client: courierClient,
|
|
2579
|
-
|
|
2795
|
+
locale,
|
|
2796
|
+
onSelectTemplate: (tpl) => setEditing({
|
|
2797
|
+
kind: "template",
|
|
2798
|
+
type: tpl.type,
|
|
2799
|
+
locale: tpl.locale ?? null,
|
|
2800
|
+
system: tpl.system === true
|
|
2801
|
+
}),
|
|
2802
|
+
onCreateTemplate: (c) => setEditing({ kind: "template-new", locales: c.locales })
|
|
2580
2803
|
}
|
|
2581
2804
|
);
|
|
2582
2805
|
break;
|
|
@@ -2608,7 +2831,7 @@ function AdminShell({
|
|
|
2608
2831
|
{
|
|
2609
2832
|
type: "button",
|
|
2610
2833
|
style: styles.buttonGhost,
|
|
2611
|
-
"aria-label": "
|
|
2834
|
+
"aria-label": t2("shell.closeMenu"),
|
|
2612
2835
|
onClick: () => setDrawer(false),
|
|
2613
2836
|
children: /* @__PURE__ */ jsx16(Icon, { name: "close" })
|
|
2614
2837
|
}
|
|
@@ -2621,14 +2844,14 @@ function AdminShell({
|
|
|
2621
2844
|
...styles.nav,
|
|
2622
2845
|
...narrow ? { width: 280, maxWidth: "85vw", boxShadow: "0 10px 40px rgba(0,0,0,.25)" } : {}
|
|
2623
2846
|
},
|
|
2624
|
-
"aria-label": "
|
|
2847
|
+
"aria-label": t2("shell.navLabel"),
|
|
2625
2848
|
children: [
|
|
2626
2849
|
brand,
|
|
2627
2850
|
/* @__PURE__ */ jsx16("div", { style: styles.navScroll, children: NAV.map((g) => {
|
|
2628
2851
|
const items = g.items.filter((i) => !i.needs || has[i.needs]);
|
|
2629
2852
|
if (items.length === 0) return null;
|
|
2630
2853
|
return /* @__PURE__ */ jsxs16("div", { children: [
|
|
2631
|
-
/* @__PURE__ */ jsx16("div", { style: styles.navGroup, children: g.group }),
|
|
2854
|
+
/* @__PURE__ */ jsx16("div", { style: styles.navGroup, children: t2(g.group) }),
|
|
2632
2855
|
items.map((i) => {
|
|
2633
2856
|
const active = current === i.page;
|
|
2634
2857
|
return /* @__PURE__ */ jsxs16(
|
|
@@ -2645,7 +2868,7 @@ function AdminShell({
|
|
|
2645
2868
|
},
|
|
2646
2869
|
children: [
|
|
2647
2870
|
/* @__PURE__ */ jsx16(Icon, { name: ICON[i.page], style: active ? styles.navIconActive : void 0 }),
|
|
2648
|
-
i.label
|
|
2871
|
+
t2(i.label)
|
|
2649
2872
|
]
|
|
2650
2873
|
},
|
|
2651
2874
|
i.page
|
|
@@ -2657,7 +2880,8 @@ function AdminShell({
|
|
|
2657
2880
|
]
|
|
2658
2881
|
}
|
|
2659
2882
|
);
|
|
2660
|
-
const
|
|
2883
|
+
const titleKey = NAV.flatMap((g) => g.items).find((i) => i.page === current)?.label;
|
|
2884
|
+
const title = titleKey ? t2(titleKey) : "";
|
|
2661
2885
|
return /* @__PURE__ */ jsxs16("div", { style: { ...styles.shell, ...narrow ? { flexDirection: "column" } : {} }, children: [
|
|
2662
2886
|
narrow ? /* @__PURE__ */ jsxs16(Fragment10, { children: [
|
|
2663
2887
|
/* @__PURE__ */ jsxs16("div", { style: styles.topbar, children: [
|
|
@@ -2666,7 +2890,7 @@ function AdminShell({
|
|
|
2666
2890
|
{
|
|
2667
2891
|
type: "button",
|
|
2668
2892
|
style: styles.buttonGhost,
|
|
2669
|
-
"aria-label": "
|
|
2893
|
+
"aria-label": t2("shell.openMenu"),
|
|
2670
2894
|
"aria-expanded": drawer,
|
|
2671
2895
|
onClick: () => setDrawer(true),
|
|
2672
2896
|
children: /* @__PURE__ */ jsx16(Icon, { name: "menu" })
|