@gatewaze/admin-embed 0.1.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.
Files changed (96) hide show
  1. package/README.md +42 -0
  2. package/dist/AiSkillsPicker-dbFhcanE.js +373 -0
  3. package/dist/ContentAccessPage-D0HRqPFc.js +264 -0
  4. package/dist/DataTable-fe6yRVpF.js +1984 -0
  5. package/dist/DetailPageHeader-D_v7924k.js +69 -0
  6. package/dist/EditionEmail-CyhC8232.js +8382 -0
  7. package/dist/GuideContent-DBXKCu7r.js +7580 -0
  8. package/dist/HostMediaTab-BsIBEQ1v.js +440 -0
  9. package/dist/InboxPage-C8ivCKdx.js +1112 -0
  10. package/dist/NewsletterCanvasEditor--B06apn3.js +11453 -0
  11. package/dist/NewsletterSetupWizard-BqV6-fa5.js +347 -0
  12. package/dist/NewsletterSignup-DRVZIpOs.js +224 -0
  13. package/dist/Page-D3u8IZ2a.js +14 -0
  14. package/dist/Toaster-Cde0i6IA.js +18 -0
  15. package/dist/Tooltip-CqxUlW1d.js +746 -0
  16. package/dist/_collectionSlug_-B3UN6M-Q.js +308 -0
  17. package/dist/_collection_-Qz4k_Qjl.js +139 -0
  18. package/dist/_edition_-DQXwkI_-.js +301 -0
  19. package/dist/_id_-CtT7rT9f.js +257 -0
  20. package/dist/_id_-CzScE4Qn.js +1197 -0
  21. package/dist/_virtual_gatewaze-modules-BeloWlOa.js +991 -0
  22. package/dist/admin-B0Mmrh_O.js +1239 -0
  23. package/dist/admin-CcfoK6vD.js +17 -0
  24. package/dist/admin-embed.js +21844 -0
  25. package/dist/admin.css +2 -0
  26. package/dist/block-editor-vXBShAue.js +226 -0
  27. package/dist/brand-DklYwIeA.js +11 -0
  28. package/dist/brick-editor-CmBitMMK.js +225 -0
  29. package/dist/broadcastService-CBqXNt_N.js +190 -0
  30. package/dist/classnames-uWIYaD6z.js +44 -0
  31. package/dist/contentAccessService-Cs7tdAo-.js +59 -0
  32. package/dist/context-jzuubYRz.js +5 -0
  33. package/dist/createSafeContext-P1pK0sAN.js +17 -0
  34. package/dist/detail-B8SVFJJr.js +26285 -0
  35. package/dist/detail-uFBxRbLF.js +2966 -0
  36. package/dist/dist-DTrOExw8.js +38806 -0
  37. package/dist/edition-slug-CARO24Bs.js +7 -0
  38. package/dist/export-edition-html-C_hdXQu5.js +18893 -0
  39. package/dist/floating-ui.dom-Cyv879E9.js +987 -0
  40. package/dist/hooks-C377EXJG.js +2974 -0
  41. package/dist/img/mlops-logo.png +0 -0
  42. package/dist/img/mlops-logo2.png +0 -0
  43. package/dist/index.d.ts +105 -0
  44. package/dist/jsx-runtime-CjozyJt-.js +180 -0
  45. package/dist/lib-CylJmhlJ.js +828 -0
  46. package/dist/list-C0cz0aQz.js +451 -0
  47. package/dist/list-CIVgIGsU.js +166 -0
  48. package/dist/logo/mlops-alt.png +0 -0
  49. package/dist/logo/mlops-logo.png +0 -0
  50. package/dist/new-r4KWpqa6.js +80 -0
  51. package/dist/outline-DwDYhYcF.js +6538 -0
  52. package/dist/pages-Ersfxcz7.js +216 -0
  53. package/dist/preview/12627f.jpg +0 -0
  54. package/dist/preview/af009d.jpg +0 -0
  55. package/dist/public-api-LD11kMxh.js +238 -0
  56. package/dist/react-DB2tPNit.js +933 -0
  57. package/dist/react-dom-giQNVXng.js +267 -0
  58. package/dist/registry-4XrV9iNG.js +7 -0
  59. package/dist/render-BtUWfMUt.js +59634 -0
  60. package/dist/resolvePeopleByEmail-hivX2l07.js +828 -0
  61. package/dist/runtime-config.js +10 -0
  62. package/dist/sends-BkPO6PG2.js +182 -0
  63. package/dist/server.browser-Pj3QUa7k.js +15227 -0
  64. package/dist/shim-BCerG8nb.js +6681 -0
  65. package/dist/sonnerHostBridge-CXuCMM3R.js +665 -0
  66. package/dist/src-BWDAOzZO.js +799 -0
  67. package/dist/starter-templates-CFs-QUdF.js +3077 -0
  68. package/dist/storage-VDSvnkvR.js +39 -0
  69. package/dist/templateParser-BQ2IsJ6c.js +49 -0
  70. package/dist/templates-rjQjWsRr.js +253 -0
  71. package/dist/theme/gatewaze/android-icon-144x144.png +0 -0
  72. package/dist/theme/gatewaze/android-icon-192x192.png +0 -0
  73. package/dist/theme/gatewaze/android-icon-36x36.png +0 -0
  74. package/dist/theme/gatewaze/android-icon-48x48.png +0 -0
  75. package/dist/theme/gatewaze/android-icon-72x72.png +0 -0
  76. package/dist/theme/gatewaze/android-icon-96x96.png +0 -0
  77. package/dist/theme/gatewaze/favicon-144x144.png +0 -0
  78. package/dist/theme/gatewaze/favicon-16x16.png +0 -0
  79. package/dist/theme/gatewaze/favicon-192x192.png +0 -0
  80. package/dist/theme/gatewaze/favicon-32x32.png +0 -0
  81. package/dist/theme/gatewaze/favicon-96x96.png +0 -0
  82. package/dist/theme/gatewaze/favicon.ico +0 -0
  83. package/dist/theme/gatewaze/gatewaze-icon-512.png +0 -0
  84. package/dist/theme/gatewaze/gatewaze-logo-black.svg +24 -0
  85. package/dist/theme/gatewaze/gatewaze-logo-white.svg +20 -0
  86. package/dist/theme/gatewaze/gatewaze-poweredby-black.svg +25 -0
  87. package/dist/theme/gatewaze/gatewaze-poweredby-white.svg +25 -0
  88. package/dist/theme/gatewaze/logo_black.svg +24 -0
  89. package/dist/theme/gatewaze/logo_white.svg +20 -0
  90. package/dist/theme-D6odw5nx.js +586 -0
  91. package/dist/ui-DRIo9Krs.js +9747 -0
  92. package/dist/upload-DMNfZ6FX.js +505 -0
  93. package/dist/useModuleFeature-DgsFIUpv.js +8 -0
  94. package/dist/utils-BcVvIjaY.js +36 -0
  95. package/dist/with-selector-B8eSdVx_.js +100 -0
  96. package/package.json +33 -0
package/README.md ADDED
@@ -0,0 +1,42 @@
1
+ # @gatewaze/admin-embed
2
+
3
+ The Gatewaze admin module set, built as a library so a host application can mount it into one of
4
+ its own DOM nodes — no iframe.
5
+
6
+ ```ts
7
+ import { mount } from '@gatewaze/admin-embed';
8
+
9
+ const handle = mount(element, {
10
+ basename: '/foundation/gw',
11
+ supabase: { url, anonKey },
12
+ apiBaseUrl: '', // '' means same-origin /api/gw
13
+ enabled: { moduleIds: [...], features: [...] },
14
+ signIn: { lfidStartUrl, returnUrl },
15
+ portalContainer: portalsElement, // where Radix overlays render
16
+ notify: (n) => hostToast(n), // optional: render our toasts as yours
17
+ });
18
+
19
+ handle.unmount();
20
+ ```
21
+
22
+ `mount()` never throws; every failure path reports through `ctx.onFatal` and returns a safe handle.
23
+ One live mount per page.
24
+
25
+ ## Stylesheet
26
+
27
+ The CSS is shipped separately as `@gatewaze/admin-embed/admin.css` and is **not** imported by the
28
+ entry — a host that renders us inside its own chrome needs to scope our styles before serving them,
29
+ which it cannot do if the bundle pulls them in. Load it yourself, ideally after passing it through
30
+ whatever containment your host needs.
31
+
32
+ ## Building
33
+
34
+ Assembled from `packages/admin`'s library build:
35
+
36
+ ```bash
37
+ pnpm --filter @gatewaze/admin exec vite build -c vite.embed.config.ts
38
+ node packages/admin-embed/scripts/build.mjs
39
+ ```
40
+
41
+ Type declarations are copied from `packages/admin/src/embed/types.ts`, never hand-written, so the
42
+ published contract cannot drift from the one the embed implements.
@@ -0,0 +1,373 @@
1
+ import { c as e, t } from "./react-DB2tPNit.js";
2
+ import { d as n } from "./shim-BCerG8nb.js";
3
+ import { t as r } from "./jsx-runtime-CjozyJt-.js";
4
+ import { D as i, E as a, n as o } from "./ui-DRIo9Krs.js";
5
+ import { n as s } from "./sonnerHostBridge-CXuCMM3R.js";
6
+ import { t as c } from "./outline-DwDYhYcF.js";
7
+ //#region ../../../gatewaze-modules/modules/editor-ai-copilot/admin/services/skillsService.ts
8
+ var l = /* @__PURE__ */ e(t()), u = c();
9
+ function d(e) {
10
+ return (Array.isArray(e) ? e[0] : e)?.label ?? "unknown source";
11
+ }
12
+ var f = {
13
+ async listSkills() {
14
+ let { data: e, error: t } = await n.from("ai_skills").select("id, source_id, dir_path, name, description, source:ai_agent_sources!source_id(label)").eq("parse_status", "ok").order("name", { ascending: !0 });
15
+ return t ? {
16
+ ok: !1,
17
+ error: { message: t.message }
18
+ } : {
19
+ ok: !0,
20
+ value: (e ?? []).map((e) => ({
21
+ id: e.id,
22
+ source_id: e.source_id,
23
+ dir_path: e.dir_path,
24
+ name: e.name,
25
+ description: e.description,
26
+ source_label: d(e.source)
27
+ }))
28
+ };
29
+ },
30
+ async readSkill(e) {
31
+ let { data: t, error: r } = await n.from("ai_skills").select("id, name, dir_path, description, body").eq("id", e).maybeSingle();
32
+ return r ? {
33
+ ok: !1,
34
+ error: { message: r.message }
35
+ } : t ? {
36
+ ok: !0,
37
+ value: t
38
+ } : {
39
+ ok: !1,
40
+ error: { message: "skill not found" }
41
+ };
42
+ },
43
+ async readUseCaseDefaultSkill(e) {
44
+ let t = await n.from("ai_use_cases").select("skill_source_id, skill_path").eq("id", e).maybeSingle();
45
+ if (t.error) return {
46
+ ok: !1,
47
+ error: { message: t.error.message }
48
+ };
49
+ let r = t.data;
50
+ if (!r?.skill_source_id || !r.skill_path) return {
51
+ ok: !0,
52
+ value: null
53
+ };
54
+ let i = "id, source_id, dir_path, name, description, source:ai_agent_sources!source_id(label)", a = (await n.from("ai_skills").select(i).eq("parse_status", "ok").eq("source_id", r.skill_source_id).eq("dir_path", r.skill_path).maybeSingle()).data;
55
+ if (!a) {
56
+ let e = r.skill_path.replace(/\/index\.md$/, "").replace(/\.md$/, "").split("/").pop() ?? "";
57
+ e.length > 0 && (a = (await n.from("ai_skills").select(i).eq("parse_status", "ok").eq("source_id", r.skill_source_id).eq("name", e).maybeSingle()).data);
58
+ }
59
+ return a ? {
60
+ ok: !0,
61
+ value: {
62
+ id: a.id,
63
+ source_id: a.source_id,
64
+ dir_path: a.dir_path,
65
+ name: a.name,
66
+ description: a.description,
67
+ source_label: d(a.source)
68
+ }
69
+ } : {
70
+ ok: !0,
71
+ value: null
72
+ };
73
+ }
74
+ }, p = r(), m = {
75
+ newsletter: "newsletters_template_collections",
76
+ site: "sites"
77
+ }, h = {
78
+ newsletter: "newsletter-editor",
79
+ site: "site-editor"
80
+ };
81
+ function g(e) {
82
+ let t = e.hostKind ?? "newsletter", r = e.id, [c, d] = (0, l.useState)("inherit"), [g, v] = (0, l.useState)([]), [y, b] = (0, l.useState)([]), [x, S] = (0, l.useState)(null), [C, w] = (0, l.useState)(!0), [T, E] = (0, l.useState)(!1), [D, O] = (0, l.useState)(null), k = (0, l.useCallback)(async () => {
83
+ w(!0);
84
+ let e = m[t], [i, a, o] = await Promise.all([
85
+ n.from(e).select("active_skill_ids").eq("id", r).maybeSingle(),
86
+ f.listSkills(),
87
+ f.readUseCaseDefaultSkill(h[t])
88
+ ]);
89
+ if (w(!1), i.error) {
90
+ s.error(`Failed to load host: ${i.error.message}`);
91
+ return;
92
+ }
93
+ let c = i.data?.active_skill_ids;
94
+ if (c == null ? (d("inherit"), v([])) : (d("override"), v(c)), !a.ok) {
95
+ s.error(`Failed to load skills: ${a.error.message}`);
96
+ return;
97
+ }
98
+ b(a.value), S(o.ok ? o.value : null);
99
+ }, [t, r]);
100
+ (0, l.useEffect)(() => {
101
+ k();
102
+ }, [k]);
103
+ let A = (0, l.useCallback)(async (e) => {
104
+ E(!0);
105
+ let i = m[t], { error: a } = await n.from(i).update({ active_skill_ids: e }).eq("id", r);
106
+ return E(!1), !a || (s.error(`Save failed: ${a.message}`), !1);
107
+ }, [t, r]), j = (0, l.useMemo)(() => {
108
+ let e = new Map(y.map((e) => [e.id, e]));
109
+ return g.map((t) => e.get(t)).filter((e) => e != null);
110
+ }, [y, g]), M = (0, l.useMemo)(() => {
111
+ let e = new Set(g);
112
+ return y.filter((t) => !e.has(t.id));
113
+ }, [y, g]);
114
+ async function N(e) {
115
+ if (e !== c) if (e === "inherit") await A(null) && (d("inherit"), v([]));
116
+ else {
117
+ let e = x ? [x.id] : [];
118
+ await A(e) && (d("override"), v(e));
119
+ }
120
+ }
121
+ async function P(e) {
122
+ let t = [...g, e];
123
+ await A(t) && v(t);
124
+ }
125
+ async function F(e) {
126
+ let t = g.filter((t) => t !== e);
127
+ await A(t) && v(t);
128
+ }
129
+ async function I(e, t) {
130
+ let n = g.indexOf(e);
131
+ if (n < 0) return;
132
+ let r = n + t;
133
+ if (r < 0 || r >= g.length) return;
134
+ let i = [...g];
135
+ [i[n], i[r]] = [i[r], i[n]], await A(i) && v(i);
136
+ }
137
+ async function L(e) {
138
+ let t = await f.readSkill(e);
139
+ if (!t.ok) {
140
+ s.error(`Preview failed: ${t.error.message}`);
141
+ return;
142
+ }
143
+ O(t.value);
144
+ }
145
+ return /* @__PURE__ */ (0, p.jsxs)(a, {
146
+ className: "p-4",
147
+ children: [
148
+ /* @__PURE__ */ (0, p.jsxs)("div", {
149
+ className: "flex items-center justify-between mb-1",
150
+ children: [/* @__PURE__ */ (0, p.jsxs)("h3", {
151
+ className: "font-semibold flex items-center gap-2 text-sm",
152
+ children: [/* @__PURE__ */ (0, p.jsx)(u.SparklesIcon, { className: "w-4 h-4" }), " AI Skills"]
153
+ }), T && /* @__PURE__ */ (0, p.jsx)("span", {
154
+ className: "text-xs text-[var(--gray-9)]",
155
+ children: "Saving…"
156
+ })]
157
+ }),
158
+ /* @__PURE__ */ (0, p.jsxs)("p", {
159
+ className: "text-xs text-[var(--gray-9)] mb-3",
160
+ children: [
161
+ "Skills inject brand voice + structure rules into every AI generation in this ",
162
+ t,
163
+ ". Manage which repos are available under ",
164
+ /* @__PURE__ */ (0, p.jsx)("em", { children: "Admin → AI → Skill Sources" }),
165
+ "; set the per-",
166
+ t,
167
+ " default under ",
168
+ /* @__PURE__ */ (0, p.jsx)("em", { children: "Admin → AI → Use cases" }),
169
+ "."
170
+ ]
171
+ }),
172
+ C && /* @__PURE__ */ (0, p.jsx)("div", {
173
+ className: "flex justify-center py-4",
174
+ children: /* @__PURE__ */ (0, p.jsx)(o, {})
175
+ }),
176
+ !C && /* @__PURE__ */ (0, p.jsxs)("div", {
177
+ className: "grid gap-4",
178
+ children: [/* @__PURE__ */ (0, p.jsx)("section", { children: /* @__PURE__ */ (0, p.jsxs)("div", {
179
+ role: "radiogroup",
180
+ className: "flex flex-col gap-1.5 text-sm",
181
+ children: [/* @__PURE__ */ (0, p.jsxs)("label", {
182
+ className: "inline-flex items-start gap-2 cursor-pointer",
183
+ children: [/* @__PURE__ */ (0, p.jsx)("input", {
184
+ type: "radio",
185
+ className: "mt-0.5",
186
+ name: `skills-mode-${r}`,
187
+ checked: c === "inherit",
188
+ disabled: T,
189
+ onChange: () => void N("inherit")
190
+ }), /* @__PURE__ */ (0, p.jsxs)("span", { children: [/* @__PURE__ */ (0, p.jsx)("span", {
191
+ className: "font-medium",
192
+ children: "Use default"
193
+ }), /* @__PURE__ */ (0, p.jsxs)("span", {
194
+ className: "text-xs text-[var(--gray-9)]",
195
+ children: [" — ", x ? /* @__PURE__ */ (0, p.jsxs)(p.Fragment, { children: [
196
+ "inherits ",
197
+ /* @__PURE__ */ (0, p.jsx)("code", {
198
+ className: "font-mono",
199
+ children: x.name
200
+ }),
201
+ " from the ",
202
+ t,
203
+ " use case"
204
+ ] }) : /* @__PURE__ */ (0, p.jsxs)(p.Fragment, { children: [
205
+ "no default skill is configured for the ",
206
+ t,
207
+ " use case"
208
+ ] })]
209
+ })] })]
210
+ }), /* @__PURE__ */ (0, p.jsxs)("label", {
211
+ className: "inline-flex items-start gap-2 cursor-pointer",
212
+ children: [/* @__PURE__ */ (0, p.jsx)("input", {
213
+ type: "radio",
214
+ className: "mt-0.5",
215
+ name: `skills-mode-${r}`,
216
+ checked: c === "override",
217
+ disabled: T,
218
+ onChange: () => void N("override")
219
+ }), /* @__PURE__ */ (0, p.jsxs)("span", { children: [/* @__PURE__ */ (0, p.jsx)("span", {
220
+ className: "font-medium",
221
+ children: "Override"
222
+ }), /* @__PURE__ */ (0, p.jsxs)("span", {
223
+ className: "text-xs text-[var(--gray-9)]",
224
+ children: [
225
+ " — pick skills for this ",
226
+ t,
227
+ " (empty = no skills)"
228
+ ]
229
+ })] })]
230
+ })]
231
+ }) }), c === "override" && /* @__PURE__ */ (0, p.jsxs)(p.Fragment, { children: [/* @__PURE__ */ (0, p.jsxs)("section", { children: [
232
+ /* @__PURE__ */ (0, p.jsxs)("h4", {
233
+ className: "text-xs font-medium uppercase tracking-wide text-[var(--gray-9)] mb-1",
234
+ children: [
235
+ "Active (",
236
+ j.length,
237
+ ")"
238
+ ]
239
+ }),
240
+ j.length === 0 && /* @__PURE__ */ (0, p.jsxs)("div", {
241
+ className: "text-xs text-[var(--gray-9)] italic",
242
+ children: [
243
+ "No skills selected — this ",
244
+ t,
245
+ " will run with no brand skills."
246
+ ]
247
+ }),
248
+ j.map((e, t) => /* @__PURE__ */ (0, p.jsxs)("div", {
249
+ className: "flex items-center gap-2 py-1 border-b border-[var(--gray-6)] last:border-b-0",
250
+ children: [/* @__PURE__ */ (0, p.jsxs)("div", {
251
+ className: "flex-1 min-w-0",
252
+ children: [/* @__PURE__ */ (0, p.jsx)("button", {
253
+ type: "button",
254
+ onClick: () => void L(e.id),
255
+ className: "text-left hover:underline",
256
+ children: /* @__PURE__ */ (0, p.jsx)("div", {
257
+ className: "text-sm font-medium truncate",
258
+ children: e.name
259
+ })
260
+ }), /* @__PURE__ */ (0, p.jsxs)("div", {
261
+ className: "text-xs text-[var(--gray-9)] truncate",
262
+ children: [
263
+ e.source_label,
264
+ " · ",
265
+ e.dir_path
266
+ ]
267
+ })]
268
+ }), /* @__PURE__ */ (0, p.jsxs)("div", {
269
+ className: "flex gap-1 flex-shrink-0",
270
+ children: [
271
+ /* @__PURE__ */ (0, p.jsx)(i, {
272
+ onClick: () => void I(e.id, -1),
273
+ disabled: t === 0,
274
+ children: /* @__PURE__ */ (0, p.jsx)(u.ChevronUpIcon, { className: "w-3 h-3" })
275
+ }),
276
+ /* @__PURE__ */ (0, p.jsx)(i, {
277
+ onClick: () => void I(e.id, 1),
278
+ disabled: t === j.length - 1,
279
+ children: /* @__PURE__ */ (0, p.jsx)(u.ChevronDownIcon, { className: "w-3 h-3" })
280
+ }),
281
+ /* @__PURE__ */ (0, p.jsx)(i, {
282
+ onClick: () => void F(e.id),
283
+ children: /* @__PURE__ */ (0, p.jsx)(u.XMarkIcon, { className: "w-3 h-3" })
284
+ })
285
+ ]
286
+ })]
287
+ }, e.id))
288
+ ] }), /* @__PURE__ */ (0, p.jsxs)("section", { children: [
289
+ /* @__PURE__ */ (0, p.jsxs)("h4", {
290
+ className: "text-xs font-medium uppercase tracking-wide text-[var(--gray-9)] mb-1",
291
+ children: [
292
+ "Available (",
293
+ M.length,
294
+ ")"
295
+ ]
296
+ }),
297
+ M.length === 0 && /* @__PURE__ */ (0, p.jsxs)("div", {
298
+ className: "text-xs text-[var(--gray-9)] italic",
299
+ children: [
300
+ "No additional skills available. Register a skill source under ",
301
+ /* @__PURE__ */ (0, p.jsx)("em", { children: "Admin → AI → Skill Sources" }),
302
+ "."
303
+ ]
304
+ }),
305
+ M.map((e) => /* @__PURE__ */ (0, p.jsxs)("div", {
306
+ className: "flex items-center gap-2 py-1 border-b border-[var(--gray-6)] last:border-b-0",
307
+ children: [/* @__PURE__ */ (0, p.jsx)(i, {
308
+ onClick: () => void P(e.id),
309
+ children: /* @__PURE__ */ (0, p.jsx)(u.PlusIcon, { className: "w-3 h-3" })
310
+ }), /* @__PURE__ */ (0, p.jsxs)("div", {
311
+ className: "flex-1 min-w-0",
312
+ children: [/* @__PURE__ */ (0, p.jsx)("button", {
313
+ type: "button",
314
+ onClick: () => void L(e.id),
315
+ className: "text-left hover:underline",
316
+ children: /* @__PURE__ */ (0, p.jsx)("div", {
317
+ className: "text-sm font-medium truncate",
318
+ children: e.name
319
+ })
320
+ }), /* @__PURE__ */ (0, p.jsxs)("div", {
321
+ className: "text-xs text-[var(--gray-9)] truncate",
322
+ children: [
323
+ e.source_label,
324
+ " · ",
325
+ e.dir_path
326
+ ]
327
+ })]
328
+ })]
329
+ }, e.id))
330
+ ] })] })]
331
+ }),
332
+ D && /* @__PURE__ */ (0, p.jsx)(_, {
333
+ skill: D,
334
+ onClose: () => O(null)
335
+ })
336
+ ]
337
+ });
338
+ }
339
+ function _({ skill: e, onClose: t }) {
340
+ return /* @__PURE__ */ (0, p.jsx)("div", {
341
+ className: "fixed inset-0 z-50 bg-black/40 flex items-center justify-center p-4",
342
+ onClick: t,
343
+ children: /* @__PURE__ */ (0, p.jsxs)(a, {
344
+ className: "w-full max-w-2xl max-h-[80vh] overflow-auto p-6 bg-[var(--gray-1)]",
345
+ onClick: (e) => e.stopPropagation(),
346
+ children: [
347
+ /* @__PURE__ */ (0, p.jsxs)("div", {
348
+ className: "flex items-start justify-between mb-3",
349
+ children: [/* @__PURE__ */ (0, p.jsxs)("div", { children: [/* @__PURE__ */ (0, p.jsx)("h3", {
350
+ className: "font-semibold",
351
+ children: e.name
352
+ }), /* @__PURE__ */ (0, p.jsx)("p", {
353
+ className: "text-xs text-[var(--gray-9)]",
354
+ children: e.dir_path
355
+ })] }), /* @__PURE__ */ (0, p.jsx)(i, {
356
+ onClick: t,
357
+ children: /* @__PURE__ */ (0, p.jsx)(u.XMarkIcon, { className: "w-4 h-4" })
358
+ })]
359
+ }),
360
+ e.description && /* @__PURE__ */ (0, p.jsx)("p", {
361
+ className: "text-sm text-[var(--gray-9)] mb-4",
362
+ children: e.description
363
+ }),
364
+ /* @__PURE__ */ (0, p.jsx)("pre", {
365
+ className: "text-xs whitespace-pre-wrap font-mono bg-[var(--gray-3)] p-3 rounded",
366
+ children: e.body
367
+ })
368
+ ]
369
+ })
370
+ });
371
+ }
372
+ //#endregion
373
+ export { g as default };
@@ -0,0 +1,264 @@
1
+ import { c as e, t } from "./react-DB2tPNit.js";
2
+ import { t as n } from "./jsx-runtime-CjozyJt-.js";
3
+ import { D as r, E as i, O as a, l as o, u as s } from "./ui-DRIo9Krs.js";
4
+ import { t as c } from "./contentAccessService-Cs7tdAo-.js";
5
+ //#region ../../../gatewaze-modules/modules/content-platform/admin/pages/ContentAccessPage.tsx
6
+ var l = /* @__PURE__ */ e(t()), u = n(), d = [
7
+ {
8
+ value: "newsletter_edition",
9
+ label: "Newsletter edition"
10
+ },
11
+ {
12
+ value: "blog_post",
13
+ label: "Blog post"
14
+ },
15
+ {
16
+ value: "resource",
17
+ label: "Resource item"
18
+ },
19
+ {
20
+ value: "podcast_episode",
21
+ label: "Podcast episode"
22
+ },
23
+ {
24
+ value: "event",
25
+ label: "Event (registration)"
26
+ }
27
+ ];
28
+ function f(e, t, n) {
29
+ return e.allowed_tiers && e.allowed_tiers.length > 0 ? ` (${e.allowed_tiers.map(n).join(", ")})` : e.min_tier_rank ? ` (${t(e.min_tier_rank)})` : "";
30
+ }
31
+ function p(e, t, n) {
32
+ let r = f(e, t, n);
33
+ return e.gated_actions?.includes("register") ? `Registration: members only${r}` : e.embargo_days ? `Members-only for ${e.embargo_days} day(s)${r}, then public` : e.audience === "members" ? `Members only${r || " (any member)"}` : "Public";
34
+ }
35
+ function m() {
36
+ let [e, t] = (0, l.useState)([]), [n, f] = (0, l.useState)([]), [m, h] = (0, l.useState)(!0), [g, _] = (0, l.useState)(null), [v, y] = (0, l.useState)(!1), [b, x] = (0, l.useState)("newsletter_edition"), [S, C] = (0, l.useState)("item"), [w, T] = (0, l.useState)(""), [E, D] = (0, l.useState)("minimum"), [O, k] = (0, l.useState)(0), [A, j] = (0, l.useState)([]), M = (0, l.useMemo)(() => {
37
+ let e = new Map(n.map((e) => [e.rank, e.display_label]));
38
+ return (t) => e.get(t) ?? `tier ≥ ${t}`;
39
+ }, [n]), N = (0, l.useMemo)(() => {
40
+ let e = new Map(n.map((e) => [e.tier, e.display_label]));
41
+ return (t) => e.get(t) ?? t;
42
+ }, [n]), P = (0, l.useMemo)(() => [{
43
+ value: 0,
44
+ label: "Any member"
45
+ }, ...n.map((e) => ({
46
+ value: e.rank,
47
+ label: `${e.display_label} or higher`
48
+ }))], [n]);
49
+ async function F() {
50
+ h(!0), _(null);
51
+ try {
52
+ let [e, n] = await Promise.all([c.listPolicies(), c.listTiers()]);
53
+ t(e), f(n);
54
+ } catch (e) {
55
+ _(e.message);
56
+ } finally {
57
+ h(!1);
58
+ }
59
+ }
60
+ (0, l.useEffect)(() => {
61
+ F();
62
+ }, []);
63
+ async function I(e) {
64
+ y(!0);
65
+ try {
66
+ await c.clearPolicy(e.content_type, e.entity_id), await F();
67
+ } catch (e) {
68
+ _(e.message);
69
+ } finally {
70
+ y(!1);
71
+ }
72
+ }
73
+ async function L() {
74
+ y(!0), _(null);
75
+ try {
76
+ let e = S === "item" ? w.trim() : null;
77
+ if (S === "item" && !e) {
78
+ _("Enter an item id, or choose \"All of this type\"."), y(!1);
79
+ return;
80
+ }
81
+ let t = b === "event", n = E === "specific" ? {
82
+ min_tier_rank: 0,
83
+ allowed_tiers: A
84
+ } : {
85
+ min_tier_rank: O,
86
+ allowed_tiers: null
87
+ };
88
+ await c.setPolicy({
89
+ content_type: b,
90
+ entity_id: e,
91
+ audience: t ? "public" : "members",
92
+ ...n,
93
+ gated_actions: t ? ["register"] : [],
94
+ note: "Added from Content Access page"
95
+ }), T(""), await F();
96
+ } catch (e) {
97
+ _(e.message);
98
+ } finally {
99
+ y(!1);
100
+ }
101
+ }
102
+ return /* @__PURE__ */ (0, u.jsxs)("div", {
103
+ className: "p-6 space-y-6 max-w-5xl",
104
+ children: [
105
+ /* @__PURE__ */ (0, u.jsxs)("div", { children: [/* @__PURE__ */ (0, u.jsx)("h1", {
106
+ className: "text-xl font-semibold text-[var(--gray-12)]",
107
+ children: "Content Access"
108
+ }), /* @__PURE__ */ (0, u.jsx)("p", {
109
+ className: "text-sm text-[var(--gray-a10)] mt-1",
110
+ children: "Every member-gating rule in one place. Rules apply to a single item (per-item override) or to a whole content type (default). Editors also set these inline on each piece of content."
111
+ })] }),
112
+ g && /* @__PURE__ */ (0, u.jsx)("p", {
113
+ className: "text-sm text-[var(--red-9)]",
114
+ children: g
115
+ }),
116
+ /* @__PURE__ */ (0, u.jsxs)(i, {
117
+ className: "p-4",
118
+ children: [
119
+ /* @__PURE__ */ (0, u.jsx)("h2", {
120
+ className: "text-sm font-semibold text-[var(--gray-12)] mb-3",
121
+ children: "Add a rule"
122
+ }),
123
+ /* @__PURE__ */ (0, u.jsxs)("div", {
124
+ className: "flex flex-wrap items-end gap-3",
125
+ children: [
126
+ /* @__PURE__ */ (0, u.jsx)(o, {
127
+ label: "Content type",
128
+ value: b,
129
+ data: d,
130
+ onChange: (e) => x(e.target.value)
131
+ }),
132
+ /* @__PURE__ */ (0, u.jsx)(o, {
133
+ label: "Applies to",
134
+ value: S,
135
+ data: [{
136
+ value: "item",
137
+ label: "A specific item"
138
+ }, {
139
+ value: "type",
140
+ label: "All of this type"
141
+ }],
142
+ onChange: (e) => C(e.target.value)
143
+ }),
144
+ S === "item" && /* @__PURE__ */ (0, u.jsx)(s, {
145
+ label: "Item id (uuid)",
146
+ value: w,
147
+ placeholder: "00000000-0000-…",
148
+ onChange: (e) => T(e.target.value)
149
+ }),
150
+ /* @__PURE__ */ (0, u.jsx)(o, {
151
+ label: "Tier requirement",
152
+ value: E,
153
+ data: [{
154
+ value: "minimum",
155
+ label: "Minimum tier"
156
+ }, {
157
+ value: "specific",
158
+ label: "Specific tiers"
159
+ }],
160
+ onChange: (e) => D(e.target.value === "specific" ? "specific" : "minimum")
161
+ }),
162
+ E === "minimum" && /* @__PURE__ */ (0, u.jsx)(o, {
163
+ label: "Minimum tier",
164
+ value: O,
165
+ data: P,
166
+ onChange: (e) => k(Number(e.target.value))
167
+ }),
168
+ /* @__PURE__ */ (0, u.jsx)(r, {
169
+ onClick: () => void L(),
170
+ disabled: v,
171
+ children: b === "event" ? "Gate registration" : "Make members-only"
172
+ })
173
+ ]
174
+ }),
175
+ E === "specific" && /* @__PURE__ */ (0, u.jsxs)("div", {
176
+ className: "mt-3",
177
+ children: [
178
+ /* @__PURE__ */ (0, u.jsx)("div", {
179
+ className: "text-xs font-medium text-[var(--gray-11)] mb-1",
180
+ children: "Allowed tiers"
181
+ }),
182
+ n.length === 0 ? /* @__PURE__ */ (0, u.jsx)("p", {
183
+ className: "text-xs text-[var(--gray-a10)]",
184
+ children: "No tiers available."
185
+ }) : /* @__PURE__ */ (0, u.jsx)("div", {
186
+ className: "flex flex-wrap gap-x-4 gap-y-1",
187
+ children: n.map((e) => /* @__PURE__ */ (0, u.jsxs)("label", {
188
+ className: "flex items-center gap-2 text-sm text-[var(--gray-11)]",
189
+ children: [/* @__PURE__ */ (0, u.jsx)("input", {
190
+ type: "checkbox",
191
+ checked: A.includes(e.tier),
192
+ onChange: (t) => j((n) => t.target.checked ? [...n, e.tier] : n.filter((t) => t !== e.tier))
193
+ }), e.display_label]
194
+ }, e.tier))
195
+ }),
196
+ /* @__PURE__ */ (0, u.jsx)("p", {
197
+ className: "text-xs text-[var(--gray-a10)] mt-1",
198
+ children: "Only members in the checked tiers can access."
199
+ })
200
+ ]
201
+ }),
202
+ /* @__PURE__ */ (0, u.jsxs)("p", {
203
+ className: "text-xs text-[var(--gray-a10)] mt-2",
204
+ children: [
205
+ "Events keep public visibility and gate the ",
206
+ /* @__PURE__ */ (0, u.jsx)("b", { children: "register" }),
207
+ " action; other types gate visibility."
208
+ ]
209
+ })
210
+ ]
211
+ }),
212
+ /* @__PURE__ */ (0, u.jsxs)(i, {
213
+ className: "p-4",
214
+ children: [/* @__PURE__ */ (0, u.jsxs)("h2", {
215
+ className: "text-sm font-semibold text-[var(--gray-12)] mb-3",
216
+ children: [
217
+ "Active rules (",
218
+ e.length,
219
+ ")"
220
+ ]
221
+ }), m ? /* @__PURE__ */ (0, u.jsx)("p", {
222
+ className: "text-sm text-[var(--gray-a10)]",
223
+ children: "Loading…"
224
+ }) : e.length === 0 ? /* @__PURE__ */ (0, u.jsx)("p", {
225
+ className: "text-sm text-[var(--gray-a10)]",
226
+ children: "No gating rules yet — all content is public."
227
+ }) : /* @__PURE__ */ (0, u.jsx)("div", {
228
+ className: "divide-y divide-[var(--gray-a4)]",
229
+ children: e.map((e) => /* @__PURE__ */ (0, u.jsxs)("div", {
230
+ className: "flex items-center justify-between py-2 gap-4",
231
+ children: [/* @__PURE__ */ (0, u.jsxs)("div", {
232
+ className: "min-w-0",
233
+ children: [
234
+ /* @__PURE__ */ (0, u.jsxs)("div", {
235
+ className: "flex items-center gap-2",
236
+ children: [/* @__PURE__ */ (0, u.jsx)(a, { children: d.find((t) => t.value === e.content_type)?.label ?? e.content_type }), /* @__PURE__ */ (0, u.jsx)("span", {
237
+ className: "text-xs text-[var(--gray-a10)] truncate",
238
+ children: e.entity_id ? `item ${e.entity_id.slice(0, 8)}…` : "All of this type"
239
+ })]
240
+ }),
241
+ /* @__PURE__ */ (0, u.jsx)("div", {
242
+ className: "text-sm text-[var(--gray-12)] mt-0.5",
243
+ children: p(e, M, N)
244
+ }),
245
+ e.note && /* @__PURE__ */ (0, u.jsx)("div", {
246
+ className: "text-xs text-[var(--gray-a9)]",
247
+ children: e.note
248
+ })
249
+ ]
250
+ }), /* @__PURE__ */ (0, u.jsx)(r, {
251
+ variant: "soft",
252
+ color: "red",
253
+ onClick: () => void I(e),
254
+ disabled: v,
255
+ children: "Remove"
256
+ })]
257
+ }, e.id))
258
+ })]
259
+ })
260
+ ]
261
+ });
262
+ }
263
+ //#endregion
264
+ export { m as default };