@fonderie/vue-admin-screens 0.3.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
@@ -14,10 +14,10 @@ Status: **experimental** (0.x).
14
14
  | Money | Catalog · Subscriber | what am I selling (configured vs stored) · what is this subscriber on, their wallet, ledger, a manual grant (`billingClient`) |
15
15
  | Settings | Config & secrets | the `@fonderie/config` admin screens, as a sub-page |
16
16
  | Messaging | Templates | the `@fonderie/courier` admin screens, as a sub-page |
17
- | 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 |
18
18
 
19
19
  ```ts
20
- import { AdminClient, AuthAdminClient, BillingAdminClient, ConfigAdminClient, CourierAdminClient } from '@fonderie/client';
20
+ import { AdminClient, AuditAdminClient, AuthAdminClient, BillingAdminClient, ConfigAdminClient, CourierAdminClient } from '@fonderie/client';
21
21
  import { AdminShell } from '@fonderie/vue-admin-screens';
22
22
 
23
23
  const base = { baseUrl: 'https://api.example.com', adminToken, actor: 'louis' };
@@ -27,10 +27,11 @@ const configClient = new ConfigAdminClient({ ...base, prefix: '/_admin' });
27
27
  const courierClient = new CourierAdminClient({ ...base, prefix: '/_admin' });
28
28
  const authClient = new AuthAdminClient(base); // @fonderie/auth ≥ 7.8
29
29
  const billingClient = new BillingAdminClient(base); // @fonderie/billing ≥ 9.10
30
+ const auditClient = new AuditAdminClient(base); // @fonderie/audit ≥ 5.2
30
31
  ```
31
32
 
32
33
  ```ts
33
- h(AdminShell, { client, configClient, courierClient, authClient, billingClient })
34
+ h(AdminShell, { client, configClient, courierClient, authClient, billingClient, auditClient })
34
35
  ```
35
36
 
36
37
  Pass `page` and listen to `navigate` to own the URL (one route per page);
package/dist/index.cjs CHANGED
@@ -23,6 +23,7 @@ __export(index_exports, {
23
23
  AdminLogScreen: () => AdminLogScreen,
24
24
  AdminShell: () => AdminShell,
25
25
  AttentionScreen: () => AttentionScreen,
26
+ AuditScreen: () => AuditScreen,
26
27
  CatalogScreen: () => CatalogScreen,
27
28
  ConfigScreen: () => ConfigScreen,
28
29
  DoctorScreen: () => DoctorScreen,
@@ -37,7 +38,7 @@ module.exports = __toCommonJS(index_exports);
37
38
  // src/screens/AdminShell.ts
38
39
  var import_vue_config_admin_screens = require("@fonderie/vue-config-admin-screens");
39
40
  var import_vue_courier_admin_screens = require("@fonderie/vue-courier-admin-screens");
40
- var import_vue12 = require("vue");
41
+ var import_vue13 = require("vue");
41
42
 
42
43
  // src/styles.ts
43
44
  var styles = {
@@ -824,6 +825,85 @@ var SubscriberScreen = (0, import_vue11.defineComponent)({
824
825
  }
825
826
  });
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
+
827
907
  // src/screens/AdminShell.ts
828
908
  var NAV = [
829
909
  { group: "Today", items: [{ page: "attention", label: "Attention" }] },
@@ -849,12 +929,13 @@ var NAV = [
849
929
  {
850
930
  group: "Activity",
851
931
  items: [
932
+ { page: "audit", label: "Audit", needs: "audit" },
852
933
  { page: "log", label: "Admin log" },
853
934
  { page: "tokens", label: "Access" }
854
935
  ]
855
936
  }
856
937
  ];
857
- var AdminShell = (0, import_vue12.defineComponent)({
938
+ var AdminShell = (0, import_vue13.defineComponent)({
858
939
  name: "FonderieAdminShell",
859
940
  props: {
860
941
  client: { type: Object, required: true },
@@ -866,6 +947,8 @@ var AdminShell = (0, import_vue12.defineComponent)({
866
947
  authClient: { type: Object, default: void 0 },
867
948
  // Given ⇒ the Money pages (catalog, subscriber) appear; needs @fonderie/billing ≥ 9.10.
868
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 },
869
952
  environment: { type: String, default: void 0 },
870
953
  // Controlled navigation: pass `page` and listen to `navigate` to own the
871
954
  // URL. Omit `page` and the shell keeps it itself.
@@ -873,15 +956,15 @@ var AdminShell = (0, import_vue12.defineComponent)({
873
956
  },
874
957
  emits: { navigate: (_page) => true },
875
958
  setup(props, { emit }) {
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);
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);
879
962
  const go = (p) => {
880
963
  editing.value = null;
881
964
  emit("navigate", p);
882
965
  if (props.page === void 0) own.value = p;
883
966
  };
884
- const back = () => (0, import_vue12.h)(
967
+ const back = () => (0, import_vue13.h)(
885
968
  "button",
886
969
  { type: "button", style: styles.button, onClick: () => editing.value = null },
887
970
  "\u2190 Back"
@@ -890,37 +973,43 @@ var AdminShell = (0, import_vue12.defineComponent)({
890
973
  const c = props.client;
891
974
  switch (current.value) {
892
975
  case "attention":
893
- return (0, import_vue12.h)(AttentionScreen, { client: c });
976
+ return (0, import_vue13.h)(AttentionScreen, { client: c });
894
977
  case "modules":
895
- return (0, import_vue12.h)(ModulesScreen, { client: c });
978
+ return (0, import_vue13.h)(ModulesScreen, { client: c });
896
979
  case "doctor":
897
- return (0, import_vue12.h)(DoctorScreen, { client: c });
980
+ return (0, import_vue13.h)(DoctorScreen, { client: c });
898
981
  case "config":
899
- return (0, import_vue12.h)(ConfigScreen, { client: c });
982
+ return (0, import_vue13.h)(ConfigScreen, { client: c });
900
983
  case "routes":
901
- return (0, import_vue12.h)(RoutesScreen, { client: c });
984
+ return (0, import_vue13.h)(RoutesScreen, { client: c });
902
985
  case "tokens":
903
- return (0, import_vue12.h)(TokensScreen, { client: c });
986
+ return (0, import_vue13.h)(TokensScreen, { client: c });
904
987
  case "log":
905
- return (0, import_vue12.h)(AdminLogScreen, { client: c });
988
+ return (0, import_vue13.h)(AdminLogScreen, { client: c });
906
989
  case "catalog":
907
- return props.billingClient ? (0, import_vue12.h)(CatalogScreen, { client: props.billingClient }) : (0, import_vue12.h)(
990
+ return props.billingClient ? (0, import_vue13.h)(CatalogScreen, { client: props.billingClient }) : (0, import_vue13.h)(
908
991
  "p",
909
992
  { style: styles.status },
910
993
  "Pass a BillingAdminClient to see the catalog here."
911
994
  );
912
995
  case "subscriber":
913
- return props.billingClient ? (0, import_vue12.h)(SubscriberScreen, { client: props.billingClient }) : (0, import_vue12.h)(
996
+ return props.billingClient ? (0, import_vue13.h)(SubscriberScreen, { client: props.billingClient }) : (0, import_vue13.h)(
914
997
  "p",
915
998
  { style: styles.status },
916
999
  "Pass a BillingAdminClient to look up subscribers here."
917
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
+ );
918
1007
  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.");
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.");
920
1009
  case "settings": {
921
1010
  const cc = props.configClient;
922
1011
  if (!cc)
923
- return (0, import_vue12.h)(
1012
+ return (0, import_vue13.h)(
924
1013
  "p",
925
1014
  { style: styles.status },
926
1015
  "Pass a ConfigAdminClient to manage config and secrets here."
@@ -929,7 +1018,7 @@ var AdminShell = (0, import_vue12.defineComponent)({
929
1018
  if (e && e.kind !== "template")
930
1019
  return [
931
1020
  back(),
932
- (0, import_vue12.h)(import_vue_config_admin_screens.ConfigEditorScreen, {
1021
+ (0, import_vue13.h)(import_vue_config_admin_screens.ConfigEditorScreen, {
933
1022
  client: cc,
934
1023
  kind: e.kind,
935
1024
  configKey: e.key,
@@ -937,7 +1026,7 @@ var AdminShell = (0, import_vue12.defineComponent)({
937
1026
  onSaved: () => editing.value = null
938
1027
  })
939
1028
  ];
940
- return (0, import_vue12.h)(import_vue_config_admin_screens.ConfigListScreen, {
1029
+ return (0, import_vue13.h)(import_vue_config_admin_screens.ConfigListScreen, {
941
1030
  client: cc,
942
1031
  ...props.environment !== void 0 ? { environment: props.environment } : {},
943
1032
  "onSelect-config": (key) => editing.value = { kind: "config", key },
@@ -947,7 +1036,7 @@ var AdminShell = (0, import_vue12.defineComponent)({
947
1036
  case "templates": {
948
1037
  const kc = props.courierClient;
949
1038
  if (!kc)
950
- return (0, import_vue12.h)(
1039
+ return (0, import_vue13.h)(
951
1040
  "p",
952
1041
  { style: styles.status },
953
1042
  "Pass a CourierAdminClient to manage templates here."
@@ -956,32 +1045,32 @@ var AdminShell = (0, import_vue12.defineComponent)({
956
1045
  if (e?.kind === "template")
957
1046
  return [
958
1047
  back(),
959
- (0, import_vue12.h)(import_vue_courier_admin_screens.TemplateEditorScreen, {
1048
+ (0, import_vue13.h)(import_vue_courier_admin_screens.TemplateEditorScreen, {
960
1049
  client: kc,
961
1050
  type: e.type,
962
1051
  onSaved: () => editing.value = null
963
1052
  })
964
1053
  ];
965
- return (0, import_vue12.h)(import_vue_courier_admin_screens.TemplateListScreen, {
1054
+ return (0, import_vue13.h)(import_vue_courier_admin_screens.TemplateListScreen, {
966
1055
  client: kc,
967
1056
  "onSelect-template": (t) => editing.value = { kind: "template", type: t.type }
968
1057
  });
969
1058
  }
970
1059
  }
971
1060
  };
972
- return () => (0, import_vue12.h)("div", { style: styles.shell }, [
973
- (0, import_vue12.h)(
1061
+ return () => (0, import_vue13.h)("div", { style: styles.shell }, [
1062
+ (0, import_vue13.h)(
974
1063
  "nav",
975
1064
  { style: styles.nav, "aria-label": "Admin" },
976
1065
  NAV.map((g) => {
977
1066
  const items = g.items.filter(
978
- (i) => !i.needs || (i.needs === "config" ? props.configClient : i.needs === "courier" ? props.courierClient : i.needs === "auth" ? props.authClient : props.billingClient)
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)
979
1068
  );
980
1069
  if (items.length === 0) return null;
981
- return (0, import_vue12.h)("div", { key: g.group }, [
982
- (0, import_vue12.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),
983
1072
  ...items.map(
984
- (i) => (0, import_vue12.h)(
1073
+ (i) => (0, import_vue13.h)(
985
1074
  "button",
986
1075
  {
987
1076
  key: i.page,
@@ -999,7 +1088,7 @@ var AdminShell = (0, import_vue12.defineComponent)({
999
1088
  ]);
1000
1089
  })
1001
1090
  ),
1002
- (0, import_vue12.h)("main", { style: styles.main }, body())
1091
+ (0, import_vue13.h)("main", { style: styles.main }, body())
1003
1092
  ]);
1004
1093
  }
1005
1094
  });
@@ -1008,6 +1097,7 @@ var AdminShell = (0, import_vue12.defineComponent)({
1008
1097
  AdminLogScreen,
1009
1098
  AdminShell,
1010
1099
  AttentionScreen,
1100
+ AuditScreen,
1011
1101
  CatalogScreen,
1012
1102
  ConfigScreen,
1013
1103
  DoctorScreen,