@fonderie/vue-admin-screens 0.1.0 → 0.3.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
@@ -10,12 +10,14 @@ Status: **experimental** (0.x).
10
10
  |---|---|---|
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
+ | 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`) |
13
15
  | Settings | Config & secrets | the `@fonderie/config` admin screens, as a sub-page |
14
16
  | Messaging | Templates | the `@fonderie/courier` admin screens, as a sub-page |
15
17
  | Activity | Admin log · Access | who did what · who can be here |
16
18
 
17
19
  ```ts
18
- import { AdminClient, ConfigAdminClient, CourierAdminClient } from '@fonderie/client';
20
+ import { AdminClient, AuthAdminClient, BillingAdminClient, ConfigAdminClient, CourierAdminClient } from '@fonderie/client';
19
21
  import { AdminShell } from '@fonderie/vue-admin-screens';
20
22
 
21
23
  const base = { baseUrl: 'https://api.example.com', adminToken, actor: 'louis' };
@@ -23,10 +25,12 @@ const client = new AdminClient(base);
23
25
  // prefix: the composed surface under /_admin — one token for everything.
24
26
  const configClient = new ConfigAdminClient({ ...base, prefix: '/_admin' });
25
27
  const courierClient = new CourierAdminClient({ ...base, prefix: '/_admin' });
28
+ const authClient = new AuthAdminClient(base); // @fonderie/auth ≥ 7.8
29
+ const billingClient = new BillingAdminClient(base); // @fonderie/billing ≥ 9.10
26
30
  ```
27
31
 
28
32
  ```ts
29
- h(AdminShell, { client, configClient, courierClient })
33
+ h(AdminShell, { client, configClient, courierClient, authClient, billingClient })
30
34
  ```
31
35
 
32
36
  Pass `page` and listen to `navigate` to own the URL (one route per page);
package/dist/index.cjs CHANGED
@@ -23,18 +23,21 @@ __export(index_exports, {
23
23
  AdminLogScreen: () => AdminLogScreen,
24
24
  AdminShell: () => AdminShell,
25
25
  AttentionScreen: () => AttentionScreen,
26
+ CatalogScreen: () => CatalogScreen,
26
27
  ConfigScreen: () => ConfigScreen,
27
28
  DoctorScreen: () => DoctorScreen,
28
29
  ModulesScreen: () => ModulesScreen,
29
30
  RoutesScreen: () => RoutesScreen,
30
- TokensScreen: () => TokensScreen
31
+ SubscriberScreen: () => SubscriberScreen,
32
+ TokensScreen: () => TokensScreen,
33
+ UsersScreen: () => UsersScreen
31
34
  });
32
35
  module.exports = __toCommonJS(index_exports);
33
36
 
34
37
  // src/screens/AdminShell.ts
35
38
  var import_vue_config_admin_screens = require("@fonderie/vue-config-admin-screens");
36
39
  var import_vue_courier_admin_screens = require("@fonderie/vue-courier-admin-screens");
37
- var import_vue9 = require("vue");
40
+ var import_vue12 = require("vue");
38
41
 
39
42
  // src/styles.ts
40
43
  var styles = {
@@ -460,6 +463,367 @@ var TokensScreen = (0, import_vue8.defineComponent)({
460
463
  }
461
464
  });
462
465
 
466
+ // src/screens/UsersScreen.ts
467
+ var import_vue_admin8 = require("@fonderie/vue-admin");
468
+ var import_vue9 = require("vue");
469
+ var UsersScreen = (0, import_vue9.defineComponent)({
470
+ name: "FonderieUsersScreen",
471
+ props: { client: { type: Object, required: true } },
472
+ setup(props) {
473
+ const input = (0, import_vue9.ref)("");
474
+ const email = (0, import_vue9.ref)("");
475
+ const { user, isLoading, error, suspend, unsuspend, revokeSessions } = (0, import_vue_admin8.useAdminUser)(
476
+ props.client,
477
+ { email }
478
+ );
479
+ const userId = (0, import_vue9.computed)(() => user.value?.id ?? null);
480
+ const sessions = (0, import_vue_admin8.useAdminUserSessions)(props.client, userId);
481
+ const history = (0, import_vue_admin8.useAdminLoginHistory)(props.client, userId, { limit: 20 });
482
+ const yesNo = (v) => (0, import_vue9.h)("span", { style: v ? styles.ok : styles.muted }, v ? "yes" : "no");
483
+ const row = (k, v) => (0, import_vue9.h)("tr", [td(k), td(v)]);
484
+ return () => {
485
+ const u = user.value;
486
+ return (0, import_vue9.h)("div", { style: styles.container }, [
487
+ (0, import_vue9.h)("h1", { style: styles.title }, "Users"),
488
+ (0, import_vue9.h)(
489
+ "form",
490
+ {
491
+ style: styles.toolbar,
492
+ onSubmit: (e) => {
493
+ e.preventDefault();
494
+ email.value = input.value.trim();
495
+ }
496
+ },
497
+ [
498
+ (0, import_vue9.h)("input", {
499
+ type: "email",
500
+ value: input.value,
501
+ onInput: (e) => input.value = e.target.value,
502
+ placeholder: "email address",
503
+ style: { ...styles.button, cursor: "text", minWidth: "280px" },
504
+ "aria-label": "Email"
505
+ }),
506
+ (0, import_vue9.h)(
507
+ "button",
508
+ { type: "submit", style: styles.button, disabled: isLoading.value },
509
+ "Look up"
510
+ )
511
+ ]
512
+ ),
513
+ error.value ? (0, import_vue9.h)(
514
+ "p",
515
+ { style: styles.error, role: "alert" },
516
+ error.value.status === 404 ? "No user with that email." : error.value.explanation
517
+ ) : null,
518
+ u ? [
519
+ (0, import_vue9.h)("h2", { style: styles.subtitle }, [
520
+ u.firstName || u.lastName ? `${u.firstName} ${u.lastName}`.trim() : u.email,
521
+ " ",
522
+ u.suspended ? (0, import_vue9.h)("span", { style: styles.badge }, "suspended") : null,
523
+ u.deletedAt ? (0, import_vue9.h)("span", { style: styles.badge }, "deleted") : null
524
+ ]),
525
+ (0, import_vue9.h)("table", { style: styles.table }, [
526
+ (0, import_vue9.h)("tbody", [
527
+ row("id", (0, import_vue9.h)("span", { style: styles.mono }, u.id)),
528
+ row("email", [u.email, " \xB7 verified ", yesNo(u.isEmailVerified)]),
529
+ row("MFA", yesNo(u.mfaEnabled)),
530
+ row(
531
+ "provider",
532
+ `${u.provider || "password"}${u.hasPassword ? "" : " \xB7 no password set"}`
533
+ ),
534
+ row(
535
+ "last login",
536
+ u.lastLogin ? new Date(u.lastLogin).toLocaleString() : (0, import_vue9.h)("span", { style: styles.muted }, "never")
537
+ ),
538
+ row("created", new Date(u.createdAt).toLocaleString())
539
+ ])
540
+ ]),
541
+ (0, import_vue9.h)("div", { style: { ...styles.toolbar, marginTop: "12px" } }, [
542
+ u.suspended ? refreshButton("Unsuspend", isLoading.value, () => void unsuspend()) : refreshButton("Suspend", isLoading.value, () => void suspend()),
543
+ refreshButton(
544
+ "Sign out everywhere",
545
+ isLoading.value,
546
+ () => void revokeSessions().then(() => sessions.refresh())
547
+ )
548
+ ]),
549
+ (0, import_vue9.h)("h2", { style: styles.subtitle }, "Live sessions"),
550
+ sessions.sessions.value.length === 0 ? (0, import_vue9.h)("p", { style: styles.muted }, "None.") : (0, import_vue9.h)(
551
+ "ul",
552
+ { style: styles.list },
553
+ sessions.sessions.value.map(
554
+ (s) => (0, import_vue9.h)("li", { key: s.id, style: styles.row }, [
555
+ (0, import_vue9.h)("span", { style: styles.mono }, s.ipAddress ?? "\u2014"),
556
+ " ",
557
+ (0, import_vue9.h)("span", { style: styles.muted }, s.userAgent ?? ""),
558
+ " ",
559
+ (0, import_vue9.h)(
560
+ "span",
561
+ { style: styles.muted },
562
+ `since ${new Date(s.createdAt).toLocaleString()}`
563
+ )
564
+ ])
565
+ )
566
+ ),
567
+ (0, import_vue9.h)("h2", { style: styles.subtitle }, "Recent sign-ins"),
568
+ history.events.value.length === 0 && !history.isLoading.value ? (0, import_vue9.h)("p", { style: styles.muted }, "None recorded.") : (0, import_vue9.h)(
569
+ "ul",
570
+ { style: styles.list },
571
+ history.events.value.map(
572
+ (e) => (0, import_vue9.h)("li", { key: e.id, style: styles.row }, [
573
+ (0, import_vue9.h)(
574
+ "span",
575
+ { style: e.outcome === "success" ? styles.ok : styles.bad },
576
+ e.outcome
577
+ ),
578
+ " ",
579
+ (0, import_vue9.h)("span", { style: styles.muted }, e.method),
580
+ " ",
581
+ (0, import_vue9.h)("span", { style: styles.muted }, new Date(e.createdAt).toLocaleString())
582
+ ])
583
+ )
584
+ ),
585
+ history.hasMore.value && !history.isLoading.value ? (0, import_vue9.h)(
586
+ "button",
587
+ {
588
+ type: "button",
589
+ style: { ...styles.button, marginTop: "8px" },
590
+ onClick: () => void history.loadMore()
591
+ },
592
+ "Load more"
593
+ ) : null
594
+ ] : null
595
+ ]);
596
+ };
597
+ }
598
+ });
599
+
600
+ // src/screens/CatalogScreen.ts
601
+ var import_vue_admin9 = require("@fonderie/vue-admin");
602
+ var import_vue10 = require("vue");
603
+ var CatalogScreen = (0, import_vue10.defineComponent)({
604
+ name: "FonderieCatalogScreen",
605
+ props: { client: { type: Object, required: true } },
606
+ setup(props) {
607
+ const { catalog, isLoading, error, refresh, deletePlan } = (0, import_vue_admin9.useAdminCatalog)(props.client);
608
+ const money = (v) => v == null ? "\u2014" : (v / 100).toFixed(2);
609
+ return () => {
610
+ const c = catalog.value;
611
+ return (0, import_vue10.h)("div", { style: styles.container }, [
612
+ (0, import_vue10.h)("div", { style: styles.toolbar }, [
613
+ (0, import_vue10.h)("h1", { style: { ...styles.title, marginBottom: 0 } }, "Catalog"),
614
+ refreshButton("Refresh", isLoading.value, () => void refresh())
615
+ ]),
616
+ error.value ? (0, import_vue10.h)("p", { style: styles.error, role: "alert" }, error.value.explanation) : null,
617
+ isLoading.value && !c ? (0, import_vue10.h)("p", { style: styles.status }, "Loading\u2026") : null,
618
+ c ? [
619
+ (0, import_vue10.h)("h2", { style: styles.subtitle }, "Configured (code)"),
620
+ (0, import_vue10.h)(
621
+ "pre",
622
+ {
623
+ style: {
624
+ ...styles.mono,
625
+ background: "#f9fafb",
626
+ padding: "12px",
627
+ overflowX: "auto"
628
+ }
629
+ },
630
+ JSON.stringify(c.configured, null, 2)
631
+ ),
632
+ (0, import_vue10.h)("h2", { style: styles.subtitle }, "Stored (database)"),
633
+ c.stored.length === 0 ? (0, import_vue10.h)("p", { style: styles.muted }, "No stored plans.") : table(
634
+ ["Plan", "Tier", "Seats", "Monthly", "Yearly", "Trial", ""],
635
+ c.stored.map(
636
+ (p) => (0, import_vue10.h)("tr", { key: p.id }, [
637
+ td([
638
+ (0, import_vue10.h)("strong", p.name),
639
+ p.description ? (0, import_vue10.h)("div", { style: styles.muted }, p.description) : ""
640
+ ]),
641
+ td(String(p.tier)),
642
+ td(p.seats == null ? "\u221E" : String(p.seats)),
643
+ td(`${money(p.pricing?.monthly)} ${p.pricing?.currency ?? ""}`),
644
+ td(money(p.pricing?.yearly)),
645
+ td(p.trialDays ? `${p.trialDays} d` : "\u2014"),
646
+ td(
647
+ (0, import_vue10.h)(
648
+ "button",
649
+ {
650
+ type: "button",
651
+ style: styles.button,
652
+ onClick: () => {
653
+ if (window.confirm(`Delete stored plan "${p.name}"?`))
654
+ void deletePlan(p.id).catch(() => {
655
+ });
656
+ }
657
+ },
658
+ "Delete"
659
+ )
660
+ )
661
+ ])
662
+ )
663
+ )
664
+ ] : null
665
+ ]);
666
+ };
667
+ }
668
+ });
669
+
670
+ // src/screens/SubscriberScreen.ts
671
+ var import_vue_admin10 = require("@fonderie/vue-admin");
672
+ var import_vue11 = require("vue");
673
+ var SubscriberScreen = (0, import_vue11.defineComponent)({
674
+ name: "FonderieSubscriberScreen",
675
+ props: { client: { type: Object, required: true } },
676
+ setup(props) {
677
+ const type = (0, import_vue11.ref)("user");
678
+ const idInput = (0, import_vue11.ref)("");
679
+ const subscriber = (0, import_vue11.ref)(null);
680
+ const { subscription, wallet, ledger, hasMoreLedger, isLoading, error, loadMoreLedger, grant } = (0, import_vue_admin10.useAdminSubscriber)(props.client, subscriber, { limit: 20 });
681
+ const amount = (0, import_vue11.ref)("");
682
+ const note = (0, import_vue11.ref)("");
683
+ const granted = (0, import_vue11.ref)(null);
684
+ const input = (model, placeholder, extra = {}) => (0, import_vue11.h)("input", {
685
+ value: model.value,
686
+ onInput: (e) => model.value = e.target.value,
687
+ placeholder,
688
+ style: { ...styles.button, cursor: "text", ...extra },
689
+ "aria-label": placeholder
690
+ });
691
+ return () => {
692
+ const s = subscription.value;
693
+ const w = wallet.value;
694
+ return (0, import_vue11.h)("div", { style: styles.container }, [
695
+ (0, import_vue11.h)("h1", { style: styles.title }, "Subscriber"),
696
+ (0, import_vue11.h)(
697
+ "form",
698
+ {
699
+ style: styles.toolbar,
700
+ onSubmit: (e) => {
701
+ e.preventDefault();
702
+ granted.value = null;
703
+ subscriber.value = idInput.value.trim() ? { type: type.value, id: idInput.value.trim() } : null;
704
+ }
705
+ },
706
+ [
707
+ (0, import_vue11.h)(
708
+ "select",
709
+ {
710
+ value: type.value,
711
+ onChange: (e) => type.value = e.target.value,
712
+ style: styles.button,
713
+ "aria-label": "Type"
714
+ },
715
+ [
716
+ (0, import_vue11.h)("option", { value: "user" }, "user"),
717
+ (0, import_vue11.h)("option", { value: "workspace" }, "workspace")
718
+ ]
719
+ ),
720
+ input(idInput, "subscriber id", { minWidth: "280px" }),
721
+ (0, import_vue11.h)(
722
+ "button",
723
+ { type: "submit", style: styles.button, disabled: isLoading.value },
724
+ "Look up"
725
+ )
726
+ ]
727
+ ),
728
+ error.value ? (0, import_vue11.h)("p", { style: styles.error, role: "alert" }, error.value.explanation) : null,
729
+ subscriber.value && !isLoading.value ? [
730
+ (0, import_vue11.h)("h2", { style: styles.subtitle }, "Subscription"),
731
+ s ? (0, import_vue11.h)("table", { style: styles.table }, [
732
+ (0, import_vue11.h)("tbody", [
733
+ (0, import_vue11.h)("tr", [td("plan"), td([(0, import_vue11.h)("strong", s.plan), ` \xB7 ${s.interval}`])]),
734
+ (0, import_vue11.h)("tr", [
735
+ td("status"),
736
+ td(`${s.status}${s.cancelAtPeriodEnd ? " \xB7 cancels at period end" : ""}`)
737
+ ]),
738
+ (0, import_vue11.h)("tr", [
739
+ td("period"),
740
+ td(
741
+ `${s.currentPeriodStart ? new Date(s.currentPeriodStart).toLocaleDateString() : "\u2014"} \u2192 ${s.currentPeriodEnd ? new Date(s.currentPeriodEnd).toLocaleDateString() : "\u2014"}`
742
+ )
743
+ ]),
744
+ (0, import_vue11.h)("tr", [td("provider"), td(s.providerSubscriptionId ?? "\u2014", styles.mono)])
745
+ ])
746
+ ]) : (0, import_vue11.h)("p", { style: styles.muted }, "No subscription."),
747
+ (0, import_vue11.h)("h2", { style: styles.subtitle }, "Wallet"),
748
+ w ? [
749
+ (0, import_vue11.h)("p", [
750
+ (0, import_vue11.h)("strong", w.balance),
751
+ ` ${w.currency} `,
752
+ (0, import_vue11.h)(
753
+ "span",
754
+ { style: styles.muted },
755
+ `(granted ${w.granted ?? "0"} \xB7 purchased ${w.purchased ?? "0"}) \xB7 minor units, precision ${w.precision}`
756
+ )
757
+ ]),
758
+ (0, import_vue11.h)(
759
+ "form",
760
+ {
761
+ style: styles.toolbar,
762
+ onSubmit: (e) => {
763
+ e.preventDefault();
764
+ const sub = subscriber.value;
765
+ if (!sub) return;
766
+ const key = `admin-grant-${sub.type}-${sub.id}-${Date.now()}`;
767
+ const amt = amount.value.trim();
768
+ void grant({
769
+ amount: amt,
770
+ ...note.value ? { description: note.value } : {},
771
+ idempotencyKey: key
772
+ }).then(() => {
773
+ granted.value = `Granted ${amt} ${w.currency}.`;
774
+ amount.value = "";
775
+ note.value = "";
776
+ }).catch(() => {
777
+ });
778
+ }
779
+ },
780
+ [
781
+ input(amount, "amount (minor units)"),
782
+ input(note, "reason (optional)", { minWidth: "220px" }),
783
+ (0, import_vue11.h)(
784
+ "button",
785
+ {
786
+ type: "submit",
787
+ style: styles.button,
788
+ disabled: !/^\d+$/.test(amount.value.trim())
789
+ },
790
+ "Grant"
791
+ ),
792
+ granted.value ? (0, import_vue11.h)("span", { style: styles.ok }, granted.value) : null
793
+ ]
794
+ ),
795
+ (0, import_vue11.h)("h2", { style: styles.subtitle }, "Ledger"),
796
+ ledger.value.length === 0 ? (0, import_vue11.h)("p", { style: styles.muted }, "Nothing moved yet.") : table(
797
+ ["When", "Kind", "Amount", "Note"],
798
+ ledger.value.map(
799
+ (t) => (0, import_vue11.h)("tr", { key: t.id }, [
800
+ td(new Date(t.createdAt).toLocaleString(), styles.muted),
801
+ td(t.type),
802
+ td(t.amount, styles.mono),
803
+ td(t.description ?? "", styles.muted)
804
+ ])
805
+ )
806
+ ),
807
+ hasMoreLedger.value ? (0, import_vue11.h)(
808
+ "button",
809
+ {
810
+ type: "button",
811
+ style: { ...styles.button, marginTop: "8px" },
812
+ onClick: () => void loadMoreLedger()
813
+ },
814
+ "Load more"
815
+ ) : null
816
+ ] : (0, import_vue11.h)(
817
+ "p",
818
+ { style: styles.muted },
819
+ "No wallet \u2014 billing has no wallet configuration."
820
+ )
821
+ ] : null
822
+ ]);
823
+ };
824
+ }
825
+ });
826
+
463
827
  // src/screens/AdminShell.ts
464
828
  var NAV = [
465
829
  { group: "Today", items: [{ page: "attention", label: "Attention" }] },
@@ -472,6 +836,14 @@ var NAV = [
472
836
  { page: "routes", label: "Routes" }
473
837
  ]
474
838
  },
839
+ { group: "People", items: [{ page: "users", label: "Users", needs: "auth" }] },
840
+ {
841
+ group: "Money",
842
+ items: [
843
+ { page: "catalog", label: "Catalog", needs: "billing" },
844
+ { page: "subscriber", label: "Subscriber", needs: "billing" }
845
+ ]
846
+ },
475
847
  { group: "Settings", items: [{ page: "settings", label: "Config & secrets", needs: "config" }] },
476
848
  { group: "Messaging", items: [{ page: "templates", label: "Templates", needs: "courier" }] },
477
849
  {
@@ -482,7 +854,7 @@ var NAV = [
482
854
  ]
483
855
  }
484
856
  ];
485
- var AdminShell = (0, import_vue9.defineComponent)({
857
+ var AdminShell = (0, import_vue12.defineComponent)({
486
858
  name: "FonderieAdminShell",
487
859
  props: {
488
860
  client: { type: Object, required: true },
@@ -490,6 +862,10 @@ var AdminShell = (0, import_vue9.defineComponent)({
490
862
  // `prefix: '/_admin'` to go through the one token.
491
863
  configClient: { type: Object, default: void 0 },
492
864
  courierClient: { type: Object, default: void 0 },
865
+ // Given ⇒ the People page (users) appears; needs @fonderie/auth ≥ 7.8.
866
+ authClient: { type: Object, default: void 0 },
867
+ // Given ⇒ the Money pages (catalog, subscriber) appear; needs @fonderie/billing ≥ 9.10.
868
+ billingClient: { type: Object, default: void 0 },
493
869
  environment: { type: String, default: void 0 },
494
870
  // Controlled navigation: pass `page` and listen to `navigate` to own the
495
871
  // URL. Omit `page` and the shell keeps it itself.
@@ -497,15 +873,15 @@ var AdminShell = (0, import_vue9.defineComponent)({
497
873
  },
498
874
  emits: { navigate: (_page) => true },
499
875
  setup(props, { emit }) {
500
- const own = (0, import_vue9.ref)("attention");
501
- const current = (0, import_vue9.computed)(() => props.page ?? own.value);
502
- const editing = (0, import_vue9.ref)(null);
876
+ const own = (0, import_vue12.ref)("attention");
877
+ const current = (0, import_vue12.computed)(() => props.page ?? own.value);
878
+ const editing = (0, import_vue12.ref)(null);
503
879
  const go = (p) => {
504
880
  editing.value = null;
505
881
  emit("navigate", p);
506
882
  if (props.page === void 0) own.value = p;
507
883
  };
508
- const back = () => (0, import_vue9.h)(
884
+ const back = () => (0, import_vue12.h)(
509
885
  "button",
510
886
  { type: "button", style: styles.button, onClick: () => editing.value = null },
511
887
  "\u2190 Back"
@@ -514,23 +890,37 @@ var AdminShell = (0, import_vue9.defineComponent)({
514
890
  const c = props.client;
515
891
  switch (current.value) {
516
892
  case "attention":
517
- return (0, import_vue9.h)(AttentionScreen, { client: c });
893
+ return (0, import_vue12.h)(AttentionScreen, { client: c });
518
894
  case "modules":
519
- return (0, import_vue9.h)(ModulesScreen, { client: c });
895
+ return (0, import_vue12.h)(ModulesScreen, { client: c });
520
896
  case "doctor":
521
- return (0, import_vue9.h)(DoctorScreen, { client: c });
897
+ return (0, import_vue12.h)(DoctorScreen, { client: c });
522
898
  case "config":
523
- return (0, import_vue9.h)(ConfigScreen, { client: c });
899
+ return (0, import_vue12.h)(ConfigScreen, { client: c });
524
900
  case "routes":
525
- return (0, import_vue9.h)(RoutesScreen, { client: c });
901
+ return (0, import_vue12.h)(RoutesScreen, { client: c });
526
902
  case "tokens":
527
- return (0, import_vue9.h)(TokensScreen, { client: c });
903
+ return (0, import_vue12.h)(TokensScreen, { client: c });
528
904
  case "log":
529
- return (0, import_vue9.h)(AdminLogScreen, { client: c });
905
+ return (0, import_vue12.h)(AdminLogScreen, { client: c });
906
+ case "catalog":
907
+ return props.billingClient ? (0, import_vue12.h)(CatalogScreen, { client: props.billingClient }) : (0, import_vue12.h)(
908
+ "p",
909
+ { style: styles.status },
910
+ "Pass a BillingAdminClient to see the catalog here."
911
+ );
912
+ case "subscriber":
913
+ return props.billingClient ? (0, import_vue12.h)(SubscriberScreen, { client: props.billingClient }) : (0, import_vue12.h)(
914
+ "p",
915
+ { style: styles.status },
916
+ "Pass a BillingAdminClient to look up subscribers here."
917
+ );
918
+ case "users":
919
+ return props.authClient ? (0, import_vue12.h)(UsersScreen, { client: props.authClient }) : (0, import_vue12.h)("p", { style: styles.status }, "Pass an AuthAdminClient to look up users here.");
530
920
  case "settings": {
531
921
  const cc = props.configClient;
532
922
  if (!cc)
533
- return (0, import_vue9.h)(
923
+ return (0, import_vue12.h)(
534
924
  "p",
535
925
  { style: styles.status },
536
926
  "Pass a ConfigAdminClient to manage config and secrets here."
@@ -539,7 +929,7 @@ var AdminShell = (0, import_vue9.defineComponent)({
539
929
  if (e && e.kind !== "template")
540
930
  return [
541
931
  back(),
542
- (0, import_vue9.h)(import_vue_config_admin_screens.ConfigEditorScreen, {
932
+ (0, import_vue12.h)(import_vue_config_admin_screens.ConfigEditorScreen, {
543
933
  client: cc,
544
934
  kind: e.kind,
545
935
  configKey: e.key,
@@ -547,7 +937,7 @@ var AdminShell = (0, import_vue9.defineComponent)({
547
937
  onSaved: () => editing.value = null
548
938
  })
549
939
  ];
550
- return (0, import_vue9.h)(import_vue_config_admin_screens.ConfigListScreen, {
940
+ return (0, import_vue12.h)(import_vue_config_admin_screens.ConfigListScreen, {
551
941
  client: cc,
552
942
  ...props.environment !== void 0 ? { environment: props.environment } : {},
553
943
  "onSelect-config": (key) => editing.value = { kind: "config", key },
@@ -557,7 +947,7 @@ var AdminShell = (0, import_vue9.defineComponent)({
557
947
  case "templates": {
558
948
  const kc = props.courierClient;
559
949
  if (!kc)
560
- return (0, import_vue9.h)(
950
+ return (0, import_vue12.h)(
561
951
  "p",
562
952
  { style: styles.status },
563
953
  "Pass a CourierAdminClient to manage templates here."
@@ -566,32 +956,32 @@ var AdminShell = (0, import_vue9.defineComponent)({
566
956
  if (e?.kind === "template")
567
957
  return [
568
958
  back(),
569
- (0, import_vue9.h)(import_vue_courier_admin_screens.TemplateEditorScreen, {
959
+ (0, import_vue12.h)(import_vue_courier_admin_screens.TemplateEditorScreen, {
570
960
  client: kc,
571
961
  type: e.type,
572
962
  onSaved: () => editing.value = null
573
963
  })
574
964
  ];
575
- return (0, import_vue9.h)(import_vue_courier_admin_screens.TemplateListScreen, {
965
+ return (0, import_vue12.h)(import_vue_courier_admin_screens.TemplateListScreen, {
576
966
  client: kc,
577
967
  "onSelect-template": (t) => editing.value = { kind: "template", type: t.type }
578
968
  });
579
969
  }
580
970
  }
581
971
  };
582
- return () => (0, import_vue9.h)("div", { style: styles.shell }, [
583
- (0, import_vue9.h)(
972
+ return () => (0, import_vue12.h)("div", { style: styles.shell }, [
973
+ (0, import_vue12.h)(
584
974
  "nav",
585
975
  { style: styles.nav, "aria-label": "Admin" },
586
976
  NAV.map((g) => {
587
977
  const items = g.items.filter(
588
- (i) => !i.needs || (i.needs === "config" ? props.configClient : props.courierClient)
978
+ (i) => !i.needs || (i.needs === "config" ? props.configClient : i.needs === "courier" ? props.courierClient : i.needs === "auth" ? props.authClient : props.billingClient)
589
979
  );
590
980
  if (items.length === 0) return null;
591
- return (0, import_vue9.h)("div", { key: g.group }, [
592
- (0, import_vue9.h)("div", { style: styles.navGroup }, g.group),
981
+ return (0, import_vue12.h)("div", { key: g.group }, [
982
+ (0, import_vue12.h)("div", { style: styles.navGroup }, g.group),
593
983
  ...items.map(
594
- (i) => (0, import_vue9.h)(
984
+ (i) => (0, import_vue12.h)(
595
985
  "button",
596
986
  {
597
987
  key: i.page,
@@ -609,7 +999,7 @@ var AdminShell = (0, import_vue9.defineComponent)({
609
999
  ]);
610
1000
  })
611
1001
  ),
612
- (0, import_vue9.h)("main", { style: styles.main }, body())
1002
+ (0, import_vue12.h)("main", { style: styles.main }, body())
613
1003
  ]);
614
1004
  }
615
1005
  });
@@ -618,10 +1008,13 @@ var AdminShell = (0, import_vue9.defineComponent)({
618
1008
  AdminLogScreen,
619
1009
  AdminShell,
620
1010
  AttentionScreen,
1011
+ CatalogScreen,
621
1012
  ConfigScreen,
622
1013
  DoctorScreen,
623
1014
  ModulesScreen,
624
1015
  RoutesScreen,
625
- TokensScreen
1016
+ SubscriberScreen,
1017
+ TokensScreen,
1018
+ UsersScreen
626
1019
  });
627
1020
  //# sourceMappingURL=index.cjs.map