@blinkk/root-cms 3.1.3 → 3.1.4
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/app.js +1 -4
- package/dist/chunk-MYN76V3L.js +764 -0
- package/dist/{chunk-4VZTYUQ7.js → chunk-NC3CRIFA.js} +191 -13
- package/dist/core/ai-tools.d.ts +82 -42
- package/dist/core/ai.d.ts +54 -218
- package/dist/core/plugin.d.ts +10 -4
- package/dist/functions.js +1 -2
- package/dist/plugin.js +42 -208
- package/dist/shared/ai/models.d.ts +110 -0
- package/dist/shared/ai/prompt-utils.d.ts +59 -0
- package/dist/ui/AIPage-4W4MFELY.js +1 -0
- package/dist/ui/AssetsPage-QUL2NBWK.js +1 -0
- package/dist/ui/CollectionPage-7VU6SUUP.js +1 -0
- package/dist/ui/ComparePage-DCP5QHDE.js +1 -0
- package/dist/ui/DataPage-TUVFBALT.js +1 -0
- package/dist/ui/DataSourcePage-YE2ZOHYI.js +1 -0
- package/dist/ui/DocTranslationsPage-3ILTQOP2.js +1 -0
- package/dist/ui/DocumentPage-JFQ3Y2GH.js +1 -0
- package/dist/ui/EditDataSourcePage-WHPZDMD4.js +1 -0
- package/dist/ui/EditReleasePage-QKWHIURV.js +1 -0
- package/dist/ui/EmbeddedAIPage-SQLOV4IT.js +1 -0
- package/dist/ui/EmbeddedDocumentPage-6FYHUHTE.js +1 -0
- package/dist/ui/{ImageEditorDialog-GGS4VFEA.js → ImageEditorDialog-Q44YTLB5.js} +1 -1
- package/dist/ui/LogsPage-RC5O722W.js +1 -0
- package/dist/ui/NewDataSourcePage-QXW54CHQ.js +1 -0
- package/dist/ui/NewReleasePage-TKYWVTOH.js +1 -0
- package/dist/ui/{NotFoundPage-WXEZQZK6.js → NotFoundPage-RMNPVSD3.js} +1 -1
- package/dist/ui/ProjectPage-VY4EJX6J.js +1 -0
- package/dist/ui/ReleasePage-VZAL4KUI.js +1 -0
- package/dist/ui/ReleasesPage-A4BLUNJE.js +1 -0
- package/dist/ui/SettingsPage-MP3YHQDP.js +1 -0
- package/dist/ui/{SidebarToolsPage-API53RRR.js → SidebarToolsPage-S5DMIEQ6.js} +1 -1
- package/dist/ui/TaskPage-LCBDMA4I.js +1 -0
- package/dist/ui/TasksPage-72KVSUQY.js +1 -0
- package/dist/ui/TranslationsArbPage-B7TIRREV.js +2 -0
- package/dist/ui/TranslationsEditPage-VQG4YHA6.js +1 -0
- package/dist/ui/{TranslationsPage-NGGZB4L6.js → TranslationsPage-6VCVMNXI.js} +1 -1
- package/dist/ui/ai-tools-7S4URTMT.js +1 -0
- package/dist/ui/chunk-2PDMFZBF.js +1 -0
- package/dist/ui/{chunk-NSI5JSVV.js → chunk-3WQCVKK4.js} +1 -1
- package/dist/ui/{chunk-FXIR2RBE.js → chunk-4N6CPIOQ.js} +1 -1
- package/dist/ui/{chunk-NJMNOITA.js → chunk-5SY2SVEX.js} +1 -1
- package/dist/ui/chunk-62VPTZJL.js +1 -0
- package/dist/ui/{chunk-GT5EQSEX.js → chunk-6P75AZ3B.js} +1 -1
- package/dist/ui/{chunk-CAY5NM4Z.js → chunk-74OB6FM4.js} +1 -1
- package/dist/ui/{chunk-DIFPCF7I.js → chunk-76PG55CM.js} +1 -1
- package/dist/ui/chunk-AAR7DBEN.js +110 -0
- package/dist/ui/{chunk-JS6TK4OP.js → chunk-ATTW36EM.js} +1 -1
- package/dist/ui/chunk-AZ2SK2ZK.js +1 -0
- package/dist/ui/chunk-CSUKZZK5.js +1 -0
- package/dist/ui/chunk-DZYYWCHX.js +3 -0
- package/dist/ui/{chunk-NSOTG64N.js → chunk-EIMRPYCD.js} +1 -1
- package/dist/ui/{chunk-HARRKJFZ.js → chunk-ELKXEMOU.js} +1 -1
- package/dist/ui/{chunk-LROR6N3B.js → chunk-ETPZ3TXX.js} +2 -2
- package/dist/ui/{chunk-LROR6N3B.js.LEGAL.txt → chunk-ETPZ3TXX.js.LEGAL.txt} +1 -0
- package/dist/ui/{chunk-J5E457OI.js → chunk-EYVQCOAD.js} +1 -1
- package/dist/ui/{chunk-T77VOWHP.js → chunk-F4F5MH7A.js} +1 -1
- package/dist/ui/{chunk-UPDL6UXI.js → chunk-FF4CLAZS.js} +1 -1
- package/dist/ui/{chunk-W6LP22IK.js → chunk-GCMX5V3P.js} +1 -1
- package/dist/ui/{chunk-FJLNXXE3.js → chunk-H3PYPGNR.js} +1 -1
- package/dist/ui/{chunk-WFQU7V3W.js → chunk-HVYNDEA7.js} +1 -1
- package/dist/ui/{chunk-TVYAZN2Q.js → chunk-IMXZTYAA.js} +1 -1
- package/dist/ui/{chunk-PPYM4O5N.js → chunk-J5KDO4RM.js} +1 -1
- package/dist/ui/chunk-JSWRHHTZ.js +1 -0
- package/dist/ui/{chunk-MSYTAJBV.js → chunk-K3UM5OQF.js} +1 -1
- package/dist/ui/{chunk-BW2MKGNP.js → chunk-KBJ4AK5O.js} +1 -1
- package/dist/ui/{chunk-4FGASIIX.js → chunk-L3O3CLWO.js} +1 -1
- package/dist/ui/{chunk-JTIQBW33.js → chunk-LC6WLVRS.js} +1 -1
- package/dist/ui/{chunk-WYJJZTCI.js → chunk-MAZJRNAL.js} +1 -1
- package/dist/ui/{chunk-3E6CASIN.js → chunk-MYKJ6VAM.js} +1 -1
- package/dist/ui/chunk-NEA3XU6N.js +19 -0
- package/dist/ui/{chunk-UUVAD4U4.js → chunk-PR7NB5VK.js} +1 -1
- package/dist/ui/{chunk-QF3GPZTI.js → chunk-QHOZXW7Y.js} +1 -1
- package/dist/ui/chunk-RN4XVVWD.js +1 -0
- package/dist/ui/{chunk-DS27MO63.js → chunk-SLLTYDVX.js} +1 -1
- package/dist/ui/chunk-SWTNOWNE.js +1 -0
- package/dist/ui/{chunk-BOER3EAW.js → chunk-SYDHFYRC.js} +1 -1
- package/dist/ui/{chunk-ZMS6NIGG.js → chunk-UHK5N75L.js} +1 -1
- package/dist/ui/chunk-V3G3554T.js +31 -0
- package/dist/ui/chunk-VB5VMEN7.js +1 -0
- package/dist/ui/{chunk-2EPQJUGM.js → chunk-VRRRFAIV.js} +1 -1
- package/dist/ui/{chunk-Y3MCFLQU.js → chunk-W2ZAVRAT.js} +53 -53
- package/dist/ui/{chunk-P2Z66DHV.js → chunk-W3ICOHMF.js} +1 -1
- package/dist/ui/{chunk-ENQKSLGJ.js → chunk-WAT22UHZ.js} +1 -1
- package/dist/ui/{chunk-G5ZZDHWA.js → chunk-WN7HUDGY.js} +1 -1
- package/dist/ui/{chunk-BUNR5EU3.js → chunk-WS37MDM3.js} +1 -1
- package/dist/ui/chunk-XACLTYBB.js +5 -0
- package/dist/ui/chunk-XJUQOX4E.js +1 -0
- package/dist/ui/{chunk-QHJOTXYB.js → chunk-XM35ZJBQ.js} +1 -1
- package/dist/ui/{chunk-VD6G5NV4.js → chunk-XOWWPE7X.js} +12 -12
- package/dist/ui/chunk-YV5SGR24.js +1 -0
- package/dist/ui/ui.css +1 -1
- package/dist/ui/ui.js +1 -1
- package/package.json +3 -3
- package/dist/chunk-4G7S2LJH.js +0 -1411
- package/dist/chunk-AJDMNTZQ.js +0 -187
- package/dist/ui/AIPage-VOTAEVJE.js +0 -1
- package/dist/ui/AssetsPage-EWGRMRPJ.js +0 -1
- package/dist/ui/CollectionPage-N5JIAUDS.js +0 -1
- package/dist/ui/ComparePage-JDPVU2VA.js +0 -1
- package/dist/ui/DataPage-37D4CMLZ.js +0 -1
- package/dist/ui/DataSourcePage-LX5ASYQN.js +0 -1
- package/dist/ui/DocTranslationsPage-V5M4KB7X.js +0 -1
- package/dist/ui/DocumentPage-SURTQJPG.js +0 -1
- package/dist/ui/EditDataSourcePage-O7DOV5LX.js +0 -1
- package/dist/ui/EditReleasePage-NDYTKGXY.js +0 -1
- package/dist/ui/EmbeddedAIPage-RJOUIPF2.js +0 -1
- package/dist/ui/EmbeddedDocumentPage-SLEULNNI.js +0 -1
- package/dist/ui/LogsPage-ZGBP3I35.js +0 -1
- package/dist/ui/NewDataSourcePage-GQONTMP4.js +0 -1
- package/dist/ui/NewReleasePage-7ZKXHDTD.js +0 -1
- package/dist/ui/ProjectPage-F7W7X6YO.js +0 -1
- package/dist/ui/ReleasePage-ZKMNYPML.js +0 -1
- package/dist/ui/ReleasesPage-JHCE6AEJ.js +0 -1
- package/dist/ui/SettingsPage-MWCPZPGE.js +0 -1
- package/dist/ui/TaskPage-73NLAR4J.js +0 -1
- package/dist/ui/TasksPage-IKPW2OQO.js +0 -1
- package/dist/ui/TranslationsArbPage-QVN66DIW.js +0 -2
- package/dist/ui/TranslationsEditPage-ZOELF5PK.js +0 -1
- package/dist/ui/ai-tools-4DWMFQS6.js +0 -1
- package/dist/ui/chunk-2RAVKX2Z.js +0 -19
- package/dist/ui/chunk-344GZOGG.js +0 -84
- package/dist/ui/chunk-4ISFTE2G.js +0 -5
- package/dist/ui/chunk-BT2NTAW2.js +0 -1
- package/dist/ui/chunk-C2BLMTPR.js +0 -3
- package/dist/ui/chunk-D3UIZHRK.js +0 -1
- package/dist/ui/chunk-HO3W4RVG.js +0 -1
- package/dist/ui/chunk-IOR72US3.js +0 -1
- package/dist/ui/chunk-KRNQ6L35.js +0 -1
- package/dist/ui/chunk-N3JSLTMV.js +0 -1
- package/dist/ui/chunk-TOGLZDK3.js +0 -1
- package/dist/ui/chunk-TPJCPCRR.js +0 -1
- package/dist/ui/chunk-VPHBKJ3I.js +0 -1
- package/dist/ui/chunk-YUU6LWQK.js +0 -1
- package/dist/ui/chunk-Z6DBYLIM.js +0 -1
- /package/dist/ui/{ImageEditorDialog-GGS4VFEA.js.LEGAL.txt → ImageEditorDialog-Q44YTLB5.js.LEGAL.txt} +0 -0
- /package/dist/ui/{chunk-NJMNOITA.js.LEGAL.txt → chunk-5SY2SVEX.js.LEGAL.txt} +0 -0
- /package/dist/ui/{chunk-Y3MCFLQU.js.LEGAL.txt → chunk-W2ZAVRAT.js.LEGAL.txt} +0 -0
- /package/dist/ui/{chunk-VD6G5NV4.js.LEGAL.txt → chunk-XOWWPE7X.js.LEGAL.txt} +0 -0
package/dist/plugin.js
CHANGED
|
@@ -1,25 +1,22 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
2
|
+
buildChatSystemPrompt,
|
|
3
|
+
buildEditSystemPrompt,
|
|
3
4
|
findModel,
|
|
4
5
|
generateAltText,
|
|
5
6
|
generateImage,
|
|
6
7
|
generatePublishMessage,
|
|
7
8
|
getAiConfig,
|
|
8
9
|
getServerVersion,
|
|
9
|
-
mergeIncomingMessage,
|
|
10
10
|
normalizeExecutionMode,
|
|
11
|
-
|
|
12
|
-
runEditObjectStream,
|
|
11
|
+
serializeAiClientModel,
|
|
13
12
|
serializeAiConfig,
|
|
14
13
|
summarizeDiff,
|
|
15
14
|
translateString
|
|
16
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-MYN76V3L.js";
|
|
17
16
|
import {
|
|
17
|
+
SearchIndexService,
|
|
18
18
|
runCronJobs
|
|
19
|
-
} from "./chunk-
|
|
20
|
-
import {
|
|
21
|
-
SearchIndexService
|
|
22
|
-
} from "./chunk-4VZTYUQ7.js";
|
|
19
|
+
} from "./chunk-NC3CRIFA.js";
|
|
23
20
|
import {
|
|
24
21
|
RootCMSClient,
|
|
25
22
|
parseDocId,
|
|
@@ -244,42 +241,6 @@ function isRecord(value) {
|
|
|
244
241
|
function isDocVersion(value) {
|
|
245
242
|
return value === "draft" || value === "published";
|
|
246
243
|
}
|
|
247
|
-
function withNoTransform(cacheControl) {
|
|
248
|
-
const value = cacheControl?.trim() || "no-cache";
|
|
249
|
-
if (/(?:^|,)\s*no-transform\s*(?:,|$)/i.test(value)) {
|
|
250
|
-
return value;
|
|
251
|
-
}
|
|
252
|
-
return `${value}, no-transform`;
|
|
253
|
-
}
|
|
254
|
-
async function pipeWebResponse(webResponse, res) {
|
|
255
|
-
res.status(webResponse.status);
|
|
256
|
-
webResponse.headers.forEach((value, key) => {
|
|
257
|
-
res.setHeader(key, value);
|
|
258
|
-
});
|
|
259
|
-
res.setHeader(
|
|
260
|
-
"Cache-Control",
|
|
261
|
-
withNoTransform(webResponse.headers.get("cache-control"))
|
|
262
|
-
);
|
|
263
|
-
res.setHeader("X-Accel-Buffering", "no");
|
|
264
|
-
if (!webResponse.body) {
|
|
265
|
-
res.end();
|
|
266
|
-
return;
|
|
267
|
-
}
|
|
268
|
-
const reader = webResponse.body.getReader();
|
|
269
|
-
try {
|
|
270
|
-
let done = false;
|
|
271
|
-
while (!done) {
|
|
272
|
-
const next = await reader.read();
|
|
273
|
-
done = next.done;
|
|
274
|
-
if (next.value) {
|
|
275
|
-
res.write(next.value);
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
} finally {
|
|
279
|
-
reader.releaseLock();
|
|
280
|
-
res.end();
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
244
|
function api(server, options) {
|
|
284
245
|
async function getCollectionSchema(req, collectionId) {
|
|
285
246
|
if (req.viteServer) {
|
|
@@ -677,9 +638,17 @@ function api(server, options) {
|
|
|
677
638
|
res.status(200).json({ success: true, enabled: false });
|
|
678
639
|
return;
|
|
679
640
|
}
|
|
680
|
-
|
|
641
|
+
const cmsClient = new RootCMSClient(req.rootConfig);
|
|
642
|
+
const role = await cmsClient.getUserRole(req.user.email).catch(() => null);
|
|
643
|
+
res.status(200).json({
|
|
644
|
+
success: true,
|
|
645
|
+
enabled: true,
|
|
646
|
+
...serializeAiConfig(aiConfig),
|
|
647
|
+
role: role || null,
|
|
648
|
+
canAutoApply: role === "ADMIN" || role === "EDITOR"
|
|
649
|
+
});
|
|
681
650
|
});
|
|
682
|
-
server.use("/cms/api/ai.chat", async (req, res) => {
|
|
651
|
+
server.use("/cms/api/ai.chat.prepare", async (req, res) => {
|
|
683
652
|
if (req.method !== "POST") {
|
|
684
653
|
res.status(400).json({ success: false, error: "BAD_REQUEST" });
|
|
685
654
|
return;
|
|
@@ -699,93 +668,44 @@ function api(server, options) {
|
|
|
699
668
|
res.status(400).json({ success: false, error: "UNKNOWN_MODEL" });
|
|
700
669
|
return;
|
|
701
670
|
}
|
|
702
|
-
const
|
|
671
|
+
const requestedMode = normalizeExecutionMode(body.executionMode);
|
|
703
672
|
const activeDocId = typeof body.docId === "string" && body.docId.trim() ? body.docId.trim() : void 0;
|
|
704
|
-
|
|
673
|
+
let canAutoApply = false;
|
|
705
674
|
try {
|
|
675
|
+
const cmsClient = new RootCMSClient(req.rootConfig);
|
|
706
676
|
const role = await cmsClient.getUserRole(req.user.email);
|
|
707
677
|
if (!role) {
|
|
708
678
|
res.status(403).json({ success: false, error: "FORBIDDEN" });
|
|
709
679
|
return;
|
|
710
680
|
}
|
|
711
|
-
|
|
712
|
-
res.status(403).json({ success: false, error: "AUTO_MODE_REQUIRES_EDITOR" });
|
|
713
|
-
return;
|
|
714
|
-
}
|
|
681
|
+
canAutoApply = role === "ADMIN" || role === "EDITOR";
|
|
715
682
|
} catch (err) {
|
|
716
683
|
console.error("failed to resolve user role:", err);
|
|
717
684
|
res.status(500).json({ success: false, error: "UNKNOWN" });
|
|
718
685
|
return;
|
|
719
686
|
}
|
|
720
|
-
const
|
|
721
|
-
const requestedChatId = typeof body.chatId === "string" ? body.chatId.trim() : "";
|
|
722
|
-
let chatId;
|
|
723
|
-
let storedMessages = [];
|
|
724
|
-
let existingTitle = "";
|
|
725
|
-
if (requestedChatId) {
|
|
726
|
-
const existing = await store.getChat(requestedChatId);
|
|
727
|
-
if (existing) {
|
|
728
|
-
chatId = existing.id;
|
|
729
|
-
storedMessages = existing.messages || [];
|
|
730
|
-
existingTitle = existing.title || "";
|
|
731
|
-
} else {
|
|
732
|
-
try {
|
|
733
|
-
const created = await store.createChat({
|
|
734
|
-
id: requestedChatId,
|
|
735
|
-
modelId: model.id
|
|
736
|
-
});
|
|
737
|
-
chatId = created.id;
|
|
738
|
-
} catch (err) {
|
|
739
|
-
if (err?.code === 6) {
|
|
740
|
-
res.status(409).json({ success: false, error: "CHAT_ID_CONFLICT" });
|
|
741
|
-
return;
|
|
742
|
-
}
|
|
743
|
-
throw err;
|
|
744
|
-
}
|
|
745
|
-
}
|
|
746
|
-
} else {
|
|
747
|
-
const created = await store.createChat({ modelId: model.id });
|
|
748
|
-
chatId = created.id;
|
|
749
|
-
}
|
|
750
|
-
let messages;
|
|
751
|
-
if (body.message && typeof body.message === "object") {
|
|
752
|
-
messages = mergeIncomingMessage(
|
|
753
|
-
storedMessages,
|
|
754
|
-
body.message
|
|
755
|
-
);
|
|
756
|
-
} else if (Array.isArray(body.messages) && body.messages.length > 0) {
|
|
757
|
-
messages = body.messages;
|
|
758
|
-
} else {
|
|
759
|
-
res.status(400).json({ success: false, error: "MISSING_MESSAGES" });
|
|
760
|
-
return;
|
|
761
|
-
}
|
|
687
|
+
const executionMode = requestedMode === "auto" && !canAutoApply ? "approve" : requestedMode;
|
|
762
688
|
try {
|
|
763
|
-
const
|
|
689
|
+
const system = await buildChatSystemPrompt({
|
|
764
690
|
rootConfig: req.rootConfig,
|
|
765
|
-
cmsClient,
|
|
766
691
|
config: aiConfig,
|
|
767
|
-
model,
|
|
768
|
-
messages,
|
|
769
|
-
chatId,
|
|
770
|
-
user: req.user.email,
|
|
771
692
|
executionMode,
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
693
|
+
activeDocId
|
|
694
|
+
});
|
|
695
|
+
res.status(200).json({
|
|
696
|
+
success: true,
|
|
697
|
+
model: serializeAiClientModel(model),
|
|
698
|
+
system,
|
|
699
|
+
executionMode,
|
|
700
|
+
canAutoApply,
|
|
701
|
+
maxSteps: aiConfig.maxSteps ?? 10
|
|
776
702
|
});
|
|
777
|
-
streamResponse.headers.set("x-root-cms-chat-id", chatId);
|
|
778
|
-
await pipeWebResponse(streamResponse, res);
|
|
779
703
|
} catch (err) {
|
|
780
704
|
console.error(err.stack || err);
|
|
781
|
-
|
|
782
|
-
res.status(500).json({ success: false, error: err.message || "UNKNOWN" });
|
|
783
|
-
} else {
|
|
784
|
-
res.end();
|
|
785
|
-
}
|
|
705
|
+
res.status(500).json({ success: false, error: err.message || "UNKNOWN" });
|
|
786
706
|
}
|
|
787
707
|
});
|
|
788
|
-
server.use("/cms/api/ai.
|
|
708
|
+
server.use("/cms/api/ai.edit.prepare", async (req, res) => {
|
|
789
709
|
if (req.method !== "POST") {
|
|
790
710
|
res.status(400).json({ success: false, error: "BAD_REQUEST" });
|
|
791
711
|
return;
|
|
@@ -800,19 +720,14 @@ function api(server, options) {
|
|
|
800
720
|
return;
|
|
801
721
|
}
|
|
802
722
|
const body = req.body || {};
|
|
803
|
-
const messages = body.messages || [];
|
|
804
|
-
if (!Array.isArray(messages) || messages.length === 0) {
|
|
805
|
-
res.status(400).json({ success: false, error: "MISSING_MESSAGES" });
|
|
806
|
-
return;
|
|
807
|
-
}
|
|
808
723
|
const model = findModel(aiConfig, body.modelId);
|
|
809
724
|
if (!model) {
|
|
810
725
|
res.status(400).json({ success: false, error: "UNKNOWN_MODEL" });
|
|
811
726
|
return;
|
|
812
727
|
}
|
|
813
|
-
const editCmsClient = new RootCMSClient(req.rootConfig);
|
|
814
728
|
try {
|
|
815
|
-
const
|
|
729
|
+
const cmsClient = new RootCMSClient(req.rootConfig);
|
|
730
|
+
const role = await cmsClient.getUserRole(req.user.email);
|
|
816
731
|
if (!role) {
|
|
817
732
|
res.status(403).json({ success: false, error: "FORBIDDEN" });
|
|
818
733
|
return;
|
|
@@ -823,102 +738,21 @@ function api(server, options) {
|
|
|
823
738
|
return;
|
|
824
739
|
}
|
|
825
740
|
try {
|
|
826
|
-
const
|
|
741
|
+
const system = await buildEditSystemPrompt({
|
|
827
742
|
rootConfig: req.rootConfig,
|
|
828
|
-
|
|
829
|
-
user: req.user.email,
|
|
830
|
-
config: aiConfig,
|
|
831
|
-
model,
|
|
832
|
-
messages,
|
|
833
|
-
editData: body.editData,
|
|
834
|
-
loadCollection: (collectionId) => getCollectionSchema(req, collectionId),
|
|
835
|
-
loadAllCollections: async () => (await options.getRenderer(req)).getCollections()
|
|
743
|
+
editData: body.editData
|
|
836
744
|
});
|
|
837
|
-
await pipeWebResponse(streamResponse, res);
|
|
838
|
-
} catch (err) {
|
|
839
|
-
console.error(err.stack || err);
|
|
840
|
-
if (!res.headersSent) {
|
|
841
|
-
res.status(500).json({ success: false, error: err.message || "UNKNOWN" });
|
|
842
|
-
} else {
|
|
843
|
-
res.end();
|
|
844
|
-
}
|
|
845
|
-
}
|
|
846
|
-
});
|
|
847
|
-
server.use("/cms/api/ai.chats.list", async (req, res) => {
|
|
848
|
-
if (!req.user?.email) {
|
|
849
|
-
res.status(401).json({ success: false, error: "UNAUTHORIZED" });
|
|
850
|
-
return;
|
|
851
|
-
}
|
|
852
|
-
const cmsClient = new RootCMSClient(req.rootConfig);
|
|
853
|
-
const store = new ChatStore(cmsClient, req.user.email);
|
|
854
|
-
try {
|
|
855
|
-
const chats = await store.listChats({ limit: req.body?.limit });
|
|
856
745
|
res.status(200).json({
|
|
857
746
|
success: true,
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
modelId: c.modelId,
|
|
862
|
-
createdAt: c.createdAt.toMillis(),
|
|
863
|
-
modifiedAt: c.modifiedAt.toMillis()
|
|
864
|
-
}))
|
|
747
|
+
model: serializeAiClientModel(model),
|
|
748
|
+
system,
|
|
749
|
+
maxSteps: aiConfig.maxSteps ?? 10
|
|
865
750
|
});
|
|
866
751
|
} catch (err) {
|
|
867
752
|
console.error(err.stack || err);
|
|
868
|
-
res.status(500).json({ success: false, error: "UNKNOWN" });
|
|
869
|
-
}
|
|
870
|
-
});
|
|
871
|
-
server.use("/cms/api/ai.chats.get", async (req, res) => {
|
|
872
|
-
if (!req.user?.email) {
|
|
873
|
-
res.status(401).json({ success: false, error: "UNAUTHORIZED" });
|
|
874
|
-
return;
|
|
875
|
-
}
|
|
876
|
-
const id = String(req.body?.id || "").trim();
|
|
877
|
-
if (!id) {
|
|
878
|
-
res.status(400).json({ success: false, error: "MISSING_ID" });
|
|
879
|
-
return;
|
|
880
|
-
}
|
|
881
|
-
const cmsClient = new RootCMSClient(req.rootConfig);
|
|
882
|
-
const store = new ChatStore(cmsClient, req.user.email);
|
|
883
|
-
const chat = await store.getChat(id);
|
|
884
|
-
if (!chat) {
|
|
885
|
-
res.status(404).json({ success: false, error: "NOT_FOUND" });
|
|
886
|
-
return;
|
|
753
|
+
res.status(500).json({ success: false, error: err.message || "UNKNOWN" });
|
|
887
754
|
}
|
|
888
|
-
res.status(200).json({
|
|
889
|
-
success: true,
|
|
890
|
-
chat: {
|
|
891
|
-
id: chat.id,
|
|
892
|
-
title: chat.title,
|
|
893
|
-
modelId: chat.modelId,
|
|
894
|
-
messages: chat.messages,
|
|
895
|
-
createdAt: chat.createdAt.toMillis(),
|
|
896
|
-
modifiedAt: chat.modifiedAt.toMillis()
|
|
897
|
-
}
|
|
898
|
-
});
|
|
899
755
|
});
|
|
900
|
-
server.use(
|
|
901
|
-
"/cms/api/ai.chats.delete",
|
|
902
|
-
async (req, res) => {
|
|
903
|
-
if (req.method !== "POST") {
|
|
904
|
-
res.status(400).json({ success: false, error: "BAD_REQUEST" });
|
|
905
|
-
return;
|
|
906
|
-
}
|
|
907
|
-
if (!req.user?.email) {
|
|
908
|
-
res.status(401).json({ success: false, error: "UNAUTHORIZED" });
|
|
909
|
-
return;
|
|
910
|
-
}
|
|
911
|
-
const id = String(req.body?.id || "").trim();
|
|
912
|
-
if (!id) {
|
|
913
|
-
res.status(400).json({ success: false, error: "MISSING_ID" });
|
|
914
|
-
return;
|
|
915
|
-
}
|
|
916
|
-
const cmsClient = new RootCMSClient(req.rootConfig);
|
|
917
|
-
const store = new ChatStore(cmsClient, req.user.email);
|
|
918
|
-
await store.deleteChat(id);
|
|
919
|
-
res.status(200).json({ success: true });
|
|
920
|
-
}
|
|
921
|
-
);
|
|
922
756
|
server.use("/cms/api/ai.translate", async (req, res) => {
|
|
923
757
|
if (req.method !== "POST" || !String(req.get("content-type")).startsWith("application/json")) {
|
|
924
758
|
res.status(400).json({ success: false, error: "BAD_REQUEST" });
|
|
@@ -1643,7 +1477,7 @@ function cmsPlugin(options) {
|
|
|
1643
1477
|
*/
|
|
1644
1478
|
configureServer: async (server, serverOptions) => {
|
|
1645
1479
|
server.use(
|
|
1646
|
-
["/cms/api/ai.chat", "/cms/api/ai.
|
|
1480
|
+
["/cms/api/ai.chat.prepare", "/cms/api/ai.edit.prepare"],
|
|
1647
1481
|
bodyParser.json({ limit: "4mb" })
|
|
1648
1482
|
);
|
|
1649
1483
|
server.use(bodyParser.json());
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { ImageModel, LanguageModel } from 'ai';
|
|
2
|
+
export type AiExecutionMode = 'read' | 'approve' | 'auto';
|
|
3
|
+
/**
|
|
4
|
+
* Provider type for an AI model. Use `openai-compatible` for any OpenAI-style
|
|
5
|
+
* endpoint (e.g. local Ollama, vLLM, OpenRouter).
|
|
6
|
+
*/
|
|
7
|
+
export type AiProvider = 'openai' | 'openai-compatible' | 'anthropic' | 'google';
|
|
8
|
+
/** Capabilities advertised to the UI. */
|
|
9
|
+
export interface AiModelCapabilities {
|
|
10
|
+
/** Whether the model can call tools. Defaults to `true`. */
|
|
11
|
+
tools?: boolean;
|
|
12
|
+
/** Whether the model can stream reasoning/thinking. Defaults to `false`. */
|
|
13
|
+
reasoning?: boolean;
|
|
14
|
+
/** Whether the model accepts image attachments. Defaults to `false`. */
|
|
15
|
+
attachments?: boolean;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Configuration for a single chat model.
|
|
19
|
+
*
|
|
20
|
+
* Inspired by Ollama's `Modelfile` and LiteLLM's model config: each entry maps
|
|
21
|
+
* a CMS-facing id to a provider, model id and credentials.
|
|
22
|
+
*/
|
|
23
|
+
export interface AiModelConfig {
|
|
24
|
+
/** Stable id used by the CMS UI and stored alongside chat history. */
|
|
25
|
+
id: string;
|
|
26
|
+
/** Optional human-readable label rendered in the model picker. */
|
|
27
|
+
label?: string;
|
|
28
|
+
/** Optional description shown under the label. */
|
|
29
|
+
description?: string;
|
|
30
|
+
/** AI provider/family to route requests to. */
|
|
31
|
+
provider: AiProvider;
|
|
32
|
+
/**
|
|
33
|
+
* Provider-specific model id (e.g. `gpt-4o`, `claude-opus-4-5`,
|
|
34
|
+
* `gemini-2.5-pro`). Defaults to `id` if omitted.
|
|
35
|
+
*/
|
|
36
|
+
modelId?: string;
|
|
37
|
+
/** API key for the provider. */
|
|
38
|
+
apiKey?: string;
|
|
39
|
+
/** Override the provider's base URL (required for `openai-compatible`). */
|
|
40
|
+
baseURL?: string;
|
|
41
|
+
/** Custom headers to send with each request. */
|
|
42
|
+
headers?: Record<string, string>;
|
|
43
|
+
/** Capabilities advertised to the UI. */
|
|
44
|
+
capabilities?: AiModelCapabilities;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Full AI config registered on the cms plugin.
|
|
48
|
+
*/
|
|
49
|
+
export interface AiConfig {
|
|
50
|
+
/** Models exposed in the model picker. The first entry is the default. */
|
|
51
|
+
models: AiModelConfig[];
|
|
52
|
+
/** Id of the default model. Defaults to the first model in `models`. */
|
|
53
|
+
defaultModel?: string;
|
|
54
|
+
/**
|
|
55
|
+
* Image generation models. Used by the image generator and any other
|
|
56
|
+
* features that produce images. Only the `openai` and `google` providers
|
|
57
|
+
* support image generation.
|
|
58
|
+
*/
|
|
59
|
+
imageModels?: AiModelConfig[];
|
|
60
|
+
/** Id of the default image model. Defaults to the first entry in `imageModels`. */
|
|
61
|
+
defaultImageModel?: string;
|
|
62
|
+
/**
|
|
63
|
+
* Optional system prompt prepended to every conversation. If a `ROOT.md`
|
|
64
|
+
* file exists at the project root, its contents are appended to this
|
|
65
|
+
* prompt automatically.
|
|
66
|
+
*/
|
|
67
|
+
systemPrompt?: string;
|
|
68
|
+
/** Maximum tool-loop steps before stopping. Defaults to 10. */
|
|
69
|
+
maxSteps?: number;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* A chat model's connection config serialized for the browser, INCLUDING the
|
|
73
|
+
* API key, so the client can build a `LanguageModel` for direct
|
|
74
|
+
* browser-to-provider streaming. Returned only from authenticated endpoints
|
|
75
|
+
* (see `serializeAiClientModel` in `core/ai.ts`).
|
|
76
|
+
*/
|
|
77
|
+
export interface SerializedClientModel {
|
|
78
|
+
id: string;
|
|
79
|
+
label: string;
|
|
80
|
+
description?: string;
|
|
81
|
+
provider: AiProvider;
|
|
82
|
+
modelId: string;
|
|
83
|
+
apiKey?: string;
|
|
84
|
+
baseURL?: string;
|
|
85
|
+
headers?: Record<string, string>;
|
|
86
|
+
capabilities: {
|
|
87
|
+
tools: boolean;
|
|
88
|
+
reasoning: boolean;
|
|
89
|
+
attachments: boolean;
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Anthropic blocks direct browser requests by default. Sending this header
|
|
94
|
+
* opts in to the browser-CORS behavior so the `/cms/ai` chat can call the
|
|
95
|
+
* Anthropic API straight from the client. OpenAI and Google's
|
|
96
|
+
* `generativelanguage` endpoint already allow browser requests with an API
|
|
97
|
+
* key, so no equivalent header is required for them.
|
|
98
|
+
*/
|
|
99
|
+
export declare const ANTHROPIC_BROWSER_ACCESS_HEADER = "anthropic-dangerous-direct-browser-access";
|
|
100
|
+
/**
|
|
101
|
+
* Returns a copy of `model` with any provider-specific headers required for
|
|
102
|
+
* direct browser-to-provider calls. Used when the AI SDK runs in the browser
|
|
103
|
+
* (client-side streaming) rather than on the server.
|
|
104
|
+
*/
|
|
105
|
+
export declare function withBrowserHeaders(model: AiModelConfig): AiModelConfig;
|
|
106
|
+
/** Resolves an `AiModelConfig` to an AI SDK `LanguageModel` instance. */
|
|
107
|
+
export declare function resolveLanguageModel(model: AiModelConfig): LanguageModel;
|
|
108
|
+
/** Resolves an `AiModelConfig` to an AI SDK `ImageModel` instance. */
|
|
109
|
+
export declare function resolveImageModel(model: AiModelConfig): ImageModel;
|
|
110
|
+
export declare function normalizeExecutionMode(value: unknown): AiExecutionMode;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure, browser-safe helpers for the Root AI chat: deriving/sanitizing chat
|
|
3
|
+
* titles, healing abandoned tool calls, and stripping `undefined` before
|
|
4
|
+
* persisting to Firestore.
|
|
5
|
+
*
|
|
6
|
+
* These were previously defined in `core/ai.ts` (server-only). They moved here
|
|
7
|
+
* so the browser can reuse them now that the `/cms/ai` chat streams directly
|
|
8
|
+
* from the client. `core/ai.ts` re-exports them for back-compat and tests.
|
|
9
|
+
*
|
|
10
|
+
* Keep this module free of Node-only and `firebase-admin` imports.
|
|
11
|
+
*/
|
|
12
|
+
import type { UIMessage } from 'ai';
|
|
13
|
+
/** Derives a short title from the first user message (used as fallback). */
|
|
14
|
+
export declare function deriveChatTitle(messages: UIMessage[]): string;
|
|
15
|
+
/**
|
|
16
|
+
* Extracts the first user turn and first assistant text turn as a plain-text
|
|
17
|
+
* transcript, suitable for the title-generation prompt. Skips tool-call
|
|
18
|
+
* parts, reasoning chunks, and attachments so the model sees the
|
|
19
|
+
* conversational substance and nothing else.
|
|
20
|
+
*
|
|
21
|
+
* Only the opening exchange is included on purpose — the chat title should
|
|
22
|
+
* describe what the conversation is *about*, anchored on the user's initial
|
|
23
|
+
* ask, not drift as later follow-ups arrive.
|
|
24
|
+
*/
|
|
25
|
+
export declare function buildTitlePromptContext(messages: UIMessage[]): string;
|
|
26
|
+
/**
|
|
27
|
+
* Strips the cruft LLMs commonly emit around a title — leading "Title:"
|
|
28
|
+
* preamble, surrounding quotes, trailing punctuation, internal newlines —
|
|
29
|
+
* and enforces a hard length cap.
|
|
30
|
+
*/
|
|
31
|
+
export declare function sanitizeGeneratedTitle(raw: string): string;
|
|
32
|
+
/** System prompt used to generate a short summary title for a chat. */
|
|
33
|
+
export declare const TITLE_GENERATION_SYSTEM_PROMPT: string;
|
|
34
|
+
/** Builds the user prompt for title generation from the opening exchange. */
|
|
35
|
+
export declare function buildTitlePrompt(context: string): string;
|
|
36
|
+
/**
|
|
37
|
+
* Synthesizes an aborted result for any tool-call part still awaiting one, so
|
|
38
|
+
* every `tool_use` keeps a matching `tool_result` when the history is handed
|
|
39
|
+
* to the model. Left unresolved, such parts (from an abandoned turn) make the
|
|
40
|
+
* provider reject the next request. Returns the original array unchanged when
|
|
41
|
+
* there is nothing to repair.
|
|
42
|
+
*/
|
|
43
|
+
export declare function sanitizeDanglingToolCalls(messages: UIMessage[]): UIMessage[];
|
|
44
|
+
/**
|
|
45
|
+
* Merges the latest incoming message into a persisted chat history. Replaces a
|
|
46
|
+
* matched entry (and drops anything after it) so message ids stay unique and
|
|
47
|
+
* tool-call/result pairing stays intact; a genuinely new id is appended.
|
|
48
|
+
*/
|
|
49
|
+
export declare function mergeIncomingMessage(stored: UIMessage[], incoming: UIMessage): UIMessage[];
|
|
50
|
+
/**
|
|
51
|
+
* Recursively removes `undefined` values from an object/array. Returns a new
|
|
52
|
+
* structure; the input is not mutated. Used to clean payloads before sending
|
|
53
|
+
* them to Firestore, which rejects `undefined` outright.
|
|
54
|
+
*/
|
|
55
|
+
export declare function stripUndefined<T>(value: T): T;
|
|
56
|
+
/**
|
|
57
|
+
* Extracts JSON from an AI response that may contain markdown code blocks.
|
|
58
|
+
*/
|
|
59
|
+
export declare function extractJsonFromResponse(responseText: string): string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{a}from"./chunk-NEA3XU6N.js";import"./chunk-V3G3554T.js";import"./chunk-VRRRFAIV.js";import"./chunk-5SY2SVEX.js";import"./chunk-AAR7DBEN.js";import"./chunk-YDO2EDVY.js";import"./chunk-5MV6XVGA.js";import{a as i}from"./chunk-W3ICOHMF.js";import{b as o}from"./chunk-4N6CPIOQ.js";import"./chunk-AAHM6RYJ.js";import"./chunk-YV5SGR24.js";import"./chunk-DZYYWCHX.js";import"./chunk-XOWWPE7X.js";import"./chunk-WS37MDM3.js";import{Ga as t}from"./chunk-ETPZ3TXX.js";import"./chunk-KUCVLANF.js";import"./chunk-7SK47HHZ.js";import"./chunk-DTMZLUNY.js";import"./chunk-PVAE643M.js";function n(r){return i("AI"),t(o,{children:t(a,{variant:"page",initialChatId:r.chatId})})}export{n as AIPage};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{a as p}from"./chunk-GCMX5V3P.js";import{a as i}from"./chunk-WN7HUDGY.js";import"./chunk-FF4CLAZS.js";import"./chunk-WAT22UHZ.js";import"./chunk-74OB6FM4.js";import{a as n}from"./chunk-K3UM5OQF.js";import"./chunk-W5DOO6ID.js";import"./chunk-EIMRPYCD.js";import"./chunk-EYVQCOAD.js";import"./chunk-XM35ZJBQ.js";import{a as d}from"./chunk-KBJ4AK5O.js";import{a as g}from"./chunk-W3ICOHMF.js";import{b as m}from"./chunk-4N6CPIOQ.js";import"./chunk-AAHM6RYJ.js";import"./chunk-YV5SGR24.js";import"./chunk-DZYYWCHX.js";import"./chunk-XOWWPE7X.js";import{d as o}from"./chunk-WS37MDM3.js";import{Ga as e,a as t,c as r,j as h}from"./chunk-ETPZ3TXX.js";import"./chunk-KUCVLANF.js";import"./chunk-7SK47HHZ.js";import"./chunk-DTMZLUNY.js";import"./chunk-PVAE643M.js";h();function k(){g("Asset Library");let[l,u]=p("folder",""),{query:c,route:f}=o(),[a]=t(c.asset||"");return r(()=>{if(a){let s=new URL(window.location.href);s.searchParams.delete("asset"),f(s.pathname+s.search,!0)}},[]),e(m,{children:e("div",{className:"AssetsPage","data-testid":"assets-page",children:[e("div",{className:"AssetsPage__header",children:[e(n,{size:"h1",children:"Asset Library"}),e(d,{as:"p",children:"The asset library can be used to store and organize files used throughout the project. Replacing a file in the asset library automatically updates all draft docs that use it (requires re-publishing)."})]}),e(i,{className:"AssetsPage__browser",mode:"manage",folder:l,onFolderChange:u,initialAssetId:a})]})})}export{k as AssetsPage};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{a as j}from"./chunk-L3O3CLWO.js";import{a as U}from"./chunk-SWTNOWNE.js";import{h as B}from"./chunk-F4F5MH7A.js";import{a as z,e as A,j as E}from"./chunk-J5KDO4RM.js";import"./chunk-LC6WLVRS.js";import{c as O,e as I}from"./chunk-SLLTYDVX.js";import"./chunk-CSUKZZK5.js";import{a as w}from"./chunk-H3PYPGNR.js";import"./chunk-JDW4UORS.js";import{a as P}from"./chunk-6P75AZ3B.js";import"./chunk-RN4XVVWD.js";import"./chunk-ELKXEMOU.js";import"./chunk-ATTW36EM.js";import"./chunk-YDO2EDVY.js";import{b as h}from"./chunk-5MV6XVGA.js";import{b as S}from"./chunk-W5DOO6ID.js";import{a as D}from"./chunk-EIMRPYCD.js";import"./chunk-EYVQCOAD.js";import"./chunk-XM35ZJBQ.js";import"./chunk-KBJ4AK5O.js";import{a as $}from"./chunk-W3ICOHMF.js";import{b as R}from"./chunk-4N6CPIOQ.js";import"./chunk-AAHM6RYJ.js";import"./chunk-YV5SGR24.js";import"./chunk-DZYYWCHX.js";import"./chunk-XOWWPE7X.js";import{d as k}from"./chunk-WS37MDM3.js";import{Ca as L,Ga as o,V as y,a as x,c as T,cb as u,da as C,j as M,za as N}from"./chunk-ETPZ3TXX.js";import{d as f}from"./chunk-KUCVLANF.js";import"./chunk-7SK47HHZ.js";import"./chunk-DTMZLUNY.js";import"./chunk-PVAE643M.js";M();function p(e){let{route:i}=k(),l=window.__ROOT_CTX.rootConfig.projectId;$(e.collection?e.collection:"Content"),T(()=>{let a=window.__ROOT_CTX.collections,s=`root-cms::${l}::last_collection`;if(e.collection)window.localStorage.setItem(s,e.collection);else{let t=window.localStorage.getItem(s);if(t&&a[t]){i(`/cms/content/${t}`);return}if(window.__ROOT_CTX.collections.Pages){i("/cms/content/Pages");return}let _=Object.keys(window.__ROOT_CTX.collections)||[];if(_.length>0){let d=_[0];i(`/cms/content/${d}`);return}console.warn("no collections")}},[e.collection,l]);let n=window.__ROOT_CTX.collections;return o(R,{children:o("div",{className:"CollectionPage",children:o("div",{className:"CollectionPage__layout",children:[o("div",{className:"CollectionPage__side",children:o(j,{collections:n,activeCollectionId:e.collection,projectId:l})}),o("div",{className:"CollectionPage__main",children:e.collection&&o(p.Collection,{collection:e.collection},e.collection)})]})})})}p.Collection=e=>{let{roles:i}=D(),l=window.firebase.user.email||"",n=S(i,l),[a,s]=w(`root::CollectionPage:${e.collection}:orderBy`,"modifiedAt"),[t,_]=w(`root::CollectionPage:${e.collection}:showArchived`,!1),[d,r]=x(!1),m=window.__ROOT_CTX.collections[e.collection];if(!m)return route("/cms/content"),o(f,{});let v=[{value:"slug",label:"A-Z"},{value:"slugDesc",label:"Z-A"},{value:"newest",label:"Newest"},{value:"oldest",label:"Oldest"},{value:"modifiedAt",label:"Last modified"},...m.sortOptions?.map(g=>({value:g.id,label:g.label}))||[]],[c,X,b]=A(e.collection,{orderBy:a,includeArchived:t});return o(f,{children:[o(E,{collection:e.collection,opened:d,onClose:()=>r(!1)}),o("div",{className:"CollectionPage__collection",children:o("div",{className:"CollectionPage__collection__docsTab",children:[!c&&o("div",{className:"CollectionPage__collection__docsTab__header",children:[o("div",{className:"CollectionPage__collection__docsTab__header__title",children:m.name||e.collection}),o("div",{className:"CollectionPage__collection__docsTab__controls",children:[o("div",{className:"CollectionPage__collection__docsTab__controls__showArchived",children:o(L,{size:"sm",color:"dark",label:"Show archived:",checked:t,onChange:g=>_(!!g.currentTarget.checked)})}),o("div",{className:"CollectionPage__collection__docsTab__controls__sort",children:[o("div",{className:"CollectionPage__collection__docsTab__controls__sort__label",children:"Sort:"}),o(N,{size:"xs",value:a,onChange:g=>s(g||"modifiedAt"),data:v})]}),o("div",{className:"CollectionPage__collection__docsTab__controls__newDoc",children:o(P,{label:"You don't have access to create new documents",condition:!n,children:o(C,{color:"dark",size:"xs",leftIcon:o(u,{size:16}),onClick:()=>r(!0),disabled:!n,children:"New"})})})]})]}),o(U,{className:"CollectionPage__collection__docsTab__content",children:c?o("div",{className:"CollectionPage__collection__docsTab__content__loading",children:o(y,{color:"gray",size:"xl"})}):b.length===0?o("div",{class:"CollectionPage__collection__docsEmpty",children:[o("div",{class:"CollectionPage__collection__docsEmpty__title",children:"Collection is empty."}),o("div",{class:"CollectionPage__collection__docsEmpty__button",children:o(P,{label:"You don't have access to create new documents",condition:!n,children:o(C,{color:"dark",size:"xs",leftIcon:o(u,{size:16}),onClick:()=>r(!0),disabled:!n,children:"New"})})})]}):o(p.DocsList,{collection:e.collection,docs:b,reloadDocs:()=>X()})})]})})]})};p.DocsList=e=>{let i=e.collection,l=window.__ROOT_CTX.collections[e.collection];if(!l)throw new Error(`could not find collection: ${i}`);let n=!!l.url,a=e.docs||[];function s(t){return n?z({collectionId:i,slug:t}):""}return o("div",{className:"CollectionPage__collection__docsList",children:a.map(t=>{let _=`/cms/content/${i}/${t.slug}`,d=s(t.slug),r=t.fields||{},m=h(r,l.preview?.title||"meta.title"),v=h(r,l.preview?.image||"meta.image")||l.preview?.defaultImage;return o("div",{className:"CollectionPage__collection__docsList__doc",children:[o("div",{className:"CollectionPage__collection__docsList__doc__image",children:o("a",{href:_,children:o(I,{file:v,width:120,height:90,withPlaceholder:!v?.src})})}),o("a",{className:"CollectionPage__collection__docsList__doc__content",href:_,children:[o("div",{className:"CollectionPage__collection__docsList__doc__content__header",children:[o("div",{className:"CollectionPage__collection__docsList__doc__content__header__docId",children:t.id}),o(O,{doc:t})]}),o("div",{className:"CollectionPage__collection__docsList__doc__content__title",children:m||"[UNTITLED]"}),n&&d&&o("div",{className:"CollectionPage__collection__docsList__doc__content__url",children:d})]}),o("div",{className:"CollectionPage__collection__docsList__doc__controls",children:o(B,{docId:t.id,data:t,onAction:c=>{(c.action==="archive"||c.action==="copy"||c.action==="unarchive"||c.action==="delete"||c.action==="unpublish"||c.action==="locked"||c.action==="unlocked")&&e.reloadDocs()}})})]},t.id)})})};export{p as CollectionPage};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{b as s}from"./chunk-3WQCVKK4.js";import"./chunk-VRRRFAIV.js";import"./chunk-5SY2SVEX.js";import"./chunk-5MV6XVGA.js";import"./chunk-KBJ4AK5O.js";import{a as m}from"./chunk-W3ICOHMF.js";import{b as d}from"./chunk-4N6CPIOQ.js";import"./chunk-AAHM6RYJ.js";import"./chunk-YV5SGR24.js";import"./chunk-DZYYWCHX.js";import"./chunk-XOWWPE7X.js";import{d as t}from"./chunk-WS37MDM3.js";import{Ga as a,g as i,j as p}from"./chunk-ETPZ3TXX.js";import"./chunk-KUCVLANF.js";import"./chunk-7SK47HHZ.js";import"./chunk-DTMZLUNY.js";import"./chunk-PVAE643M.js";p();function h(){let{query:r}=t();m("Compare");let o=i(()=>n(r.left||""),[r.left]),e=i(()=>n(r.right||""),[r.right]);return a(d,{children:a("div",{className:"ComparePage",children:o&&e?a(s,{className:"ComparePage__diff",left:o,right:e}):a("div",{className:"ComparePage__error",children:"Invalid params, double check query params."})})})}function n(r){let[o,e]=String(r).split("@");return o&&e?{docId:o,versionId:e}:null}export{h as ComparePage};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{a as m}from"./chunk-JSWRHHTZ.js";import"./chunk-MYKJ6VAM.js";import{a as y}from"./chunk-K3UM5OQF.js";import{a as k}from"./chunk-SWTNOWNE.js";import{a as x}from"./chunk-H3PYPGNR.js";import{a as w}from"./chunk-6P75AZ3B.js";import{b as v}from"./chunk-RN4XVVWD.js";import"./chunk-ATTW36EM.js";import{b as P}from"./chunk-W5DOO6ID.js";import{a as T}from"./chunk-EIMRPYCD.js";import"./chunk-XM35ZJBQ.js";import{a as p}from"./chunk-KBJ4AK5O.js";import{a as B}from"./chunk-W3ICOHMF.js";import{b as A}from"./chunk-4N6CPIOQ.js";import"./chunk-AAHM6RYJ.js";import{z as u}from"./chunk-XOWWPE7X.js";import"./chunk-WS37MDM3.js";import{Ca as b,Da as D,Fa as i,Ga as e,Nc as S,V as g,W as f,a as d,ba as s,c as h,da as _,g as c,j as G}from"./chunk-ETPZ3TXX.js";import"./chunk-KUCVLANF.js";import"./chunk-DTMZLUNY.js";import"./chunk-PVAE643M.js";G();var z={transition:"pop"};function O(a){let o=a.dataSource;return N(o.archivedAt)?e(i,{...z,label:`Archived ${L(o.archivedAt)} by ${o.archivedBy}`,children:e(s,{size:"xs",color:"gray",variant:"filled",children:"Archived"})}):N(o.publishedAt)?e(i,{...z,label:`Published ${L(o.publishedAt)} by ${o.publishedBy}`,children:e(s,{size:"xs",variant:"gradient",gradient:{from:"teal",to:"lime",deg:105},children:"Published"})}):e(s,{size:"xs",variant:"gradient",gradient:{from:"indigo",to:"cyan"},children:"Unpublished"})}function N(a){return!!(a&&a.toMillis)}function L(a){return a?.toMillis?u(a.toMillis()):u(new Date().getTime())}function E(){B("Data Sources");let{roles:a}=T(),o=window.firebase.user.email||"",r=P(a,o);return e(A,{children:e("div",{className:"DataPage",children:[e("div",{className:"DataPage__header",children:[e(y,{size:"h1",children:"Data Sources"}),e(p,{as:"p",children:"Add data sources to sync data from external services, like Google Sheets."}),e("div",{className:"DataPage__header__buttons",children:e(w,{label:"You don't have access to create new data sources",condition:!r,children:e(_,{component:"a",color:"blue",size:"xs",href:"/cms/data/new",disabled:!r,style:r?void 0:{pointerEvents:"none"},children:"New data source"})})})]}),e(E.DataSourcesTable,{})]})})}E.DataSourcesTable=()=>{let[a,o]=d(!0),[r,I]=d([]),[l,$]=x("root::DataPage:showArchived",!1),C=t=>!!t&&t.startsWith("https://docs.google.com/spreadsheets/");async function M(){let t=await v();I(t),o(!1)}let H=c(()=>r.some(t=>!!t.archivedAt),[r]),n=c(()=>r.filter(t=>{let U=!!t.archivedAt;return l?!0:!U}),[r,l]);return h(()=>{M()},[]),e("div",{className:"DataPage__DataSourcesTable",children:[!a&&H&&e("div",{className:"DataPage__DataSourcesTable__filters",children:e(b,{size:"sm",color:"dark",label:"Show archived",checked:l,onChange:t=>$(!!t.currentTarget.checked)})}),e(k,{children:[a&&e(g,{color:"gray",size:"xl"}),!a&&n.length>0&&e(D,{verticalSpacing:"xs",striped:!0,highlightOnHover:!0,fontSize:"xs",children:[e("thead",{children:e("tr",{children:[e("th",{children:"id"}),e("th",{children:"description"}),e("th",{children:"type"}),e("th",{children:"url"}),e("th",{children:"status"}),e("th",{children:"last synced"}),e("th",{children:"last published"})]})}),e("tbody",{children:n.map(t=>e("tr",{children:[e("td",{children:e("a",{href:`/cms/data/${t.id}`,children:t.id})}),e("td",{children:t.description||""}),e("td",{children:t.type}),e("td",{children:C(t.url)?e("div",{className:"DataPage__DataSourcesTable__url",children:[e(i,{label:"Open spreadsheet",children:e(f,{component:"a",href:t.url,target:"_blank",rel:"noreferrer",variant:"filled",color:"green",size:"sm","aria-label":"Open spreadsheet",children:e(S,{size:16,stroke:"2.25"})})}),e("a",{className:"DataPage__DataSourcesTable__url__text",href:t.url,target:"_blank",rel:"noreferrer",children:t.url})]}):t.url||""}),e("td",{children:e(O,{dataSource:t})}),e("td",{children:e(m,{dataSource:t,action:"sync"})}),e("td",{children:e(m,{dataSource:t,action:"publish"})})]},t.id))})]}),!a&&n.length===0&&e(p,{as:"p",children:"No data sources found for this filter."})]})]})};export{E as DataPage};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{a as f}from"./chunk-JSWRHHTZ.js";import"./chunk-MYKJ6VAM.js";import{a as g}from"./chunk-K3UM5OQF.js";import{a as h}from"./chunk-SWTNOWNE.js";import"./chunk-6P75AZ3B.js";import{c as T,d as N}from"./chunk-RN4XVVWD.js";import"./chunk-ATTW36EM.js";import"./chunk-W5DOO6ID.js";import"./chunk-EIMRPYCD.js";import"./chunk-XM35ZJBQ.js";import{a as A}from"./chunk-KBJ4AK5O.js";import{a as H}from"./chunk-W3ICOHMF.js";import{b as W}from"./chunk-4N6CPIOQ.js";import"./chunk-AAHM6RYJ.js";import"./chunk-XOWWPE7X.js";import"./chunk-WS37MDM3.js";import{Da as D,Fa as p,Ga as a,Gc as k,Nc as z,V as y,W as m,a as _,c as b,ca as v,da as P,j as B,na as x,oa as w}from"./chunk-ETPZ3TXX.js";import"./chunk-KUCVLANF.js";import"./chunk-DTMZLUNY.js";import"./chunk-PVAE643M.js";B();function r(t){H(`Data Source: ${t.id}`);let[o,l]=_(!0),[e,u]=_(null),[n,c]=_(null),i=t.id;async function d(){let s=await T(i);if(u(s),s){let I=await N(i,{mode:"draft"});c(I)}l(!1)}b(()=>{d()},[]);function S(s){s==="sync"&&d()}return a(W,{children:a("div",{className:"DataSourcePage",children:[a("div",{className:"DataSourcePage__header",children:[a(v,{className:"DataSourcePage__header__breadcrumbs",children:[a("a",{href:"/cms/data",children:"Data"}),a("div",{children:i})]}),a("div",{className:"DataSourcePage__header__titleWrap",children:[a(g,{size:"h1",children:["Data Source: ",i]}),a("div",{className:"DataSourcePage__header__controls",children:a(p,{label:"Configure",children:a(m,{component:"a",href:`/cms/data/${t.id}/edit`,children:a(k,{size:24,stroke:"1.5"})})})})]}),e?.description&&a(A,{as:"p",children:e.description})]}),e&&a(r.SyncStatus,{dataSource:e,onAction:S}),o?a(y,{color:"gray",size:"xl"}):e?a(r.DataSection,{dataSource:e,data:n}):a("div",{className:"DataSourcePage__notFound",children:"Not Found"})]})})}r.SyncStatus=t=>{let o=t.dataSource;return a("div",{className:"DataSourcePage__SyncStatus",children:[a(g,{size:"h2",children:"Status"}),a(h,{className:"DataSourcePage__SyncStatus__content",children:a(D,{verticalSpacing:"xs",striped:!0,highlightOnHover:!0,fontSize:"xs",children:[a("thead",{children:a("tr",{children:[a("th",{children:"last synced"}),a("th",{children:"last published"})]})}),a("tbody",{children:a("tr",{children:[a("td",{children:a(f,{dataSource:o,action:"sync",onAction:()=>{t.onAction&&t.onAction("sync")}})}),a("td",{children:a(f,{dataSource:o,action:"publish"})})]})})]})})]})};r.DataSection=t=>{let{data:o,headers:l}=t.data||{},e=t.dataSource;if(!o)return null;let u=e.dataFormat||"map";if(e.type==="gsheet"){let n=l,c=[];if(u==="array")c=o;else if(u==="map"){let i=o;if(!n){let d=new Set;i.forEach(S=>{for(let s in S)s&&d.add(s)}),n=Array.from(d)}i.forEach(d=>{c.push(n.map(S=>d[S]||""))})}return a(r.DataSectionWrap,{dataSource:e,children:a(r.DataTable,{headers:n,rows:c})})}return e.type==="http"?a(r.DataSectionWrap,{dataSource:e,children:a(r.DefaultDataDisplay,{data:o})}):(console.log(`unsupported data type: ${e.type}`),null)};r.DataSectionWrap=t=>a("div",{className:"DataSourcePage__DataSection",children:[a("div",{className:"DataSourcePage__DataSection__header",children:[a(g,{size:"h2",children:"Data"}),a("div",{className:"DataSourcePage__DataSection__header__actions",children:[t.dataSource.url?.startsWith("https://docs.google.com/spreadsheets/")&&a(p,{label:"Open spreadsheet",children:a(m,{component:"a",href:t.dataSource.url,target:"_blank",variant:"filled",color:"green",children:a(z,{size:16,stroke:"2.25"})})}),t.dataSource.previewUrl&&a(P,{component:"a",variant:"default",size:"xs",href:t.dataSource.previewUrl,target:"_blank",children:"Preview"})]})]}),a(h,{className:"DataSourcePage__DataSection__content",children:t.children})]});r.DataTable=t=>{let o=t.headers||[],l=t.rows||[];return a("div",{className:"DataSourcePage__DataTable",children:a(D,{className:"DataSourcePage__DataTable__table",verticalSpacing:"xs",striped:!0,highlightOnHover:!0,fontSize:"xs",children:[o.length>0&&a("thead",{children:a("tr",{children:o.map(e=>a("th",{children:e},e))})}),a("tbody",{children:l.map((e,u)=>a("tr",{children:e.map((n,c)=>a("td",{children:n},c))},u))})]})})};r.DefaultDataDisplay=t=>{let o=t.data;return typeof o=="object"?a(w,{value:JSON.stringify(o,null,2),minRows:20,maxRows:100}):a(x,{value:String(o),minRows:12,maxRows:100})};export{r as DataSourcePage};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{a as sa}from"./chunk-MAZJRNAL.js";import{a as ta}from"./chunk-SYDHFYRC.js";import{c as ia}from"./chunk-GCMX5V3P.js";import{a as na}from"./chunk-K3UM5OQF.js";import"./chunk-ELKXEMOU.js";import{b as U}from"./chunk-ATTW36EM.js";import"./chunk-YDO2EDVY.js";import"./chunk-5MV6XVGA.js";import{b as G}from"./chunk-EYVQCOAD.js";import{a as O,b as j}from"./chunk-XM35ZJBQ.js";import"./chunk-KBJ4AK5O.js";import{a as ra}from"./chunk-W3ICOHMF.js";import{b as N}from"./chunk-4N6CPIOQ.js";import"./chunk-AAHM6RYJ.js";import{Q as J,X as K}from"./chunk-YV5SGR24.js";import{c as V,g as X,i as C,l as S,n as q}from"./chunk-DZYYWCHX.js";import"./chunk-XOWWPE7X.js";import{e as M}from"./chunk-WS37MDM3.js";import{Ab as Y,Cc as aa,Fa as P,Ga as a,Nc as ea,Rc as oa,V as B,W as k,a as r,c as w,ca as W,da as b,e as E,g as R,j as fa,kc as Z,qa as y,zb as Q}from"./chunk-ETPZ3TXX.js";import"./chunk-KUCVLANF.js";import"./chunk-7SK47HHZ.js";import"./chunk-DTMZLUNY.js";import"./chunk-PVAE643M.js";fa();function u(e){ra(`Translations: ${e.collection}/${e.slug}`);let[g,l]=r(!0),[h,_]=r(!1),[o,t]=r([]),[s,c]=r({}),[L,la]=r(null),[ca,F]=r(!1),[I,z]=r({}),[da,H]=r(!1),p=e.collection,x=e.slug,i=`${p}/${x}`,ga=sa(),_a=window.__ROOT_CTX.rootConfig.i18n||{},D=S((_a.locales||[]).filter(n=>!C(n))),[$,A]=ia("locale",D);async function Ta(){try{let[n,d]=await Promise.all([ta(i),K(i)]),T=await Promise.all(n.map(f=>X(f))),m=await V(T);t(n),c(m),la(d),l(!1)}catch(n){console.error(n),l(!1),_(!0)}}if(w(()=>{Ta()},[]),h)return a(u.NotFound,{docId:i});function ua(n,d,T){F(!0),z(m=>{let f={...m},v=f[n]??{};return v.source=n,v[d]=T,f[n]=v,f})}async function ha(){H(!0),await G(async()=>{console.log("EditTranslationsModal.onSave()");let n=`edit-translations-${i}`;O({id:n,loading:!0,title:"Saving translations",message:`Updating for ${i}...`,autoClose:!1,disallowClose:!0});let d=Object.values(I);console.log(d),await J(i,d),j({id:n,title:"Saved translations",message:`Updated translations for ${i}!`,autoClose:!0}),z({}),F(!1)}),H(!1)}function ma(n){$.length===D.length?A([n]):A(D)}return a(N,{children:a("div",{className:"DocTranslationsPage",children:[a("div",{className:"DocTranslationsPage__header",children:[a(W,{className:"DocTranslationsPage__header__breadcrumbs",children:[a("a",{href:`/cms/content/${p}`,children:p}),a("a",{href:`/cms/content/${p}/${x}`,children:x}),a("div",{children:"translations"})]}),a("div",{className:"DocTranslationsPage__header__titleWrap",children:a(na,{size:"h1",children:["Translations: ",i]})}),a("div",{className:"DocTranslationsPage__header__controls",children:[L&&a("div",{className:"DocTranslationsPage__header__linkedSheet",children:a("div",{className:"DocTranslationsPage__header__linkedSheet__controls",children:[a(P,{label:"Open Google Sheet",children:a(k,{component:"a",href:U(L),target:"_blank",variant:"filled",color:"green",size:"sm",children:a(ea,{size:16,strokeWidth:2.25})})}),a(b,{variant:"default",size:"xs",leftIcon:a(Y,{size:16,strokeWidth:1.75}),children:"Import from Sheet"}),a(b,{variant:"default",size:"xs",leftIcon:a(Q,{size:16,strokeWidth:1.75}),children:"Export to Sheet"})]})}),a(y,{className:"DocTranslationsPage__toolsMenu",control:a(P,{label:"Tools",children:a(k,{variant:"default",children:a(oa,{size:16})})}),size:220,children:a(y.Item,{className:"DocTranslationsPage__toolsMenu__item",icon:a(aa,{size:16}),onClick:()=>ga.open({docId:i,sourceStrings:o,onPruned:n=>{c(d=>{let T={...d};return n.forEach(m=>delete T[m]),T})}}),children:"Prune unused strings"})})]})]}),a("div",{className:M("DocTranslationsPage__content",g&&"DocTranslationsPage__content--loading"),children:g?a(B,{color:"gray",size:"xl"}):a(u.Table,{locales:$,sourceStrings:o,translationsMap:s,onChange:ua,changesMap:I,onSelectLocale:n=>ma(n)})}),a("div",{className:"DocTranslationsPage__footer",children:a("div",{className:"DocTranslationsPage__footer__buttons",children:a(b,{variant:"filled",color:"dark",disabled:!ca,loading:da,onClick:()=>ha(),children:"Save"})})})]})})}u.NotFound=e=>a(N,{children:a("div",{className:"DocTranslationsPage DocTranslationsPage--error",children:a("div",{className:"DocTranslationsPage__error",children:[a("div",{className:"DocTranslationsPage__error__icon",children:a(Z,{size:60})}),a("div",{className:"DocTranslationsPage__error__title",children:["Not found: ",e.docId]})]})})});u.Table=e=>{let g=window.__ROOT_CTX.rootConfig.i18n||{},l=S((g.locales||[]).filter(o=>!C(o))),h=R(()=>{let o={};return Object.values(e.translationsMap).forEach(t=>{o[t.source]=t}),o},[e.translationsMap]);function _(o,t){let s=h[o]||{};return{translation:q(s,t),hasChanges:!1}}return a("div",{className:"DocTranslationsPage__TableWrap",children:a("table",{className:"DocTranslationsPage__Table",children:[a("thead",{children:a("tr",{children:[a("th",{className:"DocTranslationsPage__Table__sourceCellHeader",children:a("div",{className:"DocTranslationsPage__Table__headerLabel",children:"source"})}),e.locales.map(o=>a("th",{onClick:()=>e.onSelectLocale(o),className:"DocTranslationsPage__Table__localeHeader",children:a(P,{className:"DocTranslationsPage__Table__headerTooltip",placement:"start",withArrow:!0,label:e.locales.length===l.length?`Show only ${o}`:"Show all locales",children:a("div",{className:"DocTranslationsPage__Table__headerLabel",children:o})})},o))]})}),a("tbody",{children:e.sourceStrings.map(o=>a("tr",{children:[a("td",{className:"DocTranslationsPage__Table__sourceCellWrap",children:a("div",{className:"DocTranslationsPage__Table__sourceCell",children:o})}),e.locales.map(t=>{let s=_(o,t);return a("td",{children:a(u.Textarea,{source:o,locale:t,value:s.translation,onChange:e.onChange,changesMap:e.changesMap})},t)})]},o))})]})})};u.Textarea=e=>{let g=E(null),[l,h]=r(e.value),_=null;e.locale in(e.changesMap[e.source]||{})&&(_=e.changesMap[e.source][e.locale]);let o=_!==null&&_!==e.value;function t(){window.requestAnimationFrame(()=>{let s=g.current;s.style.minHeight="auto";let c=s.scrollHeight;s.style.minHeight=`${c}px`})}return w(()=>{t()},[l]),a("textarea",{ref:g,className:M("DocTranslationsPage__Textarea",o&&"DocTranslationsPage__Textarea--hasChanges",!l&&"DocTranslationsPage__Textarea--empty"),onFocus:()=>t(),rows:1,onChange:s=>{let c=s.target.value;h(c),e.onChange(e.source,e.locale,c)},value:l})};export{u as DocTranslationsPage};
|