@vertebr/react 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/admin/AdminContent.d.ts +36 -0
- package/dist/components/admin/AdminContent.d.ts.map +1 -0
- package/dist/components/admin/AdminContent.js +107 -0
- package/dist/components/admin/AdminHeader.d.ts +13 -0
- package/dist/components/admin/AdminHeader.d.ts.map +1 -0
- package/dist/components/admin/AdminHeader.js +32 -0
- package/dist/components/admin/AdminSidebar.d.ts +25 -0
- package/dist/components/admin/AdminSidebar.d.ts.map +1 -0
- package/dist/components/admin/AdminSidebar.js +31 -0
- package/dist/components/admin/VertebrAdmin.d.ts +3 -18
- package/dist/components/admin/VertebrAdmin.d.ts.map +1 -1
- package/dist/components/admin/VertebrAdmin.js +130 -120
- package/dist/components/admin/sidebar.d.ts +3 -0
- package/dist/components/admin/sidebar.d.ts.map +1 -0
- package/dist/components/admin/sidebar.js +13 -0
- package/dist/components/admin/storage.d.ts +4 -0
- package/dist/components/admin/storage.d.ts.map +1 -0
- package/dist/components/admin/storage.js +24 -0
- package/dist/components/admin/types.d.ts +53 -0
- package/dist/components/admin/types.d.ts.map +1 -0
- package/dist/components/admin/types.js +1 -0
- package/dist/components/config/form/ConfigForm.d.ts +1 -1
- package/dist/components/config/form/ConfigForm.d.ts.map +1 -1
- package/dist/components/config/form/ConfigForm.js +5 -1
- package/dist/components/config/form/RecordConfigForm.d.ts +1 -0
- package/dist/components/config/form/RecordConfigForm.d.ts.map +1 -1
- package/dist/components/config/form/SettingsConfigForm.d.ts +2 -1
- package/dist/components/config/form/SettingsConfigForm.d.ts.map +1 -1
- package/dist/components/config/form/SettingsConfigForm.js +2 -2
- package/dist/components/config/form/helpers/fields.js +1 -1
- package/dist/components/config/form/types.d.ts +4 -0
- package/dist/components/config/form/types.d.ts.map +1 -1
- package/dist/components/emails/EmailRecipientSelect.d.ts +16 -0
- package/dist/components/emails/EmailRecipientSelect.d.ts.map +1 -0
- package/dist/components/emails/EmailRecipientSelect.js +10 -0
- package/dist/components/emails/EmailsActivityPanel.d.ts +11 -0
- package/dist/components/emails/EmailsActivityPanel.d.ts.map +1 -0
- package/dist/components/emails/EmailsActivityPanel.js +139 -0
- package/dist/components/emails/EmailsBoard.d.ts +47 -0
- package/dist/components/emails/EmailsBoard.d.ts.map +1 -0
- package/dist/components/emails/EmailsBoard.js +594 -0
- package/dist/components/emails/EmailsLibraryPanel.d.ts +25 -0
- package/dist/components/emails/EmailsLibraryPanel.d.ts.map +1 -0
- package/dist/components/emails/EmailsLibraryPanel.js +379 -0
- package/dist/components/emails/EmailsNavSelect.d.ts +18 -0
- package/dist/components/emails/EmailsNavSelect.d.ts.map +1 -0
- package/dist/components/emails/EmailsNavSelect.js +37 -0
- package/dist/components/emails/MultiCheckSelect.d.ts +18 -0
- package/dist/components/emails/MultiCheckSelect.d.ts.map +1 -0
- package/dist/components/emails/MultiCheckSelect.js +74 -0
- package/dist/components/metrics/MetricsBoard.d.ts +8 -2
- package/dist/components/metrics/MetricsBoard.d.ts.map +1 -1
- package/dist/components/metrics/MetricsBoard.js +55 -2
- package/dist/components/metrics/charts.d.ts +14 -0
- package/dist/components/metrics/charts.d.ts.map +1 -0
- package/dist/components/metrics/charts.js +212 -0
- package/dist/components/resources/ResourceActionModal.d.ts +14 -0
- package/dist/components/resources/ResourceActionModal.d.ts.map +1 -0
- package/dist/components/resources/ResourceActionModal.js +64 -0
- package/dist/components/resources/ResourceCell.d.ts.map +1 -1
- package/dist/components/resources/ResourceCell.js +25 -9
- package/dist/components/resources/ResourceMailModal.d.ts +12 -0
- package/dist/components/resources/ResourceMailModal.d.ts.map +1 -0
- package/dist/components/resources/ResourceMailModal.js +196 -0
- package/dist/components/resources/ResourceTable.d.ts +7 -3
- package/dist/components/resources/ResourceTable.d.ts.map +1 -1
- package/dist/components/resources/ResourceTable.js +204 -34
- package/dist/index.d.ts +7 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/lib/metricsRanges.d.ts +20 -0
- package/dist/lib/metricsRanges.d.ts.map +1 -0
- package/dist/lib/metricsRanges.js +14 -0
- package/dist/styles/cells.css +42 -0
- package/dist/styles/emails.css +632 -0
- package/dist/styles/index.css +3 -0
- package/dist/styles/mail.css +240 -0
- package/dist/styles/metrics.css +633 -0
- package/dist/styles/nav.css +103 -1
- package/dist/styles/panel.css +2 -68
- package/dist/styles/table.css +26 -3
- package/package.json +1 -1
|
@@ -1,38 +1,14 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useCallback, useEffect, useMemo, useState } from "react";
|
|
3
3
|
import { createVertebrClient, } from "@vertebr/client";
|
|
4
|
-
import { ConfigForm } from "../config/ConfigForm";
|
|
5
|
-
import { EnvSelect } from "../env/EnvSelect";
|
|
6
|
-
import { GalleryBoard } from "../gallery/GalleryBoard";
|
|
7
|
-
import { MetricsBoard } from "../metrics/MetricsBoard";
|
|
8
|
-
import { ResourcePanel } from "../resources/ResourceTable";
|
|
9
|
-
import { ThemeToggle } from "../theme/ThemeToggle";
|
|
10
4
|
import { useVertebrTheme } from "../../hooks/useVertebrTheme";
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
}
|
|
19
|
-
function writeStored(key, value) {
|
|
20
|
-
try {
|
|
21
|
-
localStorage.setItem(key, value);
|
|
22
|
-
}
|
|
23
|
-
catch {
|
|
24
|
-
// ignore
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
function clearStored(key) {
|
|
28
|
-
try {
|
|
29
|
-
localStorage.removeItem(key);
|
|
30
|
-
}
|
|
31
|
-
catch {
|
|
32
|
-
// ignore
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
export function VertebrAdmin({ apiBase = "/admin/api", title = "Control plane", envStorageKey = "vertebr:env", tokenStorageKey = "vertebr:token", themeStorageKey = "vertebr:theme", getAccessToken, authUserLabel, onSignOut, }) {
|
|
5
|
+
import { parseMetricsRangeId, } from "../../lib/metricsRanges";
|
|
6
|
+
import { AdminContent } from "./AdminContent";
|
|
7
|
+
import { AdminHeader } from "./AdminHeader";
|
|
8
|
+
import { AdminSidebar } from "./AdminSidebar";
|
|
9
|
+
import { sidebarGroups } from "./sidebar";
|
|
10
|
+
import { clearStored, readStored, writeStored } from "./storage";
|
|
11
|
+
export function VertebrAdmin({ apiBase = "/admin/api", title = "Control plane", envStorageKey = "vertebr:env", tokenStorageKey = "vertebr:token", themeStorageKey = "vertebr:theme", metricsRangeStorageKey = "vertebr:metrics-range", getAccessToken, authUserLabel, onSignOut, }) {
|
|
36
12
|
const { theme, setTheme } = useVertebrTheme(themeStorageKey);
|
|
37
13
|
const [environment, setEnvironment] = useState(() => readStored(envStorageKey) ?? "");
|
|
38
14
|
const [token, setToken] = useState(() => readStored(tokenStorageKey) ?? "");
|
|
@@ -50,8 +26,11 @@ export function VertebrAdmin({ apiBase = "/admin/api", title = "Control plane",
|
|
|
50
26
|
const [configData, setConfigData] = useState(null);
|
|
51
27
|
const [metricsData, setMetricsData] = useState(null);
|
|
52
28
|
const [metricsLoading, setMetricsLoading] = useState(false);
|
|
29
|
+
const [metricsRange, setMetricsRange] = useState(() => parseMetricsRangeId(readStored(metricsRangeStorageKey)));
|
|
53
30
|
const [galleryData, setGalleryData] = useState(null);
|
|
54
31
|
const [galleryLoading, setGalleryLoading] = useState(false);
|
|
32
|
+
const [emailsData, setEmailsData] = useState(null);
|
|
33
|
+
const [emailsLoading, setEmailsLoading] = useState(false);
|
|
55
34
|
const [error, setError] = useState(null);
|
|
56
35
|
const [loading, setLoading] = useState(true);
|
|
57
36
|
useEffect(() => {
|
|
@@ -97,6 +76,8 @@ export function VertebrAdmin({ apiBase = "/admin/api", title = "Control plane",
|
|
|
97
76
|
return current;
|
|
98
77
|
if (current?.kind === "gallery" && next.gallery)
|
|
99
78
|
return current;
|
|
79
|
+
if (current?.kind === "emails" && next.emails)
|
|
80
|
+
return current;
|
|
100
81
|
if (current?.kind === "resource") {
|
|
101
82
|
if (next.resources.some((r) => r.id === current.id))
|
|
102
83
|
return current;
|
|
@@ -112,6 +93,8 @@ export function VertebrAdmin({ apiBase = "/admin/api", title = "Control plane",
|
|
|
112
93
|
return { kind: "resource", id: firstResource.id };
|
|
113
94
|
if (next.gallery)
|
|
114
95
|
return { kind: "gallery" };
|
|
96
|
+
if (next.emails)
|
|
97
|
+
return { kind: "emails", tab: "compose" };
|
|
115
98
|
const firstConfig = next.configs[0];
|
|
116
99
|
if (firstConfig)
|
|
117
100
|
return { kind: "config", id: firstConfig.id };
|
|
@@ -142,12 +125,13 @@ export function VertebrAdmin({ apiBase = "/admin/api", title = "Control plane",
|
|
|
142
125
|
setError(null);
|
|
143
126
|
if (selection.kind === "overview") {
|
|
144
127
|
setMetricsLoading(true);
|
|
145
|
-
const data = await client.getMetrics();
|
|
128
|
+
const data = await client.getMetrics({ range: metricsRange });
|
|
146
129
|
if (!cancelled) {
|
|
147
130
|
setMetricsData(data);
|
|
148
131
|
setResourceData(null);
|
|
149
132
|
setConfigData(null);
|
|
150
133
|
setGalleryData(null);
|
|
134
|
+
setEmailsData(null);
|
|
151
135
|
}
|
|
152
136
|
}
|
|
153
137
|
else if (selection.kind === "gallery") {
|
|
@@ -158,6 +142,18 @@ export function VertebrAdmin({ apiBase = "/admin/api", title = "Control plane",
|
|
|
158
142
|
setResourceData(null);
|
|
159
143
|
setConfigData(null);
|
|
160
144
|
setMetricsData(null);
|
|
145
|
+
setEmailsData(null);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
else if (selection.kind === "emails") {
|
|
149
|
+
setEmailsLoading(true);
|
|
150
|
+
const data = await client.getEmails();
|
|
151
|
+
if (!cancelled) {
|
|
152
|
+
setEmailsData(data);
|
|
153
|
+
setResourceData(null);
|
|
154
|
+
setConfigData(null);
|
|
155
|
+
setMetricsData(null);
|
|
156
|
+
setGalleryData(null);
|
|
161
157
|
}
|
|
162
158
|
}
|
|
163
159
|
else if (selection.kind === "resource") {
|
|
@@ -167,6 +163,7 @@ export function VertebrAdmin({ apiBase = "/admin/api", title = "Control plane",
|
|
|
167
163
|
setConfigData(null);
|
|
168
164
|
setMetricsData(null);
|
|
169
165
|
setGalleryData(null);
|
|
166
|
+
setEmailsData(null);
|
|
170
167
|
}
|
|
171
168
|
}
|
|
172
169
|
else {
|
|
@@ -176,6 +173,7 @@ export function VertebrAdmin({ apiBase = "/admin/api", title = "Control plane",
|
|
|
176
173
|
setResourceData(null);
|
|
177
174
|
setMetricsData(null);
|
|
178
175
|
setGalleryData(null);
|
|
176
|
+
setEmailsData(null);
|
|
179
177
|
}
|
|
180
178
|
}
|
|
181
179
|
}
|
|
@@ -188,13 +186,14 @@ export function VertebrAdmin({ apiBase = "/admin/api", title = "Control plane",
|
|
|
188
186
|
if (!cancelled) {
|
|
189
187
|
setMetricsLoading(false);
|
|
190
188
|
setGalleryLoading(false);
|
|
189
|
+
setEmailsLoading(false);
|
|
191
190
|
}
|
|
192
191
|
}
|
|
193
192
|
})();
|
|
194
193
|
return () => {
|
|
195
194
|
cancelled = true;
|
|
196
195
|
};
|
|
197
|
-
}, [client, selection, catalog, environment]);
|
|
196
|
+
}, [client, selection, catalog, environment, metricsRange]);
|
|
198
197
|
const refreshResource = useCallback(async () => {
|
|
199
198
|
if (selection?.kind !== "resource")
|
|
200
199
|
return;
|
|
@@ -204,13 +203,17 @@ export function VertebrAdmin({ apiBase = "/admin/api", title = "Control plane",
|
|
|
204
203
|
const refreshMetrics = useCallback(async () => {
|
|
205
204
|
setMetricsLoading(true);
|
|
206
205
|
try {
|
|
207
|
-
const data = await client.getMetrics();
|
|
206
|
+
const data = await client.getMetrics({ range: metricsRange, fresh: true });
|
|
208
207
|
setMetricsData(data);
|
|
209
208
|
}
|
|
210
209
|
finally {
|
|
211
210
|
setMetricsLoading(false);
|
|
212
211
|
}
|
|
213
|
-
}, [client]);
|
|
212
|
+
}, [client, metricsRange]);
|
|
213
|
+
const changeMetricsRange = useCallback((next) => {
|
|
214
|
+
setMetricsRange(next);
|
|
215
|
+
writeStored(metricsRangeStorageKey, next);
|
|
216
|
+
}, [metricsRangeStorageKey]);
|
|
214
217
|
const refreshGallery = useCallback(async () => {
|
|
215
218
|
setGalleryLoading(true);
|
|
216
219
|
try {
|
|
@@ -221,6 +224,16 @@ export function VertebrAdmin({ apiBase = "/admin/api", title = "Control plane",
|
|
|
221
224
|
setGalleryLoading(false);
|
|
222
225
|
}
|
|
223
226
|
}, [client]);
|
|
227
|
+
const refreshEmails = useCallback(async () => {
|
|
228
|
+
setEmailsLoading(true);
|
|
229
|
+
try {
|
|
230
|
+
const data = await client.getEmails({ fresh: true });
|
|
231
|
+
setEmailsData(data);
|
|
232
|
+
}
|
|
233
|
+
finally {
|
|
234
|
+
setEmailsLoading(false);
|
|
235
|
+
}
|
|
236
|
+
}, [client]);
|
|
224
237
|
const listGallery = useCallback(async () => {
|
|
225
238
|
const data = await client.getGallery();
|
|
226
239
|
return data.items;
|
|
@@ -278,6 +291,79 @@ export function VertebrAdmin({ apiBase = "/admin/api", title = "Control plane",
|
|
|
278
291
|
setTokenDraft("");
|
|
279
292
|
clearStored(tokenStorageKey);
|
|
280
293
|
};
|
|
294
|
+
const navGroups = useMemo(() => {
|
|
295
|
+
if (!catalog)
|
|
296
|
+
return [];
|
|
297
|
+
const entries = [];
|
|
298
|
+
if (catalog.metrics) {
|
|
299
|
+
entries.push({
|
|
300
|
+
key: "overview",
|
|
301
|
+
group: catalog.metrics.group ?? "Analytics",
|
|
302
|
+
label: catalog.metrics.label,
|
|
303
|
+
active: selection?.kind === "overview",
|
|
304
|
+
onSelect: () => setSelection({ kind: "overview" }),
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
for (const resource of catalog.resources) {
|
|
308
|
+
entries.push({
|
|
309
|
+
key: `resource:${resource.id}`,
|
|
310
|
+
group: resource.group ?? "Resources",
|
|
311
|
+
label: resource.label,
|
|
312
|
+
active: selection?.kind === "resource" && selection.id === resource.id,
|
|
313
|
+
onSelect: () => setSelection({ kind: "resource", id: resource.id }),
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
if (catalog.gallery) {
|
|
317
|
+
entries.push({
|
|
318
|
+
key: "gallery",
|
|
319
|
+
group: catalog.gallery.group ?? "Resources",
|
|
320
|
+
label: catalog.gallery.label,
|
|
321
|
+
active: selection?.kind === "gallery",
|
|
322
|
+
onSelect: () => setSelection({ kind: "gallery" }),
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
if (catalog.emails) {
|
|
326
|
+
const emailsTab = selection?.kind === "emails" ? (selection.tab ?? "compose") : null;
|
|
327
|
+
entries.push({
|
|
328
|
+
key: "emails",
|
|
329
|
+
group: catalog.emails.group ?? "Growth",
|
|
330
|
+
label: catalog.emails.label,
|
|
331
|
+
active: selection?.kind === "emails",
|
|
332
|
+
onSelect: () => setSelection({ kind: "emails", tab: "compose" }),
|
|
333
|
+
children: [
|
|
334
|
+
{
|
|
335
|
+
key: "emails:compose",
|
|
336
|
+
label: "Compose",
|
|
337
|
+
active: emailsTab === "compose",
|
|
338
|
+
onSelect: () => setSelection({ kind: "emails", tab: "compose" }),
|
|
339
|
+
},
|
|
340
|
+
{
|
|
341
|
+
key: "emails:templates",
|
|
342
|
+
label: "Templates",
|
|
343
|
+
active: emailsTab === "templates",
|
|
344
|
+
onSelect: () => setSelection({ kind: "emails", tab: "templates" }),
|
|
345
|
+
},
|
|
346
|
+
{
|
|
347
|
+
key: "emails:activity",
|
|
348
|
+
label: "Activity",
|
|
349
|
+
active: emailsTab === "activity",
|
|
350
|
+
onSelect: () => setSelection({ kind: "emails", tab: "activity" }),
|
|
351
|
+
},
|
|
352
|
+
],
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
for (const config of catalog.configs) {
|
|
356
|
+
const fallback = config.section === "page" ? "Pages" : "Config";
|
|
357
|
+
entries.push({
|
|
358
|
+
key: `config:${config.id}`,
|
|
359
|
+
group: config.group ?? fallback,
|
|
360
|
+
label: config.label,
|
|
361
|
+
active: selection?.kind === "config" && selection.id === config.id,
|
|
362
|
+
onSelect: () => setSelection({ kind: "config", id: config.id }),
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
return sidebarGroups(entries);
|
|
366
|
+
}, [catalog, selection]);
|
|
281
367
|
if (!bootstrap && loading) {
|
|
282
368
|
return _jsx("div", { className: "vertebr-loading", children: "Loading Vertebr\u2026" });
|
|
283
369
|
}
|
|
@@ -288,88 +374,12 @@ export function VertebrAdmin({ apiBase = "/admin/api", title = "Control plane",
|
|
|
288
374
|
? (catalog?.metrics?.label ?? "Overview")
|
|
289
375
|
: selection?.kind === "gallery"
|
|
290
376
|
? (catalog?.gallery?.label ?? "Gallery")
|
|
291
|
-
: selection?.kind === "
|
|
292
|
-
? catalog?.
|
|
293
|
-
: selection?.kind === "
|
|
294
|
-
? catalog?.
|
|
295
|
-
:
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
catalog.configs.some((c) => (c.section ?? "config") !== "page") ? (_jsxs("div", { className: "vertebr-nav-group", children: [_jsx("div", { className: "vertebr-nav-label", children: "Config" }), catalog.configs
|
|
300
|
-
.filter((c) => (c.section ?? "config") !== "page")
|
|
301
|
-
.map((config) => (_jsx("button", { type: "button", "data-active": selection?.kind === "config" &&
|
|
302
|
-
selection.id === config.id, onClick: () => setSelection({ kind: "config", id: config.id }), children: config.label }, config.id)))] })) : null, catalog &&
|
|
303
|
-
catalog.configs.some((c) => c.section === "page") ? (_jsxs("div", { className: "vertebr-nav-group", children: [_jsx("div", { className: "vertebr-nav-label", children: "Pages" }), catalog.configs
|
|
304
|
-
.filter((c) => c.section === "page")
|
|
305
|
-
.map((config) => (_jsx("button", { type: "button", "data-active": selection?.kind === "config" &&
|
|
306
|
-
selection.id === config.id, onClick: () => setSelection({ kind: "config", id: config.id }), children: config.label }, config.id)))] })) : null] })] }), _jsxs("div", { className: "vertebr-sidebar-bottom", children: [getAccessToken && authUserLabel ? (_jsxs("div", { className: "vertebr-auth", children: [_jsx("div", { className: "vertebr-nav-label", children: "Signed in" }), _jsx("p", { className: "vertebr-auth-hint", children: authUserLabel }), onSignOut ? (_jsx("button", { type: "button", className: "vertebr-btn", onClick: () => void onSignOut(), children: "Sign out" })) : null] })) : null, !getAccessToken && (authRequired || token) ? (_jsxs("div", { className: "vertebr-auth", children: [_jsx("div", { className: "vertebr-nav-label", children: "Access" }), _jsx("p", { className: "vertebr-auth-hint", children: authRequired
|
|
307
|
-
? `This environment requires auth${activeEnv?.auth?.claimKey
|
|
308
|
-
? ` (${activeEnv.auth.claimKey})`
|
|
309
|
-
: ""}.`
|
|
310
|
-
: "Optional access token for protected environments." }), _jsx("input", { className: "vertebr-auth-input", type: "password", placeholder: "Bearer token", value: tokenDraft, onChange: (event) => setTokenDraft(event.target.value), autoComplete: "off" }), _jsxs("div", { className: "vertebr-auth-actions", children: [_jsx("button", { type: "button", className: "vertebr-btn vertebr-btn-primary", onClick: saveToken, children: "Use token" }), token ? (_jsx("button", { type: "button", className: "vertebr-btn", onClick: clearToken, children: "Clear" })) : null] })] })) : null, _jsx(ThemeToggle, { theme: theme, onChange: setTheme })] })] }), _jsxs("main", { className: "vertebr-main", children: [_jsxs("header", { className: "vertebr-header", children: [_jsxs("div", { children: [_jsxs("div", { className: "vertebr-heading-row", children: [_jsx("h1", { children: activeLabel ?? (catalog ? "Dashboard" : "Sign in") }), activeEnv ? (_jsx("span", { className: "vertebr-env-badge", "data-tone": activeEnv.tone ?? "neutral", children: activeEnv.label })) : null] }), _jsx("p", { children: !catalog && authRequired
|
|
311
|
-
? "Provide an access token to load this environment."
|
|
312
|
-
: selection?.kind === "overview"
|
|
313
|
-
? "Live metrics for the selected environment."
|
|
314
|
-
: selection?.kind === "gallery"
|
|
315
|
-
? "Browse and upload shared media assets."
|
|
316
|
-
: selection?.kind === "resource"
|
|
317
|
-
? "Manage records scoped to the selected environment."
|
|
318
|
-
: selection?.kind === "config"
|
|
319
|
-
? isPageSelection
|
|
320
|
-
? "Edit content for this page."
|
|
321
|
-
: "Owner-managed config for this environment."
|
|
322
|
-
: "Select a panel." })] }), error ? (_jsx("span", { className: "vertebr-status", "data-tone": "danger", children: error })) : null] }), _jsx("div", { className: "vertebr-content", children: catalog ? (_jsxs("section", { className: "vertebr-panel", children: [selection?.kind === "overview" ? (_jsx(MetricsBoard, { label: metricsData?.label ?? catalog.metrics?.label, metrics: metricsData?.metrics ?? [], loading: metricsLoading, onRefresh: () => void refreshMetrics() })) : null, selection?.kind === "gallery" && galleryData ? (_jsx(GalleryBoard, { label: galleryData.label, items: galleryData.items, accept: galleryData.accept, maxBytes: galleryData.maxBytes, canDelete: galleryData.canDelete, loading: galleryLoading, onRefresh: () => void refreshGallery(), onUpload: async (files) => {
|
|
323
|
-
if (files.length === 1 && files[0]) {
|
|
324
|
-
await client.uploadGalleryFile(files[0]);
|
|
325
|
-
}
|
|
326
|
-
else {
|
|
327
|
-
await client.uploadGalleryFiles(files);
|
|
328
|
-
}
|
|
329
|
-
await refreshGallery();
|
|
330
|
-
}, onDelete: galleryData.canDelete
|
|
331
|
-
? async (id) => {
|
|
332
|
-
await client.deleteGalleryItem(id);
|
|
333
|
-
await refreshGallery();
|
|
334
|
-
}
|
|
335
|
-
: undefined })) : null, selection?.kind === "resource" && resourceData ? (_jsx(ResourcePanel, { schema: resourceData.schema, items: resourceData.items, label: resourceData.label, permissions: resourceData.permissions, actions: resourceData.actions, uploads: resourceData.uploads, storageKey: resourceData.id, onUpdate: resourceData.permissions.update
|
|
336
|
-
? async (rowId, value) => {
|
|
337
|
-
await client.updateResource(resourceData.id, rowId, value);
|
|
338
|
-
await refreshResource();
|
|
339
|
-
}
|
|
340
|
-
: undefined, onCreate: resourceData.permissions.create
|
|
341
|
-
? async (value) => {
|
|
342
|
-
await client.createResource(resourceData.id, value);
|
|
343
|
-
await refreshResource();
|
|
344
|
-
}
|
|
345
|
-
: undefined, onDelete: resourceData.permissions.delete
|
|
346
|
-
? async (rowId) => {
|
|
347
|
-
await client.deleteResource(resourceData.id, rowId);
|
|
348
|
-
await refreshResource();
|
|
349
|
-
}
|
|
350
|
-
: undefined, onAction: async (rowId, actionId) => {
|
|
351
|
-
await client.runResourceAction(resourceData.id, rowId, actionId);
|
|
352
|
-
await refreshResource();
|
|
353
|
-
}, onUpload: resourceData.uploads
|
|
354
|
-
? async (field, files) => {
|
|
355
|
-
if (files.length === 1 && files[0]) {
|
|
356
|
-
const result = await client.uploadResourceFile(resourceData.id, field, files[0]);
|
|
357
|
-
return [
|
|
358
|
-
{ url: result.url, name: result.name },
|
|
359
|
-
];
|
|
360
|
-
}
|
|
361
|
-
const result = await client.uploadResourceFiles(resourceData.id, field, files);
|
|
362
|
-
return result.files;
|
|
363
|
-
}
|
|
364
|
-
: undefined, ...galleryPicker })) : null, selection?.kind === "config" && configData ? (_jsxs(_Fragment, { children: [_jsxs("div", { className: "vertebr-panel-head", children: [_jsx("h2", { children: isPageSelection ? "Page content" : "Settings" }), _jsxs("span", { className: "vertebr-count", children: [Object.keys(configData.schema).length, " fields"] })] }), _jsx(ConfigForm, { schema: configData.schema, value: configData.value, onSave: async (next) => {
|
|
365
|
-
const saved = await client.setConfig(configData.id, next);
|
|
366
|
-
setConfigData({
|
|
367
|
-
...configData,
|
|
368
|
-
value: saved.value,
|
|
369
|
-
});
|
|
370
|
-
}, ...galleryPicker })] })) : null] })) : (_jsx("section", { className: "vertebr-panel", children: _jsx("div", { className: "vertebr-empty", children: authRequired
|
|
371
|
-
? "Authenticated access required for this environment."
|
|
372
|
-
: loading
|
|
373
|
-
? "Loading…"
|
|
374
|
-
: "Unable to load catalog." }) })) })] })] }));
|
|
377
|
+
: selection?.kind === "emails"
|
|
378
|
+
? (catalog?.emails?.label ?? "Emails")
|
|
379
|
+
: selection?.kind === "resource"
|
|
380
|
+
? catalog?.resources.find((r) => r.id === selection.id)?.label
|
|
381
|
+
: selection?.kind === "config"
|
|
382
|
+
? catalog?.configs.find((c) => c.id === selection.id)?.label
|
|
383
|
+
: null;
|
|
384
|
+
return (_jsxs("div", { className: "vertebr-root", "data-env": environment, children: [_jsx(AdminSidebar, { brand: bootstrap?.brand ?? catalog?.brand ?? "Vertebr", title: title, envList: envList, environment: environment, onEnvironmentChange: switchEnvironment, navGroups: navGroups, getAccessToken: getAccessToken, authUserLabel: authUserLabel, onSignOut: onSignOut, authRequired: authRequired, activeEnv: activeEnv, token: token, tokenDraft: tokenDraft, onTokenDraftChange: setTokenDraft, onSaveToken: saveToken, onClearToken: clearToken, theme: theme, onThemeChange: setTheme }), _jsxs("main", { className: "vertebr-main", children: [_jsx(AdminHeader, { activeLabel: activeLabel ?? (catalog ? "Dashboard" : "Sign in"), activeEnv: activeEnv, catalogLoaded: Boolean(catalog), authRequired: authRequired, selection: selection, isPageSelection: isPageSelection, error: error }), _jsx(AdminContent, { client: client, catalog: catalog, selection: selection, authRequired: authRequired, loading: loading, isPageSelection: isPageSelection, metricsData: metricsData, metricsLoading: metricsLoading, metricsRange: metricsRange, onMetricsRangeChange: changeMetricsRange, onRefreshMetrics: refreshMetrics, galleryData: galleryData, galleryLoading: galleryLoading, onRefreshGallery: refreshGallery, emailsData: emailsData, emailsLoading: emailsLoading, onRefreshEmails: refreshEmails, resourceData: resourceData, onRefreshResource: refreshResource, configData: configData, onConfigSaved: setConfigData, galleryPicker: galleryPicker })] })] }));
|
|
375
385
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sidebar.d.ts","sourceRoot":"","sources":["../../../src/components/admin/sidebar.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE7D,wBAAgB,aAAa,CAAC,OAAO,EAAE,YAAY,EAAE,GAAG,eAAe,EAAE,CAYxE"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export function sidebarGroups(entries) {
|
|
2
|
+
const order = [];
|
|
3
|
+
const map = new Map();
|
|
4
|
+
for (const entry of entries) {
|
|
5
|
+
const group = entry.group.trim() || "Resources";
|
|
6
|
+
if (!map.has(group)) {
|
|
7
|
+
map.set(group, []);
|
|
8
|
+
order.push(group);
|
|
9
|
+
}
|
|
10
|
+
map.get(group).push(entry);
|
|
11
|
+
}
|
|
12
|
+
return order.map((label) => ({ label, items: map.get(label) }));
|
|
13
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../../src/components/admin/storage.ts"],"names":[],"mappings":"AAAA,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAMrD;AAED,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAM5D;AAED,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAM7C"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export function readStored(key) {
|
|
2
|
+
try {
|
|
3
|
+
return localStorage.getItem(key);
|
|
4
|
+
}
|
|
5
|
+
catch {
|
|
6
|
+
return null;
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
export function writeStored(key, value) {
|
|
10
|
+
try {
|
|
11
|
+
localStorage.setItem(key, value);
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
// ignore
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
export function clearStored(key) {
|
|
18
|
+
try {
|
|
19
|
+
localStorage.removeItem(key);
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
// ignore
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
export type VertebrAdminProps = {
|
|
2
|
+
/** Base URL for Vertebr API, e.g. `/admin/api` */
|
|
3
|
+
apiBase?: string;
|
|
4
|
+
title?: string;
|
|
5
|
+
/** localStorage key for remembering the selected environment */
|
|
6
|
+
envStorageKey?: string;
|
|
7
|
+
/** localStorage key for the access token */
|
|
8
|
+
tokenStorageKey?: string;
|
|
9
|
+
/** localStorage key for light/dark theme preference */
|
|
10
|
+
themeStorageKey?: string;
|
|
11
|
+
/** localStorage key for the overview metrics range */
|
|
12
|
+
metricsRangeStorageKey?: string;
|
|
13
|
+
/** Optional host-provided token getter (Firebase ID token, etc.) */
|
|
14
|
+
getAccessToken?: () => string | null | undefined | Promise<string | null | undefined>;
|
|
15
|
+
/** Signed-in identity shown in the dashboard. */
|
|
16
|
+
authUserLabel?: string;
|
|
17
|
+
/** Host-provided sign-out action. */
|
|
18
|
+
onSignOut?: () => void | Promise<void>;
|
|
19
|
+
};
|
|
20
|
+
export type EmailsTab = "compose" | "templates" | "activity";
|
|
21
|
+
export type Selection = {
|
|
22
|
+
kind: "overview";
|
|
23
|
+
} | {
|
|
24
|
+
kind: "resource";
|
|
25
|
+
id: string;
|
|
26
|
+
} | {
|
|
27
|
+
kind: "gallery";
|
|
28
|
+
} | {
|
|
29
|
+
kind: "emails";
|
|
30
|
+
tab?: EmailsTab;
|
|
31
|
+
} | {
|
|
32
|
+
kind: "config";
|
|
33
|
+
id: string;
|
|
34
|
+
} | null;
|
|
35
|
+
export type SidebarEntry = {
|
|
36
|
+
key: string;
|
|
37
|
+
group: string;
|
|
38
|
+
label: string;
|
|
39
|
+
active: boolean;
|
|
40
|
+
onSelect: () => void;
|
|
41
|
+
/** Nested items shown under this entry (e.g. Emails sections). */
|
|
42
|
+
children?: Array<{
|
|
43
|
+
key: string;
|
|
44
|
+
label: string;
|
|
45
|
+
active: boolean;
|
|
46
|
+
onSelect: () => void;
|
|
47
|
+
}>;
|
|
48
|
+
};
|
|
49
|
+
export type SidebarNavGroup = {
|
|
50
|
+
label: string;
|
|
51
|
+
items: SidebarEntry[];
|
|
52
|
+
};
|
|
53
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/components/admin/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,iBAAiB,GAAG;IAC9B,kDAAkD;IAClD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gEAAgE;IAChE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,4CAA4C;IAC5C,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,uDAAuD;IACvD,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,sDAAsD;IACtD,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,oEAAoE;IACpE,cAAc,CAAC,EAAE,MACb,MAAM,GACN,IAAI,GACJ,SAAS,GACT,OAAO,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,CAAC;IACvC,iDAAiD;IACjD,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,qCAAqC;IACrC,SAAS,CAAC,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACxC,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG,SAAS,GAAG,WAAW,GAAG,UAAU,CAAC;AAE7D,MAAM,MAAM,SAAS,GACjB;IAAE,IAAI,EAAE,UAAU,CAAA;CAAE,GACpB;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GAChC;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,GACnB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,GAAG,CAAC,EAAE,SAAS,CAAA;CAAE,GACnC;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GAC9B,IAAI,CAAC;AAET,MAAM,MAAM,YAAY,GAAG;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,kEAAkE;IAClE,QAAQ,CAAC,EAAE,KAAK,CAAC;QACf,GAAG,EAAE,MAAM,CAAC;QACZ,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,OAAO,CAAC;QAChB,QAAQ,EAAE,MAAM,IAAI,CAAC;KACtB,CAAC,CAAC;CACJ,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,YAAY,EAAE,CAAC;CACvB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import type { ConfigFormProps } from "./types";
|
|
2
2
|
export type { ConfigFormProps, ConfigFormVariant } from "./types";
|
|
3
|
-
export declare function ConfigForm({ schema, value, onSave, submitLabel, variant, uploads, onUpload, galleryUpload, onListGallery, onUploadGallery, }: ConfigFormProps): import("react").JSX.Element;
|
|
3
|
+
export declare function ConfigForm({ schema, value, onSave, submitLabel, variant, uploads, onUpload, galleryUpload, onListGallery, onUploadGallery, onChange, hideActions, }: ConfigFormProps): import("react").JSX.Element;
|
|
4
4
|
//# sourceMappingURL=ConfigForm.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ConfigForm.d.ts","sourceRoot":"","sources":["../../../../src/components/config/form/ConfigForm.tsx"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE/C,YAAY,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAElE,wBAAgB,UAAU,CAAC,EACzB,MAAM,EACN,KAAK,EACL,MAAM,EACN,WAAW,EACX,OAAkB,EAClB,OAAO,EACP,QAAQ,EACR,aAAa,EACb,aAAa,EACb,eAAe,
|
|
1
|
+
{"version":3,"file":"ConfigForm.d.ts","sourceRoot":"","sources":["../../../../src/components/config/form/ConfigForm.tsx"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE/C,YAAY,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAElE,wBAAgB,UAAU,CAAC,EACzB,MAAM,EACN,KAAK,EACL,MAAM,EACN,WAAW,EACX,OAAkB,EAClB,OAAO,EACP,QAAQ,EACR,aAAa,EACb,aAAa,EACb,eAAe,EACf,QAAQ,EACR,WAAW,GACZ,EAAE,eAAe,+BA8FjB"}
|
|
@@ -5,7 +5,7 @@ import { zodResolver } from "@hookform/resolvers/zod";
|
|
|
5
5
|
import { buildZodSchema, groupFields, withSpecVisibility, withSpecVisibilityValues, } from "./helpers";
|
|
6
6
|
import { RecordConfigForm } from "./RecordConfigForm";
|
|
7
7
|
import { SettingsConfigForm } from "./SettingsConfigForm";
|
|
8
|
-
export function ConfigForm({ schema, value, onSave, submitLabel, variant = "config", uploads, onUpload, galleryUpload, onListGallery, onUploadGallery, }) {
|
|
8
|
+
export function ConfigForm({ schema, value, onSave, submitLabel, variant = "config", uploads, onUpload, galleryUpload, onListGallery, onUploadGallery, onChange, hideActions, }) {
|
|
9
9
|
const editorSchema = useMemo(() => (variant === "record" ? withSpecVisibility(schema) : schema), [schema, variant]);
|
|
10
10
|
const editorValue = useMemo(() => variant === "record"
|
|
11
11
|
? withSpecVisibilityValues(editorSchema, value)
|
|
@@ -19,6 +19,9 @@ export function ConfigForm({ schema, value, onSave, submitLabel, variant = "conf
|
|
|
19
19
|
defaultValues: editorValue,
|
|
20
20
|
});
|
|
21
21
|
const watched = useWatch({ control: form.control });
|
|
22
|
+
useEffect(() => {
|
|
23
|
+
onChange?.((watched ?? {}));
|
|
24
|
+
}, [watched, onChange]);
|
|
22
25
|
useEffect(() => {
|
|
23
26
|
form.reset(editorValue);
|
|
24
27
|
}, [editorValue, form]);
|
|
@@ -67,6 +70,7 @@ export function ConfigForm({ schema, value, onSave, submitLabel, variant = "conf
|
|
|
67
70
|
tone,
|
|
68
71
|
onDiscard,
|
|
69
72
|
submitLabel,
|
|
73
|
+
hideActions,
|
|
70
74
|
};
|
|
71
75
|
if (variant === "record") {
|
|
72
76
|
return _jsx(RecordConfigForm, { ...shared });
|
|
@@ -17,6 +17,7 @@ export type RecordConfigFormProps = GalleryHandlers & {
|
|
|
17
17
|
tone?: "ok" | "danger";
|
|
18
18
|
onDiscard: () => void;
|
|
19
19
|
submitLabel?: string;
|
|
20
|
+
hideActions?: boolean;
|
|
20
21
|
};
|
|
21
22
|
export declare function RecordConfigForm({ schema, groups, watched, form, uploads, onUpload, galleryUpload, onListGallery, onUploadGallery, onSubmit, isDirty, status, tone, onDiscard, submitLabel, }: RecordConfigFormProps): import("react").JSX.Element;
|
|
22
23
|
//# sourceMappingURL=RecordConfigForm.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RecordConfigForm.d.ts","sourceRoot":"","sources":["../../../../src/components/config/form/RecordConfigForm.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,KAAK,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAYvE,OAAO,KAAK,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE3D,MAAM,MAAM,qBAAqB,GAAG,eAAe,GAAG;IACpD,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACpC,MAAM,EAAE,UAAU,EAAE,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAC7C,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;IAC7C,QAAQ,CAAC,EAAE,CACT,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,IAAI,EAAE,KACV,OAAO,CAAC,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC,CAAC;IACpD,QAAQ,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,SAAS,CAAC,eAAe,CAAC,KAAK,IAAI,CAAC;IAC5D,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,IAAI,CAAC,EAAE,IAAI,GAAG,QAAQ,CAAC;IACvB,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"RecordConfigForm.d.ts","sourceRoot":"","sources":["../../../../src/components/config/form/RecordConfigForm.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,KAAK,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAYvE,OAAO,KAAK,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE3D,MAAM,MAAM,qBAAqB,GAAG,eAAe,GAAG;IACpD,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACpC,MAAM,EAAE,UAAU,EAAE,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAC7C,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;IAC7C,QAAQ,CAAC,EAAE,CACT,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,IAAI,EAAE,KACV,OAAO,CAAC,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC,CAAC;IACpD,QAAQ,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,SAAS,CAAC,eAAe,CAAC,KAAK,IAAI,CAAC;IAC5D,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,IAAI,CAAC,EAAE,IAAI,GAAG,QAAQ,CAAC;IACvB,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,CAAC;AAEF,wBAAgB,gBAAgB,CAAC,EAC/B,MAAM,EACN,MAAM,EACN,OAAO,EACP,IAAI,EACJ,OAAO,EACP,QAAQ,EACR,aAAa,EACb,aAAa,EACb,eAAe,EACf,QAAQ,EACR,OAAO,EACP,MAAM,EACN,IAAI,EACJ,SAAS,EACT,WAAW,GACZ,EAAE,qBAAqB,+BAoJvB"}
|
|
@@ -17,6 +17,7 @@ export type SettingsConfigFormProps = GalleryHandlers & {
|
|
|
17
17
|
tone?: "ok" | "danger";
|
|
18
18
|
onDiscard: () => void;
|
|
19
19
|
submitLabel?: string;
|
|
20
|
+
hideActions?: boolean;
|
|
20
21
|
};
|
|
21
|
-
export declare function SettingsConfigForm({ schema, groups, watched, form, uploads, onUpload, galleryUpload, onListGallery, onUploadGallery, onSubmit, isDirty, status, tone, onDiscard, submitLabel, }: SettingsConfigFormProps): import("react").JSX.Element;
|
|
22
|
+
export declare function SettingsConfigForm({ schema, groups, watched, form, uploads, onUpload, galleryUpload, onListGallery, onUploadGallery, onSubmit, isDirty, status, tone, onDiscard, submitLabel, hideActions, }: SettingsConfigFormProps): import("react").JSX.Element;
|
|
22
23
|
//# sourceMappingURL=SettingsConfigForm.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SettingsConfigForm.d.ts","sourceRoot":"","sources":["../../../../src/components/config/form/SettingsConfigForm.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,KAAK,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAGvE,OAAO,KAAK,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE3D,MAAM,MAAM,uBAAuB,GAAG,eAAe,GAAG;IACtD,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACpC,MAAM,EAAE,UAAU,EAAE,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAC7C,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;IAC7C,QAAQ,CAAC,EAAE,CACT,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,IAAI,EAAE,KACV,OAAO,CAAC,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC,CAAC;IACpD,QAAQ,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,SAAS,CAAC,eAAe,CAAC,KAAK,IAAI,CAAC;IAC5D,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,IAAI,CAAC,EAAE,IAAI,GAAG,QAAQ,CAAC;IACvB,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"SettingsConfigForm.d.ts","sourceRoot":"","sources":["../../../../src/components/config/form/SettingsConfigForm.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,KAAK,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAGvE,OAAO,KAAK,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE3D,MAAM,MAAM,uBAAuB,GAAG,eAAe,GAAG;IACtD,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACpC,MAAM,EAAE,UAAU,EAAE,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAC7C,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;IAC7C,QAAQ,CAAC,EAAE,CACT,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,IAAI,EAAE,KACV,OAAO,CAAC,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC,CAAC;IACpD,QAAQ,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,SAAS,CAAC,eAAe,CAAC,KAAK,IAAI,CAAC;IAC5D,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,IAAI,CAAC,EAAE,IAAI,GAAG,QAAQ,CAAC;IACvB,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,CAAC;AAEF,wBAAgB,kBAAkB,CAAC,EACjC,MAAM,EACN,MAAM,EACN,OAAO,EACP,IAAI,EACJ,OAAO,EACP,QAAQ,EACR,aAAa,EACb,aAAa,EACb,eAAe,EACf,QAAQ,EACR,OAAO,EACP,MAAM,EACN,IAAI,EACJ,SAAS,EACT,WAAW,EACX,WAAW,GACZ,EAAE,uBAAuB,+BAsDzB"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { ConfigField } from "./ConfigField";
|
|
3
3
|
import { ConfigFormActions } from "./ConfigFormActions";
|
|
4
|
-
export function SettingsConfigForm({ schema, groups, watched, form, uploads, onUpload, galleryUpload, onListGallery, onUploadGallery, onSubmit, isDirty, status, tone, onDiscard, submitLabel, }) {
|
|
4
|
+
export function SettingsConfigForm({ schema, groups, watched, form, uploads, onUpload, galleryUpload, onListGallery, onUploadGallery, onSubmit, isDirty, status, tone, onDiscard, submitLabel, hideActions, }) {
|
|
5
5
|
const singleGroup = groups.length === 1;
|
|
6
|
-
return (_jsxs("form", { className: "vertebr-form", "data-variant": "config", onSubmit: onSubmit, children: [_jsx("div", { className: "vertebr-form-scroll", children: groups.map((group) => (_jsxs("div", { className: "vertebr-form-section", "data-plain": singleGroup ? "true" : undefined, children: [!singleGroup ? (_jsxs("div", { className: "vertebr-form-section-head", children: [_jsx("h3", { children: group.label }), _jsx("span", { className: "vertebr-form-section-count", children: group.fields.length })] })) : null, _jsx("div", { className: "vertebr-form-fields", children: group.fields.map(([key, field]) => (_jsx(ConfigField, { fieldKey: key, field: field, groupLabel: group.label, variant: "config", schema: schema, watched: watched, form: form, uploads: uploads, onUpload: onUpload, galleryUpload: galleryUpload, onListGallery: onListGallery, onUploadGallery: onUploadGallery }, key))) })] }, group.id))) }), _jsx(ConfigFormActions, { form: form, isDirty: isDirty, status: status, tone: tone, onDiscard: onDiscard, submitLabel: submitLabel })] }));
|
|
6
|
+
return (_jsxs("form", { className: "vertebr-form", "data-variant": "config", onSubmit: onSubmit, children: [_jsx("div", { className: "vertebr-form-scroll", children: groups.map((group) => (_jsxs("div", { className: "vertebr-form-section", "data-plain": singleGroup ? "true" : undefined, children: [!singleGroup ? (_jsxs("div", { className: "vertebr-form-section-head", children: [_jsx("h3", { children: group.label }), _jsx("span", { className: "vertebr-form-section-count", children: group.fields.length })] })) : null, _jsx("div", { className: "vertebr-form-fields", children: group.fields.map(([key, field]) => (_jsx(ConfigField, { fieldKey: key, field: field, groupLabel: group.label, variant: "config", schema: schema, watched: watched, form: form, uploads: uploads, onUpload: onUpload, galleryUpload: galleryUpload, onListGallery: onListGallery, onUploadGallery: onUploadGallery }, key))) })] }, group.id))) }), hideActions ? null : (_jsx(ConfigFormActions, { form: form, isDirty: isDirty, status: status, tone: tone, onDiscard: onDiscard, submitLabel: submitLabel }))] }));
|
|
7
7
|
}
|
|
@@ -14,7 +14,7 @@ export function isSpecsField(key, field) {
|
|
|
14
14
|
}
|
|
15
15
|
export function isMultilineField(key, field) {
|
|
16
16
|
const hay = `${key} ${field?.label ?? ""}`;
|
|
17
|
-
return /(detail|notes|bio|bullets)/i.test(hay);
|
|
17
|
+
return /(detail|notes|bio|bullets|body|message|html)/i.test(hay);
|
|
18
18
|
}
|
|
19
19
|
export function spanFor(key, field, variant) {
|
|
20
20
|
if (field.type === "boolean")
|
|
@@ -18,6 +18,10 @@ export type ConfigFormProps = {
|
|
|
18
18
|
galleryUpload?: Pick<ResourceUploadMeta, "accept" | "maxBytes">;
|
|
19
19
|
onListGallery?: () => Promise<GalleryItem[]>;
|
|
20
20
|
onUploadGallery?: (files: File[]) => Promise<GalleryItem[]>;
|
|
21
|
+
/** Live field values (e.g. mail preview). */
|
|
22
|
+
onChange?: (value: Record<string, unknown>) => void;
|
|
23
|
+
/** Hide Save / Discard — parent owns submit. */
|
|
24
|
+
hideActions?: boolean;
|
|
21
25
|
};
|
|
22
26
|
export type FieldEntry = [string, FieldSchema];
|
|
23
27
|
export type FieldGroup = {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/components/config/form/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAEpF,MAAM,MAAM,iBAAiB,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAEpD,MAAM,MAAM,eAAe,GAAG;IAC5B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACpC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,MAAM,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1D,2DAA2D;IAC3D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,kDAAkD;IAClD,OAAO,CAAC,EAAE,iBAAiB,CAAC;IAC5B,8DAA8D;IAC9D,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;IAC7C,sDAAsD;IACtD,QAAQ,CAAC,EAAE,CACT,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,IAAI,EAAE,KACV,OAAO,CAAC,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC,CAAC;IACpD,aAAa,CAAC,EAAE,IAAI,CAAC,kBAAkB,EAAE,QAAQ,GAAG,UAAU,CAAC,CAAC;IAChE,aAAa,CAAC,EAAE,MAAM,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;IAC7C,eAAe,CAAC,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/components/config/form/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAEpF,MAAM,MAAM,iBAAiB,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAEpD,MAAM,MAAM,eAAe,GAAG;IAC5B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACpC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,MAAM,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1D,2DAA2D;IAC3D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,kDAAkD;IAClD,OAAO,CAAC,EAAE,iBAAiB,CAAC;IAC5B,8DAA8D;IAC9D,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;IAC7C,sDAAsD;IACtD,QAAQ,CAAC,EAAE,CACT,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,IAAI,EAAE,KACV,OAAO,CAAC,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC,CAAC;IACpD,aAAa,CAAC,EAAE,IAAI,CAAC,kBAAkB,EAAE,QAAQ,GAAG,UAAU,CAAC,CAAC;IAChE,aAAa,CAAC,EAAE,MAAM,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;IAC7C,eAAe,CAAC,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;IAC5D,6CAA6C;IAC7C,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;IACpD,gDAAgD;IAChD,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;AAE/C,MAAM,MAAM,UAAU,GAAG;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,UAAU,EAAE,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG,IAAI,CAChC,eAAe,EACf,eAAe,GAAG,eAAe,GAAG,iBAAiB,CACtD,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export type EmailRecipientOption = {
|
|
2
|
+
email: string;
|
|
3
|
+
id?: string;
|
|
4
|
+
label?: string;
|
|
5
|
+
/** Audience resource this address came from. */
|
|
6
|
+
resourceId?: string;
|
|
7
|
+
};
|
|
8
|
+
export type EmailRecipientSelectProps = {
|
|
9
|
+
options: EmailRecipientOption[];
|
|
10
|
+
value: string[];
|
|
11
|
+
loading?: boolean;
|
|
12
|
+
disabled?: boolean;
|
|
13
|
+
onChange: (emails: string[]) => void;
|
|
14
|
+
};
|
|
15
|
+
export declare function EmailRecipientSelect({ options, value, loading, disabled, onChange, }: EmailRecipientSelectProps): import("react").JSX.Element;
|
|
16
|
+
//# sourceMappingURL=EmailRecipientSelect.d.ts.map
|