@fonderie/react-admin-screens 0.3.0 → 0.5.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.js CHANGED
@@ -1,7 +1,7 @@
1
1
  // src/screens/AdminShell.tsx
2
2
  import { ConfigEditorScreen, ConfigListScreen } from "@fonderie/react-config-admin-screens";
3
3
  import { TemplateEditorScreen, TemplateListScreen } from "@fonderie/react-courier-admin-screens";
4
- import { useState as useState3 } from "react";
4
+ import { useState as useState5 } from "react";
5
5
 
6
6
  // src/styles.ts
7
7
  var styles = {
@@ -309,34 +309,146 @@ function RoutesScreen({ client }) {
309
309
 
310
310
  // src/screens/TokensScreen.tsx
311
311
  import { useAdminTokens } from "@fonderie/react-admin";
312
+ import { useState } from "react";
312
313
  import { Fragment as Fragment4, jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
314
+ var ALL = ["read", "write", "secrets"];
313
315
  function TokensScreen({ client }) {
314
- const { report, isLoading, error } = useAdminTokens(client);
316
+ const { report, isLoading, error, issue, revoke } = useAdminTokens(client);
317
+ const [name, setName] = useState("");
318
+ const [scopes, setScopes] = useState(["read"]);
319
+ const [days, setDays] = useState("");
320
+ const [minted, setMinted] = useState(null);
321
+ const toggle = (s) => setScopes((prev) => prev.includes(s) ? prev.filter((x) => x !== s) : [...prev, s]);
315
322
  return /* @__PURE__ */ jsxs7("div", { style: styles.container, children: [
316
323
  /* @__PURE__ */ jsx7("h1", { style: styles.title, children: "Access" }),
317
- isLoading ? /* @__PURE__ */ jsx7("p", { style: styles.status, children: "Loading\u2026" }) : error ? /* @__PURE__ */ jsx7("p", { style: styles.error, role: "alert", children: error.explanation }) : report ? /* @__PURE__ */ jsxs7(Fragment4, { children: [
318
- /* @__PURE__ */ jsx7("h2", { style: styles.subtitle, children: "Admin token" }),
319
- /* @__PURE__ */ jsxs7("p", { children: [
320
- report.admin.ok ? /* @__PURE__ */ jsx7("span", { style: styles.ok, children: "strong" }) : /* @__PURE__ */ jsx7("span", { style: styles.bad, children: "weak" }),
321
- report.admin.problems.map((p) => /* @__PURE__ */ jsx7("div", { style: styles.bad, children: p.message }, p.message))
322
- ] }),
323
- /* @__PURE__ */ jsx7("h2", { style: styles.subtitle, children: "Legacy per-brick tokens" }),
324
- report.legacy.length === 0 ? /* @__PURE__ */ jsx7("p", { style: styles.muted, children: "None \u2014 every brick's admin surface goes through this token." }) : /* @__PURE__ */ jsx7("ul", { style: styles.list, children: report.legacy.map((l) => /* @__PURE__ */ jsxs7("li", { style: styles.row, children: [
325
- /* @__PURE__ */ jsx7("span", { style: styles.mono, children: l.module }),
324
+ error ? /* @__PURE__ */ jsx7("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,
325
+ /* @__PURE__ */ jsx7("h2", { style: styles.subtitle, children: "Root token" }),
326
+ report ? /* @__PURE__ */ jsxs7("p", { children: [
327
+ report.admin.ok ? /* @__PURE__ */ jsx7("span", { style: styles.ok, children: "strong" }) : /* @__PURE__ */ jsx7("span", { style: styles.bad, children: "weak" }),
328
+ report.admin.problems.map((p) => /* @__PURE__ */ jsx7("div", { style: styles.bad, children: p.message }, p.message))
329
+ ] }) : null,
330
+ /* @__PURE__ */ jsx7("h2", { style: styles.subtitle, children: "Issued tokens" }),
331
+ report?.issued === null ? /* @__PURE__ */ jsx7("p", { style: styles.muted, children: "Issuing is off \u2014 give AdminModule a store and run its migrations." }) : /* @__PURE__ */ jsxs7(Fragment4, { children: [
332
+ minted ? /* @__PURE__ */ jsxs7("p", { style: styles.ok, children: [
333
+ "Copy this now \u2014 it is never shown again.",
326
334
  " ",
327
- /* @__PURE__ */ jsx7("span", { style: styles.muted, children: "still registers its standalone routes with its own token (deprecated)" })
328
- ] }, l.module)) })
329
- ] }) : null
335
+ /* @__PURE__ */ jsx7("span", { style: styles.mono, children: minted.token }),
336
+ " (",
337
+ minted.name,
338
+ ")"
339
+ ] }) : null,
340
+ /* @__PURE__ */ jsxs7(
341
+ "form",
342
+ {
343
+ style: styles.toolbar,
344
+ onSubmit: (e) => {
345
+ e.preventDefault();
346
+ const d = Number(days);
347
+ void issue({
348
+ name: name.trim(),
349
+ scopes,
350
+ ...days && Number.isInteger(d) && d > 0 ? { expiresInDays: d } : {}
351
+ }).then((t) => {
352
+ setMinted({ name: t.name, token: t.token });
353
+ setName("");
354
+ setDays("");
355
+ }).catch(() => {
356
+ });
357
+ },
358
+ children: [
359
+ /* @__PURE__ */ jsx7(
360
+ "input",
361
+ {
362
+ value: name,
363
+ onChange: (e) => setName(e.target.value),
364
+ placeholder: "name",
365
+ style: { ...styles.button, cursor: "text" },
366
+ "aria-label": "Name"
367
+ }
368
+ ),
369
+ ALL.map((s) => /* @__PURE__ */ jsxs7("label", { style: { ...styles.badge, cursor: "pointer" }, children: [
370
+ /* @__PURE__ */ jsx7("input", { type: "checkbox", checked: scopes.includes(s), onChange: () => toggle(s) }),
371
+ " ",
372
+ s
373
+ ] }, s)),
374
+ /* @__PURE__ */ jsx7(
375
+ "input",
376
+ {
377
+ value: days,
378
+ onChange: (e) => setDays(e.target.value),
379
+ placeholder: "days (optional)",
380
+ style: { ...styles.button, cursor: "text", width: 140 },
381
+ "aria-label": "Days"
382
+ }
383
+ ),
384
+ /* @__PURE__ */ jsx7(
385
+ "button",
386
+ {
387
+ type: "submit",
388
+ style: styles.button,
389
+ disabled: !name.trim() || scopes.length === 0 || isLoading,
390
+ children: "Issue"
391
+ }
392
+ )
393
+ ]
394
+ }
395
+ ),
396
+ report?.issued && report.issued.length > 0 ? /* @__PURE__ */ jsxs7("table", { style: styles.table, children: [
397
+ /* @__PURE__ */ jsx7("thead", { children: /* @__PURE__ */ jsxs7("tr", { children: [
398
+ /* @__PURE__ */ jsx7("th", { style: styles.th, children: "Name" }),
399
+ /* @__PURE__ */ jsx7("th", { style: styles.th, children: "Scopes" }),
400
+ /* @__PURE__ */ jsx7("th", { style: styles.th, children: "Created" }),
401
+ /* @__PURE__ */ jsx7("th", { style: styles.th, children: "Expires" }),
402
+ /* @__PURE__ */ jsx7("th", { style: styles.th, children: "Last used" }),
403
+ /* @__PURE__ */ jsx7("th", { style: styles.th })
404
+ ] }) }),
405
+ /* @__PURE__ */ jsx7("tbody", { children: report.issued.map((t) => /* @__PURE__ */ jsxs7("tr", { children: [
406
+ /* @__PURE__ */ jsxs7("td", { style: styles.td, children: [
407
+ t.name,
408
+ t.revokedAt ? /* @__PURE__ */ jsx7("span", { style: styles.badge, children: " revoked" }) : null
409
+ ] }),
410
+ /* @__PURE__ */ jsx7("td", { style: { ...styles.td, ...styles.mono }, children: t.scopes.join(", ") }),
411
+ /* @__PURE__ */ jsxs7("td", { style: { ...styles.td, ...styles.muted }, children: [
412
+ new Date(t.createdAt).toLocaleDateString(),
413
+ " \xB7 ",
414
+ t.createdBy
415
+ ] }),
416
+ /* @__PURE__ */ jsx7("td", { style: { ...styles.td, ...styles.muted }, children: t.expiresAt ? new Date(t.expiresAt).toLocaleDateString() : "never" }),
417
+ /* @__PURE__ */ jsx7("td", { style: { ...styles.td, ...styles.muted }, children: t.lastUsedAt ? new Date(t.lastUsedAt).toLocaleString() : "never" }),
418
+ /* @__PURE__ */ jsx7("td", { style: styles.td, children: t.revokedAt ? null : /* @__PURE__ */ jsx7(
419
+ "button",
420
+ {
421
+ type: "button",
422
+ style: styles.button,
423
+ onClick: () => {
424
+ if (window.confirm(
425
+ `Revoke "${t.name}"? Anything using it stops working immediately.`
426
+ ))
427
+ void revoke(t.id).catch(() => {
428
+ });
429
+ },
430
+ children: "Revoke"
431
+ }
432
+ ) })
433
+ ] }, t.id)) })
434
+ ] }) : /* @__PURE__ */ jsx7("p", { style: styles.muted, children: "None issued." })
435
+ ] }),
436
+ /* @__PURE__ */ jsx7("h2", { style: styles.subtitle, children: "Legacy per-brick tokens" }),
437
+ report && report.legacy.length === 0 ? /* @__PURE__ */ jsx7("p", { style: styles.muted, children: "None \u2014 every brick's admin surface goes through this token." }) : /* @__PURE__ */ jsx7("ul", { style: styles.list, children: report?.legacy.map((l) => /* @__PURE__ */ jsxs7("li", { style: styles.row, children: [
438
+ /* @__PURE__ */ jsx7("span", { style: styles.mono, children: l.module }),
439
+ " ",
440
+ /* @__PURE__ */ jsx7("span", { style: styles.muted, children: "still registers its standalone routes with its own token (deprecated)" })
441
+ ] }, l.module)) })
330
442
  ] });
331
443
  }
332
444
 
333
445
  // src/screens/UsersScreen.tsx
334
446
  import { useAdminLoginHistory, useAdminUser, useAdminUserSessions } from "@fonderie/react-admin";
335
- import { useState } from "react";
447
+ import { useState as useState2 } from "react";
336
448
  import { Fragment as Fragment5, jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
337
449
  function UsersScreen({ client }) {
338
- const [input, setInput] = useState("");
339
- const [email, setEmail] = useState(void 0);
450
+ const [input, setInput] = useState2("");
451
+ const [email, setEmail] = useState2(void 0);
340
452
  const { user, isLoading, error, suspend, unsuspend, revokeSessions } = useAdminUser(
341
453
  client,
342
454
  email ? { email } : {}
@@ -546,16 +658,16 @@ function CatalogScreen({ client }) {
546
658
 
547
659
  // src/screens/SubscriberScreen.tsx
548
660
  import { useAdminSubscriber } from "@fonderie/react-admin";
549
- import { useState as useState2 } from "react";
661
+ import { useState as useState3 } from "react";
550
662
  import { Fragment as Fragment7, jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
551
663
  function SubscriberScreen({ client }) {
552
- const [type, setType] = useState2("user");
553
- const [idInput, setIdInput] = useState2("");
554
- const [subscriber, setSubscriber] = useState2(null);
664
+ const [type, setType] = useState3("user");
665
+ const [idInput, setIdInput] = useState3("");
666
+ const [subscriber, setSubscriber] = useState3(null);
555
667
  const { subscription, wallet, ledger, hasMoreLedger, isLoading, error, loadMoreLedger, grant } = useAdminSubscriber(client, subscriber, { limit: 20 });
556
- const [amount, setAmount] = useState2("");
557
- const [note, setNote] = useState2("");
558
- const [granted, setGranted] = useState2(null);
668
+ const [amount, setAmount] = useState3("");
669
+ const [note, setNote] = useState3("");
670
+ const [granted, setGranted] = useState3(null);
559
671
  return /* @__PURE__ */ jsxs10("div", { style: styles.container, children: [
560
672
  /* @__PURE__ */ jsx10("h1", { style: styles.title, children: "Subscriber" }),
561
673
  /* @__PURE__ */ jsxs10(
@@ -718,8 +830,93 @@ function SubscriberScreen({ client }) {
718
830
  ] });
719
831
  }
720
832
 
833
+ // src/screens/AuditScreen.tsx
834
+ import { useAdminAudit } from "@fonderie/react-admin";
835
+ import { useState as useState4 } from "react";
836
+ import { jsx as jsx11, jsxs as jsxs11 } from "react/jsx-runtime";
837
+ function AuditScreen({ client, pageSize = 50 }) {
838
+ const [draft, setDraft] = useState4({ workspaceId: "", type: "", actorId: "" });
839
+ const [filter, setFilter] = useState4(
840
+ {}
841
+ );
842
+ const { events, hasMore, isLoading, error, refresh, loadMore } = useAdminAudit(client, {
843
+ ...filter,
844
+ limit: pageSize
845
+ });
846
+ const field = (key, placeholder) => /* @__PURE__ */ jsx11(
847
+ "input",
848
+ {
849
+ value: draft[key],
850
+ onChange: (e) => setDraft({ ...draft, [key]: e.target.value }),
851
+ placeholder,
852
+ style: { ...styles.button, cursor: "text" },
853
+ "aria-label": placeholder
854
+ }
855
+ );
856
+ return /* @__PURE__ */ jsxs11("div", { style: styles.container, children: [
857
+ /* @__PURE__ */ jsx11("h1", { style: styles.title, children: "Audit" }),
858
+ /* @__PURE__ */ jsxs11(
859
+ "form",
860
+ {
861
+ style: styles.toolbar,
862
+ onSubmit: (e) => {
863
+ e.preventDefault();
864
+ setFilter({
865
+ ...draft.workspaceId.trim() ? { workspaceId: draft.workspaceId.trim() } : {},
866
+ ...draft.type.trim() ? { type: draft.type.trim() } : {},
867
+ ...draft.actorId.trim() ? { actorId: draft.actorId.trim() } : {}
868
+ });
869
+ },
870
+ children: [
871
+ field("workspaceId", "workspace id (all if empty)"),
872
+ field("type", "event type"),
873
+ field("actorId", "actor id"),
874
+ /* @__PURE__ */ jsx11("button", { type: "submit", style: styles.button, disabled: isLoading, children: "Filter" }),
875
+ /* @__PURE__ */ jsx11(
876
+ "button",
877
+ {
878
+ type: "button",
879
+ style: styles.button,
880
+ onClick: () => void refresh(),
881
+ disabled: isLoading,
882
+ children: "Refresh"
883
+ }
884
+ )
885
+ ]
886
+ }
887
+ ),
888
+ error ? /* @__PURE__ */ jsx11("p", { style: styles.error, role: "alert", children: error.explanation }) : null,
889
+ events.length === 0 && !isLoading ? /* @__PURE__ */ jsx11("p", { style: styles.muted, children: "Nothing recorded for this filter." }) : /* @__PURE__ */ jsxs11("table", { style: styles.table, children: [
890
+ /* @__PURE__ */ jsx11("thead", { children: /* @__PURE__ */ jsxs11("tr", { children: [
891
+ /* @__PURE__ */ jsx11("th", { style: styles.th, children: "When" }),
892
+ /* @__PURE__ */ jsx11("th", { style: styles.th, children: "Type" }),
893
+ /* @__PURE__ */ jsx11("th", { style: styles.th, children: "Workspace" }),
894
+ /* @__PURE__ */ jsx11("th", { style: styles.th, children: "Actor" }),
895
+ /* @__PURE__ */ jsx11("th", { style: styles.th, children: "Request" })
896
+ ] }) }),
897
+ /* @__PURE__ */ jsx11("tbody", { children: events.map((e) => /* @__PURE__ */ jsxs11("tr", { children: [
898
+ /* @__PURE__ */ jsx11("td", { style: { ...styles.td, ...styles.muted }, children: new Date(e.createdAt).toLocaleString() }),
899
+ /* @__PURE__ */ jsx11("td", { style: { ...styles.td, ...styles.mono }, children: e.type }),
900
+ /* @__PURE__ */ jsx11("td", { style: { ...styles.td, ...styles.mono }, children: String(e.payload["workspaceId"] ?? "\u2014") }),
901
+ /* @__PURE__ */ jsx11("td", { style: { ...styles.td, ...styles.mono }, children: e.actorId ?? "\u2014" }),
902
+ /* @__PURE__ */ jsx11("td", { style: { ...styles.td, ...styles.muted }, children: e.requestId ?? "" })
903
+ ] }, e.id)) })
904
+ ] }),
905
+ isLoading ? /* @__PURE__ */ jsx11("p", { style: styles.status, children: "Loading\u2026" }) : null,
906
+ hasMore && !isLoading ? /* @__PURE__ */ jsx11(
907
+ "button",
908
+ {
909
+ type: "button",
910
+ style: { ...styles.button, marginTop: 8 },
911
+ onClick: () => void loadMore(),
912
+ children: "Load more"
913
+ }
914
+ ) : null
915
+ ] });
916
+ }
917
+
721
918
  // src/screens/AdminShell.tsx
722
- import { Fragment as Fragment8, jsx as jsx11, jsxs as jsxs11 } from "react/jsx-runtime";
919
+ import { Fragment as Fragment8, jsx as jsx12, jsxs as jsxs12 } from "react/jsx-runtime";
723
920
  var NAV = [
724
921
  { group: "Today", items: [{ page: "attention", label: "Attention" }] },
725
922
  {
@@ -744,6 +941,7 @@ var NAV = [
744
941
  {
745
942
  group: "Activity",
746
943
  items: [
944
+ { page: "audit", label: "Audit", needs: "audit" },
747
945
  { page: "log", label: "Admin log" },
748
946
  { page: "tokens", label: "Access" }
749
947
  ]
@@ -755,59 +953,64 @@ function AdminShell({
755
953
  courierClient,
756
954
  authClient,
757
955
  billingClient,
956
+ auditClient,
758
957
  environment,
759
958
  page,
760
959
  onNavigate
761
960
  }) {
762
- const [own, setOwn] = useState3("attention");
961
+ const [own, setOwn] = useState5("attention");
763
962
  const current = page ?? own;
764
963
  const go = (p) => {
765
964
  if (onNavigate) onNavigate(p);
766
965
  if (page === void 0) setOwn(p);
767
966
  };
768
- const [editing, setEditing] = useState3(null);
967
+ const [editing, setEditing] = useState5(null);
769
968
  const has = {
770
969
  config: Boolean(configClient),
771
970
  courier: Boolean(courierClient),
772
971
  auth: Boolean(authClient),
773
- billing: Boolean(billingClient)
972
+ billing: Boolean(billingClient),
973
+ audit: Boolean(auditClient)
774
974
  };
775
975
  let body;
776
976
  switch (current) {
777
977
  case "attention":
778
- body = /* @__PURE__ */ jsx11(AttentionScreen, { client });
978
+ body = /* @__PURE__ */ jsx12(AttentionScreen, { client });
779
979
  break;
780
980
  case "modules":
781
- body = /* @__PURE__ */ jsx11(ModulesScreen, { client });
981
+ body = /* @__PURE__ */ jsx12(ModulesScreen, { client });
782
982
  break;
783
983
  case "doctor":
784
- body = /* @__PURE__ */ jsx11(DoctorScreen, { client });
984
+ body = /* @__PURE__ */ jsx12(DoctorScreen, { client });
785
985
  break;
786
986
  case "config":
787
- body = /* @__PURE__ */ jsx11(ConfigScreen, { client });
987
+ body = /* @__PURE__ */ jsx12(ConfigScreen, { client });
788
988
  break;
789
989
  case "routes":
790
- body = /* @__PURE__ */ jsx11(RoutesScreen, { client });
990
+ body = /* @__PURE__ */ jsx12(RoutesScreen, { client });
791
991
  break;
792
992
  case "tokens":
793
- body = /* @__PURE__ */ jsx11(TokensScreen, { client });
993
+ body = /* @__PURE__ */ jsx12(TokensScreen, { client });
794
994
  break;
795
995
  case "log":
796
- body = /* @__PURE__ */ jsx11(AdminLogScreen, { client });
996
+ body = /* @__PURE__ */ jsx12(AdminLogScreen, { client });
797
997
  break;
798
998
  case "catalog":
799
- body = billingClient ? /* @__PURE__ */ jsx11(CatalogScreen, { client: billingClient }) : /* @__PURE__ */ jsx11("p", { style: styles.status, children: "Pass a BillingAdminClient to see the catalog here." });
999
+ body = billingClient ? /* @__PURE__ */ jsx12(CatalogScreen, { client: billingClient }) : /* @__PURE__ */ jsx12("p", { style: styles.status, children: "Pass a BillingAdminClient to see the catalog here." });
800
1000
  break;
801
1001
  case "subscriber":
802
- body = billingClient ? /* @__PURE__ */ jsx11(SubscriberScreen, { client: billingClient }) : /* @__PURE__ */ jsx11("p", { style: styles.status, children: "Pass a BillingAdminClient to look up subscribers here." });
1002
+ body = billingClient ? /* @__PURE__ */ jsx12(SubscriberScreen, { client: billingClient }) : /* @__PURE__ */ jsx12("p", { style: styles.status, children: "Pass a BillingAdminClient to look up subscribers here." });
1003
+ break;
1004
+ case "audit":
1005
+ body = auditClient ? /* @__PURE__ */ jsx12(AuditScreen, { client: auditClient }) : /* @__PURE__ */ jsx12("p", { style: styles.status, children: "Pass an AuditAdminClient to see the audit trail here." });
803
1006
  break;
804
1007
  case "users":
805
- body = authClient ? /* @__PURE__ */ jsx11(UsersScreen, { client: authClient }) : /* @__PURE__ */ jsx11("p", { style: styles.status, children: "Pass an AuthAdminClient to look up users here." });
1008
+ body = authClient ? /* @__PURE__ */ jsx12(UsersScreen, { client: authClient }) : /* @__PURE__ */ jsx12("p", { style: styles.status, children: "Pass an AuthAdminClient to look up users here." });
806
1009
  break;
807
1010
  case "settings":
808
- body = !configClient ? /* @__PURE__ */ jsx11("p", { style: styles.status, children: "Pass a ConfigAdminClient to manage config and secrets here." }) : editing && editing.kind !== "template" ? /* @__PURE__ */ jsxs11(Fragment8, { children: [
809
- /* @__PURE__ */ jsx11("button", { type: "button", style: styles.button, onClick: () => setEditing(null), children: "\u2190 Back" }),
810
- /* @__PURE__ */ jsx11(
1011
+ body = !configClient ? /* @__PURE__ */ jsx12("p", { style: styles.status, children: "Pass a ConfigAdminClient to manage config and secrets here." }) : editing && editing.kind !== "template" ? /* @__PURE__ */ jsxs12(Fragment8, { children: [
1012
+ /* @__PURE__ */ jsx12("button", { type: "button", style: styles.button, onClick: () => setEditing(null), children: "\u2190 Back" }),
1013
+ /* @__PURE__ */ jsx12(
811
1014
  ConfigEditorScreen,
812
1015
  {
813
1016
  client: configClient,
@@ -817,7 +1020,7 @@ function AdminShell({
817
1020
  onSaved: () => setEditing(null)
818
1021
  }
819
1022
  )
820
- ] }) : /* @__PURE__ */ jsx11(
1023
+ ] }) : /* @__PURE__ */ jsx12(
821
1024
  ConfigListScreen,
822
1025
  {
823
1026
  client: configClient,
@@ -828,9 +1031,9 @@ function AdminShell({
828
1031
  );
829
1032
  break;
830
1033
  case "templates":
831
- body = !courierClient ? /* @__PURE__ */ jsx11("p", { style: styles.status, children: "Pass a CourierAdminClient to manage templates here." }) : editing?.kind === "template" ? /* @__PURE__ */ jsxs11(Fragment8, { children: [
832
- /* @__PURE__ */ jsx11("button", { type: "button", style: styles.button, onClick: () => setEditing(null), children: "\u2190 Back" }),
833
- /* @__PURE__ */ jsx11(
1034
+ body = !courierClient ? /* @__PURE__ */ jsx12("p", { style: styles.status, children: "Pass a CourierAdminClient to manage templates here." }) : editing?.kind === "template" ? /* @__PURE__ */ jsxs12(Fragment8, { children: [
1035
+ /* @__PURE__ */ jsx12("button", { type: "button", style: styles.button, onClick: () => setEditing(null), children: "\u2190 Back" }),
1036
+ /* @__PURE__ */ jsx12(
834
1037
  TemplateEditorScreen,
835
1038
  {
836
1039
  client: courierClient,
@@ -838,7 +1041,7 @@ function AdminShell({
838
1041
  onSaved: () => setEditing(null)
839
1042
  }
840
1043
  )
841
- ] }) : /* @__PURE__ */ jsx11(
1044
+ ] }) : /* @__PURE__ */ jsx12(
842
1045
  TemplateListScreen,
843
1046
  {
844
1047
  client: courierClient,
@@ -847,13 +1050,13 @@ function AdminShell({
847
1050
  );
848
1051
  break;
849
1052
  }
850
- return /* @__PURE__ */ jsxs11("div", { style: styles.shell, children: [
851
- /* @__PURE__ */ jsx11("nav", { style: styles.nav, "aria-label": "Admin", children: NAV.map((g) => {
1053
+ return /* @__PURE__ */ jsxs12("div", { style: styles.shell, children: [
1054
+ /* @__PURE__ */ jsx12("nav", { style: styles.nav, "aria-label": "Admin", children: NAV.map((g) => {
852
1055
  const items = g.items.filter((i) => !i.needs || has[i.needs]);
853
1056
  if (items.length === 0) return null;
854
- return /* @__PURE__ */ jsxs11("div", { children: [
855
- /* @__PURE__ */ jsx11("div", { style: styles.navGroup, children: g.group }),
856
- items.map((i) => /* @__PURE__ */ jsx11(
1057
+ return /* @__PURE__ */ jsxs12("div", { children: [
1058
+ /* @__PURE__ */ jsx12("div", { style: styles.navGroup, children: g.group }),
1059
+ items.map((i) => /* @__PURE__ */ jsx12(
857
1060
  "button",
858
1061
  {
859
1062
  type: "button",
@@ -869,13 +1072,14 @@ function AdminShell({
869
1072
  ))
870
1073
  ] }, g.group);
871
1074
  }) }),
872
- /* @__PURE__ */ jsx11("main", { style: styles.main, children: body })
1075
+ /* @__PURE__ */ jsx12("main", { style: styles.main, children: body })
873
1076
  ] });
874
1077
  }
875
1078
  export {
876
1079
  AdminLogScreen,
877
1080
  AdminShell,
878
1081
  AttentionScreen,
1082
+ AuditScreen,
879
1083
  CatalogScreen,
880
1084
  ConfigScreen,
881
1085
  DoctorScreen,