@fonderie/vue-admin-screens 0.2.0 → 0.4.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/README.md CHANGED
@@ -11,12 +11,13 @@ Status: **experimental** (0.x).
11
11
  | Today | Attention | what needs me today — empty is green |
12
12
  | System | Modules · Configuration · Doctor · Routes | what did I deploy · is it configured · is it working · what is exposed |
13
13
  | People | Users | why can't this person log in — lookup, sessions, sign-ins, suspend, sign out everywhere (`authClient`) |
14
+ | Money | Catalog · Subscriber | what am I selling (configured vs stored) · what is this subscriber on, their wallet, ledger, a manual grant (`billingClient`) |
14
15
  | Settings | Config & secrets | the `@fonderie/config` admin screens, as a sub-page |
15
16
  | Messaging | Templates | the `@fonderie/courier` admin screens, as a sub-page |
16
- | Activity | Admin log · Access | who did what · who can be here |
17
+ | Activity | Audit · Admin log · Access | what happened, every workspace (`auditClient`) · who did what through here · who can be here |
17
18
 
18
19
  ```ts
19
- import { AdminClient, AuthAdminClient, ConfigAdminClient, CourierAdminClient } from '@fonderie/client';
20
+ import { AdminClient, AuditAdminClient, AuthAdminClient, BillingAdminClient, ConfigAdminClient, CourierAdminClient } from '@fonderie/client';
20
21
  import { AdminShell } from '@fonderie/vue-admin-screens';
21
22
 
22
23
  const base = { baseUrl: 'https://api.example.com', adminToken, actor: 'louis' };
@@ -25,10 +26,12 @@ const client = new AdminClient(base);
25
26
  const configClient = new ConfigAdminClient({ ...base, prefix: '/_admin' });
26
27
  const courierClient = new CourierAdminClient({ ...base, prefix: '/_admin' });
27
28
  const authClient = new AuthAdminClient(base); // @fonderie/auth ≥ 7.8
29
+ const billingClient = new BillingAdminClient(base); // @fonderie/billing ≥ 9.10
30
+ const auditClient = new AuditAdminClient(base); // @fonderie/audit ≥ 5.2
28
31
  ```
29
32
 
30
33
  ```ts
31
- h(AdminShell, { client, configClient, courierClient, authClient })
34
+ h(AdminShell, { client, configClient, courierClient, authClient, billingClient, auditClient })
32
35
  ```
33
36
 
34
37
  Pass `page` and listen to `navigate` to own the URL (one route per page);
package/dist/index.cjs CHANGED
@@ -23,10 +23,13 @@ __export(index_exports, {
23
23
  AdminLogScreen: () => AdminLogScreen,
24
24
  AdminShell: () => AdminShell,
25
25
  AttentionScreen: () => AttentionScreen,
26
+ AuditScreen: () => AuditScreen,
27
+ CatalogScreen: () => CatalogScreen,
26
28
  ConfigScreen: () => ConfigScreen,
27
29
  DoctorScreen: () => DoctorScreen,
28
30
  ModulesScreen: () => ModulesScreen,
29
31
  RoutesScreen: () => RoutesScreen,
32
+ SubscriberScreen: () => SubscriberScreen,
30
33
  TokensScreen: () => TokensScreen,
31
34
  UsersScreen: () => UsersScreen
32
35
  });
@@ -35,7 +38,7 @@ module.exports = __toCommonJS(index_exports);
35
38
  // src/screens/AdminShell.ts
36
39
  var import_vue_config_admin_screens = require("@fonderie/vue-config-admin-screens");
37
40
  var import_vue_courier_admin_screens = require("@fonderie/vue-courier-admin-screens");
38
- var import_vue10 = require("vue");
41
+ var import_vue13 = require("vue");
39
42
 
40
43
  // src/styles.ts
41
44
  var styles = {
@@ -595,6 +598,312 @@ var UsersScreen = (0, import_vue9.defineComponent)({
595
598
  }
596
599
  });
597
600
 
601
+ // src/screens/CatalogScreen.ts
602
+ var import_vue_admin9 = require("@fonderie/vue-admin");
603
+ var import_vue10 = require("vue");
604
+ var CatalogScreen = (0, import_vue10.defineComponent)({
605
+ name: "FonderieCatalogScreen",
606
+ props: { client: { type: Object, required: true } },
607
+ setup(props) {
608
+ const { catalog, isLoading, error, refresh, deletePlan } = (0, import_vue_admin9.useAdminCatalog)(props.client);
609
+ const money = (v) => v == null ? "\u2014" : (v / 100).toFixed(2);
610
+ return () => {
611
+ const c = catalog.value;
612
+ return (0, import_vue10.h)("div", { style: styles.container }, [
613
+ (0, import_vue10.h)("div", { style: styles.toolbar }, [
614
+ (0, import_vue10.h)("h1", { style: { ...styles.title, marginBottom: 0 } }, "Catalog"),
615
+ refreshButton("Refresh", isLoading.value, () => void refresh())
616
+ ]),
617
+ error.value ? (0, import_vue10.h)("p", { style: styles.error, role: "alert" }, error.value.explanation) : null,
618
+ isLoading.value && !c ? (0, import_vue10.h)("p", { style: styles.status }, "Loading\u2026") : null,
619
+ c ? [
620
+ (0, import_vue10.h)("h2", { style: styles.subtitle }, "Configured (code)"),
621
+ (0, import_vue10.h)(
622
+ "pre",
623
+ {
624
+ style: {
625
+ ...styles.mono,
626
+ background: "#f9fafb",
627
+ padding: "12px",
628
+ overflowX: "auto"
629
+ }
630
+ },
631
+ JSON.stringify(c.configured, null, 2)
632
+ ),
633
+ (0, import_vue10.h)("h2", { style: styles.subtitle }, "Stored (database)"),
634
+ c.stored.length === 0 ? (0, import_vue10.h)("p", { style: styles.muted }, "No stored plans.") : table(
635
+ ["Plan", "Tier", "Seats", "Monthly", "Yearly", "Trial", ""],
636
+ c.stored.map(
637
+ (p) => (0, import_vue10.h)("tr", { key: p.id }, [
638
+ td([
639
+ (0, import_vue10.h)("strong", p.name),
640
+ p.description ? (0, import_vue10.h)("div", { style: styles.muted }, p.description) : ""
641
+ ]),
642
+ td(String(p.tier)),
643
+ td(p.seats == null ? "\u221E" : String(p.seats)),
644
+ td(`${money(p.pricing?.monthly)} ${p.pricing?.currency ?? ""}`),
645
+ td(money(p.pricing?.yearly)),
646
+ td(p.trialDays ? `${p.trialDays} d` : "\u2014"),
647
+ td(
648
+ (0, import_vue10.h)(
649
+ "button",
650
+ {
651
+ type: "button",
652
+ style: styles.button,
653
+ onClick: () => {
654
+ if (window.confirm(`Delete stored plan "${p.name}"?`))
655
+ void deletePlan(p.id).catch(() => {
656
+ });
657
+ }
658
+ },
659
+ "Delete"
660
+ )
661
+ )
662
+ ])
663
+ )
664
+ )
665
+ ] : null
666
+ ]);
667
+ };
668
+ }
669
+ });
670
+
671
+ // src/screens/SubscriberScreen.ts
672
+ var import_vue_admin10 = require("@fonderie/vue-admin");
673
+ var import_vue11 = require("vue");
674
+ var SubscriberScreen = (0, import_vue11.defineComponent)({
675
+ name: "FonderieSubscriberScreen",
676
+ props: { client: { type: Object, required: true } },
677
+ setup(props) {
678
+ const type = (0, import_vue11.ref)("user");
679
+ const idInput = (0, import_vue11.ref)("");
680
+ const subscriber = (0, import_vue11.ref)(null);
681
+ const { subscription, wallet, ledger, hasMoreLedger, isLoading, error, loadMoreLedger, grant } = (0, import_vue_admin10.useAdminSubscriber)(props.client, subscriber, { limit: 20 });
682
+ const amount = (0, import_vue11.ref)("");
683
+ const note = (0, import_vue11.ref)("");
684
+ const granted = (0, import_vue11.ref)(null);
685
+ const input = (model, placeholder, extra = {}) => (0, import_vue11.h)("input", {
686
+ value: model.value,
687
+ onInput: (e) => model.value = e.target.value,
688
+ placeholder,
689
+ style: { ...styles.button, cursor: "text", ...extra },
690
+ "aria-label": placeholder
691
+ });
692
+ return () => {
693
+ const s = subscription.value;
694
+ const w = wallet.value;
695
+ return (0, import_vue11.h)("div", { style: styles.container }, [
696
+ (0, import_vue11.h)("h1", { style: styles.title }, "Subscriber"),
697
+ (0, import_vue11.h)(
698
+ "form",
699
+ {
700
+ style: styles.toolbar,
701
+ onSubmit: (e) => {
702
+ e.preventDefault();
703
+ granted.value = null;
704
+ subscriber.value = idInput.value.trim() ? { type: type.value, id: idInput.value.trim() } : null;
705
+ }
706
+ },
707
+ [
708
+ (0, import_vue11.h)(
709
+ "select",
710
+ {
711
+ value: type.value,
712
+ onChange: (e) => type.value = e.target.value,
713
+ style: styles.button,
714
+ "aria-label": "Type"
715
+ },
716
+ [
717
+ (0, import_vue11.h)("option", { value: "user" }, "user"),
718
+ (0, import_vue11.h)("option", { value: "workspace" }, "workspace")
719
+ ]
720
+ ),
721
+ input(idInput, "subscriber id", { minWidth: "280px" }),
722
+ (0, import_vue11.h)(
723
+ "button",
724
+ { type: "submit", style: styles.button, disabled: isLoading.value },
725
+ "Look up"
726
+ )
727
+ ]
728
+ ),
729
+ error.value ? (0, import_vue11.h)("p", { style: styles.error, role: "alert" }, error.value.explanation) : null,
730
+ subscriber.value && !isLoading.value ? [
731
+ (0, import_vue11.h)("h2", { style: styles.subtitle }, "Subscription"),
732
+ s ? (0, import_vue11.h)("table", { style: styles.table }, [
733
+ (0, import_vue11.h)("tbody", [
734
+ (0, import_vue11.h)("tr", [td("plan"), td([(0, import_vue11.h)("strong", s.plan), ` \xB7 ${s.interval}`])]),
735
+ (0, import_vue11.h)("tr", [
736
+ td("status"),
737
+ td(`${s.status}${s.cancelAtPeriodEnd ? " \xB7 cancels at period end" : ""}`)
738
+ ]),
739
+ (0, import_vue11.h)("tr", [
740
+ td("period"),
741
+ td(
742
+ `${s.currentPeriodStart ? new Date(s.currentPeriodStart).toLocaleDateString() : "\u2014"} \u2192 ${s.currentPeriodEnd ? new Date(s.currentPeriodEnd).toLocaleDateString() : "\u2014"}`
743
+ )
744
+ ]),
745
+ (0, import_vue11.h)("tr", [td("provider"), td(s.providerSubscriptionId ?? "\u2014", styles.mono)])
746
+ ])
747
+ ]) : (0, import_vue11.h)("p", { style: styles.muted }, "No subscription."),
748
+ (0, import_vue11.h)("h2", { style: styles.subtitle }, "Wallet"),
749
+ w ? [
750
+ (0, import_vue11.h)("p", [
751
+ (0, import_vue11.h)("strong", w.balance),
752
+ ` ${w.currency} `,
753
+ (0, import_vue11.h)(
754
+ "span",
755
+ { style: styles.muted },
756
+ `(granted ${w.granted ?? "0"} \xB7 purchased ${w.purchased ?? "0"}) \xB7 minor units, precision ${w.precision}`
757
+ )
758
+ ]),
759
+ (0, import_vue11.h)(
760
+ "form",
761
+ {
762
+ style: styles.toolbar,
763
+ onSubmit: (e) => {
764
+ e.preventDefault();
765
+ const sub = subscriber.value;
766
+ if (!sub) return;
767
+ const key = `admin-grant-${sub.type}-${sub.id}-${Date.now()}`;
768
+ const amt = amount.value.trim();
769
+ void grant({
770
+ amount: amt,
771
+ ...note.value ? { description: note.value } : {},
772
+ idempotencyKey: key
773
+ }).then(() => {
774
+ granted.value = `Granted ${amt} ${w.currency}.`;
775
+ amount.value = "";
776
+ note.value = "";
777
+ }).catch(() => {
778
+ });
779
+ }
780
+ },
781
+ [
782
+ input(amount, "amount (minor units)"),
783
+ input(note, "reason (optional)", { minWidth: "220px" }),
784
+ (0, import_vue11.h)(
785
+ "button",
786
+ {
787
+ type: "submit",
788
+ style: styles.button,
789
+ disabled: !/^\d+$/.test(amount.value.trim())
790
+ },
791
+ "Grant"
792
+ ),
793
+ granted.value ? (0, import_vue11.h)("span", { style: styles.ok }, granted.value) : null
794
+ ]
795
+ ),
796
+ (0, import_vue11.h)("h2", { style: styles.subtitle }, "Ledger"),
797
+ ledger.value.length === 0 ? (0, import_vue11.h)("p", { style: styles.muted }, "Nothing moved yet.") : table(
798
+ ["When", "Kind", "Amount", "Note"],
799
+ ledger.value.map(
800
+ (t) => (0, import_vue11.h)("tr", { key: t.id }, [
801
+ td(new Date(t.createdAt).toLocaleString(), styles.muted),
802
+ td(t.type),
803
+ td(t.amount, styles.mono),
804
+ td(t.description ?? "", styles.muted)
805
+ ])
806
+ )
807
+ ),
808
+ hasMoreLedger.value ? (0, import_vue11.h)(
809
+ "button",
810
+ {
811
+ type: "button",
812
+ style: { ...styles.button, marginTop: "8px" },
813
+ onClick: () => void loadMoreLedger()
814
+ },
815
+ "Load more"
816
+ ) : null
817
+ ] : (0, import_vue11.h)(
818
+ "p",
819
+ { style: styles.muted },
820
+ "No wallet \u2014 billing has no wallet configuration."
821
+ )
822
+ ] : null
823
+ ]);
824
+ };
825
+ }
826
+ });
827
+
828
+ // src/screens/AuditScreen.ts
829
+ var import_vue_admin11 = require("@fonderie/vue-admin");
830
+ var import_vue12 = require("vue");
831
+ var AuditScreen = (0, import_vue12.defineComponent)({
832
+ name: "FonderieAuditScreen",
833
+ props: {
834
+ client: { type: Object, required: true },
835
+ pageSize: { type: Number, default: 50 }
836
+ },
837
+ setup(props) {
838
+ const draft = (0, import_vue12.ref)({ workspaceId: "", type: "", actorId: "" });
839
+ const query = (0, import_vue12.ref)({ limit: props.pageSize });
840
+ const { events, hasMore, isLoading, error, refresh, loadMore } = (0, import_vue_admin11.useAdminAudit)(
841
+ props.client,
842
+ query
843
+ );
844
+ const field = (key, placeholder) => (0, import_vue12.h)("input", {
845
+ value: draft.value[key],
846
+ onInput: (e) => draft.value = { ...draft.value, [key]: e.target.value },
847
+ placeholder,
848
+ style: { ...styles.button, cursor: "text" },
849
+ "aria-label": placeholder
850
+ });
851
+ return () => (0, import_vue12.h)("div", { style: styles.container }, [
852
+ (0, import_vue12.h)("h1", { style: styles.title }, "Audit"),
853
+ (0, import_vue12.h)(
854
+ "form",
855
+ {
856
+ style: styles.toolbar,
857
+ onSubmit: (e) => {
858
+ e.preventDefault();
859
+ const d = draft.value;
860
+ query.value = {
861
+ limit: props.pageSize,
862
+ ...d.workspaceId.trim() ? { workspaceId: d.workspaceId.trim() } : {},
863
+ ...d.type.trim() ? { type: d.type.trim() } : {},
864
+ ...d.actorId.trim() ? { actorId: d.actorId.trim() } : {}
865
+ };
866
+ }
867
+ },
868
+ [
869
+ field("workspaceId", "workspace id (all if empty)"),
870
+ field("type", "event type"),
871
+ field("actorId", "actor id"),
872
+ (0, import_vue12.h)(
873
+ "button",
874
+ { type: "submit", style: styles.button, disabled: isLoading.value },
875
+ "Filter"
876
+ ),
877
+ refreshButton("Refresh", isLoading.value, () => void refresh())
878
+ ]
879
+ ),
880
+ error.value ? (0, import_vue12.h)("p", { style: styles.error, role: "alert" }, error.value.explanation) : null,
881
+ events.value.length === 0 && !isLoading.value ? (0, import_vue12.h)("p", { style: styles.muted }, "Nothing recorded for this filter.") : table(
882
+ ["When", "Type", "Workspace", "Actor", "Request"],
883
+ events.value.map(
884
+ (e) => (0, import_vue12.h)("tr", { key: e.id }, [
885
+ td(new Date(e.createdAt).toLocaleString(), styles.muted),
886
+ td(e.type, styles.mono),
887
+ td(String(e.payload["workspaceId"] ?? "\u2014"), styles.mono),
888
+ td(e.actorId ?? "\u2014", styles.mono),
889
+ td(e.requestId ?? "", styles.muted)
890
+ ])
891
+ )
892
+ ),
893
+ isLoading.value ? (0, import_vue12.h)("p", { style: styles.status }, "Loading\u2026") : null,
894
+ hasMore.value && !isLoading.value ? (0, import_vue12.h)(
895
+ "button",
896
+ {
897
+ type: "button",
898
+ style: { ...styles.button, marginTop: "8px" },
899
+ onClick: () => void loadMore()
900
+ },
901
+ "Load more"
902
+ ) : null
903
+ ]);
904
+ }
905
+ });
906
+
598
907
  // src/screens/AdminShell.ts
599
908
  var NAV = [
600
909
  { group: "Today", items: [{ page: "attention", label: "Attention" }] },
@@ -608,17 +917,25 @@ var NAV = [
608
917
  ]
609
918
  },
610
919
  { group: "People", items: [{ page: "users", label: "Users", needs: "auth" }] },
920
+ {
921
+ group: "Money",
922
+ items: [
923
+ { page: "catalog", label: "Catalog", needs: "billing" },
924
+ { page: "subscriber", label: "Subscriber", needs: "billing" }
925
+ ]
926
+ },
611
927
  { group: "Settings", items: [{ page: "settings", label: "Config & secrets", needs: "config" }] },
612
928
  { group: "Messaging", items: [{ page: "templates", label: "Templates", needs: "courier" }] },
613
929
  {
614
930
  group: "Activity",
615
931
  items: [
932
+ { page: "audit", label: "Audit", needs: "audit" },
616
933
  { page: "log", label: "Admin log" },
617
934
  { page: "tokens", label: "Access" }
618
935
  ]
619
936
  }
620
937
  ];
621
- var AdminShell = (0, import_vue10.defineComponent)({
938
+ var AdminShell = (0, import_vue13.defineComponent)({
622
939
  name: "FonderieAdminShell",
623
940
  props: {
624
941
  client: { type: Object, required: true },
@@ -628,6 +945,10 @@ var AdminShell = (0, import_vue10.defineComponent)({
628
945
  courierClient: { type: Object, default: void 0 },
629
946
  // Given ⇒ the People page (users) appears; needs @fonderie/auth ≥ 7.8.
630
947
  authClient: { type: Object, default: void 0 },
948
+ // Given ⇒ the Money pages (catalog, subscriber) appear; needs @fonderie/billing ≥ 9.10.
949
+ billingClient: { type: Object, default: void 0 },
950
+ // Given ⇒ the Audit page appears; needs @fonderie/audit ≥ 5.2.
951
+ auditClient: { type: Object, default: void 0 },
631
952
  environment: { type: String, default: void 0 },
632
953
  // Controlled navigation: pass `page` and listen to `navigate` to own the
633
954
  // URL. Omit `page` and the shell keeps it itself.
@@ -635,15 +956,15 @@ var AdminShell = (0, import_vue10.defineComponent)({
635
956
  },
636
957
  emits: { navigate: (_page) => true },
637
958
  setup(props, { emit }) {
638
- const own = (0, import_vue10.ref)("attention");
639
- const current = (0, import_vue10.computed)(() => props.page ?? own.value);
640
- const editing = (0, import_vue10.ref)(null);
959
+ const own = (0, import_vue13.ref)("attention");
960
+ const current = (0, import_vue13.computed)(() => props.page ?? own.value);
961
+ const editing = (0, import_vue13.ref)(null);
641
962
  const go = (p) => {
642
963
  editing.value = null;
643
964
  emit("navigate", p);
644
965
  if (props.page === void 0) own.value = p;
645
966
  };
646
- const back = () => (0, import_vue10.h)(
967
+ const back = () => (0, import_vue13.h)(
647
968
  "button",
648
969
  { type: "button", style: styles.button, onClick: () => editing.value = null },
649
970
  "\u2190 Back"
@@ -652,25 +973,43 @@ var AdminShell = (0, import_vue10.defineComponent)({
652
973
  const c = props.client;
653
974
  switch (current.value) {
654
975
  case "attention":
655
- return (0, import_vue10.h)(AttentionScreen, { client: c });
976
+ return (0, import_vue13.h)(AttentionScreen, { client: c });
656
977
  case "modules":
657
- return (0, import_vue10.h)(ModulesScreen, { client: c });
978
+ return (0, import_vue13.h)(ModulesScreen, { client: c });
658
979
  case "doctor":
659
- return (0, import_vue10.h)(DoctorScreen, { client: c });
980
+ return (0, import_vue13.h)(DoctorScreen, { client: c });
660
981
  case "config":
661
- return (0, import_vue10.h)(ConfigScreen, { client: c });
982
+ return (0, import_vue13.h)(ConfigScreen, { client: c });
662
983
  case "routes":
663
- return (0, import_vue10.h)(RoutesScreen, { client: c });
984
+ return (0, import_vue13.h)(RoutesScreen, { client: c });
664
985
  case "tokens":
665
- return (0, import_vue10.h)(TokensScreen, { client: c });
986
+ return (0, import_vue13.h)(TokensScreen, { client: c });
666
987
  case "log":
667
- return (0, import_vue10.h)(AdminLogScreen, { client: c });
988
+ return (0, import_vue13.h)(AdminLogScreen, { client: c });
989
+ case "catalog":
990
+ return props.billingClient ? (0, import_vue13.h)(CatalogScreen, { client: props.billingClient }) : (0, import_vue13.h)(
991
+ "p",
992
+ { style: styles.status },
993
+ "Pass a BillingAdminClient to see the catalog here."
994
+ );
995
+ case "subscriber":
996
+ return props.billingClient ? (0, import_vue13.h)(SubscriberScreen, { client: props.billingClient }) : (0, import_vue13.h)(
997
+ "p",
998
+ { style: styles.status },
999
+ "Pass a BillingAdminClient to look up subscribers here."
1000
+ );
1001
+ case "audit":
1002
+ return props.auditClient ? (0, import_vue13.h)(AuditScreen, { client: props.auditClient }) : (0, import_vue13.h)(
1003
+ "p",
1004
+ { style: styles.status },
1005
+ "Pass an AuditAdminClient to see the audit trail here."
1006
+ );
668
1007
  case "users":
669
- return props.authClient ? (0, import_vue10.h)(UsersScreen, { client: props.authClient }) : (0, import_vue10.h)("p", { style: styles.status }, "Pass an AuthAdminClient to look up users here.");
1008
+ return props.authClient ? (0, import_vue13.h)(UsersScreen, { client: props.authClient }) : (0, import_vue13.h)("p", { style: styles.status }, "Pass an AuthAdminClient to look up users here.");
670
1009
  case "settings": {
671
1010
  const cc = props.configClient;
672
1011
  if (!cc)
673
- return (0, import_vue10.h)(
1012
+ return (0, import_vue13.h)(
674
1013
  "p",
675
1014
  { style: styles.status },
676
1015
  "Pass a ConfigAdminClient to manage config and secrets here."
@@ -679,7 +1018,7 @@ var AdminShell = (0, import_vue10.defineComponent)({
679
1018
  if (e && e.kind !== "template")
680
1019
  return [
681
1020
  back(),
682
- (0, import_vue10.h)(import_vue_config_admin_screens.ConfigEditorScreen, {
1021
+ (0, import_vue13.h)(import_vue_config_admin_screens.ConfigEditorScreen, {
683
1022
  client: cc,
684
1023
  kind: e.kind,
685
1024
  configKey: e.key,
@@ -687,7 +1026,7 @@ var AdminShell = (0, import_vue10.defineComponent)({
687
1026
  onSaved: () => editing.value = null
688
1027
  })
689
1028
  ];
690
- return (0, import_vue10.h)(import_vue_config_admin_screens.ConfigListScreen, {
1029
+ return (0, import_vue13.h)(import_vue_config_admin_screens.ConfigListScreen, {
691
1030
  client: cc,
692
1031
  ...props.environment !== void 0 ? { environment: props.environment } : {},
693
1032
  "onSelect-config": (key) => editing.value = { kind: "config", key },
@@ -697,7 +1036,7 @@ var AdminShell = (0, import_vue10.defineComponent)({
697
1036
  case "templates": {
698
1037
  const kc = props.courierClient;
699
1038
  if (!kc)
700
- return (0, import_vue10.h)(
1039
+ return (0, import_vue13.h)(
701
1040
  "p",
702
1041
  { style: styles.status },
703
1042
  "Pass a CourierAdminClient to manage templates here."
@@ -706,32 +1045,32 @@ var AdminShell = (0, import_vue10.defineComponent)({
706
1045
  if (e?.kind === "template")
707
1046
  return [
708
1047
  back(),
709
- (0, import_vue10.h)(import_vue_courier_admin_screens.TemplateEditorScreen, {
1048
+ (0, import_vue13.h)(import_vue_courier_admin_screens.TemplateEditorScreen, {
710
1049
  client: kc,
711
1050
  type: e.type,
712
1051
  onSaved: () => editing.value = null
713
1052
  })
714
1053
  ];
715
- return (0, import_vue10.h)(import_vue_courier_admin_screens.TemplateListScreen, {
1054
+ return (0, import_vue13.h)(import_vue_courier_admin_screens.TemplateListScreen, {
716
1055
  client: kc,
717
1056
  "onSelect-template": (t) => editing.value = { kind: "template", type: t.type }
718
1057
  });
719
1058
  }
720
1059
  }
721
1060
  };
722
- return () => (0, import_vue10.h)("div", { style: styles.shell }, [
723
- (0, import_vue10.h)(
1061
+ return () => (0, import_vue13.h)("div", { style: styles.shell }, [
1062
+ (0, import_vue13.h)(
724
1063
  "nav",
725
1064
  { style: styles.nav, "aria-label": "Admin" },
726
1065
  NAV.map((g) => {
727
1066
  const items = g.items.filter(
728
- (i) => !i.needs || (i.needs === "config" ? props.configClient : i.needs === "courier" ? props.courierClient : props.authClient)
1067
+ (i) => !i.needs || (i.needs === "config" ? props.configClient : i.needs === "courier" ? props.courierClient : i.needs === "auth" ? props.authClient : i.needs === "billing" ? props.billingClient : props.auditClient)
729
1068
  );
730
1069
  if (items.length === 0) return null;
731
- return (0, import_vue10.h)("div", { key: g.group }, [
732
- (0, import_vue10.h)("div", { style: styles.navGroup }, g.group),
1070
+ return (0, import_vue13.h)("div", { key: g.group }, [
1071
+ (0, import_vue13.h)("div", { style: styles.navGroup }, g.group),
733
1072
  ...items.map(
734
- (i) => (0, import_vue10.h)(
1073
+ (i) => (0, import_vue13.h)(
735
1074
  "button",
736
1075
  {
737
1076
  key: i.page,
@@ -749,7 +1088,7 @@ var AdminShell = (0, import_vue10.defineComponent)({
749
1088
  ]);
750
1089
  })
751
1090
  ),
752
- (0, import_vue10.h)("main", { style: styles.main }, body())
1091
+ (0, import_vue13.h)("main", { style: styles.main }, body())
753
1092
  ]);
754
1093
  }
755
1094
  });
@@ -758,10 +1097,13 @@ var AdminShell = (0, import_vue10.defineComponent)({
758
1097
  AdminLogScreen,
759
1098
  AdminShell,
760
1099
  AttentionScreen,
1100
+ AuditScreen,
1101
+ CatalogScreen,
761
1102
  ConfigScreen,
762
1103
  DoctorScreen,
763
1104
  ModulesScreen,
764
1105
  RoutesScreen,
1106
+ SubscriberScreen,
765
1107
  TokensScreen,
766
1108
  UsersScreen
767
1109
  });