@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/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 useState4 } from "react";
4
+ import { useState as useState5 } from "react";
5
5
 
6
6
  // src/styles.ts
7
7
  var styles = {
@@ -309,42 +309,164 @@ 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
- import { useAdminLoginHistory, useAdminUser, useAdminUserSessions } from "@fonderie/react-admin";
335
- import { useState } from "react";
446
+ import {
447
+ useAdminLoginHistory,
448
+ useAdminUser,
449
+ useAdminUserSessions,
450
+ useAdminUsers
451
+ } from "@fonderie/react-admin";
452
+ import { useState as useState2 } from "react";
336
453
  import { Fragment as Fragment5, jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
337
- function UsersScreen({ client }) {
338
- const [input, setInput] = useState("");
339
- const [email, setEmail] = useState(void 0);
454
+ function UsersScreen({ client, pageSize = 50 }) {
455
+ const [input, setInput] = useState2("");
456
+ const [selected, setSelected] = useState2(null);
457
+ const list = useAdminUsers(client, { limit: pageSize });
340
458
  const { user, isLoading, error, suspend, unsuspend, revokeSessions } = useAdminUser(
341
459
  client,
342
- email ? { email } : {}
460
+ selected ?? {}
343
461
  );
344
462
  const userId = user?.id ?? null;
345
463
  const sessions = useAdminUserSessions(client, userId);
346
464
  const history = useAdminLoginHistory(client, userId, { limit: 20 });
347
465
  const yesNo = (v) => v ? /* @__PURE__ */ jsx8("span", { style: styles.ok, children: "yes" }) : /* @__PURE__ */ jsx8("span", { style: styles.muted, children: "no" });
466
+ const clear = () => {
467
+ setSelected(null);
468
+ setInput("");
469
+ };
348
470
  return /* @__PURE__ */ jsxs8("div", { style: styles.container, children: [
349
471
  /* @__PURE__ */ jsx8("h1", { style: styles.title, children: "Users" }),
350
472
  /* @__PURE__ */ jsxs8(
@@ -353,7 +475,8 @@ function UsersScreen({ client }) {
353
475
  style: styles.toolbar,
354
476
  onSubmit: (e) => {
355
477
  e.preventDefault();
356
- setEmail(input.trim() || void 0);
478
+ const email = input.trim();
479
+ setSelected(email ? { email } : null);
357
480
  },
358
481
  children: [
359
482
  /* @__PURE__ */ jsx8(
@@ -367,11 +490,60 @@ function UsersScreen({ client }) {
367
490
  "aria-label": "Email"
368
491
  }
369
492
  ),
370
- /* @__PURE__ */ jsx8("button", { type: "submit", style: styles.button, disabled: isLoading, children: "Look up" })
493
+ /* @__PURE__ */ jsx8("button", { type: "submit", style: styles.button, disabled: isLoading, children: "Look up" }),
494
+ selected ? /* @__PURE__ */ jsx8("button", { type: "button", style: styles.button, onClick: clear, children: "\u2190 All users" }) : /* @__PURE__ */ jsx8(
495
+ "button",
496
+ {
497
+ type: "button",
498
+ style: styles.button,
499
+ onClick: () => void list.refresh(),
500
+ disabled: list.isLoading,
501
+ children: "Refresh"
502
+ }
503
+ )
371
504
  ]
372
505
  }
373
506
  ),
374
507
  error ? /* @__PURE__ */ jsx8("p", { style: styles.error, role: "alert", children: error.status === 404 ? "No user with that email." : error.explanation }) : null,
508
+ !selected ? /* @__PURE__ */ jsxs8(Fragment5, { children: [
509
+ list.error ? /* @__PURE__ */ jsx8("p", { style: styles.error, role: "alert", children: list.error.explanation }) : null,
510
+ list.users.length === 0 && !list.isLoading ? /* @__PURE__ */ jsx8("p", { style: styles.muted, children: "No users yet." }) : /* @__PURE__ */ jsxs8("table", { style: styles.table, children: [
511
+ /* @__PURE__ */ jsx8("thead", { children: /* @__PURE__ */ jsxs8("tr", { children: [
512
+ /* @__PURE__ */ jsx8("th", { style: styles.th, children: "Email" }),
513
+ /* @__PURE__ */ jsx8("th", { style: styles.th, children: "Name" }),
514
+ /* @__PURE__ */ jsx8("th", { style: styles.th, children: "Created" }),
515
+ /* @__PURE__ */ jsx8("th", { style: styles.th, children: "Status" })
516
+ ] }) }),
517
+ /* @__PURE__ */ jsx8("tbody", { children: list.users.map((u) => /* @__PURE__ */ jsxs8("tr", { children: [
518
+ /* @__PURE__ */ jsx8("td", { style: styles.td, children: /* @__PURE__ */ jsx8(
519
+ "button",
520
+ {
521
+ type: "button",
522
+ style: { ...styles.navItem, padding: 0 },
523
+ onClick: () => setSelected({ id: u.id }),
524
+ children: u.email
525
+ }
526
+ ) }),
527
+ /* @__PURE__ */ jsx8("td", { style: styles.td, children: `${u.firstName ?? ""} ${u.lastName ?? ""}`.trim() || /* @__PURE__ */ jsx8("span", { style: styles.muted, children: "\u2014" }) }),
528
+ /* @__PURE__ */ jsx8("td", { style: styles.td, children: new Date(u.createdAt).toLocaleDateString() }),
529
+ /* @__PURE__ */ jsxs8("td", { style: styles.td, children: [
530
+ u.suspended ? /* @__PURE__ */ jsx8("span", { style: styles.badge, children: "suspended" }) : null,
531
+ u.deletedAt ? /* @__PURE__ */ jsx8("span", { style: styles.badge, children: "deleted" }) : null,
532
+ !u.suspended && !u.deletedAt ? /* @__PURE__ */ jsx8("span", { style: styles.muted, children: "active" }) : null
533
+ ] })
534
+ ] }, u.id)) })
535
+ ] }),
536
+ list.isLoading ? /* @__PURE__ */ jsx8("p", { style: styles.status, children: "Loading\u2026" }) : null,
537
+ list.hasMore && !list.isLoading ? /* @__PURE__ */ jsx8(
538
+ "button",
539
+ {
540
+ type: "button",
541
+ style: { ...styles.button, marginTop: 8 },
542
+ onClick: () => void list.loadMore(),
543
+ children: "Load more"
544
+ }
545
+ ) : null
546
+ ] }) : null,
375
547
  user ? /* @__PURE__ */ jsxs8(Fragment5, { children: [
376
548
  /* @__PURE__ */ jsxs8("h2", { style: styles.subtitle, children: [
377
549
  user.firstName || user.lastName ? `${user.firstName} ${user.lastName}`.trim() : user.email,
@@ -545,17 +717,24 @@ function CatalogScreen({ client }) {
545
717
  }
546
718
 
547
719
  // src/screens/SubscriberScreen.tsx
548
- import { useAdminSubscriber } from "@fonderie/react-admin";
549
- import { useState as useState2 } from "react";
720
+ import { useAdminSubscriber, useAdminSubscribers } from "@fonderie/react-admin";
721
+ import { useState as useState3 } from "react";
550
722
  import { Fragment as Fragment7, jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
551
- function SubscriberScreen({ client }) {
552
- const [type, setType] = useState2("user");
553
- const [idInput, setIdInput] = useState2("");
554
- const [subscriber, setSubscriber] = useState2(null);
723
+ function SubscriberScreen({ client, pageSize = 50 }) {
724
+ const [type, setType] = useState3("user");
725
+ const [idInput, setIdInput] = useState3("");
726
+ const [subscriber, setSubscriber] = useState3(null);
727
+ const list = useAdminSubscribers(client, { limit: pageSize });
555
728
  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);
729
+ const [amount, setAmount] = useState3("");
730
+ const [note, setNote] = useState3("");
731
+ const [granted, setGranted] = useState3(null);
732
+ const open = (t, id) => {
733
+ setGranted(null);
734
+ setType(t);
735
+ setIdInput(id);
736
+ setSubscriber({ type: t, id });
737
+ };
559
738
  return /* @__PURE__ */ jsxs10("div", { style: styles.container, children: [
560
739
  /* @__PURE__ */ jsx10("h1", { style: styles.title, children: "Subscriber" }),
561
740
  /* @__PURE__ */ jsxs10(
@@ -591,11 +770,79 @@ function SubscriberScreen({ client }) {
591
770
  "aria-label": "Subscriber id"
592
771
  }
593
772
  ),
594
- /* @__PURE__ */ jsx10("button", { type: "submit", style: styles.button, disabled: isLoading, children: "Look up" })
773
+ /* @__PURE__ */ jsx10("button", { type: "submit", style: styles.button, disabled: isLoading, children: "Look up" }),
774
+ subscriber ? /* @__PURE__ */ jsx10(
775
+ "button",
776
+ {
777
+ type: "button",
778
+ style: styles.button,
779
+ onClick: () => {
780
+ setSubscriber(null);
781
+ setIdInput("");
782
+ setGranted(null);
783
+ },
784
+ children: "\u2190 All subscribers"
785
+ }
786
+ ) : /* @__PURE__ */ jsx10(
787
+ "button",
788
+ {
789
+ type: "button",
790
+ style: styles.button,
791
+ onClick: () => void list.refresh(),
792
+ disabled: list.isLoading,
793
+ children: "Refresh"
794
+ }
795
+ )
595
796
  ]
596
797
  }
597
798
  ),
598
799
  error ? /* @__PURE__ */ jsx10("p", { style: styles.error, role: "alert", children: error.explanation }) : null,
800
+ !subscriber ? /* @__PURE__ */ jsxs10(Fragment7, { children: [
801
+ list.error ? /* @__PURE__ */ jsx10("p", { style: styles.error, role: "alert", children: list.error.explanation }) : null,
802
+ list.subscriptions.length === 0 && !list.isLoading ? /* @__PURE__ */ jsx10("p", { style: styles.muted, children: "No subscribers yet." }) : /* @__PURE__ */ jsxs10("table", { style: styles.table, children: [
803
+ /* @__PURE__ */ jsx10("thead", { children: /* @__PURE__ */ jsxs10("tr", { children: [
804
+ /* @__PURE__ */ jsx10("th", { style: styles.th, children: "Subscriber" }),
805
+ /* @__PURE__ */ jsx10("th", { style: styles.th, children: "Plan" }),
806
+ /* @__PURE__ */ jsx10("th", { style: styles.th, children: "Status" }),
807
+ /* @__PURE__ */ jsx10("th", { style: styles.th, children: "Renews" })
808
+ ] }) }),
809
+ /* @__PURE__ */ jsx10("tbody", { children: list.subscriptions.map((s) => /* @__PURE__ */ jsxs10("tr", { children: [
810
+ /* @__PURE__ */ jsx10("td", { style: styles.td, children: /* @__PURE__ */ jsxs10(
811
+ "button",
812
+ {
813
+ type: "button",
814
+ style: { ...styles.navItem, padding: 0, ...styles.mono },
815
+ onClick: () => open(s.subscriberType, s.subscriberId),
816
+ children: [
817
+ s.subscriberType,
818
+ "/",
819
+ s.subscriberId
820
+ ]
821
+ }
822
+ ) }),
823
+ /* @__PURE__ */ jsxs10("td", { style: styles.td, children: [
824
+ /* @__PURE__ */ jsx10("strong", { children: s.plan }),
825
+ " \xB7 ",
826
+ s.interval
827
+ ] }),
828
+ /* @__PURE__ */ jsxs10("td", { style: styles.td, children: [
829
+ s.status,
830
+ s.cancelAtPeriodEnd ? /* @__PURE__ */ jsx10("span", { style: styles.badge, children: "cancels" }) : null
831
+ ] }),
832
+ /* @__PURE__ */ jsx10("td", { style: styles.td, children: s.currentPeriodEnd ? new Date(s.currentPeriodEnd).toLocaleDateString() : /* @__PURE__ */ jsx10("span", { style: styles.muted, children: "\u2014" }) })
833
+ ] }, s.id)) })
834
+ ] }),
835
+ list.isLoading ? /* @__PURE__ */ jsx10("p", { style: styles.status, children: "Loading\u2026" }) : null,
836
+ list.hasMore && !list.isLoading ? /* @__PURE__ */ jsx10(
837
+ "button",
838
+ {
839
+ type: "button",
840
+ style: { ...styles.button, marginTop: 8 },
841
+ onClick: () => void list.loadMore(),
842
+ children: "Load more"
843
+ }
844
+ ) : null
845
+ ] }) : null,
599
846
  subscriber && !isLoading ? /* @__PURE__ */ jsxs10(Fragment7, { children: [
600
847
  /* @__PURE__ */ jsx10("h2", { style: styles.subtitle, children: "Subscription" }),
601
848
  subscription ? /* @__PURE__ */ jsx10("table", { style: styles.table, children: /* @__PURE__ */ jsxs10("tbody", { children: [
@@ -720,11 +967,11 @@ function SubscriberScreen({ client }) {
720
967
 
721
968
  // src/screens/AuditScreen.tsx
722
969
  import { useAdminAudit } from "@fonderie/react-admin";
723
- import { useState as useState3 } from "react";
970
+ import { useState as useState4 } from "react";
724
971
  import { jsx as jsx11, jsxs as jsxs11 } from "react/jsx-runtime";
725
972
  function AuditScreen({ client, pageSize = 50 }) {
726
- const [draft, setDraft] = useState3({ workspaceId: "", type: "", actorId: "" });
727
- const [filter, setFilter] = useState3(
973
+ const [draft, setDraft] = useState4({ workspaceId: "", type: "", actorId: "" });
974
+ const [filter, setFilter] = useState4(
728
975
  {}
729
976
  );
730
977
  const { events, hasMore, isLoading, error, refresh, loadMore } = useAdminAudit(client, {
@@ -846,13 +1093,13 @@ function AdminShell({
846
1093
  page,
847
1094
  onNavigate
848
1095
  }) {
849
- const [own, setOwn] = useState4("attention");
1096
+ const [own, setOwn] = useState5("attention");
850
1097
  const current = page ?? own;
851
1098
  const go = (p) => {
852
1099
  if (onNavigate) onNavigate(p);
853
1100
  if (page === void 0) setOwn(p);
854
1101
  };
855
- const [editing, setEditing] = useState4(null);
1102
+ const [editing, setEditing] = useState5(null);
856
1103
  const has = {
857
1104
  config: Boolean(configClient),
858
1105
  courier: Boolean(courierClient),