@fonderie/react-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 +4 -3
- package/dist/index.cjs +122 -29
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +121 -29
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
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/react-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
|
```tsx
|
|
33
|
-
<AdminShell client={client} configClient={configClient} courierClient={courierClient} authClient={authClient} billingClient={billingClient} />
|
|
34
|
+
<AdminShell client={client} configClient={configClient} courierClient={courierClient} authClient={authClient} billingClient={billingClient} auditClient={auditClient} />
|
|
34
35
|
```
|
|
35
36
|
|
|
36
37
|
Pass `page` and `onNavigate` to own the URL (one route per page); omit both
|
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.tsx
|
|
38
39
|
var import_react_config_admin_screens = require("@fonderie/react-config-admin-screens");
|
|
39
40
|
var import_react_courier_admin_screens = require("@fonderie/react-courier-admin-screens");
|
|
40
|
-
var
|
|
41
|
+
var import_react4 = require("react");
|
|
41
42
|
|
|
42
43
|
// src/styles.ts
|
|
43
44
|
var styles = {
|
|
@@ -754,8 +755,93 @@ function SubscriberScreen({ client }) {
|
|
|
754
755
|
] });
|
|
755
756
|
}
|
|
756
757
|
|
|
757
|
-
// src/screens/
|
|
758
|
+
// src/screens/AuditScreen.tsx
|
|
759
|
+
var import_react_admin11 = require("@fonderie/react-admin");
|
|
760
|
+
var import_react3 = require("react");
|
|
758
761
|
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
762
|
+
function AuditScreen({ client, pageSize = 50 }) {
|
|
763
|
+
const [draft, setDraft] = (0, import_react3.useState)({ workspaceId: "", type: "", actorId: "" });
|
|
764
|
+
const [filter, setFilter] = (0, import_react3.useState)(
|
|
765
|
+
{}
|
|
766
|
+
);
|
|
767
|
+
const { events, hasMore, isLoading, error, refresh, loadMore } = (0, import_react_admin11.useAdminAudit)(client, {
|
|
768
|
+
...filter,
|
|
769
|
+
limit: pageSize
|
|
770
|
+
});
|
|
771
|
+
const field = (key, placeholder) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
772
|
+
"input",
|
|
773
|
+
{
|
|
774
|
+
value: draft[key],
|
|
775
|
+
onChange: (e) => setDraft({ ...draft, [key]: e.target.value }),
|
|
776
|
+
placeholder,
|
|
777
|
+
style: { ...styles.button, cursor: "text" },
|
|
778
|
+
"aria-label": placeholder
|
|
779
|
+
}
|
|
780
|
+
);
|
|
781
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: styles.container, children: [
|
|
782
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("h1", { style: styles.title, children: "Audit" }),
|
|
783
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
|
|
784
|
+
"form",
|
|
785
|
+
{
|
|
786
|
+
style: styles.toolbar,
|
|
787
|
+
onSubmit: (e) => {
|
|
788
|
+
e.preventDefault();
|
|
789
|
+
setFilter({
|
|
790
|
+
...draft.workspaceId.trim() ? { workspaceId: draft.workspaceId.trim() } : {},
|
|
791
|
+
...draft.type.trim() ? { type: draft.type.trim() } : {},
|
|
792
|
+
...draft.actorId.trim() ? { actorId: draft.actorId.trim() } : {}
|
|
793
|
+
});
|
|
794
|
+
},
|
|
795
|
+
children: [
|
|
796
|
+
field("workspaceId", "workspace id (all if empty)"),
|
|
797
|
+
field("type", "event type"),
|
|
798
|
+
field("actorId", "actor id"),
|
|
799
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { type: "submit", style: styles.button, disabled: isLoading, children: "Filter" }),
|
|
800
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
801
|
+
"button",
|
|
802
|
+
{
|
|
803
|
+
type: "button",
|
|
804
|
+
style: styles.button,
|
|
805
|
+
onClick: () => void refresh(),
|
|
806
|
+
disabled: isLoading,
|
|
807
|
+
children: "Refresh"
|
|
808
|
+
}
|
|
809
|
+
)
|
|
810
|
+
]
|
|
811
|
+
}
|
|
812
|
+
),
|
|
813
|
+
error ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { style: styles.error, role: "alert", children: error.explanation }) : null,
|
|
814
|
+
events.length === 0 && !isLoading ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { style: styles.muted, children: "Nothing recorded for this filter." }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("table", { style: styles.table, children: [
|
|
815
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("tr", { children: [
|
|
816
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("th", { style: styles.th, children: "When" }),
|
|
817
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("th", { style: styles.th, children: "Type" }),
|
|
818
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("th", { style: styles.th, children: "Workspace" }),
|
|
819
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("th", { style: styles.th, children: "Actor" }),
|
|
820
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("th", { style: styles.th, children: "Request" })
|
|
821
|
+
] }) }),
|
|
822
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("tbody", { children: events.map((e) => /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("tr", { children: [
|
|
823
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("td", { style: { ...styles.td, ...styles.muted }, children: new Date(e.createdAt).toLocaleString() }),
|
|
824
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("td", { style: { ...styles.td, ...styles.mono }, children: e.type }),
|
|
825
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("td", { style: { ...styles.td, ...styles.mono }, children: String(e.payload["workspaceId"] ?? "\u2014") }),
|
|
826
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("td", { style: { ...styles.td, ...styles.mono }, children: e.actorId ?? "\u2014" }),
|
|
827
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("td", { style: { ...styles.td, ...styles.muted }, children: e.requestId ?? "" })
|
|
828
|
+
] }, e.id)) })
|
|
829
|
+
] }),
|
|
830
|
+
isLoading ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { style: styles.status, children: "Loading\u2026" }) : null,
|
|
831
|
+
hasMore && !isLoading ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
832
|
+
"button",
|
|
833
|
+
{
|
|
834
|
+
type: "button",
|
|
835
|
+
style: { ...styles.button, marginTop: 8 },
|
|
836
|
+
onClick: () => void loadMore(),
|
|
837
|
+
children: "Load more"
|
|
838
|
+
}
|
|
839
|
+
) : null
|
|
840
|
+
] });
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
// src/screens/AdminShell.tsx
|
|
844
|
+
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
759
845
|
var NAV = [
|
|
760
846
|
{ group: "Today", items: [{ page: "attention", label: "Attention" }] },
|
|
761
847
|
{
|
|
@@ -780,6 +866,7 @@ var NAV = [
|
|
|
780
866
|
{
|
|
781
867
|
group: "Activity",
|
|
782
868
|
items: [
|
|
869
|
+
{ page: "audit", label: "Audit", needs: "audit" },
|
|
783
870
|
{ page: "log", label: "Admin log" },
|
|
784
871
|
{ page: "tokens", label: "Access" }
|
|
785
872
|
]
|
|
@@ -791,59 +878,64 @@ function AdminShell({
|
|
|
791
878
|
courierClient,
|
|
792
879
|
authClient,
|
|
793
880
|
billingClient,
|
|
881
|
+
auditClient,
|
|
794
882
|
environment,
|
|
795
883
|
page,
|
|
796
884
|
onNavigate
|
|
797
885
|
}) {
|
|
798
|
-
const [own, setOwn] = (0,
|
|
886
|
+
const [own, setOwn] = (0, import_react4.useState)("attention");
|
|
799
887
|
const current = page ?? own;
|
|
800
888
|
const go = (p) => {
|
|
801
889
|
if (onNavigate) onNavigate(p);
|
|
802
890
|
if (page === void 0) setOwn(p);
|
|
803
891
|
};
|
|
804
|
-
const [editing, setEditing] = (0,
|
|
892
|
+
const [editing, setEditing] = (0, import_react4.useState)(null);
|
|
805
893
|
const has = {
|
|
806
894
|
config: Boolean(configClient),
|
|
807
895
|
courier: Boolean(courierClient),
|
|
808
896
|
auth: Boolean(authClient),
|
|
809
|
-
billing: Boolean(billingClient)
|
|
897
|
+
billing: Boolean(billingClient),
|
|
898
|
+
audit: Boolean(auditClient)
|
|
810
899
|
};
|
|
811
900
|
let body;
|
|
812
901
|
switch (current) {
|
|
813
902
|
case "attention":
|
|
814
|
-
body = /* @__PURE__ */ (0,
|
|
903
|
+
body = /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(AttentionScreen, { client });
|
|
815
904
|
break;
|
|
816
905
|
case "modules":
|
|
817
|
-
body = /* @__PURE__ */ (0,
|
|
906
|
+
body = /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(ModulesScreen, { client });
|
|
818
907
|
break;
|
|
819
908
|
case "doctor":
|
|
820
|
-
body = /* @__PURE__ */ (0,
|
|
909
|
+
body = /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(DoctorScreen, { client });
|
|
821
910
|
break;
|
|
822
911
|
case "config":
|
|
823
|
-
body = /* @__PURE__ */ (0,
|
|
912
|
+
body = /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(ConfigScreen, { client });
|
|
824
913
|
break;
|
|
825
914
|
case "routes":
|
|
826
|
-
body = /* @__PURE__ */ (0,
|
|
915
|
+
body = /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(RoutesScreen, { client });
|
|
827
916
|
break;
|
|
828
917
|
case "tokens":
|
|
829
|
-
body = /* @__PURE__ */ (0,
|
|
918
|
+
body = /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(TokensScreen, { client });
|
|
830
919
|
break;
|
|
831
920
|
case "log":
|
|
832
|
-
body = /* @__PURE__ */ (0,
|
|
921
|
+
body = /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(AdminLogScreen, { client });
|
|
833
922
|
break;
|
|
834
923
|
case "catalog":
|
|
835
|
-
body = billingClient ? /* @__PURE__ */ (0,
|
|
924
|
+
body = billingClient ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(CatalogScreen, { client: billingClient }) : /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { style: styles.status, children: "Pass a BillingAdminClient to see the catalog here." });
|
|
836
925
|
break;
|
|
837
926
|
case "subscriber":
|
|
838
|
-
body = billingClient ? /* @__PURE__ */ (0,
|
|
927
|
+
body = billingClient ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(SubscriberScreen, { client: billingClient }) : /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { style: styles.status, children: "Pass a BillingAdminClient to look up subscribers here." });
|
|
928
|
+
break;
|
|
929
|
+
case "audit":
|
|
930
|
+
body = auditClient ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(AuditScreen, { client: auditClient }) : /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { style: styles.status, children: "Pass an AuditAdminClient to see the audit trail here." });
|
|
839
931
|
break;
|
|
840
932
|
case "users":
|
|
841
|
-
body = authClient ? /* @__PURE__ */ (0,
|
|
933
|
+
body = authClient ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(UsersScreen, { client: authClient }) : /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { style: styles.status, children: "Pass an AuthAdminClient to look up users here." });
|
|
842
934
|
break;
|
|
843
935
|
case "settings":
|
|
844
|
-
body = !configClient ? /* @__PURE__ */ (0,
|
|
845
|
-
/* @__PURE__ */ (0,
|
|
846
|
-
/* @__PURE__ */ (0,
|
|
936
|
+
body = !configClient ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { style: styles.status, children: "Pass a ConfigAdminClient to manage config and secrets here." }) : editing && editing.kind !== "template" ? /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
|
|
937
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("button", { type: "button", style: styles.button, onClick: () => setEditing(null), children: "\u2190 Back" }),
|
|
938
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
847
939
|
import_react_config_admin_screens.ConfigEditorScreen,
|
|
848
940
|
{
|
|
849
941
|
client: configClient,
|
|
@@ -853,7 +945,7 @@ function AdminShell({
|
|
|
853
945
|
onSaved: () => setEditing(null)
|
|
854
946
|
}
|
|
855
947
|
)
|
|
856
|
-
] }) : /* @__PURE__ */ (0,
|
|
948
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
857
949
|
import_react_config_admin_screens.ConfigListScreen,
|
|
858
950
|
{
|
|
859
951
|
client: configClient,
|
|
@@ -864,9 +956,9 @@ function AdminShell({
|
|
|
864
956
|
);
|
|
865
957
|
break;
|
|
866
958
|
case "templates":
|
|
867
|
-
body = !courierClient ? /* @__PURE__ */ (0,
|
|
868
|
-
/* @__PURE__ */ (0,
|
|
869
|
-
/* @__PURE__ */ (0,
|
|
959
|
+
body = !courierClient ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { style: styles.status, children: "Pass a CourierAdminClient to manage templates here." }) : editing?.kind === "template" ? /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
|
|
960
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("button", { type: "button", style: styles.button, onClick: () => setEditing(null), children: "\u2190 Back" }),
|
|
961
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
870
962
|
import_react_courier_admin_screens.TemplateEditorScreen,
|
|
871
963
|
{
|
|
872
964
|
client: courierClient,
|
|
@@ -874,7 +966,7 @@ function AdminShell({
|
|
|
874
966
|
onSaved: () => setEditing(null)
|
|
875
967
|
}
|
|
876
968
|
)
|
|
877
|
-
] }) : /* @__PURE__ */ (0,
|
|
969
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
878
970
|
import_react_courier_admin_screens.TemplateListScreen,
|
|
879
971
|
{
|
|
880
972
|
client: courierClient,
|
|
@@ -883,13 +975,13 @@ function AdminShell({
|
|
|
883
975
|
);
|
|
884
976
|
break;
|
|
885
977
|
}
|
|
886
|
-
return /* @__PURE__ */ (0,
|
|
887
|
-
/* @__PURE__ */ (0,
|
|
978
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { style: styles.shell, children: [
|
|
979
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("nav", { style: styles.nav, "aria-label": "Admin", children: NAV.map((g) => {
|
|
888
980
|
const items = g.items.filter((i) => !i.needs || has[i.needs]);
|
|
889
981
|
if (items.length === 0) return null;
|
|
890
|
-
return /* @__PURE__ */ (0,
|
|
891
|
-
/* @__PURE__ */ (0,
|
|
892
|
-
items.map((i) => /* @__PURE__ */ (0,
|
|
982
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { children: [
|
|
983
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { style: styles.navGroup, children: g.group }),
|
|
984
|
+
items.map((i) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
893
985
|
"button",
|
|
894
986
|
{
|
|
895
987
|
type: "button",
|
|
@@ -905,7 +997,7 @@ function AdminShell({
|
|
|
905
997
|
))
|
|
906
998
|
] }, g.group);
|
|
907
999
|
}) }),
|
|
908
|
-
/* @__PURE__ */ (0,
|
|
1000
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("main", { style: styles.main, children: body })
|
|
909
1001
|
] });
|
|
910
1002
|
}
|
|
911
1003
|
// Annotate the CommonJS export names for ESM import in node:
|
|
@@ -913,6 +1005,7 @@ function AdminShell({
|
|
|
913
1005
|
AdminLogScreen,
|
|
914
1006
|
AdminShell,
|
|
915
1007
|
AttentionScreen,
|
|
1008
|
+
AuditScreen,
|
|
916
1009
|
CatalogScreen,
|
|
917
1010
|
ConfigScreen,
|
|
918
1011
|
DoctorScreen,
|