@openrails/contentkit-ui 0.103.2 → 0.104.0-rc.2
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 +111 -49
- package/dist/client/beacons.d.ts +3 -13
- package/dist/client/beacons.js +8 -46
- package/dist/client/beacons.js.map +1 -1
- package/dist/client/client.d.ts +3 -0
- package/dist/client/client.js +45 -43
- package/dist/client/client.js.map +1 -1
- package/dist/client/content/favorites.d.ts +2 -0
- package/dist/client/content/favorites.js.map +1 -1
- package/dist/client/content/types.d.ts +3 -0
- package/dist/client/content/types.js.map +1 -1
- package/dist/client/contents.d.ts +7 -1
- package/dist/client/contents.js +8 -0
- package/dist/client/contents.js.map +1 -1
- package/dist/client/discovery.d.ts +34 -5
- package/dist/client/discovery.js +23 -2
- package/dist/client/discovery.js.map +1 -1
- package/dist/client/engagement.d.ts +70 -0
- package/dist/client/engagement.js +191 -0
- package/dist/client/engagement.js.map +1 -0
- package/dist/client/generated/routes.d.ts +74 -35
- package/dist/client/generated/routes.js +119 -60
- package/dist/client/generated/routes.js.map +1 -1
- package/dist/client/generated/wire.d.ts +88 -85
- package/dist/client/generated/wire.js.map +1 -1
- package/dist/client/guest-reading-history.d.ts +40 -0
- package/dist/client/guest-reading-history.js +144 -0
- package/dist/client/guest-reading-history.js.map +1 -0
- package/dist/client/index.d.ts +5 -3
- package/dist/client/media/windows.d.ts +2 -0
- package/dist/client/media/windows.js +4 -1
- package/dist/client/media/windows.js.map +1 -1
- package/dist/client/stats.d.ts +4 -20
- package/dist/client/stats.js +0 -11
- package/dist/client/stats.js.map +1 -1
- package/dist/client/versions.d.ts +8 -6
- package/dist/client/versions.js +15 -10
- package/dist/client/versions.js.map +1 -1
- package/dist/client.js +24 -22
- package/dist/components/admin/bulk-drafts.d.ts +17 -0
- package/dist/components/admin/bulk-drafts.js +41 -0
- package/dist/components/admin/bulk-drafts.js.map +1 -0
- package/dist/components/admin/content-admin.d.ts +1 -1
- package/dist/components/admin/content-admin.js.map +1 -1
- package/dist/components/admin/content-manager.d.ts +11 -3
- package/dist/components/admin/content-manager.js +751 -394
- package/dist/components/admin/content-manager.js.map +1 -1
- package/dist/components/admin/group-manager.d.ts +8 -3
- package/dist/components/admin/group-manager.js +218 -146
- package/dist/components/admin/group-manager.js.map +1 -1
- package/dist/components/admin/page-notices.d.ts +16 -0
- package/dist/components/admin/page-notices.js +113 -0
- package/dist/components/admin/page-notices.js.map +1 -0
- package/dist/components/admin/page-picker.d.ts +38 -0
- package/dist/components/admin/page-picker.js +159 -0
- package/dist/components/admin/page-picker.js.map +1 -0
- package/dist/components/admin/quick-search.d.ts +14 -0
- package/dist/components/admin/quick-search.js +60 -0
- package/dist/components/admin/quick-search.js.map +1 -0
- package/dist/components/admin/reader-content-editor.js +382 -321
- package/dist/components/admin/reader-content-editor.js.map +1 -1
- package/dist/components/admin/reader-manifest.js +181 -179
- package/dist/components/admin/reader-manifest.js.map +1 -1
- package/dist/components/admin/shell.d.ts +10 -2
- package/dist/components/admin/shell.js +114 -42
- package/dist/components/admin/shell.js.map +1 -1
- package/dist/components/admin/stats-dashboard.d.ts +4 -9
- package/dist/components/admin/stats-dashboard.js +303 -207
- package/dist/components/admin/stats-dashboard.js.map +1 -1
- package/dist/components/admin/upload-queue.d.ts +14 -0
- package/dist/components/admin/upload-queue.js +115 -98
- package/dist/components/admin/upload-queue.js.map +1 -1
- package/dist/components/content/card.d.ts +31 -3
- package/dist/components/content/card.js +324 -158
- package/dist/components/content/card.js.map +1 -1
- package/dist/components/content/daily-releases.js +144 -190
- package/dist/components/content/daily-releases.js.map +1 -1
- package/dist/components/content/editor-save.js +27 -25
- package/dist/components/content/editor-save.js.map +1 -1
- package/dist/components/content/editors.js +274 -253
- package/dist/components/content/editors.js.map +1 -1
- package/dist/components/content/favorites.d.ts +6 -0
- package/dist/components/content/favorites.js +47 -0
- package/dist/components/content/favorites.js.map +1 -0
- package/dist/components/content/filter-dialog.js +19 -15
- package/dist/components/content/filter-dialog.js.map +1 -1
- package/dist/components/content/filters.d.ts +2 -0
- package/dist/components/content/filters.js +5 -1
- package/dist/components/content/filters.js.map +1 -1
- package/dist/components/content/grid.d.ts +44 -16
- package/dist/components/content/grid.js +308 -270
- package/dist/components/content/grid.js.map +1 -1
- package/dist/components/content/history.d.ts +6 -0
- package/dist/components/content/history.js +111 -0
- package/dist/components/content/history.js.map +1 -0
- package/dist/components/content/index.d.ts +6 -3
- package/dist/components/content/listing.d.ts +14 -3
- package/dist/components/content/listing.js +65 -56
- package/dist/components/content/listing.js.map +1 -1
- package/dist/components/content/offer-fields.js +6 -6
- package/dist/components/content/paged-grid.d.ts +10 -0
- package/dist/components/content/paged-grid.js +116 -0
- package/dist/components/content/paged-grid.js.map +1 -0
- package/dist/components/content/pagination.d.ts +19 -0
- package/dist/components/content/pagination.js +97 -0
- package/dist/components/content/pagination.js.map +1 -0
- package/dist/components/content/paywall.d.ts +9 -0
- package/dist/components/content/paywall.js +27 -3
- package/dist/components/content/paywall.js.map +1 -1
- package/dist/components/content/post-list.d.ts +37 -0
- package/dist/components/content/post-list.js +203 -0
- package/dist/components/content/post-list.js.map +1 -0
- package/dist/components/content/reader-settings.d.ts +2 -0
- package/dist/components/content/reader-settings.js +1 -1
- package/dist/components/content/reader-settings.js.map +1 -1
- package/dist/components/content/search.d.ts +11 -4
- package/dist/components/content/search.js +22 -11
- package/dist/components/content/search.js.map +1 -1
- package/dist/components/content/summary-tile.d.ts +14 -0
- package/dist/components/content/summary-tile.js +63 -0
- package/dist/components/content/summary-tile.js.map +1 -0
- package/dist/components/groups/banner.d.ts +6 -2
- package/dist/components/groups/banner.js +79 -61
- package/dist/components/groups/banner.js.map +1 -1
- package/dist/components/groups/directory.d.ts +12 -2
- package/dist/components/groups/directory.js +168 -105
- package/dist/components/groups/directory.js.map +1 -1
- package/dist/components/groups/editor.js +10 -10
- package/dist/components/groups/editor.js.map +1 -1
- package/dist/components/groups/entity-chips.d.ts +61 -0
- package/dist/components/groups/entity-chips.js +382 -0
- package/dist/components/groups/entity-chips.js.map +1 -0
- package/dist/components/groups/group-members.d.ts +29 -0
- package/dist/components/groups/group-members.js +474 -0
- package/dist/components/groups/group-members.js.map +1 -0
- package/dist/components/groups/header.js +53 -45
- package/dist/components/groups/header.js.map +1 -1
- package/dist/components/groups/index.d.ts +3 -1
- package/dist/components/groups/memberships.d.ts +3 -36
- package/dist/components/groups/memberships.js +105 -480
- package/dist/components/groups/memberships.js.map +1 -1
- package/dist/components/groups/scoped.d.ts +23 -0
- package/dist/components/groups/scoped.js +92 -0
- package/dist/components/groups/scoped.js.map +1 -0
- package/dist/components/media-folder-editor.d.ts +5 -0
- package/dist/components/media-folder-editor.js +419 -231
- package/dist/components/media-folder-editor.js.map +1 -1
- package/dist/components/sortable-list.d.ts +5 -1
- package/dist/components/sortable-list.js +97 -81
- package/dist/components/sortable-list.js.map +1 -1
- package/dist/components/video-mini-player.d.ts +4 -1
- package/dist/components/video-mini-player.js +77 -71
- package/dist/components/video-mini-player.js.map +1 -1
- package/dist/components/video-player.d.ts +4 -1
- package/dist/components/video-player.js +280 -276
- package/dist/components/video-player.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +41 -34
- package/dist/locales/admin/de.js +80 -47
- package/dist/locales/admin/de.js.map +1 -1
- package/dist/locales/admin/en.d.ts +74 -41
- package/dist/locales/admin/en.js +80 -47
- package/dist/locales/admin/en.js.map +1 -1
- package/dist/locales/admin/es.js +80 -47
- package/dist/locales/admin/es.js.map +1 -1
- package/dist/locales/admin/ja.js +80 -47
- package/dist/locales/admin/ja.js.map +1 -1
- package/dist/locales/admin/ko.js +80 -47
- package/dist/locales/admin/ko.js.map +1 -1
- package/dist/locales/admin/zh.js +80 -47
- package/dist/locales/admin/zh.js.map +1 -1
- package/dist/locales/de.js +1 -0
- package/dist/locales/de.js.map +1 -1
- package/dist/locales/discovery/de.js +25 -2
- package/dist/locales/discovery/de.js.map +1 -1
- package/dist/locales/discovery/en.d.ts +24 -1
- package/dist/locales/discovery/en.js +25 -2
- package/dist/locales/discovery/en.js.map +1 -1
- package/dist/locales/discovery/es.js +25 -2
- package/dist/locales/discovery/es.js.map +1 -1
- package/dist/locales/discovery/ja.js +25 -2
- package/dist/locales/discovery/ja.js.map +1 -1
- package/dist/locales/discovery/ko.js +25 -2
- package/dist/locales/discovery/ko.js.map +1 -1
- package/dist/locales/discovery/zh.js +25 -2
- package/dist/locales/discovery/zh.js.map +1 -1
- package/dist/locales/en.d.ts +119 -44
- package/dist/locales/en.js +1 -0
- package/dist/locales/en.js.map +1 -1
- package/dist/locales/es.js +1 -0
- package/dist/locales/es.js.map +1 -1
- package/dist/locales/groups/de.js +22 -4
- package/dist/locales/groups/de.js.map +1 -1
- package/dist/locales/groups/en.d.ts +20 -2
- package/dist/locales/groups/en.js +22 -4
- package/dist/locales/groups/en.js.map +1 -1
- package/dist/locales/groups/es.js +22 -4
- package/dist/locales/groups/es.js.map +1 -1
- package/dist/locales/groups/ja.js +22 -4
- package/dist/locales/groups/ja.js.map +1 -1
- package/dist/locales/groups/ko.js +22 -4
- package/dist/locales/groups/ko.js.map +1 -1
- package/dist/locales/groups/zh.js +22 -4
- package/dist/locales/groups/zh.js.map +1 -1
- package/dist/locales/ja.js +1 -0
- package/dist/locales/ja.js.map +1 -1
- package/dist/locales/ko.js +1 -0
- package/dist/locales/ko.js.map +1 -1
- package/dist/locales/zh.js +1 -0
- package/dist/locales/zh.js.map +1 -1
- package/dist/react/discovery.d.ts +36 -17
- package/dist/react/discovery.js +305 -221
- package/dist/react/discovery.js.map +1 -1
- package/dist/react/groups.d.ts +19 -3
- package/dist/react/groups.js +49 -22
- package/dist/react/groups.js.map +1 -1
- package/dist/react/index.d.ts +7 -4
- package/dist/react/page-notices.d.ts +13 -0
- package/dist/react/page-notices.js +38 -0
- package/dist/react/page-notices.js.map +1 -0
- package/dist/react/post-reads.d.ts +23 -0
- package/dist/react/post-reads.js +90 -0
- package/dist/react/post-reads.js.map +1 -0
- package/dist/react/remembered-sort.d.ts +5 -0
- package/dist/react/remembered-sort.js +29 -0
- package/dist/react/remembered-sort.js.map +1 -0
- package/dist/react/resources.d.ts +3 -1
- package/dist/react/resources.js +6 -2
- package/dist/react/resources.js.map +1 -1
- package/dist/react/stats.d.ts +3 -7
- package/dist/react/stats.js +2 -6
- package/dist/react/stats.js.map +1 -1
- package/dist/react/use-engagement.d.ts +28 -0
- package/dist/react/use-engagement.js +226 -0
- package/dist/react/use-engagement.js.map +1 -0
- package/dist/react/use-resource.d.ts +4 -3
- package/dist/react/use-resource.js +2 -1
- package/dist/react/use-resource.js.map +1 -1
- package/dist/react.js +29 -26
- package/dist/styles.css +1 -1
- package/dist/ui/dialog.d.ts +2 -1
- package/dist/ui/dialog.js +23 -20
- package/dist/ui/dialog.js.map +1 -1
- package/dist/urls/index.d.ts +1 -1
- package/dist/urls.js +2 -2
- package/dist/urls.js.map +1 -1
- package/package.json +1 -1
- package/dist/components/admin/page-review.d.ts +0 -13
- package/dist/components/admin/page-review.js +0 -225
- package/dist/components/admin/page-review.js.map +0 -1
- package/dist/react/page-review.d.ts +0 -14
- package/dist/react/page-review.js +0 -37
- package/dist/react/page-review.js.map +0 -1
|
@@ -2,83 +2,86 @@ import { useLanguageName as e, useMessages as t } from "../../i18n/context.js";
|
|
|
2
2
|
import { useGroups as n, useKinds as r } from "../../react/groups.js";
|
|
3
3
|
import { Button as i } from "../../ui/button.js";
|
|
4
4
|
import { Badge as a } from "../../ui/badge.js";
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
5
|
+
import { Input as o } from "../../ui/input.js";
|
|
6
|
+
import { Select as s, SelectContent as c, SelectItem as l, SelectTrigger as u, SelectValue as d } from "../../ui/select.js";
|
|
7
|
+
import { contentError as f, useAction as p } from "../social/parts.js";
|
|
8
|
+
import { AdminRoot as m, LoadFailed as h, NoAccess as g, Rows as _ } from "./shell.js";
|
|
9
|
+
import { useAdminLocation as v, useFlowClient as y, useStaffAccess as b } from "../../react/admin.js";
|
|
10
|
+
import { Tabs as x, TabsList as S, TabsTrigger as C } from "../../ui/tabs.js";
|
|
11
|
+
import { LETTERS as w } from "../../client/group-fields.js";
|
|
12
|
+
import { labelOf as T } from "../groups/parts.js";
|
|
13
|
+
import { ScopedGroups as E } from "../groups/scoped.js";
|
|
14
|
+
import { GroupEditor as D } from "../groups/editor.js";
|
|
15
|
+
import { GroupMembers as O } from "../groups/group-members.js";
|
|
16
|
+
import { useEffect as k, useMemo as A, useState as j } from "react";
|
|
17
|
+
import { Fragment as M, jsx as N, jsxs as P } from "react/jsx-runtime";
|
|
18
|
+
import { cn as F } from "cn";
|
|
16
19
|
//#region src/components/admin/group-manager.tsx
|
|
17
|
-
function
|
|
18
|
-
return
|
|
20
|
+
function I(e = {}) {
|
|
21
|
+
return b(["groups"], e);
|
|
19
22
|
}
|
|
20
|
-
var
|
|
23
|
+
var L = [
|
|
21
24
|
"name",
|
|
22
25
|
"count",
|
|
23
26
|
"newest"
|
|
24
27
|
];
|
|
25
|
-
function
|
|
26
|
-
let l =
|
|
28
|
+
function R({ client: e, baseUrl: t, auth: n, guard: r, appearance: i, className: a, language: o, messages: s, ...c }) {
|
|
29
|
+
let l = y({
|
|
27
30
|
client: e,
|
|
28
31
|
baseUrl: t,
|
|
29
32
|
auth: n
|
|
30
33
|
});
|
|
31
|
-
return /* @__PURE__ */
|
|
34
|
+
return /* @__PURE__ */ N(m, {
|
|
32
35
|
flow: "group-manager",
|
|
33
36
|
appearance: i,
|
|
34
37
|
className: a,
|
|
35
38
|
language: o,
|
|
36
39
|
messages: s,
|
|
37
40
|
guard: r,
|
|
38
|
-
children: /* @__PURE__ */
|
|
41
|
+
children: /* @__PURE__ */ N(z, {
|
|
39
42
|
...c,
|
|
40
43
|
client: l
|
|
41
44
|
})
|
|
42
45
|
});
|
|
43
46
|
}
|
|
44
|
-
function
|
|
45
|
-
let { t: a } = t(), o =
|
|
46
|
-
if (s.loading || c.loading) return /* @__PURE__ */
|
|
47
|
-
if (!s.allowed.groups) return /* @__PURE__ */
|
|
48
|
-
if (!l) return /* @__PURE__ */
|
|
47
|
+
function z({ basePath: e, navigation: n, ...i }) {
|
|
48
|
+
let { t: a } = t(), o = v(e, n), s = I({ client: i.client }), c = r({ client: i.client }), l = c.kinds, u = A(() => i.groupKinds ?? Object.entries(l?.entity_kinds ?? {}).filter(([, e]) => e.owner !== "user").map(([e]) => e).sort(), [i.groupKinds, l]);
|
|
49
|
+
if (s.loading || c.loading) return /* @__PURE__ */ N(_, {});
|
|
50
|
+
if (!s.allowed.groups) return /* @__PURE__ */ N(g, { children: a("groupManager.noAccess") });
|
|
51
|
+
if (!l) return /* @__PURE__ */ N(h, {
|
|
49
52
|
error: c.error,
|
|
50
53
|
message: a("groupManager.kindsFailed"),
|
|
51
54
|
retry: c.reload
|
|
52
55
|
});
|
|
53
|
-
if (!u.length) return /* @__PURE__ */
|
|
56
|
+
if (!u.length) return /* @__PURE__ */ N("p", {
|
|
54
57
|
className: "text-muted-foreground",
|
|
55
58
|
children: a("groupManager.noKinds")
|
|
56
59
|
});
|
|
57
|
-
let [d, f] = o.view.split("/"),
|
|
60
|
+
let [d, f] = o.view.split("/"), p = u.includes(d ?? "") ? d : u[0], m = {
|
|
58
61
|
...i,
|
|
59
62
|
loc: o,
|
|
60
|
-
kind:
|
|
63
|
+
kind: p,
|
|
61
64
|
kinds: l
|
|
62
65
|
};
|
|
63
|
-
return /* @__PURE__ */
|
|
64
|
-
value:
|
|
66
|
+
return /* @__PURE__ */ P(M, { children: [u.length > 1 && /* @__PURE__ */ N(x, {
|
|
67
|
+
value: p,
|
|
65
68
|
onValueChange: (e) => o.go(String(e)),
|
|
66
|
-
children: /* @__PURE__ */
|
|
69
|
+
children: /* @__PURE__ */ N(S, {
|
|
67
70
|
className: "flex-wrap group-data-horizontal/tabs:h-auto",
|
|
68
|
-
children: u.map((e) => /* @__PURE__ */
|
|
71
|
+
children: u.map((e) => /* @__PURE__ */ N(C, {
|
|
69
72
|
value: e,
|
|
70
73
|
className: "h-7.5",
|
|
71
|
-
children:
|
|
74
|
+
children: T(i.labels, e)
|
|
72
75
|
}, e))
|
|
73
76
|
})
|
|
74
|
-
}), f ? f === "new" ? /* @__PURE__ */
|
|
75
|
-
...
|
|
77
|
+
}), f ? f === "new" ? /* @__PURE__ */ N(H, { ...m }, p) : /* @__PURE__ */ N(U, {
|
|
78
|
+
...m,
|
|
76
79
|
id: f
|
|
77
|
-
}, f) : /* @__PURE__ */
|
|
80
|
+
}, f) : /* @__PURE__ */ N(V, { ...m }, p)] });
|
|
78
81
|
}
|
|
79
|
-
function
|
|
82
|
+
function B({ loc: e, kind: n }) {
|
|
80
83
|
let { t: r } = t();
|
|
81
|
-
return /* @__PURE__ */
|
|
84
|
+
return /* @__PURE__ */ N(i, {
|
|
82
85
|
variant: "ghost",
|
|
83
86
|
size: "sm",
|
|
84
87
|
className: "justify-self-start",
|
|
@@ -86,145 +89,206 @@ function P({ loc: e, kind: n }) {
|
|
|
86
89
|
children: r("groupManager.back")
|
|
87
90
|
});
|
|
88
91
|
}
|
|
89
|
-
function
|
|
90
|
-
let
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
92
|
+
function V({ loc: r, kind: m, kinds: g, client: v, contentKind: y, labels: b, onError: x, pageSize: S = 50 }) {
|
|
93
|
+
let C = t(), { t: E } = C, D = e(), O = g.languages, A = r.query.get("deleted") === "1", M = r.query.get("q") ?? "", [I, R] = j(M);
|
|
94
|
+
k(() => R(M), [M]);
|
|
95
|
+
let z = r.query.get("letter") ?? "", B = w.includes(z) ? z : void 0, V = r.query.get("sort") ?? "", H = L.includes(V) ? V : "name", U = r.query.get("language") ?? "", W = O.includes(U) ? U : O[0], G = {
|
|
96
|
+
letter: B,
|
|
97
|
+
sort: H === "name" ? void 0 : H,
|
|
98
|
+
language: W === O[0] ? void 0 : W,
|
|
99
|
+
q: M || void 0,
|
|
100
|
+
deleted: A ? "1" : void 0
|
|
101
|
+
}, K = (e) => r.go(m, {
|
|
102
|
+
...G,
|
|
96
103
|
...e
|
|
97
|
-
})
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
+
});
|
|
105
|
+
k(() => {
|
|
106
|
+
if (I.trim() === M) return;
|
|
107
|
+
let e = setTimeout(() => r.go(m, {
|
|
108
|
+
...G,
|
|
109
|
+
q: I.trim() || void 0
|
|
110
|
+
}, { replace: !0 }), 250);
|
|
111
|
+
return () => clearTimeout(e);
|
|
112
|
+
}, [I]);
|
|
113
|
+
let q = n({
|
|
114
|
+
kind: m,
|
|
115
|
+
letter: B,
|
|
116
|
+
sort: H,
|
|
117
|
+
language: W,
|
|
118
|
+
contentKind: y,
|
|
119
|
+
pageSize: S,
|
|
120
|
+
query: M || void 0,
|
|
121
|
+
deleted: A
|
|
104
122
|
}, {
|
|
105
|
-
client:
|
|
123
|
+
client: v,
|
|
106
124
|
management: !0
|
|
107
|
-
}),
|
|
108
|
-
return /* @__PURE__ */
|
|
125
|
+
}), J = p("group.save", x), Y = T(b, m);
|
|
126
|
+
return /* @__PURE__ */ P("div", {
|
|
109
127
|
className: "grid gap-4",
|
|
110
128
|
"data-ckui": "group-list",
|
|
111
|
-
"data-kind":
|
|
129
|
+
"data-kind": m,
|
|
112
130
|
children: [
|
|
113
|
-
/* @__PURE__ */
|
|
131
|
+
/* @__PURE__ */ P("div", {
|
|
114
132
|
className: "flex flex-wrap items-center justify-between gap-2",
|
|
115
|
-
children: [/* @__PURE__ */
|
|
133
|
+
children: [/* @__PURE__ */ N("h2", {
|
|
116
134
|
className: "text-base font-semibold",
|
|
117
|
-
children:
|
|
118
|
-
}), /* @__PURE__ */
|
|
135
|
+
children: Y
|
|
136
|
+
}), /* @__PURE__ */ N(i, {
|
|
119
137
|
size: "sm",
|
|
120
|
-
onClick: () => r.go(`${
|
|
121
|
-
children:
|
|
138
|
+
onClick: () => r.go(`${m}/new`),
|
|
139
|
+
children: E("groupManager.new", { kind: Y })
|
|
122
140
|
})]
|
|
123
141
|
}),
|
|
124
|
-
/* @__PURE__ */
|
|
125
|
-
className: "flex
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
children: [/* @__PURE__ */ O(l, {
|
|
141
|
-
size: "sm",
|
|
142
|
-
"aria-label": x("groupManager.language"),
|
|
143
|
-
children: /* @__PURE__ */ O(u, { children: (e) => w(e) })
|
|
144
|
-
}), /* @__PURE__ */ O(s, { children: T.map((e) => /* @__PURE__ */ O(c, {
|
|
145
|
-
value: e,
|
|
146
|
-
children: w(e)
|
|
147
|
-
}, e)) })]
|
|
142
|
+
/* @__PURE__ */ P("div", {
|
|
143
|
+
className: "flex gap-2",
|
|
144
|
+
role: "group",
|
|
145
|
+
"aria-label": Y,
|
|
146
|
+
children: [/* @__PURE__ */ N(i, {
|
|
147
|
+
size: "sm",
|
|
148
|
+
variant: A ? "outline" : "default",
|
|
149
|
+
"aria-pressed": !A,
|
|
150
|
+
onClick: () => K({ deleted: void 0 }),
|
|
151
|
+
children: E("groupManager.active")
|
|
152
|
+
}), /* @__PURE__ */ N(i, {
|
|
153
|
+
size: "sm",
|
|
154
|
+
variant: A ? "default" : "outline",
|
|
155
|
+
"aria-pressed": A,
|
|
156
|
+
onClick: () => K({ deleted: "1" }),
|
|
157
|
+
children: E("groupManager.deleted")
|
|
148
158
|
})]
|
|
149
159
|
}),
|
|
150
|
-
/* @__PURE__ */
|
|
151
|
-
"
|
|
160
|
+
/* @__PURE__ */ P("div", {
|
|
161
|
+
className: "flex flex-wrap items-center gap-2",
|
|
162
|
+
children: [
|
|
163
|
+
/* @__PURE__ */ N(o, {
|
|
164
|
+
type: "search",
|
|
165
|
+
className: "h-8 min-w-48 flex-1",
|
|
166
|
+
"aria-label": E("groupManager.search"),
|
|
167
|
+
placeholder: E("groupManager.search"),
|
|
168
|
+
value: I,
|
|
169
|
+
onChange: (e) => R(e.target.value)
|
|
170
|
+
}),
|
|
171
|
+
/* @__PURE__ */ P(s, {
|
|
172
|
+
value: H,
|
|
173
|
+
onValueChange: (e) => K({ sort: e === "name" ? void 0 : String(e) }),
|
|
174
|
+
children: [/* @__PURE__ */ N(u, {
|
|
175
|
+
size: "sm",
|
|
176
|
+
"aria-label": E("groupManager.sort"),
|
|
177
|
+
children: /* @__PURE__ */ N(d, { children: (e) => E(`groupManager.sort_${e}`) })
|
|
178
|
+
}), /* @__PURE__ */ N(c, { children: L.map((e) => /* @__PURE__ */ N(l, {
|
|
179
|
+
value: e,
|
|
180
|
+
children: E(`groupManager.sort_${e}`)
|
|
181
|
+
}, e)) })]
|
|
182
|
+
}),
|
|
183
|
+
O.length > 1 && /* @__PURE__ */ P(s, {
|
|
184
|
+
value: W,
|
|
185
|
+
onValueChange: (e) => K({ language: e === O[0] ? void 0 : String(e) }),
|
|
186
|
+
children: [/* @__PURE__ */ N(u, {
|
|
187
|
+
size: "sm",
|
|
188
|
+
"aria-label": E("groupManager.language"),
|
|
189
|
+
children: /* @__PURE__ */ N(d, { children: (e) => D(e) })
|
|
190
|
+
}), /* @__PURE__ */ N(c, { children: O.map((e) => /* @__PURE__ */ N(l, {
|
|
191
|
+
value: e,
|
|
192
|
+
children: D(e)
|
|
193
|
+
}, e)) })]
|
|
194
|
+
})
|
|
195
|
+
]
|
|
196
|
+
}),
|
|
197
|
+
/* @__PURE__ */ N("nav", {
|
|
198
|
+
"aria-label": E("groups.byLetter"),
|
|
152
199
|
className: "flex flex-wrap gap-1",
|
|
153
200
|
"data-ckui": "letters",
|
|
154
|
-
children: [void 0, ...
|
|
201
|
+
children: [void 0, ...w].map((e) => /* @__PURE__ */ N(i, {
|
|
155
202
|
size: "xs",
|
|
156
|
-
variant:
|
|
157
|
-
"aria-pressed":
|
|
158
|
-
"aria-label": e === void 0 ? void 0 : e === "#" ?
|
|
203
|
+
variant: B === e ? "default" : "ghost",
|
|
204
|
+
"aria-pressed": B === e,
|
|
205
|
+
"aria-label": e === void 0 ? void 0 : e === "#" ? E("groups.otherLetters") : e.toUpperCase(),
|
|
159
206
|
className: "min-w-7",
|
|
160
|
-
onClick: () =>
|
|
161
|
-
children: e === void 0 ?
|
|
207
|
+
onClick: () => K({ letter: e }),
|
|
208
|
+
children: e === void 0 ? E("groups.all") : e.toUpperCase()
|
|
162
209
|
}, e ?? "all"))
|
|
163
210
|
}),
|
|
164
|
-
|
|
165
|
-
error:
|
|
166
|
-
message:
|
|
167
|
-
retry:
|
|
168
|
-
}) :
|
|
211
|
+
q.loading && !q.items.length ? /* @__PURE__ */ N(_, {}) : q.error && !q.items.length ? /* @__PURE__ */ N(h, {
|
|
212
|
+
error: q.error,
|
|
213
|
+
message: E("groupManager.loadFailed"),
|
|
214
|
+
retry: q.reload
|
|
215
|
+
}) : q.items.length ? /* @__PURE__ */ N("ul", {
|
|
169
216
|
className: "grid divide-y divide-border rounded-lg border border-border",
|
|
170
|
-
"aria-busy":
|
|
171
|
-
children:
|
|
217
|
+
"aria-busy": q.loading,
|
|
218
|
+
children: q.items.map((e) => /* @__PURE__ */ P("li", {
|
|
172
219
|
className: "flex flex-wrap items-center gap-3 p-3",
|
|
173
220
|
"data-ckui": "group-row",
|
|
174
221
|
"data-slug": e.slug,
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
222
|
+
"data-state": A ? "deleted" : "active",
|
|
223
|
+
children: [
|
|
224
|
+
(e.avatar?.renditions?.[0] ?? e.cover?.renditions?.[0]) && /* @__PURE__ */ N("img", {
|
|
225
|
+
src: (e.avatar?.renditions?.[0] ?? e.cover?.renditions?.[0]).url,
|
|
226
|
+
alt: "",
|
|
227
|
+
loading: "lazy",
|
|
228
|
+
className: F("size-9 shrink-0 object-cover", e.avatar?.renditions?.[0] ? "rounded-full" : "rounded-sm")
|
|
229
|
+
}),
|
|
230
|
+
/* @__PURE__ */ P("div", {
|
|
231
|
+
className: "grid min-w-0 flex-1 gap-0.5",
|
|
232
|
+
children: [
|
|
233
|
+
/* @__PURE__ */ N("button", {
|
|
234
|
+
type: "button",
|
|
235
|
+
className: "text-left font-medium break-words hover:underline",
|
|
236
|
+
onClick: () => r.go(`${m}/${e.id}`),
|
|
237
|
+
children: e.name || e.slug
|
|
238
|
+
}),
|
|
239
|
+
/* @__PURE__ */ N("span", {
|
|
240
|
+
className: "text-xs text-muted-foreground",
|
|
241
|
+
children: e.slug
|
|
242
|
+
}),
|
|
243
|
+
e.internal && /* @__PURE__ */ N(a, {
|
|
244
|
+
variant: "secondary",
|
|
245
|
+
className: "justify-self-start",
|
|
246
|
+
children: E("groupEditor.internal")
|
|
247
|
+
})
|
|
248
|
+
]
|
|
249
|
+
}),
|
|
250
|
+
/* @__PURE__ */ N("span", {
|
|
251
|
+
className: "text-sm text-muted-foreground tabular-nums",
|
|
252
|
+
title: E("groupManager.count"),
|
|
253
|
+
children: new Intl.NumberFormat(C.language).format(e.count)
|
|
254
|
+
}),
|
|
255
|
+
A && /* @__PURE__ */ N(i, {
|
|
256
|
+
size: "sm",
|
|
257
|
+
variant: "outline",
|
|
258
|
+
disabled: J.pending,
|
|
259
|
+
onClick: () => void J.run(() => v.entities.update(e.id, { state: "active" })).then((e) => e !== void 0 && q.reload()),
|
|
260
|
+
children: E("groupEditor.restore")
|
|
261
|
+
})
|
|
262
|
+
]
|
|
199
263
|
}, e.id))
|
|
200
|
-
}) : /* @__PURE__ */
|
|
264
|
+
}) : /* @__PURE__ */ N("p", {
|
|
201
265
|
className: "text-muted-foreground",
|
|
202
|
-
children:
|
|
266
|
+
children: E(A ? "groupManager.noDeleted" : M ? "groupManager.noMatches" : "groups.empty")
|
|
203
267
|
}),
|
|
204
|
-
|
|
268
|
+
q.hasMore && /* @__PURE__ */ P("div", {
|
|
205
269
|
className: "grid justify-items-center gap-2",
|
|
206
|
-
children: [
|
|
270
|
+
children: [q.error && /* @__PURE__ */ N("p", {
|
|
207
271
|
role: "alert",
|
|
208
272
|
className: "text-destructive",
|
|
209
|
-
children:
|
|
210
|
-
}), /* @__PURE__ */
|
|
273
|
+
children: f(C, q.error)
|
|
274
|
+
}), /* @__PURE__ */ N(i, {
|
|
211
275
|
variant: "outline",
|
|
212
276
|
size: "sm",
|
|
213
|
-
disabled:
|
|
214
|
-
onClick: () => void
|
|
215
|
-
children:
|
|
277
|
+
disabled: q.loadingMore,
|
|
278
|
+
onClick: () => void q.loadMore(),
|
|
279
|
+
children: q.loadingMore ? E("groups.loading") : q.error ? E("common.retry") : E("groups.loadMore")
|
|
216
280
|
})]
|
|
217
281
|
})
|
|
218
282
|
]
|
|
219
283
|
});
|
|
220
284
|
}
|
|
221
|
-
function
|
|
222
|
-
return /* @__PURE__ */
|
|
285
|
+
function H({ loc: e, kind: t, client: n, labels: r, onError: i }) {
|
|
286
|
+
return /* @__PURE__ */ P("div", {
|
|
223
287
|
className: "grid gap-4",
|
|
224
|
-
children: [/* @__PURE__ */
|
|
288
|
+
children: [/* @__PURE__ */ N(B, {
|
|
225
289
|
loc: e,
|
|
226
290
|
kind: t
|
|
227
|
-
}), /* @__PURE__ */
|
|
291
|
+
}), /* @__PURE__ */ N(D, {
|
|
228
292
|
management: !0,
|
|
229
293
|
id: null,
|
|
230
294
|
kind: t,
|
|
@@ -235,32 +299,40 @@ function I({ loc: e, kind: t, client: n, labels: r, onError: i }) {
|
|
|
235
299
|
})]
|
|
236
300
|
});
|
|
237
301
|
}
|
|
238
|
-
function
|
|
239
|
-
return /* @__PURE__ */
|
|
302
|
+
function U({ loc: e, kind: t, client: n, labels: r, onError: i, renderContent: a, contentHref: o, newContentHref: s, id: c }) {
|
|
303
|
+
return /* @__PURE__ */ P("div", {
|
|
240
304
|
className: "grid gap-4",
|
|
241
|
-
children: [/* @__PURE__ */
|
|
305
|
+
children: [/* @__PURE__ */ N(B, {
|
|
242
306
|
loc: e,
|
|
243
307
|
kind: t
|
|
244
|
-
}), /* @__PURE__ */
|
|
308
|
+
}), /* @__PURE__ */ N(D, {
|
|
245
309
|
management: !0,
|
|
246
|
-
id:
|
|
310
|
+
id: c,
|
|
247
311
|
kind: t,
|
|
248
312
|
labels: r,
|
|
249
313
|
client: n,
|
|
250
314
|
onError: i,
|
|
251
315
|
onMerged: (n) => e.go(`${t}/${n.into}`, void 0, { replace: !0 }),
|
|
252
|
-
children: (
|
|
253
|
-
group:
|
|
316
|
+
children: (t) => /* @__PURE__ */ P(M, { children: [/* @__PURE__ */ N(E, {
|
|
317
|
+
group: t,
|
|
318
|
+
management: !0,
|
|
319
|
+
labels: r,
|
|
320
|
+
client: n,
|
|
321
|
+
onSelect: (t) => e.go(`${t.kind}/${t.id}`)
|
|
322
|
+
}), /* @__PURE__ */ N(O, {
|
|
323
|
+
group: t,
|
|
254
324
|
labels: r,
|
|
255
325
|
client: n,
|
|
256
326
|
onError: i,
|
|
257
327
|
renderContent: a,
|
|
258
|
-
|
|
259
|
-
|
|
328
|
+
contentHref: o,
|
|
329
|
+
newContentHref: s,
|
|
330
|
+
onUseCover: (e) => n.entities.update(t.id, { cover: { content_id: e } })
|
|
331
|
+
})] })
|
|
260
332
|
})]
|
|
261
333
|
});
|
|
262
334
|
}
|
|
263
335
|
//#endregion
|
|
264
|
-
export {
|
|
336
|
+
export { R as GroupManager, I as useGroupManagerAccess };
|
|
265
337
|
|
|
266
338
|
//# sourceMappingURL=group-manager.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"group-manager.js","names":[],"sources":["../../../src/components/admin/group-manager.tsx"],"sourcesContent":["import { useMemo, type ReactNode } from \"react\";\nimport type { ContentKitClient } from \"../../client/client.js\";\nimport { LETTERS } from \"../../client/group-fields.js\";\nimport type { ContentModel, Membership } from \"../../client/generated/wire.js\";\nimport { useLanguageName, useMessages } from \"../../i18n/context.js\";\nimport { useAdminLocation, useFlowClient, useStaffAccess, type AdminLocation, type FlowClientOptions, type StaffAccess } from \"../../react/admin.js\";\nimport { useGroups, useKinds, type GroupSort } from \"../../react/groups.js\";\nimport { Badge } from \"#ckui/ui/badge\";\nimport { Button } from \"#ckui/ui/button\";\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from \"#ckui/ui/select\";\nimport { Tabs, TabsList, TabsTrigger } from \"#ckui/ui/tabs\";\nimport { GroupEditor } from \"../groups/editor.js\";\nimport { GroupMembers } from \"../groups/memberships.js\";\nimport { labelOf, type Labels } from \"../groups/parts.js\";\nimport { contentError } from \"../social/parts.js\";\nimport { AdminRoot, LoadFailed, NoAccess, Rows, type AdminFlowProps, type AdminRouteProps } from \"./shell.js\";\n\nexport interface GroupManagerProps extends AdminFlowProps, AdminRouteProps {\n /** The group kinds managed, in tab order; default the content model's site-owned kinds. */\n groupKinds?: readonly string[];\n /** Display names of kinds, attributes, roles and values by identifier. */\n labels?: Labels;\n /** Counts of this content kind; default every kind. */\n contentKind?: string;\n /** One member, e.g. a link with its title; default its content id. */\n renderContent?: (member: Membership) => ReactNode;\n pageSize?: number;\n}\n\n/** Whether the caller may manage groups (root:groups:write). */\nexport function useGroupManagerAccess(o: FlowClientOptions = {}): StaffAccess<\"groups\"> {\n return useStaffAccess([\"groups\"] as const, o);\n}\n\nconst SORTS: readonly GroupSort[] = [\"name\", \"count\", \"newest\"];\n\n/**\n * Staff: groups per kind. A kind's groups by letter, order and language; a\n * new group; a group's editor (GroupEditor) and its members (GroupMembers).\n * Kinds are at basePath/{kind}, a group at basePath/{kind}/{id}, filters in the query.\n */\nexport function GroupManager({ client: own, baseUrl, auth, guard, appearance, className, language, messages, ...p }: GroupManagerProps) {\n const client = useFlowClient({ client: own, baseUrl, auth });\n return (\n <AdminRoot flow=\"group-manager\" appearance={appearance} className={className} language={language} messages={messages} guard={guard}>\n <Manager {...p} client={client} />\n </AdminRoot>\n );\n}\n\ntype Inner = Omit<GroupManagerProps, \"client\" | \"baseUrl\" | \"auth\" | \"guard\" | \"appearance\" | \"className\" | \"language\" | \"messages\"> & { client: ContentKitClient };\ntype Ctx = Inner & { loc: AdminLocation; kind: string; kinds: ContentModel };\n\nfunction Manager({ basePath, navigation, ...p }: Inner) {\n const { t } = useMessages();\n const loc = useAdminLocation(basePath, navigation);\n const access = useGroupManagerAccess({ client: p.client });\n const model = useKinds({ client: p.client });\n const kinds = model.kinds;\n const list = useMemo(\n () =>\n p.groupKinds ??\n Object.entries(kinds?.entity_kinds ?? {})\n .filter(([, k]) => k.owner !== \"user\")\n .map(([name]) => name)\n .sort(),\n [p.groupKinds, kinds],\n );\n if (access.loading || model.loading) return <Rows />;\n if (!access.allowed.groups) return <NoAccess>{t(\"groupManager.noAccess\")}</NoAccess>;\n if (!kinds) return <LoadFailed error={model.error} message={t(\"groupManager.kindsFailed\")} retry={model.reload} />;\n if (!list.length) return <p className=\"text-muted-foreground\">{t(\"groupManager.noKinds\")}</p>;\n const [k, sub] = loc.view.split(\"/\");\n const kind = list.includes(k ?? \"\") ? k! : list[0]!;\n const ctx: Ctx = { ...p, loc, kind, kinds };\n return (\n <>\n {list.length > 1 && (\n <Tabs value={kind} onValueChange={(v) => loc.go(String(v))}>\n <TabsList className=\"flex-wrap group-data-horizontal/tabs:h-auto\">\n {list.map((x) => (\n <TabsTrigger key={x} value={x} className=\"h-7.5\">\n {labelOf(p.labels, x)}\n </TabsTrigger>\n ))}\n </TabsList>\n </Tabs>\n )}\n {!sub ? <List key={kind} {...ctx} /> : sub === \"new\" ? <Create key={kind} {...ctx} /> : <Edit key={sub} {...ctx} id={sub} />}\n </>\n );\n}\n\nfunction Back({ loc, kind }: { loc: AdminLocation; kind: string }) {\n const { t } = useMessages();\n return (\n <Button variant=\"ghost\" size=\"sm\" className=\"justify-self-start\" onClick={() => loc.go(kind)}>\n {t(\"groupManager.back\")}\n </Button>\n );\n}\n\nfunction List({ loc, kind, kinds, client, contentKind, labels, pageSize = 50 }: Ctx) {\n const m = useMessages();\n const { t } = m;\n const languageName = useLanguageName();\n const languages = kinds.languages;\n const letterParam = loc.query.get(\"letter\") ?? \"\";\n const letter = LETTERS.includes(letterParam) ? letterParam : undefined;\n const sortParam = loc.query.get(\"sort\") ?? \"\";\n const sort = (SORTS as readonly string[]).includes(sortParam) ? (sortParam as GroupSort) : \"name\";\n const languageParam = loc.query.get(\"language\") ?? \"\";\n const language = languages.includes(languageParam) ? languageParam : languages[0];\n const filters: { letter?: string; sort?: GroupSort; language?: string } = { letter, sort: sort === \"name\" ? undefined : sort, language: language === languages[0] ? undefined : language };\n const filter = (next: Partial<typeof filters>) => loc.go(kind, { ...filters, ...next });\n const groups = useGroups({ kind, letter, sort, language, contentKind, pageSize }, { client, management: true });\n const label = labelOf(labels, kind);\n return (\n <div className=\"grid gap-4\" data-ckui=\"group-list\" data-kind={kind}>\n <div className=\"flex flex-wrap items-center justify-between gap-2\">\n <h2 className=\"text-base font-semibold\">{label}</h2>\n <Button size=\"sm\" onClick={() => loc.go(`${kind}/new`)}>\n {t(\"groupManager.new\", { kind: label })}\n </Button>\n </div>\n <div className=\"flex flex-wrap items-center gap-2\">\n <Select value={sort} onValueChange={(v) => filter({ sort: v === \"name\" ? undefined : (String(v) as GroupSort) })}>\n <SelectTrigger size=\"sm\" aria-label={t(\"groupManager.sort\")}>\n <SelectValue>{(v: string) => t(`groupManager.sort_${v as GroupSort}`)}</SelectValue>\n </SelectTrigger>\n <SelectContent>\n {SORTS.map((s) => (\n <SelectItem key={s} value={s}>\n {t(`groupManager.sort_${s}`)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n {languages.length > 1 && (\n <Select value={language} onValueChange={(v) => filter({ language: v === languages[0] ? undefined : String(v) })}>\n <SelectTrigger size=\"sm\" aria-label={t(\"groupManager.language\")}>\n <SelectValue>{(v: string) => languageName(v)}</SelectValue>\n </SelectTrigger>\n <SelectContent>\n {languages.map((l) => (\n <SelectItem key={l} value={l}>\n {languageName(l)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n )}\n </div>\n <nav aria-label={t(\"groups.byLetter\")} className=\"flex flex-wrap gap-1\" data-ckui=\"letters\">\n {[undefined, ...LETTERS].map((l) => (\n <Button\n key={l ?? \"all\"}\n size=\"xs\"\n variant={letter === l ? \"default\" : \"ghost\"}\n aria-pressed={letter === l}\n aria-label={l === undefined ? undefined : l === \"#\" ? t(\"groups.otherLetters\") : l.toUpperCase()}\n className=\"min-w-7\"\n onClick={() => filter({ letter: l })}\n >\n {l === undefined ? t(\"groups.all\") : l.toUpperCase()}\n </Button>\n ))}\n </nav>\n {groups.loading && !groups.items.length ? (\n <Rows />\n ) : groups.error && !groups.items.length ? (\n <LoadFailed error={groups.error} message={t(\"groupManager.loadFailed\")} retry={groups.reload} />\n ) : !groups.items.length ? (\n <p className=\"text-muted-foreground\">{t(\"groups.empty\")}</p>\n ) : (\n <ul className=\"grid divide-y divide-border rounded-lg border border-border\" aria-busy={groups.loading}>\n {groups.items.map((g) => (\n <li key={g.id} className=\"flex flex-wrap items-center gap-3 p-3\" data-ckui=\"group-row\" data-slug={g.slug}>\n <div className=\"grid min-w-0 flex-1 gap-0.5\">\n <button type=\"button\" className=\"text-left font-medium break-words hover:underline\" onClick={() => loc.go(`${kind}/${g.id}`)}>\n {g.name || g.slug}\n </button>\n <span className=\"text-xs text-muted-foreground\">{g.slug}</span>\n {g.internal && <Badge variant=\"secondary\" className=\"justify-self-start\">{t(\"groupEditor.internal\")}</Badge>}\n </div>\n <span className=\"text-sm text-muted-foreground tabular-nums\" title={t(\"groupManager.count\")}>\n {new Intl.NumberFormat(m.language).format(g.count)}\n </span>\n </li>\n ))}\n </ul>\n )}\n {groups.hasMore && (\n <div className=\"grid justify-items-center gap-2\">\n {groups.error && <p role=\"alert\" className=\"text-destructive\">{contentError(m, groups.error)}</p>}\n <Button variant=\"outline\" size=\"sm\" disabled={groups.loadingMore} onClick={() => void groups.loadMore()}>\n {groups.loadingMore ? t(\"groups.loading\") : groups.error ? t(\"common.retry\") : t(\"groups.loadMore\")}\n </Button>\n </div>\n )}\n </div>\n );\n}\n\nfunction Create({ loc, kind, client, labels, onError }: Ctx) {\n return (\n <div className=\"grid gap-4\">\n <Back loc={loc} kind={kind} />\n <GroupEditor\n management\n id={null}\n kind={kind}\n labels={labels}\n client={client}\n onError={onError}\n onCreated={(g) => loc.go(`${kind}/${g.id}`, undefined, { replace: true })}\n />\n </div>\n );\n}\n\nfunction Edit({ loc, kind, client, labels, onError, renderContent, id }: Ctx & { id: string }) {\n return (\n <div className=\"grid gap-4\">\n <Back loc={loc} kind={kind} />\n <GroupEditor\n management\n id={id}\n kind={kind}\n labels={labels}\n client={client}\n onError={onError}\n onMerged={(r) => loc.go(`${kind}/${r.into}`, undefined, { replace: true })}\n >\n {(group) => (\n <GroupMembers\n group={group}\n labels={labels}\n client={client}\n onError={onError}\n renderContent={renderContent}\n onUseCover={(content) => client.entities.update(group.id, { cover: { content_id: content } })}\n />\n )}\n </GroupEditor>\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;AA8BA,SAAgB,EAAsB,IAAuB,CAAC,GAA0B;CACtF,OAAO,EAAe,CAAC,QAAQ,GAAY,CAAC;AAC9C;AAEA,IAAM,IAA8B;CAAC;CAAQ;CAAS;AAAQ;AAO9D,SAAgB,EAAa,EAAE,QAAQ,GAAK,YAAS,SAAM,UAAO,eAAY,cAAW,aAAU,aAAU,GAAG,KAAwB;CACtI,IAAM,IAAS,EAAc;EAAE,QAAQ;EAAK;EAAS;CAAK,CAAC;CAC3D,OACE,kBAAC,GAAD;EAAW,MAAK;EAA4B;EAAuB;EAAqB;EAAoB;EAAiB;EAC3H,UAAA,kBAAC,GAAD;GAAS,GAAI;GAAW;EAAS,CAAA;CACxB,CAAA;AAEf;AAKA,SAAS,EAAQ,EAAE,aAAU,eAAY,GAAG,KAAY;CACtD,IAAM,EAAE,SAAM,EAAY,GACpB,IAAM,EAAiB,GAAU,CAAU,GAC3C,IAAS,EAAsB,EAAE,QAAQ,EAAE,OAAO,CAAC,GACnD,IAAQ,EAAS,EAAE,QAAQ,EAAE,OAAO,CAAC,GACrC,IAAQ,EAAM,OACd,IAAO,QAET,EAAE,cACF,OAAO,QAAQ,GAAO,gBAAgB,CAAC,CAAC,CAAC,CACtC,QAAQ,GAAG,OAAO,EAAE,UAAU,MAAM,CAAC,CACrC,KAAK,CAAC,OAAU,CAAI,CAAC,CACrB,KAAK,GACV,CAAC,EAAE,YAAY,CAAK,CACtB;CACA,IAAI,EAAO,WAAW,EAAM,SAAS,OAAO,kBAAC,GAAD,CAAO,CAAA;CACnD,IAAI,CAAC,EAAO,QAAQ,QAAQ,OAAO,kBAAC,GAAD,EAAA,UAAW,EAAE,uBAAuB,EAAY,CAAA;CACnF,IAAI,CAAC,GAAO,OAAO,kBAAC,GAAD;EAAY,OAAO,EAAM;EAAO,SAAS,EAAE,0BAA0B;EAAG,OAAO,EAAM;CAAS,CAAA;CACjH,IAAI,CAAC,EAAK,QAAQ,OAAO,kBAAC,KAAD;EAAG,WAAU;EAAyB,UAAA,EAAE,sBAAsB;CAAK,CAAA;CAC5F,IAAM,CAAC,GAAG,KAAO,EAAI,KAAK,MAAM,GAAG,GAC7B,IAAO,EAAK,SAAS,KAAK,EAAE,IAAI,IAAK,EAAK,IAC1C,IAAW;EAAE,GAAG;EAAG;EAAK;EAAM;CAAM;CAC1C,OACE,kBAAA,GAAA,EAAA,UAAA,CACG,EAAK,SAAS,KACb,kBAAC,GAAD;EAAM,OAAO;EAAM,gBAAgB,MAAM,EAAI,GAAG,OAAO,CAAC,CAAC;EACvD,UAAA,kBAAC,GAAD;GAAU,WAAU;GACjB,UAAA,EAAK,KAAK,MACT,kBAAC,GAAD;IAAqB,OAAO;IAAG,WAAU;IACtC,UAAA,EAAQ,EAAE,QAAQ,CAAC;GACT,GAFK,CAEL,CACd;EACO,CAAA;CACN,CAAA,GAEN,IAAqC,MAAQ,QAAQ,kBAAC,GAAD,EAAmB,GAAI,EAAM,GAAhB,CAAgB,IAAI,kBAAC,GAAD;EAAgB,GAAI;EAAK,IAAI;CAAM,GAAxB,CAAwB,IAAnH,kBAAC,GAAD,EAAiB,GAAI,EAAM,GAAhB,CAAgB,CACnC,EAAA,CAAA;AAEN;AAEA,SAAS,EAAK,EAAE,QAAK,WAA8C;CACjE,IAAM,EAAE,SAAM,EAAY;CAC1B,OACE,kBAAC,GAAD;EAAQ,SAAQ;EAAQ,MAAK;EAAK,WAAU;EAAqB,eAAe,EAAI,GAAG,CAAI;EACxF,UAAA,EAAE,mBAAmB;CAChB,CAAA;AAEZ;AAEA,SAAS,EAAK,EAAE,QAAK,SAAM,UAAO,WAAQ,gBAAa,WAAQ,cAAW,MAAW;CACnF,IAAM,IAAI,EAAY,GAChB,EAAE,SAAM,GACR,IAAe,EAAgB,GAC/B,IAAY,EAAM,WAClB,IAAc,EAAI,MAAM,IAAI,QAAQ,KAAK,IACzC,IAAS,EAAQ,SAAS,CAAW,IAAI,IAAc,KAAA,GACvD,IAAY,EAAI,MAAM,IAAI,MAAM,KAAK,IACrC,IAAQ,EAA4B,SAAS,CAAS,IAAK,IAA0B,QACrF,IAAgB,EAAI,MAAM,IAAI,UAAU,KAAK,IAC7C,IAAW,EAAU,SAAS,CAAa,IAAI,IAAgB,EAAU,IACzE,IAAoE;EAAE;EAAQ,MAAM,MAAS,SAAS,KAAA,IAAY;EAAM,UAAU,MAAa,EAAU,KAAK,KAAA,IAAY;CAAS,GACnL,KAAU,MAAkC,EAAI,GAAG,GAAM;EAAE,GAAG;EAAS,GAAG;CAAK,CAAC,GAChF,IAAS,EAAU;EAAE;EAAM;EAAQ;EAAM;EAAU;EAAa;CAAS,GAAG;EAAE;EAAQ,YAAY;CAAK,CAAC,GACxG,IAAQ,EAAQ,GAAQ,CAAI;CAClC,OACE,kBAAC,OAAD;EAAK,WAAU;EAAa,aAAU;EAAa,aAAW;EAA9D,UAAA;GACE,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACE,kBAAC,MAAD;KAAI,WAAU;KAA2B,UAAA;IAAU,CAAA,GACnD,kBAAC,GAAD;KAAQ,MAAK;KAAK,eAAe,EAAI,GAAG,GAAG,EAAK,KAAK;KAClD,UAAA,EAAE,oBAAoB,EAAE,MAAM,EAAM,CAAC;IAChC,CAAA,CACL;;GACL,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACE,kBAAC,GAAD;KAAQ,OAAO;KAAM,gBAAgB,MAAM,EAAO,EAAE,MAAM,MAAM,SAAS,KAAA,IAAa,OAAO,CAAC,EAAgB,CAAC;KAA/G,UAAA,CACE,kBAAC,GAAD;MAAe,MAAK;MAAK,cAAY,EAAE,mBAAmB;MACxD,UAAA,kBAAC,GAAD,EAAA,WAAe,MAAc,EAAE,qBAAqB,GAAgB,EAAe,CAAA;KACtE,CAAA,GACf,kBAAC,GAAD,EAAA,UACG,EAAM,KAAK,MACV,kBAAC,GAAD;MAAoB,OAAO;MACxB,UAAA,EAAE,qBAAqB,GAAG;KACjB,GAFK,CAEL,CACb,EACY,CAAA,CACT;IACP,CAAA,GAAA,EAAU,SAAS,KAClB,kBAAC,GAAD;KAAQ,OAAO;KAAU,gBAAgB,MAAM,EAAO,EAAE,UAAU,MAAM,EAAU,KAAK,KAAA,IAAY,OAAO,CAAC,EAAE,CAAC;KAA9G,UAAA,CACE,kBAAC,GAAD;MAAe,MAAK;MAAK,cAAY,EAAE,uBAAuB;MAC5D,UAAA,kBAAC,GAAD,EAAA,WAAe,MAAc,EAAa,CAAC,EAAe,CAAA;KAC7C,CAAA,GACf,kBAAC,GAAD,EAAA,UACG,EAAU,KAAK,MACd,kBAAC,GAAD;MAAoB,OAAO;MACxB,UAAA,EAAa,CAAC;KACL,GAFK,CAEL,CACb,EACY,CAAA,CACT;IAEP,CAAA,CAAA;;GACL,kBAAC,OAAD;IAAK,cAAY,EAAE,iBAAiB;IAAG,WAAU;IAAuB,aAAU;IAC/E,UAAA,CAAC,KAAA,GAAW,GAAG,CAAO,CAAC,CAAC,KAAK,MAC5B,kBAAC,GAAD;KAEE,MAAK;KACL,SAAS,MAAW,IAAI,YAAY;KACpC,gBAAc,MAAW;KACzB,cAAY,MAAM,KAAA,IAAY,KAAA,IAAY,MAAM,MAAM,EAAE,qBAAqB,IAAI,EAAE,YAAY;KAC/F,WAAU;KACV,eAAe,EAAO,EAAE,QAAQ,EAAE,CAAC;KAElC,UAAA,MAAM,KAAA,IAAY,EAAE,YAAY,IAAI,EAAE,YAAY;IAC7C,GATD,KAAK,KASJ,CACT;GACE,CAAA;GACJ,EAAO,WAAW,CAAC,EAAO,MAAM,SAC/B,kBAAC,GAAD,CAAO,CAAA,IACL,EAAO,SAAS,CAAC,EAAO,MAAM,SAChC,kBAAC,GAAD;IAAY,OAAO,EAAO;IAAO,SAAS,EAAE,yBAAyB;IAAG,OAAO,EAAO;GAAS,CAAA,IAC5F,EAAO,MAAM,SAGhB,kBAAC,MAAD;IAAI,WAAU;IAA8D,aAAW,EAAO;IAC3F,UAAA,EAAO,MAAM,KAAK,MACjB,kBAAC,MAAD;KAAe,WAAU;KAAwC,aAAU;KAAY,aAAW,EAAE;KAApG,UAAA,CACE,kBAAC,OAAD;MAAK,WAAU;MAAf,UAAA;OACE,kBAAC,UAAD;QAAQ,MAAK;QAAS,WAAU;QAAoD,eAAe,EAAI,GAAG,GAAG,EAAK,GAAG,EAAE,IAAI;QACxH,UAAA,EAAE,QAAQ,EAAE;OACP,CAAA;OACR,kBAAC,QAAD;QAAM,WAAU;QAAiC,UAAA,EAAE;OAAW,CAAA;OAC7D,EAAE,YAAY,kBAAC,GAAD;QAAO,SAAQ;QAAY,WAAU;QAAsB,UAAA,EAAE,sBAAsB;OAAS,CAAA;MACxG;KACL,CAAA,GAAA,kBAAC,QAAD;MAAM,WAAU;MAA6C,OAAO,EAAE,oBAAoB;MACvF,UAAA,IAAI,KAAK,aAAa,EAAE,QAAQ,CAAC,CAAC,OAAO,EAAE,KAAK;KAC7C,CAAA,CACJ;IAXK,GAAA,EAAE,EAWP,CACL;GACC,CAAA,IAjBJ,kBAAC,KAAD;IAAG,WAAU;IAAyB,UAAA,EAAE,cAAc;GAAK,CAAA;GAmB5D,EAAO,WACN,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACG,EAAO,SAAS,kBAAC,KAAD;KAAG,MAAK;KAAQ,WAAU;KAAoB,UAAA,EAAa,GAAG,EAAO,KAAK;IAAK,CAAA,GAChG,kBAAC,GAAD;KAAQ,SAAQ;KAAU,MAAK;KAAK,UAAU,EAAO;KAAa,eAAe,KAAK,EAAO,SAAS;KACnG,UAAA,EAAO,cAAc,EAAE,gBAAgB,IAAI,EAAO,QAAQ,EAAE,cAAc,IAAI,EAAE,iBAAiB;IAC5F,CAAA,CACL;;EAEJ;;AAET;AAEA,SAAS,EAAO,EAAE,QAAK,SAAM,WAAQ,WAAQ,cAAgB;CAC3D,OACE,kBAAC,OAAD;EAAK,WAAU;EAAf,UAAA,CACE,kBAAC,GAAD;GAAW;GAAW;EAAO,CAAA,GAC7B,kBAAC,GAAD;GACE,YAAA;GACA,IAAI;GACE;GACE;GACA;GACC;GACT,YAAY,MAAM,EAAI,GAAG,GAAG,EAAK,GAAG,EAAE,MAAM,KAAA,GAAW,EAAE,SAAS,GAAK,CAAC;EACzE,CAAA,CACE;;AAET;AAEA,SAAS,EAAK,EAAE,QAAK,SAAM,WAAQ,WAAQ,YAAS,kBAAe,SAA4B;CAC7F,OACE,kBAAC,OAAD;EAAK,WAAU;EAAf,UAAA,CACE,kBAAC,GAAD;GAAW;GAAW;EAAO,CAAA,GAC7B,kBAAC,GAAD;GACE,YAAA;GACI;GACE;GACE;GACA;GACC;GACT,WAAW,MAAM,EAAI,GAAG,GAAG,EAAK,GAAG,EAAE,QAAQ,KAAA,GAAW,EAAE,SAAS,GAAK,CAAC;GAEvE,WAAA,MACA,kBAAC,GAAD;IACS;IACK;IACJ;IACC;IACM;IACf,aAAa,MAAY,EAAO,SAAS,OAAO,EAAM,IAAI,EAAE,OAAO,EAAE,YAAY,EAAQ,EAAE,CAAC;GAC7F,CAAA;EAEQ,CAAA,CACV;;AAET"}
|
|
1
|
+
{"version":3,"file":"group-manager.js","names":[],"sources":["../../../src/components/admin/group-manager.tsx"],"sourcesContent":["import { cn } from \"cn\";\nimport { useEffect, useMemo, useState, type ReactNode } from \"react\";\nimport type { ContentKitClient } from \"../../client/client.js\";\nimport { LETTERS } from \"../../client/group-fields.js\";\nimport type { Content, ContentModel, Membership } from \"../../client/generated/wire.js\";\nimport { useLanguageName, useMessages } from \"../../i18n/context.js\";\nimport { useAdminLocation, useFlowClient, useStaffAccess, type AdminLocation, type FlowClientOptions, type StaffAccess } from \"../../react/admin.js\";\nimport { useGroups, useKinds, type GroupSort } from \"../../react/groups.js\";\nimport { Badge } from \"#ckui/ui/badge\";\nimport { Button } from \"#ckui/ui/button\";\nimport { Input } from \"#ckui/ui/input\";\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from \"#ckui/ui/select\";\nimport { Tabs, TabsList, TabsTrigger } from \"#ckui/ui/tabs\";\nimport { GroupEditor } from \"../groups/editor.js\";\nimport { GroupMembers, type GroupMembersProps } from \"../groups/group-members.js\";\nimport { labelOf, type Labels } from \"../groups/parts.js\";\nimport { ScopedGroups } from \"../groups/scoped.js\";\nimport { contentError, useAction } from \"../social/parts.js\";\nimport { AdminRoot, LoadFailed, NoAccess, Rows, type AdminFlowProps, type AdminRouteProps } from \"./shell.js\";\n\nexport interface GroupManagerProps extends AdminFlowProps, AdminRouteProps {\n /** The group kinds managed, in tab order; default the content model's site-owned kinds. */\n groupKinds?: readonly string[];\n /** Display names of kinds, attributes, roles and values by identifier. */\n labels?: Labels;\n /** Counts of this content kind; default every kind. */\n contentKind?: string;\n /** Where a member's card links, e.g. the host's editor; none: not a link. */\n contentHref?: (content: Content) => string | undefined;\n /** Where a new item of a content kind starts already in the group being edited; none: no action. */\n newContentHref?: GroupMembersProps[\"newContentHref\"];\n /** Replaces a member's card body; default its cover and title. */\n renderContent?: (member: Membership, content?: Content) => ReactNode;\n pageSize?: number;\n}\n\n/** Whether the caller may manage groups (root:groups:write). */\nexport function useGroupManagerAccess(o: FlowClientOptions = {}): StaffAccess<\"groups\"> {\n return useStaffAccess([\"groups\"] as const, o);\n}\n\nconst SORTS: readonly GroupSort[] = [\"name\", \"count\", \"newest\"];\n\n/**\n * Staff: groups per kind. A kind's groups by letter, order and language; a\n * new group; a group's editor (GroupEditor) and its members (GroupMembers).\n * Kinds are at basePath/{kind}, a group at basePath/{kind}/{id}, filters in the query.\n */\nexport function GroupManager({ client: own, baseUrl, auth, guard, appearance, className, language, messages, ...p }: GroupManagerProps) {\n const client = useFlowClient({ client: own, baseUrl, auth });\n return (\n <AdminRoot flow=\"group-manager\" appearance={appearance} className={className} language={language} messages={messages} guard={guard}>\n <Manager {...p} client={client} />\n </AdminRoot>\n );\n}\n\ntype Inner = Omit<GroupManagerProps, \"client\" | \"baseUrl\" | \"auth\" | \"guard\" | \"appearance\" | \"className\" | \"language\" | \"messages\"> & { client: ContentKitClient };\ntype Ctx = Inner & { loc: AdminLocation; kind: string; kinds: ContentModel };\n\nfunction Manager({ basePath, navigation, ...p }: Inner) {\n const { t } = useMessages();\n const loc = useAdminLocation(basePath, navigation);\n const access = useGroupManagerAccess({ client: p.client });\n const model = useKinds({ client: p.client });\n const kinds = model.kinds;\n const list = useMemo(\n () =>\n p.groupKinds ??\n Object.entries(kinds?.entity_kinds ?? {})\n .filter(([, k]) => k.owner !== \"user\")\n .map(([name]) => name)\n .sort(),\n [p.groupKinds, kinds],\n );\n if (access.loading || model.loading) return <Rows />;\n if (!access.allowed.groups) return <NoAccess>{t(\"groupManager.noAccess\")}</NoAccess>;\n if (!kinds) return <LoadFailed error={model.error} message={t(\"groupManager.kindsFailed\")} retry={model.reload} />;\n if (!list.length) return <p className=\"text-muted-foreground\">{t(\"groupManager.noKinds\")}</p>;\n const [k, sub] = loc.view.split(\"/\");\n const kind = list.includes(k ?? \"\") ? k! : list[0]!;\n const ctx: Ctx = { ...p, loc, kind, kinds };\n return (\n <>\n {list.length > 1 && (\n <Tabs value={kind} onValueChange={(v) => loc.go(String(v))}>\n <TabsList className=\"flex-wrap group-data-horizontal/tabs:h-auto\">\n {list.map((x) => (\n <TabsTrigger key={x} value={x} className=\"h-7.5\">\n {labelOf(p.labels, x)}\n </TabsTrigger>\n ))}\n </TabsList>\n </Tabs>\n )}\n {!sub ? <List key={kind} {...ctx} /> : sub === \"new\" ? <Create key={kind} {...ctx} /> : <Edit key={sub} {...ctx} id={sub} />}\n </>\n );\n}\n\nfunction Back({ loc, kind }: { loc: AdminLocation; kind: string }) {\n const { t } = useMessages();\n return (\n <Button variant=\"ghost\" size=\"sm\" className=\"justify-self-start\" onClick={() => loc.go(kind)}>\n {t(\"groupManager.back\")}\n </Button>\n );\n}\n\nfunction List({ loc, kind, kinds, client, contentKind, labels, onError, pageSize = 50 }: Ctx) {\n const m = useMessages();\n const { t } = m;\n const languageName = useLanguageName();\n const languages = kinds.languages;\n const deleted = loc.query.get(\"deleted\") === \"1\";\n const query = loc.query.get(\"q\") ?? \"\";\n // Typing narrows the list as it goes; the URL keeps the search.\n const [text, setText] = useState(query);\n useEffect(() => setText(query), [query]);\n const letterParam = loc.query.get(\"letter\") ?? \"\";\n const letter = LETTERS.includes(letterParam) ? letterParam : undefined;\n const sortParam = loc.query.get(\"sort\") ?? \"\";\n const sort = (SORTS as readonly string[]).includes(sortParam) ? (sortParam as GroupSort) : \"name\";\n const languageParam = loc.query.get(\"language\") ?? \"\";\n const language = languages.includes(languageParam) ? languageParam : languages[0];\n const filters: { letter?: string; sort?: GroupSort; language?: string; q?: string; deleted?: string } = {\n letter,\n sort: sort === \"name\" ? undefined : sort,\n language: language === languages[0] ? undefined : language,\n q: query || undefined,\n deleted: deleted ? \"1\" : undefined,\n };\n const filter = (next: Partial<typeof filters>) => loc.go(kind, { ...filters, ...next });\n useEffect(() => {\n if (text.trim() === query) return;\n const timer = setTimeout(() => loc.go(kind, { ...filters, q: text.trim() || undefined }, { replace: true }), 250);\n return () => clearTimeout(timer);\n }, [text]); // eslint-disable-line react-hooks/exhaustive-deps\n const groups = useGroups({ kind, letter, sort, language, contentKind, pageSize, query: query || undefined, deleted }, { client, management: true });\n const restore = useAction(\"group.save\", onError);\n const label = labelOf(labels, kind);\n return (\n <div className=\"grid gap-4\" data-ckui=\"group-list\" data-kind={kind}>\n <div className=\"flex flex-wrap items-center justify-between gap-2\">\n <h2 className=\"text-base font-semibold\">{label}</h2>\n <Button size=\"sm\" onClick={() => loc.go(`${kind}/new`)}>\n {t(\"groupManager.new\", { kind: label })}\n </Button>\n </div>\n <div className=\"flex gap-2\" role=\"group\" aria-label={label}>\n <Button size=\"sm\" variant={deleted ? \"outline\" : \"default\"} aria-pressed={!deleted} onClick={() => filter({ deleted: undefined })}>\n {t(\"groupManager.active\")}\n </Button>\n <Button size=\"sm\" variant={deleted ? \"default\" : \"outline\"} aria-pressed={deleted} onClick={() => filter({ deleted: \"1\" })}>\n {t(\"groupManager.deleted\")}\n </Button>\n </div>\n <div className=\"flex flex-wrap items-center gap-2\">\n <Input\n type=\"search\"\n className=\"h-8 min-w-48 flex-1\"\n aria-label={t(\"groupManager.search\")}\n placeholder={t(\"groupManager.search\")}\n value={text}\n onChange={(e) => setText(e.target.value)}\n />\n <Select value={sort} onValueChange={(v) => filter({ sort: v === \"name\" ? undefined : (String(v) as GroupSort) })}>\n <SelectTrigger size=\"sm\" aria-label={t(\"groupManager.sort\")}>\n <SelectValue>{(v: string) => t(`groupManager.sort_${v as GroupSort}`)}</SelectValue>\n </SelectTrigger>\n <SelectContent>\n {SORTS.map((s) => (\n <SelectItem key={s} value={s}>\n {t(`groupManager.sort_${s}`)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n {languages.length > 1 && (\n <Select value={language} onValueChange={(v) => filter({ language: v === languages[0] ? undefined : String(v) })}>\n <SelectTrigger size=\"sm\" aria-label={t(\"groupManager.language\")}>\n <SelectValue>{(v: string) => languageName(v)}</SelectValue>\n </SelectTrigger>\n <SelectContent>\n {languages.map((l) => (\n <SelectItem key={l} value={l}>\n {languageName(l)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n )}\n </div>\n <nav aria-label={t(\"groups.byLetter\")} className=\"flex flex-wrap gap-1\" data-ckui=\"letters\">\n {[undefined, ...LETTERS].map((l) => (\n <Button\n key={l ?? \"all\"}\n size=\"xs\"\n variant={letter === l ? \"default\" : \"ghost\"}\n aria-pressed={letter === l}\n aria-label={l === undefined ? undefined : l === \"#\" ? t(\"groups.otherLetters\") : l.toUpperCase()}\n className=\"min-w-7\"\n onClick={() => filter({ letter: l })}\n >\n {l === undefined ? t(\"groups.all\") : l.toUpperCase()}\n </Button>\n ))}\n </nav>\n {groups.loading && !groups.items.length ? (\n <Rows />\n ) : groups.error && !groups.items.length ? (\n <LoadFailed error={groups.error} message={t(\"groupManager.loadFailed\")} retry={groups.reload} />\n ) : !groups.items.length ? (\n <p className=\"text-muted-foreground\">{t(deleted ? \"groupManager.noDeleted\" : query ? \"groupManager.noMatches\" : \"groups.empty\")}</p>\n ) : (\n <ul className=\"grid divide-y divide-border rounded-lg border border-border\" aria-busy={groups.loading}>\n {groups.items.map((g) => (\n <li key={g.id} className=\"flex flex-wrap items-center gap-3 p-3\" data-ckui=\"group-row\" data-slug={g.slug} data-state={deleted ? \"deleted\" : \"active\"}>\n {(g.avatar?.renditions?.[0] ?? g.cover?.renditions?.[0]) && (\n <img src={(g.avatar?.renditions?.[0] ?? g.cover?.renditions?.[0])!.url} alt=\"\" loading=\"lazy\" className={cn(\"size-9 shrink-0 object-cover\", g.avatar?.renditions?.[0] ? \"rounded-full\" : \"rounded-sm\")} />\n )}\n <div className=\"grid min-w-0 flex-1 gap-0.5\">\n <button type=\"button\" className=\"text-left font-medium break-words hover:underline\" onClick={() => loc.go(`${kind}/${g.id}`)}>\n {g.name || g.slug}\n </button>\n <span className=\"text-xs text-muted-foreground\">{g.slug}</span>\n {g.internal && <Badge variant=\"secondary\" className=\"justify-self-start\">{t(\"groupEditor.internal\")}</Badge>}\n </div>\n <span className=\"text-sm text-muted-foreground tabular-nums\" title={t(\"groupManager.count\")}>\n {new Intl.NumberFormat(m.language).format(g.count)}\n </span>\n {deleted && (\n <Button size=\"sm\" variant=\"outline\" disabled={restore.pending}\n onClick={() => void restore.run(() => client.entities.update(g.id, { state: \"active\" })).then((d) => d !== undefined && groups.reload())}>\n {t(\"groupEditor.restore\")}\n </Button>\n )}\n </li>\n ))}\n </ul>\n )}\n {groups.hasMore && (\n <div className=\"grid justify-items-center gap-2\">\n {groups.error && <p role=\"alert\" className=\"text-destructive\">{contentError(m, groups.error)}</p>}\n <Button variant=\"outline\" size=\"sm\" disabled={groups.loadingMore} onClick={() => void groups.loadMore()}>\n {groups.loadingMore ? t(\"groups.loading\") : groups.error ? t(\"common.retry\") : t(\"groups.loadMore\")}\n </Button>\n </div>\n )}\n </div>\n );\n}\n\nfunction Create({ loc, kind, client, labels, onError }: Ctx) {\n return (\n <div className=\"grid gap-4\">\n <Back loc={loc} kind={kind} />\n <GroupEditor\n management\n id={null}\n kind={kind}\n labels={labels}\n client={client}\n onError={onError}\n onCreated={(g) => loc.go(`${kind}/${g.id}`, undefined, { replace: true })}\n />\n </div>\n );\n}\n\nfunction Edit({ loc, kind, client, labels, onError, renderContent, contentHref, newContentHref, id }: Ctx & { id: string }) {\n return (\n <div className=\"grid gap-4\">\n <Back loc={loc} kind={kind} />\n <GroupEditor\n management\n id={id}\n kind={kind}\n labels={labels}\n client={client}\n onError={onError}\n onMerged={(r) => loc.go(`${kind}/${r.into}`, undefined, { replace: true })}\n >\n {(group) => (\n <>\n <ScopedGroups group={group} management labels={labels} client={client} onSelect={(c) => loc.go(`${c.kind}/${c.id}`)} />\n <GroupMembers\n group={group}\n labels={labels}\n client={client}\n onError={onError}\n renderContent={renderContent}\n contentHref={contentHref}\n newContentHref={newContentHref}\n onUseCover={(content) => client.entities.update(group.id, { cover: { content_id: content } })}\n />\n </>\n )}\n </GroupEditor>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { ContentKitClient } from '../../client/client.js';
|
|
2
|
+
import { ContentKitErrorHandler } from '../../react/context.js';
|
|
3
|
+
export interface PageNoticesProps {
|
|
4
|
+
content: string;
|
|
5
|
+
version: string;
|
|
6
|
+
client?: ContentKitClient;
|
|
7
|
+
onError?: ContentKitErrorHandler;
|
|
8
|
+
className?: string;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Low-key notes about what automatic page processing did: pages removed as
|
|
12
|
+
* blank, duplicate or covered by a two-page spread (restorable), and an
|
|
13
|
+
* archive put into name order. Collapsed by default; nothing here blocks
|
|
14
|
+
* saving or publishing. Renders nothing without notices.
|
|
15
|
+
*/
|
|
16
|
+
export declare function PageNotices({ content, version, client, onError, className }: PageNoticesProps): import('react').JSX.Element | null;
|