@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/README.md +11 -3
- package/dist/index.cjs +257 -52
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +75 -0
- package/dist/index.d.ts +75 -0
- package/dist/index.js +256 -52
- 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, and issue or revoke scoped tokens |
|
|
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,16 +27,24 @@ 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
|
|
37
38
|
and the shell keeps the page itself. Settings and Messaging appear only when
|
|
38
39
|
their client is given.
|
|
39
40
|
|
|
41
|
+
**Give the shell a `read` token, not the root one.** With `@fonderie/admin`
|
|
42
|
+
≥ 0.6 the configured `adminToken` is the root — every scope, including the
|
|
43
|
+
plaintext secret reveal, and the only credential that can mint or revoke.
|
|
44
|
+
Issue a scoped one for the dashboard (`fonderie admin token issue dashboard
|
|
45
|
+
--scopes read`, or the Access page itself) and hand the shell that. The
|
|
46
|
+
Access page then shows issuing as unavailable, which is the point.
|
|
47
|
+
|
|
40
48
|
Nothing here stores the token: the app constructs the clients and decides
|
|
41
49
|
where the token lives. Every request through the shell lands in the admin
|
|
42
50
|
log, including the ones the token refuses.
|
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_react5 = require("react");
|
|
41
42
|
|
|
42
43
|
// src/styles.ts
|
|
43
44
|
var styles = {
|
|
@@ -345,34 +346,146 @@ function RoutesScreen({ client }) {
|
|
|
345
346
|
|
|
346
347
|
// src/screens/TokensScreen.tsx
|
|
347
348
|
var import_react_admin7 = require("@fonderie/react-admin");
|
|
349
|
+
var import_react = require("react");
|
|
348
350
|
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
351
|
+
var ALL = ["read", "write", "secrets"];
|
|
349
352
|
function TokensScreen({ client }) {
|
|
350
|
-
const { report, isLoading, error } = (0, import_react_admin7.useAdminTokens)(client);
|
|
353
|
+
const { report, isLoading, error, issue, revoke } = (0, import_react_admin7.useAdminTokens)(client);
|
|
354
|
+
const [name, setName] = (0, import_react.useState)("");
|
|
355
|
+
const [scopes, setScopes] = (0, import_react.useState)(["read"]);
|
|
356
|
+
const [days, setDays] = (0, import_react.useState)("");
|
|
357
|
+
const [minted, setMinted] = (0, import_react.useState)(null);
|
|
358
|
+
const toggle = (s) => setScopes((prev) => prev.includes(s) ? prev.filter((x) => x !== s) : [...prev, s]);
|
|
351
359
|
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: styles.container, children: [
|
|
352
360
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("h1", { style: styles.title, children: "Access" }),
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
361
|
+
error ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("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,
|
|
362
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("h2", { style: styles.subtitle, children: "Root token" }),
|
|
363
|
+
report ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("p", { children: [
|
|
364
|
+
report.admin.ok ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { style: styles.ok, children: "strong" }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { style: styles.bad, children: "weak" }),
|
|
365
|
+
report.admin.problems.map((p) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: styles.bad, children: p.message }, p.message))
|
|
366
|
+
] }) : null,
|
|
367
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("h2", { style: styles.subtitle, children: "Issued tokens" }),
|
|
368
|
+
report?.issued === null ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { style: styles.muted, children: "Issuing is off \u2014 give AdminModule a store and run its migrations." }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
|
|
369
|
+
minted ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("p", { style: styles.ok, children: [
|
|
370
|
+
"Copy this now \u2014 it is never shown again.",
|
|
362
371
|
" ",
|
|
363
|
-
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { style: styles.
|
|
364
|
-
|
|
365
|
-
|
|
372
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { style: styles.mono, children: minted.token }),
|
|
373
|
+
" (",
|
|
374
|
+
minted.name,
|
|
375
|
+
")"
|
|
376
|
+
] }) : null,
|
|
377
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
378
|
+
"form",
|
|
379
|
+
{
|
|
380
|
+
style: styles.toolbar,
|
|
381
|
+
onSubmit: (e) => {
|
|
382
|
+
e.preventDefault();
|
|
383
|
+
const d = Number(days);
|
|
384
|
+
void issue({
|
|
385
|
+
name: name.trim(),
|
|
386
|
+
scopes,
|
|
387
|
+
...days && Number.isInteger(d) && d > 0 ? { expiresInDays: d } : {}
|
|
388
|
+
}).then((t) => {
|
|
389
|
+
setMinted({ name: t.name, token: t.token });
|
|
390
|
+
setName("");
|
|
391
|
+
setDays("");
|
|
392
|
+
}).catch(() => {
|
|
393
|
+
});
|
|
394
|
+
},
|
|
395
|
+
children: [
|
|
396
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
397
|
+
"input",
|
|
398
|
+
{
|
|
399
|
+
value: name,
|
|
400
|
+
onChange: (e) => setName(e.target.value),
|
|
401
|
+
placeholder: "name",
|
|
402
|
+
style: { ...styles.button, cursor: "text" },
|
|
403
|
+
"aria-label": "Name"
|
|
404
|
+
}
|
|
405
|
+
),
|
|
406
|
+
ALL.map((s) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { style: { ...styles.badge, cursor: "pointer" }, children: [
|
|
407
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("input", { type: "checkbox", checked: scopes.includes(s), onChange: () => toggle(s) }),
|
|
408
|
+
" ",
|
|
409
|
+
s
|
|
410
|
+
] }, s)),
|
|
411
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
412
|
+
"input",
|
|
413
|
+
{
|
|
414
|
+
value: days,
|
|
415
|
+
onChange: (e) => setDays(e.target.value),
|
|
416
|
+
placeholder: "days (optional)",
|
|
417
|
+
style: { ...styles.button, cursor: "text", width: 140 },
|
|
418
|
+
"aria-label": "Days"
|
|
419
|
+
}
|
|
420
|
+
),
|
|
421
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
422
|
+
"button",
|
|
423
|
+
{
|
|
424
|
+
type: "submit",
|
|
425
|
+
style: styles.button,
|
|
426
|
+
disabled: !name.trim() || scopes.length === 0 || isLoading,
|
|
427
|
+
children: "Issue"
|
|
428
|
+
}
|
|
429
|
+
)
|
|
430
|
+
]
|
|
431
|
+
}
|
|
432
|
+
),
|
|
433
|
+
report?.issued && report.issued.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("table", { style: styles.table, children: [
|
|
434
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("tr", { children: [
|
|
435
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("th", { style: styles.th, children: "Name" }),
|
|
436
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("th", { style: styles.th, children: "Scopes" }),
|
|
437
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("th", { style: styles.th, children: "Created" }),
|
|
438
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("th", { style: styles.th, children: "Expires" }),
|
|
439
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("th", { style: styles.th, children: "Last used" }),
|
|
440
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("th", { style: styles.th })
|
|
441
|
+
] }) }),
|
|
442
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("tbody", { children: report.issued.map((t) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("tr", { children: [
|
|
443
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("td", { style: styles.td, children: [
|
|
444
|
+
t.name,
|
|
445
|
+
t.revokedAt ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { style: styles.badge, children: " revoked" }) : null
|
|
446
|
+
] }),
|
|
447
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("td", { style: { ...styles.td, ...styles.mono }, children: t.scopes.join(", ") }),
|
|
448
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("td", { style: { ...styles.td, ...styles.muted }, children: [
|
|
449
|
+
new Date(t.createdAt).toLocaleDateString(),
|
|
450
|
+
" \xB7 ",
|
|
451
|
+
t.createdBy
|
|
452
|
+
] }),
|
|
453
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("td", { style: { ...styles.td, ...styles.muted }, children: t.expiresAt ? new Date(t.expiresAt).toLocaleDateString() : "never" }),
|
|
454
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("td", { style: { ...styles.td, ...styles.muted }, children: t.lastUsedAt ? new Date(t.lastUsedAt).toLocaleString() : "never" }),
|
|
455
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("td", { style: styles.td, children: t.revokedAt ? null : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
456
|
+
"button",
|
|
457
|
+
{
|
|
458
|
+
type: "button",
|
|
459
|
+
style: styles.button,
|
|
460
|
+
onClick: () => {
|
|
461
|
+
if (window.confirm(
|
|
462
|
+
`Revoke "${t.name}"? Anything using it stops working immediately.`
|
|
463
|
+
))
|
|
464
|
+
void revoke(t.id).catch(() => {
|
|
465
|
+
});
|
|
466
|
+
},
|
|
467
|
+
children: "Revoke"
|
|
468
|
+
}
|
|
469
|
+
) })
|
|
470
|
+
] }, t.id)) })
|
|
471
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { style: styles.muted, children: "None issued." })
|
|
472
|
+
] }),
|
|
473
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("h2", { style: styles.subtitle, children: "Legacy per-brick tokens" }),
|
|
474
|
+
report && report.legacy.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { style: styles.muted, children: "None \u2014 every brick's admin surface goes through this token." }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("ul", { style: styles.list, children: report?.legacy.map((l) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("li", { style: styles.row, children: [
|
|
475
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { style: styles.mono, children: l.module }),
|
|
476
|
+
" ",
|
|
477
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { style: styles.muted, children: "still registers its standalone routes with its own token (deprecated)" })
|
|
478
|
+
] }, l.module)) })
|
|
366
479
|
] });
|
|
367
480
|
}
|
|
368
481
|
|
|
369
482
|
// src/screens/UsersScreen.tsx
|
|
370
483
|
var import_react_admin8 = require("@fonderie/react-admin");
|
|
371
|
-
var
|
|
484
|
+
var import_react2 = require("react");
|
|
372
485
|
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
373
486
|
function UsersScreen({ client }) {
|
|
374
|
-
const [input, setInput] = (0,
|
|
375
|
-
const [email, setEmail] = (0,
|
|
487
|
+
const [input, setInput] = (0, import_react2.useState)("");
|
|
488
|
+
const [email, setEmail] = (0, import_react2.useState)(void 0);
|
|
376
489
|
const { user, isLoading, error, suspend, unsuspend, revokeSessions } = (0, import_react_admin8.useAdminUser)(
|
|
377
490
|
client,
|
|
378
491
|
email ? { email } : {}
|
|
@@ -582,16 +695,16 @@ function CatalogScreen({ client }) {
|
|
|
582
695
|
|
|
583
696
|
// src/screens/SubscriberScreen.tsx
|
|
584
697
|
var import_react_admin10 = require("@fonderie/react-admin");
|
|
585
|
-
var
|
|
698
|
+
var import_react3 = require("react");
|
|
586
699
|
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
587
700
|
function SubscriberScreen({ client }) {
|
|
588
|
-
const [type, setType] = (0,
|
|
589
|
-
const [idInput, setIdInput] = (0,
|
|
590
|
-
const [subscriber, setSubscriber] = (0,
|
|
701
|
+
const [type, setType] = (0, import_react3.useState)("user");
|
|
702
|
+
const [idInput, setIdInput] = (0, import_react3.useState)("");
|
|
703
|
+
const [subscriber, setSubscriber] = (0, import_react3.useState)(null);
|
|
591
704
|
const { subscription, wallet, ledger, hasMoreLedger, isLoading, error, loadMoreLedger, grant } = (0, import_react_admin10.useAdminSubscriber)(client, subscriber, { limit: 20 });
|
|
592
|
-
const [amount, setAmount] = (0,
|
|
593
|
-
const [note, setNote] = (0,
|
|
594
|
-
const [granted, setGranted] = (0,
|
|
705
|
+
const [amount, setAmount] = (0, import_react3.useState)("");
|
|
706
|
+
const [note, setNote] = (0, import_react3.useState)("");
|
|
707
|
+
const [granted, setGranted] = (0, import_react3.useState)(null);
|
|
595
708
|
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { style: styles.container, children: [
|
|
596
709
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("h1", { style: styles.title, children: "Subscriber" }),
|
|
597
710
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
@@ -754,8 +867,93 @@ function SubscriberScreen({ client }) {
|
|
|
754
867
|
] });
|
|
755
868
|
}
|
|
756
869
|
|
|
757
|
-
// src/screens/
|
|
870
|
+
// src/screens/AuditScreen.tsx
|
|
871
|
+
var import_react_admin11 = require("@fonderie/react-admin");
|
|
872
|
+
var import_react4 = require("react");
|
|
758
873
|
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
874
|
+
function AuditScreen({ client, pageSize = 50 }) {
|
|
875
|
+
const [draft, setDraft] = (0, import_react4.useState)({ workspaceId: "", type: "", actorId: "" });
|
|
876
|
+
const [filter, setFilter] = (0, import_react4.useState)(
|
|
877
|
+
{}
|
|
878
|
+
);
|
|
879
|
+
const { events, hasMore, isLoading, error, refresh, loadMore } = (0, import_react_admin11.useAdminAudit)(client, {
|
|
880
|
+
...filter,
|
|
881
|
+
limit: pageSize
|
|
882
|
+
});
|
|
883
|
+
const field = (key, placeholder) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
884
|
+
"input",
|
|
885
|
+
{
|
|
886
|
+
value: draft[key],
|
|
887
|
+
onChange: (e) => setDraft({ ...draft, [key]: e.target.value }),
|
|
888
|
+
placeholder,
|
|
889
|
+
style: { ...styles.button, cursor: "text" },
|
|
890
|
+
"aria-label": placeholder
|
|
891
|
+
}
|
|
892
|
+
);
|
|
893
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: styles.container, children: [
|
|
894
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("h1", { style: styles.title, children: "Audit" }),
|
|
895
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
|
|
896
|
+
"form",
|
|
897
|
+
{
|
|
898
|
+
style: styles.toolbar,
|
|
899
|
+
onSubmit: (e) => {
|
|
900
|
+
e.preventDefault();
|
|
901
|
+
setFilter({
|
|
902
|
+
...draft.workspaceId.trim() ? { workspaceId: draft.workspaceId.trim() } : {},
|
|
903
|
+
...draft.type.trim() ? { type: draft.type.trim() } : {},
|
|
904
|
+
...draft.actorId.trim() ? { actorId: draft.actorId.trim() } : {}
|
|
905
|
+
});
|
|
906
|
+
},
|
|
907
|
+
children: [
|
|
908
|
+
field("workspaceId", "workspace id (all if empty)"),
|
|
909
|
+
field("type", "event type"),
|
|
910
|
+
field("actorId", "actor id"),
|
|
911
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { type: "submit", style: styles.button, disabled: isLoading, children: "Filter" }),
|
|
912
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
913
|
+
"button",
|
|
914
|
+
{
|
|
915
|
+
type: "button",
|
|
916
|
+
style: styles.button,
|
|
917
|
+
onClick: () => void refresh(),
|
|
918
|
+
disabled: isLoading,
|
|
919
|
+
children: "Refresh"
|
|
920
|
+
}
|
|
921
|
+
)
|
|
922
|
+
]
|
|
923
|
+
}
|
|
924
|
+
),
|
|
925
|
+
error ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { style: styles.error, role: "alert", children: error.explanation }) : null,
|
|
926
|
+
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: [
|
|
927
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("tr", { children: [
|
|
928
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("th", { style: styles.th, children: "When" }),
|
|
929
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("th", { style: styles.th, children: "Type" }),
|
|
930
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("th", { style: styles.th, children: "Workspace" }),
|
|
931
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("th", { style: styles.th, children: "Actor" }),
|
|
932
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("th", { style: styles.th, children: "Request" })
|
|
933
|
+
] }) }),
|
|
934
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("tbody", { children: events.map((e) => /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("tr", { children: [
|
|
935
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("td", { style: { ...styles.td, ...styles.muted }, children: new Date(e.createdAt).toLocaleString() }),
|
|
936
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("td", { style: { ...styles.td, ...styles.mono }, children: e.type }),
|
|
937
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("td", { style: { ...styles.td, ...styles.mono }, children: String(e.payload["workspaceId"] ?? "\u2014") }),
|
|
938
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("td", { style: { ...styles.td, ...styles.mono }, children: e.actorId ?? "\u2014" }),
|
|
939
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("td", { style: { ...styles.td, ...styles.muted }, children: e.requestId ?? "" })
|
|
940
|
+
] }, e.id)) })
|
|
941
|
+
] }),
|
|
942
|
+
isLoading ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { style: styles.status, children: "Loading\u2026" }) : null,
|
|
943
|
+
hasMore && !isLoading ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
944
|
+
"button",
|
|
945
|
+
{
|
|
946
|
+
type: "button",
|
|
947
|
+
style: { ...styles.button, marginTop: 8 },
|
|
948
|
+
onClick: () => void loadMore(),
|
|
949
|
+
children: "Load more"
|
|
950
|
+
}
|
|
951
|
+
) : null
|
|
952
|
+
] });
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
// src/screens/AdminShell.tsx
|
|
956
|
+
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
759
957
|
var NAV = [
|
|
760
958
|
{ group: "Today", items: [{ page: "attention", label: "Attention" }] },
|
|
761
959
|
{
|
|
@@ -780,6 +978,7 @@ var NAV = [
|
|
|
780
978
|
{
|
|
781
979
|
group: "Activity",
|
|
782
980
|
items: [
|
|
981
|
+
{ page: "audit", label: "Audit", needs: "audit" },
|
|
783
982
|
{ page: "log", label: "Admin log" },
|
|
784
983
|
{ page: "tokens", label: "Access" }
|
|
785
984
|
]
|
|
@@ -791,59 +990,64 @@ function AdminShell({
|
|
|
791
990
|
courierClient,
|
|
792
991
|
authClient,
|
|
793
992
|
billingClient,
|
|
993
|
+
auditClient,
|
|
794
994
|
environment,
|
|
795
995
|
page,
|
|
796
996
|
onNavigate
|
|
797
997
|
}) {
|
|
798
|
-
const [own, setOwn] = (0,
|
|
998
|
+
const [own, setOwn] = (0, import_react5.useState)("attention");
|
|
799
999
|
const current = page ?? own;
|
|
800
1000
|
const go = (p) => {
|
|
801
1001
|
if (onNavigate) onNavigate(p);
|
|
802
1002
|
if (page === void 0) setOwn(p);
|
|
803
1003
|
};
|
|
804
|
-
const [editing, setEditing] = (0,
|
|
1004
|
+
const [editing, setEditing] = (0, import_react5.useState)(null);
|
|
805
1005
|
const has = {
|
|
806
1006
|
config: Boolean(configClient),
|
|
807
1007
|
courier: Boolean(courierClient),
|
|
808
1008
|
auth: Boolean(authClient),
|
|
809
|
-
billing: Boolean(billingClient)
|
|
1009
|
+
billing: Boolean(billingClient),
|
|
1010
|
+
audit: Boolean(auditClient)
|
|
810
1011
|
};
|
|
811
1012
|
let body;
|
|
812
1013
|
switch (current) {
|
|
813
1014
|
case "attention":
|
|
814
|
-
body = /* @__PURE__ */ (0,
|
|
1015
|
+
body = /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(AttentionScreen, { client });
|
|
815
1016
|
break;
|
|
816
1017
|
case "modules":
|
|
817
|
-
body = /* @__PURE__ */ (0,
|
|
1018
|
+
body = /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(ModulesScreen, { client });
|
|
818
1019
|
break;
|
|
819
1020
|
case "doctor":
|
|
820
|
-
body = /* @__PURE__ */ (0,
|
|
1021
|
+
body = /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(DoctorScreen, { client });
|
|
821
1022
|
break;
|
|
822
1023
|
case "config":
|
|
823
|
-
body = /* @__PURE__ */ (0,
|
|
1024
|
+
body = /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(ConfigScreen, { client });
|
|
824
1025
|
break;
|
|
825
1026
|
case "routes":
|
|
826
|
-
body = /* @__PURE__ */ (0,
|
|
1027
|
+
body = /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(RoutesScreen, { client });
|
|
827
1028
|
break;
|
|
828
1029
|
case "tokens":
|
|
829
|
-
body = /* @__PURE__ */ (0,
|
|
1030
|
+
body = /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(TokensScreen, { client });
|
|
830
1031
|
break;
|
|
831
1032
|
case "log":
|
|
832
|
-
body = /* @__PURE__ */ (0,
|
|
1033
|
+
body = /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(AdminLogScreen, { client });
|
|
833
1034
|
break;
|
|
834
1035
|
case "catalog":
|
|
835
|
-
body = billingClient ? /* @__PURE__ */ (0,
|
|
1036
|
+
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
1037
|
break;
|
|
837
1038
|
case "subscriber":
|
|
838
|
-
body = billingClient ? /* @__PURE__ */ (0,
|
|
1039
|
+
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." });
|
|
1040
|
+
break;
|
|
1041
|
+
case "audit":
|
|
1042
|
+
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
1043
|
break;
|
|
840
1044
|
case "users":
|
|
841
|
-
body = authClient ? /* @__PURE__ */ (0,
|
|
1045
|
+
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
1046
|
break;
|
|
843
1047
|
case "settings":
|
|
844
|
-
body = !configClient ? /* @__PURE__ */ (0,
|
|
845
|
-
/* @__PURE__ */ (0,
|
|
846
|
-
/* @__PURE__ */ (0,
|
|
1048
|
+
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: [
|
|
1049
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("button", { type: "button", style: styles.button, onClick: () => setEditing(null), children: "\u2190 Back" }),
|
|
1050
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
847
1051
|
import_react_config_admin_screens.ConfigEditorScreen,
|
|
848
1052
|
{
|
|
849
1053
|
client: configClient,
|
|
@@ -853,7 +1057,7 @@ function AdminShell({
|
|
|
853
1057
|
onSaved: () => setEditing(null)
|
|
854
1058
|
}
|
|
855
1059
|
)
|
|
856
|
-
] }) : /* @__PURE__ */ (0,
|
|
1060
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
857
1061
|
import_react_config_admin_screens.ConfigListScreen,
|
|
858
1062
|
{
|
|
859
1063
|
client: configClient,
|
|
@@ -864,9 +1068,9 @@ function AdminShell({
|
|
|
864
1068
|
);
|
|
865
1069
|
break;
|
|
866
1070
|
case "templates":
|
|
867
|
-
body = !courierClient ? /* @__PURE__ */ (0,
|
|
868
|
-
/* @__PURE__ */ (0,
|
|
869
|
-
/* @__PURE__ */ (0,
|
|
1071
|
+
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: [
|
|
1072
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("button", { type: "button", style: styles.button, onClick: () => setEditing(null), children: "\u2190 Back" }),
|
|
1073
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
870
1074
|
import_react_courier_admin_screens.TemplateEditorScreen,
|
|
871
1075
|
{
|
|
872
1076
|
client: courierClient,
|
|
@@ -874,7 +1078,7 @@ function AdminShell({
|
|
|
874
1078
|
onSaved: () => setEditing(null)
|
|
875
1079
|
}
|
|
876
1080
|
)
|
|
877
|
-
] }) : /* @__PURE__ */ (0,
|
|
1081
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
878
1082
|
import_react_courier_admin_screens.TemplateListScreen,
|
|
879
1083
|
{
|
|
880
1084
|
client: courierClient,
|
|
@@ -883,13 +1087,13 @@ function AdminShell({
|
|
|
883
1087
|
);
|
|
884
1088
|
break;
|
|
885
1089
|
}
|
|
886
|
-
return /* @__PURE__ */ (0,
|
|
887
|
-
/* @__PURE__ */ (0,
|
|
1090
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { style: styles.shell, children: [
|
|
1091
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("nav", { style: styles.nav, "aria-label": "Admin", children: NAV.map((g) => {
|
|
888
1092
|
const items = g.items.filter((i) => !i.needs || has[i.needs]);
|
|
889
1093
|
if (items.length === 0) return null;
|
|
890
|
-
return /* @__PURE__ */ (0,
|
|
891
|
-
/* @__PURE__ */ (0,
|
|
892
|
-
items.map((i) => /* @__PURE__ */ (0,
|
|
1094
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { children: [
|
|
1095
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { style: styles.navGroup, children: g.group }),
|
|
1096
|
+
items.map((i) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
893
1097
|
"button",
|
|
894
1098
|
{
|
|
895
1099
|
type: "button",
|
|
@@ -905,7 +1109,7 @@ function AdminShell({
|
|
|
905
1109
|
))
|
|
906
1110
|
] }, g.group);
|
|
907
1111
|
}) }),
|
|
908
|
-
/* @__PURE__ */ (0,
|
|
1112
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("main", { style: styles.main, children: body })
|
|
909
1113
|
] });
|
|
910
1114
|
}
|
|
911
1115
|
// Annotate the CommonJS export names for ESM import in node:
|
|
@@ -913,6 +1117,7 @@ function AdminShell({
|
|
|
913
1117
|
AdminLogScreen,
|
|
914
1118
|
AdminShell,
|
|
915
1119
|
AttentionScreen,
|
|
1120
|
+
AuditScreen,
|
|
916
1121
|
CatalogScreen,
|
|
917
1122
|
ConfigScreen,
|
|
918
1123
|
DoctorScreen,
|