@fonderie/react-admin-screens 0.4.0 → 0.6.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 +8 -1
- package/dist/index.cjs +277 -35
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +77 -0
- package/dist/index.d.ts +77 -0
- package/dist/index.js +284 -37
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -14,7 +14,7 @@ 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 | Audit · Admin log · Access | what happened, every workspace (`auditClient`) · who did what through here · 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
20
|
import { AdminClient, AuditAdminClient, AuthAdminClient, BillingAdminClient, ConfigAdminClient, CourierAdminClient } from '@fonderie/client';
|
|
@@ -38,6 +38,13 @@ Pass `page` and `onNavigate` to own the URL (one route per page); omit both
|
|
|
38
38
|
and the shell keeps the page itself. Settings and Messaging appear only when
|
|
39
39
|
their client is given.
|
|
40
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
|
+
|
|
41
48
|
Nothing here stores the token: the app constructs the clients and decides
|
|
42
49
|
where the token lives. Every request through the shell lands in the admin
|
|
43
50
|
log, including the ones the token refuses.
|
package/dist/index.cjs
CHANGED
|
@@ -38,7 +38,7 @@ module.exports = __toCommonJS(index_exports);
|
|
|
38
38
|
// src/screens/AdminShell.tsx
|
|
39
39
|
var import_react_config_admin_screens = require("@fonderie/react-config-admin-screens");
|
|
40
40
|
var import_react_courier_admin_screens = require("@fonderie/react-courier-admin-screens");
|
|
41
|
-
var
|
|
41
|
+
var import_react5 = require("react");
|
|
42
42
|
|
|
43
43
|
// src/styles.ts
|
|
44
44
|
var styles = {
|
|
@@ -346,42 +346,159 @@ function RoutesScreen({ client }) {
|
|
|
346
346
|
|
|
347
347
|
// src/screens/TokensScreen.tsx
|
|
348
348
|
var import_react_admin7 = require("@fonderie/react-admin");
|
|
349
|
+
var import_react = require("react");
|
|
349
350
|
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
351
|
+
var ALL = ["read", "write", "secrets"];
|
|
350
352
|
function TokensScreen({ client }) {
|
|
351
|
-
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]);
|
|
352
359
|
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: styles.container, children: [
|
|
353
360
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("h1", { style: styles.title, children: "Access" }),
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
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.",
|
|
363
371
|
" ",
|
|
364
|
-
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { style: styles.
|
|
365
|
-
|
|
366
|
-
|
|
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)) })
|
|
367
479
|
] });
|
|
368
480
|
}
|
|
369
481
|
|
|
370
482
|
// src/screens/UsersScreen.tsx
|
|
371
483
|
var import_react_admin8 = require("@fonderie/react-admin");
|
|
372
|
-
var
|
|
484
|
+
var import_react2 = require("react");
|
|
373
485
|
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
374
|
-
function UsersScreen({ client }) {
|
|
375
|
-
const [input, setInput] = (0,
|
|
376
|
-
const [
|
|
486
|
+
function UsersScreen({ client, pageSize = 50 }) {
|
|
487
|
+
const [input, setInput] = (0, import_react2.useState)("");
|
|
488
|
+
const [selected, setSelected] = (0, import_react2.useState)(null);
|
|
489
|
+
const list = (0, import_react_admin8.useAdminUsers)(client, { limit: pageSize });
|
|
377
490
|
const { user, isLoading, error, suspend, unsuspend, revokeSessions } = (0, import_react_admin8.useAdminUser)(
|
|
378
491
|
client,
|
|
379
|
-
|
|
492
|
+
selected ?? {}
|
|
380
493
|
);
|
|
381
494
|
const userId = user?.id ?? null;
|
|
382
495
|
const sessions = (0, import_react_admin8.useAdminUserSessions)(client, userId);
|
|
383
496
|
const history = (0, import_react_admin8.useAdminLoginHistory)(client, userId, { limit: 20 });
|
|
384
497
|
const yesNo = (v) => v ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { style: styles.ok, children: "yes" }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { style: styles.muted, children: "no" });
|
|
498
|
+
const clear = () => {
|
|
499
|
+
setSelected(null);
|
|
500
|
+
setInput("");
|
|
501
|
+
};
|
|
385
502
|
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: styles.container, children: [
|
|
386
503
|
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("h1", { style: styles.title, children: "Users" }),
|
|
387
504
|
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
@@ -390,7 +507,8 @@ function UsersScreen({ client }) {
|
|
|
390
507
|
style: styles.toolbar,
|
|
391
508
|
onSubmit: (e) => {
|
|
392
509
|
e.preventDefault();
|
|
393
|
-
|
|
510
|
+
const email = input.trim();
|
|
511
|
+
setSelected(email ? { email } : null);
|
|
394
512
|
},
|
|
395
513
|
children: [
|
|
396
514
|
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
@@ -404,11 +522,60 @@ function UsersScreen({ client }) {
|
|
|
404
522
|
"aria-label": "Email"
|
|
405
523
|
}
|
|
406
524
|
),
|
|
407
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "submit", style: styles.button, disabled: isLoading, children: "Look up" })
|
|
525
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "submit", style: styles.button, disabled: isLoading, children: "Look up" }),
|
|
526
|
+
selected ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", style: styles.button, onClick: clear, children: "\u2190 All users" }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
527
|
+
"button",
|
|
528
|
+
{
|
|
529
|
+
type: "button",
|
|
530
|
+
style: styles.button,
|
|
531
|
+
onClick: () => void list.refresh(),
|
|
532
|
+
disabled: list.isLoading,
|
|
533
|
+
children: "Refresh"
|
|
534
|
+
}
|
|
535
|
+
)
|
|
408
536
|
]
|
|
409
537
|
}
|
|
410
538
|
),
|
|
411
539
|
error ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { style: styles.error, role: "alert", children: error.status === 404 ? "No user with that email." : error.explanation }) : null,
|
|
540
|
+
!selected ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
|
|
541
|
+
list.error ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { style: styles.error, role: "alert", children: list.error.explanation }) : null,
|
|
542
|
+
list.users.length === 0 && !list.isLoading ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { style: styles.muted, children: "No users yet." }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("table", { style: styles.table, children: [
|
|
543
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("tr", { children: [
|
|
544
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("th", { style: styles.th, children: "Email" }),
|
|
545
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("th", { style: styles.th, children: "Name" }),
|
|
546
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("th", { style: styles.th, children: "Created" }),
|
|
547
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("th", { style: styles.th, children: "Status" })
|
|
548
|
+
] }) }),
|
|
549
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("tbody", { children: list.users.map((u) => /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("tr", { children: [
|
|
550
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("td", { style: styles.td, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
551
|
+
"button",
|
|
552
|
+
{
|
|
553
|
+
type: "button",
|
|
554
|
+
style: { ...styles.navItem, padding: 0 },
|
|
555
|
+
onClick: () => setSelected({ id: u.id }),
|
|
556
|
+
children: u.email
|
|
557
|
+
}
|
|
558
|
+
) }),
|
|
559
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("td", { style: styles.td, children: `${u.firstName ?? ""} ${u.lastName ?? ""}`.trim() || /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { style: styles.muted, children: "\u2014" }) }),
|
|
560
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("td", { style: styles.td, children: new Date(u.createdAt).toLocaleDateString() }),
|
|
561
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("td", { style: styles.td, children: [
|
|
562
|
+
u.suspended ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { style: styles.badge, children: "suspended" }) : null,
|
|
563
|
+
u.deletedAt ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { style: styles.badge, children: "deleted" }) : null,
|
|
564
|
+
!u.suspended && !u.deletedAt ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { style: styles.muted, children: "active" }) : null
|
|
565
|
+
] })
|
|
566
|
+
] }, u.id)) })
|
|
567
|
+
] }),
|
|
568
|
+
list.isLoading ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { style: styles.status, children: "Loading\u2026" }) : null,
|
|
569
|
+
list.hasMore && !list.isLoading ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
570
|
+
"button",
|
|
571
|
+
{
|
|
572
|
+
type: "button",
|
|
573
|
+
style: { ...styles.button, marginTop: 8 },
|
|
574
|
+
onClick: () => void list.loadMore(),
|
|
575
|
+
children: "Load more"
|
|
576
|
+
}
|
|
577
|
+
) : null
|
|
578
|
+
] }) : null,
|
|
412
579
|
user ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
|
|
413
580
|
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("h2", { style: styles.subtitle, children: [
|
|
414
581
|
user.firstName || user.lastName ? `${user.firstName} ${user.lastName}`.trim() : user.email,
|
|
@@ -583,16 +750,23 @@ function CatalogScreen({ client }) {
|
|
|
583
750
|
|
|
584
751
|
// src/screens/SubscriberScreen.tsx
|
|
585
752
|
var import_react_admin10 = require("@fonderie/react-admin");
|
|
586
|
-
var
|
|
753
|
+
var import_react3 = require("react");
|
|
587
754
|
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
588
|
-
function SubscriberScreen({ client }) {
|
|
589
|
-
const [type, setType] = (0,
|
|
590
|
-
const [idInput, setIdInput] = (0,
|
|
591
|
-
const [subscriber, setSubscriber] = (0,
|
|
755
|
+
function SubscriberScreen({ client, pageSize = 50 }) {
|
|
756
|
+
const [type, setType] = (0, import_react3.useState)("user");
|
|
757
|
+
const [idInput, setIdInput] = (0, import_react3.useState)("");
|
|
758
|
+
const [subscriber, setSubscriber] = (0, import_react3.useState)(null);
|
|
759
|
+
const list = (0, import_react_admin10.useAdminSubscribers)(client, { limit: pageSize });
|
|
592
760
|
const { subscription, wallet, ledger, hasMoreLedger, isLoading, error, loadMoreLedger, grant } = (0, import_react_admin10.useAdminSubscriber)(client, subscriber, { limit: 20 });
|
|
593
|
-
const [amount, setAmount] = (0,
|
|
594
|
-
const [note, setNote] = (0,
|
|
595
|
-
const [granted, setGranted] = (0,
|
|
761
|
+
const [amount, setAmount] = (0, import_react3.useState)("");
|
|
762
|
+
const [note, setNote] = (0, import_react3.useState)("");
|
|
763
|
+
const [granted, setGranted] = (0, import_react3.useState)(null);
|
|
764
|
+
const open = (t, id) => {
|
|
765
|
+
setGranted(null);
|
|
766
|
+
setType(t);
|
|
767
|
+
setIdInput(id);
|
|
768
|
+
setSubscriber({ type: t, id });
|
|
769
|
+
};
|
|
596
770
|
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { style: styles.container, children: [
|
|
597
771
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("h1", { style: styles.title, children: "Subscriber" }),
|
|
598
772
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
@@ -628,11 +802,79 @@ function SubscriberScreen({ client }) {
|
|
|
628
802
|
"aria-label": "Subscriber id"
|
|
629
803
|
}
|
|
630
804
|
),
|
|
631
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "submit", style: styles.button, disabled: isLoading, children: "Look up" })
|
|
805
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "submit", style: styles.button, disabled: isLoading, children: "Look up" }),
|
|
806
|
+
subscriber ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
807
|
+
"button",
|
|
808
|
+
{
|
|
809
|
+
type: "button",
|
|
810
|
+
style: styles.button,
|
|
811
|
+
onClick: () => {
|
|
812
|
+
setSubscriber(null);
|
|
813
|
+
setIdInput("");
|
|
814
|
+
setGranted(null);
|
|
815
|
+
},
|
|
816
|
+
children: "\u2190 All subscribers"
|
|
817
|
+
}
|
|
818
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
819
|
+
"button",
|
|
820
|
+
{
|
|
821
|
+
type: "button",
|
|
822
|
+
style: styles.button,
|
|
823
|
+
onClick: () => void list.refresh(),
|
|
824
|
+
disabled: list.isLoading,
|
|
825
|
+
children: "Refresh"
|
|
826
|
+
}
|
|
827
|
+
)
|
|
632
828
|
]
|
|
633
829
|
}
|
|
634
830
|
),
|
|
635
831
|
error ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { style: styles.error, role: "alert", children: error.explanation }) : null,
|
|
832
|
+
!subscriber ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
|
|
833
|
+
list.error ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { style: styles.error, role: "alert", children: list.error.explanation }) : null,
|
|
834
|
+
list.subscriptions.length === 0 && !list.isLoading ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { style: styles.muted, children: "No subscribers yet." }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("table", { style: styles.table, children: [
|
|
835
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("tr", { children: [
|
|
836
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("th", { style: styles.th, children: "Subscriber" }),
|
|
837
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("th", { style: styles.th, children: "Plan" }),
|
|
838
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("th", { style: styles.th, children: "Status" }),
|
|
839
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("th", { style: styles.th, children: "Renews" })
|
|
840
|
+
] }) }),
|
|
841
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("tbody", { children: list.subscriptions.map((s) => /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("tr", { children: [
|
|
842
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("td", { style: styles.td, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
843
|
+
"button",
|
|
844
|
+
{
|
|
845
|
+
type: "button",
|
|
846
|
+
style: { ...styles.navItem, padding: 0, ...styles.mono },
|
|
847
|
+
onClick: () => open(s.subscriberType, s.subscriberId),
|
|
848
|
+
children: [
|
|
849
|
+
s.subscriberType,
|
|
850
|
+
"/",
|
|
851
|
+
s.subscriberId
|
|
852
|
+
]
|
|
853
|
+
}
|
|
854
|
+
) }),
|
|
855
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("td", { style: styles.td, children: [
|
|
856
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("strong", { children: s.plan }),
|
|
857
|
+
" \xB7 ",
|
|
858
|
+
s.interval
|
|
859
|
+
] }),
|
|
860
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("td", { style: styles.td, children: [
|
|
861
|
+
s.status,
|
|
862
|
+
s.cancelAtPeriodEnd ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { style: styles.badge, children: "cancels" }) : null
|
|
863
|
+
] }),
|
|
864
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("td", { style: styles.td, children: s.currentPeriodEnd ? new Date(s.currentPeriodEnd).toLocaleDateString() : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { style: styles.muted, children: "\u2014" }) })
|
|
865
|
+
] }, s.id)) })
|
|
866
|
+
] }),
|
|
867
|
+
list.isLoading ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { style: styles.status, children: "Loading\u2026" }) : null,
|
|
868
|
+
list.hasMore && !list.isLoading ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
869
|
+
"button",
|
|
870
|
+
{
|
|
871
|
+
type: "button",
|
|
872
|
+
style: { ...styles.button, marginTop: 8 },
|
|
873
|
+
onClick: () => void list.loadMore(),
|
|
874
|
+
children: "Load more"
|
|
875
|
+
}
|
|
876
|
+
) : null
|
|
877
|
+
] }) : null,
|
|
636
878
|
subscriber && !isLoading ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
|
|
637
879
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("h2", { style: styles.subtitle, children: "Subscription" }),
|
|
638
880
|
subscription ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("table", { style: styles.table, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("tbody", { children: [
|
|
@@ -757,11 +999,11 @@ function SubscriberScreen({ client }) {
|
|
|
757
999
|
|
|
758
1000
|
// src/screens/AuditScreen.tsx
|
|
759
1001
|
var import_react_admin11 = require("@fonderie/react-admin");
|
|
760
|
-
var
|
|
1002
|
+
var import_react4 = require("react");
|
|
761
1003
|
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
762
1004
|
function AuditScreen({ client, pageSize = 50 }) {
|
|
763
|
-
const [draft, setDraft] = (0,
|
|
764
|
-
const [filter, setFilter] = (0,
|
|
1005
|
+
const [draft, setDraft] = (0, import_react4.useState)({ workspaceId: "", type: "", actorId: "" });
|
|
1006
|
+
const [filter, setFilter] = (0, import_react4.useState)(
|
|
765
1007
|
{}
|
|
766
1008
|
);
|
|
767
1009
|
const { events, hasMore, isLoading, error, refresh, loadMore } = (0, import_react_admin11.useAdminAudit)(client, {
|
|
@@ -883,13 +1125,13 @@ function AdminShell({
|
|
|
883
1125
|
page,
|
|
884
1126
|
onNavigate
|
|
885
1127
|
}) {
|
|
886
|
-
const [own, setOwn] = (0,
|
|
1128
|
+
const [own, setOwn] = (0, import_react5.useState)("attention");
|
|
887
1129
|
const current = page ?? own;
|
|
888
1130
|
const go = (p) => {
|
|
889
1131
|
if (onNavigate) onNavigate(p);
|
|
890
1132
|
if (page === void 0) setOwn(p);
|
|
891
1133
|
};
|
|
892
|
-
const [editing, setEditing] = (0,
|
|
1134
|
+
const [editing, setEditing] = (0, import_react5.useState)(null);
|
|
893
1135
|
const has = {
|
|
894
1136
|
config: Boolean(configClient),
|
|
895
1137
|
courier: Boolean(courierClient),
|