@alpaca-editor/core 1.0.3993 → 1.0.3995
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/ui/copy-button.d.ts +10 -0
- package/dist/components/ui/copy-button.js +33 -0
- package/dist/components/ui/copy-button.js.map +1 -0
- package/dist/components/ui/sonner.d.ts +3 -0
- package/dist/components/ui/sonner.js +14 -0
- package/dist/components/ui/sonner.js.map +1 -0
- package/dist/config/config.js +4 -4
- package/dist/config/config.js.map +1 -1
- package/dist/editor/ComponentInfo.js +2 -2
- package/dist/editor/ComponentInfo.js.map +1 -1
- package/dist/editor/ContentTree.js +2 -6
- package/dist/editor/ContentTree.js.map +1 -1
- package/dist/editor/FieldListField.js +3 -10
- package/dist/editor/FieldListField.js.map +1 -1
- package/dist/editor/ItemInfo.js +3 -3
- package/dist/editor/ItemInfo.js.map +1 -1
- package/dist/editor/ai/Agents.d.ts +6 -0
- package/dist/editor/ai/Agents.js +48 -0
- package/dist/editor/ai/Agents.js.map +1 -0
- package/dist/editor/ai/AiTerminal.js +4 -2
- package/dist/editor/ai/AiTerminal.js.map +1 -1
- package/dist/editor/client/EditorClient.js +48 -91
- package/dist/editor/client/EditorClient.js.map +1 -1
- package/dist/editor/client/editContext.d.ts +3 -2
- package/dist/editor/client/editContext.js.map +1 -1
- package/dist/editor/commands/itemCommands.js +5 -24
- package/dist/editor/commands/itemCommands.js.map +1 -1
- package/dist/editor/component-designer/ComponentEditor.js +3 -5
- package/dist/editor/component-designer/ComponentEditor.js.map +1 -1
- package/dist/editor/field-types/RichTextEditor.d.ts +2 -1
- package/dist/editor/field-types/RichTextEditor.js +2 -2
- package/dist/editor/field-types/RichTextEditor.js.map +1 -1
- package/dist/editor/field-types/RichTextEditorComponent.d.ts +2 -1
- package/dist/editor/field-types/RichTextEditorComponent.js +25 -15
- package/dist/editor/field-types/RichTextEditorComponent.js.map +1 -1
- package/dist/editor/field-types/richtext/components/EditorDropdown.d.ts +2 -2
- package/dist/editor/field-types/richtext/components/EditorDropdown.js +40 -53
- package/dist/editor/field-types/richtext/components/EditorDropdown.js.map +1 -1
- package/dist/editor/field-types/richtext/components/ReactSlate.js +8 -4
- package/dist/editor/field-types/richtext/components/ReactSlate.js.map +1 -1
- package/dist/editor/field-types/richtext/utils/profileMapper.js +4 -4
- package/dist/editor/field-types/richtext/utils/profileMapper.js.map +1 -1
- package/dist/editor/media-selector/AiImageSearch.js +2 -5
- package/dist/editor/media-selector/AiImageSearch.js.map +1 -1
- package/dist/editor/media-selector/MediaFolderBrowser.js +2 -5
- package/dist/editor/media-selector/MediaFolderBrowser.js.map +1 -1
- package/dist/editor/media-selector/TreeSelector.js +2 -5
- package/dist/editor/media-selector/TreeSelector.js.map +1 -1
- package/dist/editor/menubar/FavoritesControls.d.ts +8 -0
- package/dist/editor/menubar/FavoritesControls.js +124 -0
- package/dist/editor/menubar/FavoritesControls.js.map +1 -0
- package/dist/editor/menubar/ItemLanguageVersion.js +2 -1
- package/dist/editor/menubar/ItemLanguageVersion.js.map +1 -1
- package/dist/editor/menubar/PageSelector.js +3 -6
- package/dist/editor/menubar/PageSelector.js.map +1 -1
- package/dist/editor/reviews/reviewCommands.js +3 -8
- package/dist/editor/reviews/reviewCommands.js.map +1 -1
- package/dist/editor/services/favouritesService.d.ts +33 -0
- package/dist/editor/services/favouritesService.js +22 -0
- package/dist/editor/services/favouritesService.js.map +1 -0
- package/dist/editor/sidebar/Debug.js +2 -2
- package/dist/editor/sidebar/Debug.js.map +1 -1
- package/dist/editor/sidebar/SEOInfo.js +4 -15
- package/dist/editor/sidebar/SEOInfo.js.map +1 -1
- package/dist/editor/ui/ItemSearch.js +2 -5
- package/dist/editor/ui/ItemSearch.js.map +1 -1
- package/dist/editor/ui/Section.js +1 -1
- package/dist/editor/utils/keyboardNavigation.d.ts +32 -0
- package/dist/editor/utils/keyboardNavigation.js +156 -0
- package/dist/editor/utils/keyboardNavigation.js.map +1 -0
- package/dist/page-wizard/PageWizard.d.ts +2 -2
- package/dist/page-wizard/steps/ContentStep.js +6 -4
- package/dist/page-wizard/steps/ContentStep.js.map +1 -1
- package/dist/page-wizard/steps/schema.js +4 -2
- package/dist/page-wizard/steps/schema.js.map +1 -1
- package/dist/revision.d.ts +2 -2
- package/dist/revision.js +2 -2
- package/dist/splash-screen/NewPage.js +7 -10
- package/dist/splash-screen/NewPage.js.map +1 -1
- package/dist/styles.css +25 -5
- package/package.json +3 -1
- package/src/components/ui/copy-button.tsx +75 -0
- package/src/components/ui/sonner.tsx +25 -0
- package/src/config/config.tsx +5 -7
- package/src/editor/ComponentInfo.tsx +5 -4
- package/src/editor/ContentTree.tsx +2 -6
- package/src/editor/FieldListField.tsx +4 -25
- package/src/editor/ItemInfo.tsx +4 -4
- package/src/editor/ai/Agents.tsx +125 -0
- package/src/editor/ai/AiTerminal.tsx +4 -0
- package/src/editor/client/EditorClient.tsx +58 -119
- package/src/editor/client/editContext.ts +3 -2
- package/src/editor/commands/itemCommands.tsx +10 -25
- package/src/editor/component-designer/ComponentEditor.tsx +8 -10
- package/src/editor/field-types/RichTextEditor.tsx +10 -1
- package/src/editor/field-types/RichTextEditorComponent.tsx +25 -11
- package/src/editor/field-types/richtext/components/EditorDropdown.css +81 -0
- package/src/editor/field-types/richtext/components/EditorDropdown.tsx +57 -72
- package/src/editor/field-types/richtext/components/ReactSlate.css +1 -3
- package/src/editor/field-types/richtext/components/ReactSlate.tsx +13 -4
- package/src/editor/field-types/richtext/utils/profileMapper.ts +4 -4
- package/src/editor/media-selector/AiImageSearch.tsx +2 -5
- package/src/editor/media-selector/MediaFolderBrowser.tsx +2 -5
- package/src/editor/media-selector/TreeSelector.tsx +2 -5
- package/src/editor/menubar/FavoritesControls.tsx +250 -0
- package/src/editor/menubar/ItemLanguageVersion.tsx +3 -1
- package/src/editor/menubar/PageSelector.tsx +76 -75
- package/src/editor/reviews/reviewCommands.tsx +3 -8
- package/src/editor/services/favouritesService.ts +60 -0
- package/src/editor/sidebar/Debug.tsx +4 -3
- package/src/editor/sidebar/SEOInfo.tsx +6 -16
- package/src/editor/ui/ItemSearch.tsx +2 -5
- package/src/editor/ui/Section.tsx +1 -1
- package/src/editor/utils/keyboardNavigation.ts +234 -0
- package/src/page-wizard/PageWizard.tsx +2 -2
- package/src/page-wizard/steps/ContentStep.tsx +6 -6
- package/src/page-wizard/steps/schema.ts +10 -7
- package/src/revision.ts +2 -2
- package/src/splash-screen/NewPage.tsx +28 -24
- package/dist/editor/ui/CopyToClipboardButton.d.ts +0 -3
- package/dist/editor/ui/CopyToClipboardButton.js +0 -16
- package/dist/editor/ui/CopyToClipboardButton.js.map +0 -1
- package/src/editor/ui/CopyToClipboardButton.tsx +0 -24
|
@@ -78,6 +78,7 @@ export function AiTerminal({
|
|
|
78
78
|
const [profiles, setProfiles] = useState<AiProfile[]>([]);
|
|
79
79
|
const [activeProfile, setActiveProfile] = useState<AiProfile>();
|
|
80
80
|
const [initialPromptExecuted, setInitialPromptExecuted] = useState(false);
|
|
81
|
+
const [agentId] = useState<string>(() => crypto.randomUUID());
|
|
81
82
|
const selection = editContext.selection;
|
|
82
83
|
const terminalRef = useRef<{ submit: () => void }>(null);
|
|
83
84
|
const [responseMessages, setResponseMessages] = useState<Message[]>([]);
|
|
@@ -229,6 +230,7 @@ export function AiTerminal({
|
|
|
229
230
|
model,
|
|
230
231
|
selectedText,
|
|
231
232
|
context,
|
|
233
|
+
agentId,
|
|
232
234
|
(response: any) => {
|
|
233
235
|
setResponse(response);
|
|
234
236
|
handleResponse(response, callback, false);
|
|
@@ -455,6 +457,7 @@ async function executePrompt(
|
|
|
455
457
|
model: string | null,
|
|
456
458
|
selectedText: string | null,
|
|
457
459
|
context: AiContext,
|
|
460
|
+
agentId: string,
|
|
458
461
|
callback: (response: any) => void,
|
|
459
462
|
): Promise<Response | null> {
|
|
460
463
|
const response = await fetch(context.endpoint, {
|
|
@@ -468,6 +471,7 @@ async function executePrompt(
|
|
|
468
471
|
selectedText,
|
|
469
472
|
model,
|
|
470
473
|
sessionId: session,
|
|
474
|
+
agentId,
|
|
471
475
|
}),
|
|
472
476
|
credentials: "include",
|
|
473
477
|
headers: {
|
|
@@ -10,7 +10,7 @@ import React, {
|
|
|
10
10
|
ReactNode,
|
|
11
11
|
} from "react";
|
|
12
12
|
|
|
13
|
-
import {
|
|
13
|
+
import { toast } from "sonner";
|
|
14
14
|
|
|
15
15
|
import {
|
|
16
16
|
EditContextProvider,
|
|
@@ -113,6 +113,8 @@ import { Spinner } from "../ui/Spinner";
|
|
|
113
113
|
import { cleanId } from "../utils/id-helper";
|
|
114
114
|
|
|
115
115
|
import { useDebouncedCallback } from "use-debounce";
|
|
116
|
+
import { useKeyboardNavigation } from "../utils/keyboardNavigation";
|
|
117
|
+
import { Toaster } from "../../components/ui/sonner";
|
|
116
118
|
|
|
117
119
|
import { Tour } from "../../tour/Tour";
|
|
118
120
|
import { usePageViewContext } from "../page-viewer/pageViewContext";
|
|
@@ -344,6 +346,8 @@ export function EditorClient({
|
|
|
344
346
|
WebSocketMessage[]
|
|
345
347
|
>([]);
|
|
346
348
|
|
|
349
|
+
const [favorites, setFavorites] = useState<any[]>([]);
|
|
350
|
+
|
|
347
351
|
useEffect(() => {
|
|
348
352
|
const queryMode = searchParams.get("mode");
|
|
349
353
|
if (queryMode) setMode(queryMode as EditorMode);
|
|
@@ -959,6 +963,19 @@ export function EditorClient({
|
|
|
959
963
|
setSuggestedEdits(result.data || []);
|
|
960
964
|
}, [contentEditorItem]);
|
|
961
965
|
|
|
966
|
+
const loadFavorites = useCallback(async () => {
|
|
967
|
+
try {
|
|
968
|
+
const { getAllFavorites } = await import("../services/favouritesService");
|
|
969
|
+
const result = await getAllFavorites();
|
|
970
|
+
if (result.data) {
|
|
971
|
+
setFavorites(result.data);
|
|
972
|
+
}
|
|
973
|
+
} catch (error) {
|
|
974
|
+
console.error("Failed to load favorites:", error);
|
|
975
|
+
setFavorites([]);
|
|
976
|
+
}
|
|
977
|
+
}, []);
|
|
978
|
+
|
|
962
979
|
const page = pageViewContext.page;
|
|
963
980
|
|
|
964
981
|
useEffect(() => {
|
|
@@ -1043,6 +1060,11 @@ export function EditorClient({
|
|
|
1043
1060
|
loadSuggestedEdits();
|
|
1044
1061
|
}, [currentItemDescriptor]);
|
|
1045
1062
|
|
|
1063
|
+
// Load favorites on mount
|
|
1064
|
+
useEffect(() => {
|
|
1065
|
+
loadFavorites();
|
|
1066
|
+
}, [loadFavorites]);
|
|
1067
|
+
|
|
1046
1068
|
// Automatically focus the first rendered field when a new component is added
|
|
1047
1069
|
useEffect(() => {
|
|
1048
1070
|
async function setFocus() {
|
|
@@ -1273,107 +1295,6 @@ export function EditorClient({
|
|
|
1273
1295
|
[editContextRef, pathname, router, searchParams],
|
|
1274
1296
|
);
|
|
1275
1297
|
|
|
1276
|
-
const handleKeyDownDebounced = useDebouncedCallback(
|
|
1277
|
-
async (event: KeyboardEvent) => {
|
|
1278
|
-
if (!event.key) return;
|
|
1279
|
-
|
|
1280
|
-
if (event.ctrlKey && event.key === "z") {
|
|
1281
|
-
await operations.undo();
|
|
1282
|
-
}
|
|
1283
|
-
if (event.ctrlKey && event.key === "y") {
|
|
1284
|
-
await operations.redo();
|
|
1285
|
-
}
|
|
1286
|
-
if (event.ctrlKey && event.key === "F11") {
|
|
1287
|
-
event.preventDefault();
|
|
1288
|
-
pageViewContext.setFullscreen(false);
|
|
1289
|
-
}
|
|
1290
|
-
|
|
1291
|
-
const command = configuration.commands.allItemCommands.find(
|
|
1292
|
-
(x) => x.keyBinding === event.key,
|
|
1293
|
-
);
|
|
1294
|
-
|
|
1295
|
-
if (command) {
|
|
1296
|
-
event.preventDefault();
|
|
1297
|
-
const contentEditorItem = editContextRef.current?.contentEditorItem;
|
|
1298
|
-
if (!contentEditorItem) return;
|
|
1299
|
-
|
|
1300
|
-
const items =
|
|
1301
|
-
editContextRef.current?.selection?.map((x) => ({
|
|
1302
|
-
id: x,
|
|
1303
|
-
language: contentEditorItem.language,
|
|
1304
|
-
version: 0,
|
|
1305
|
-
})) || [];
|
|
1306
|
-
|
|
1307
|
-
if (!items.length) items.push(contentEditorItem.descriptor);
|
|
1308
|
-
|
|
1309
|
-
if (items.length > 0) {
|
|
1310
|
-
const fullItems =
|
|
1311
|
-
await editContextRef.current?.itemsRepository.getItems(items);
|
|
1312
|
-
executeCommand({
|
|
1313
|
-
command,
|
|
1314
|
-
data: {
|
|
1315
|
-
items: fullItems,
|
|
1316
|
-
},
|
|
1317
|
-
});
|
|
1318
|
-
}
|
|
1319
|
-
}
|
|
1320
|
-
},
|
|
1321
|
-
50,
|
|
1322
|
-
);
|
|
1323
|
-
|
|
1324
|
-
const handleKeyDown = useCallback(
|
|
1325
|
-
async (event: KeyboardEvent) => {
|
|
1326
|
-
if (event.key === "Insert") {
|
|
1327
|
-
event.preventDefault();
|
|
1328
|
-
event.stopPropagation();
|
|
1329
|
-
editContext.setInsertMode((x) => !x);
|
|
1330
|
-
}
|
|
1331
|
-
|
|
1332
|
-
if (event.ctrlKey && event.key === "s") {
|
|
1333
|
-
event.preventDefault();
|
|
1334
|
-
event.stopPropagation();
|
|
1335
|
-
return;
|
|
1336
|
-
}
|
|
1337
|
-
|
|
1338
|
-
const target = event.target as HTMLElement;
|
|
1339
|
-
const isTyping =
|
|
1340
|
-
target instanceof HTMLInputElement ||
|
|
1341
|
-
target instanceof HTMLTextAreaElement ||
|
|
1342
|
-
target.isContentEditable;
|
|
1343
|
-
|
|
1344
|
-
if (
|
|
1345
|
-
(event.ctrlKey && event.key === "z") ||
|
|
1346
|
-
(event.ctrlKey && event.key === "y")
|
|
1347
|
-
) {
|
|
1348
|
-
if (!isTyping) {
|
|
1349
|
-
event.preventDefault();
|
|
1350
|
-
event.stopPropagation();
|
|
1351
|
-
handleKeyDownDebounced(event);
|
|
1352
|
-
}
|
|
1353
|
-
return;
|
|
1354
|
-
}
|
|
1355
|
-
handleKeyDownDebounced(event);
|
|
1356
|
-
},
|
|
1357
|
-
[
|
|
1358
|
-
configuration.commands.allItemCommands,
|
|
1359
|
-
executeCommand,
|
|
1360
|
-
editContextRef.current,
|
|
1361
|
-
],
|
|
1362
|
-
);
|
|
1363
|
-
|
|
1364
|
-
if (typeof window !== "undefined")
|
|
1365
|
-
if (typeof window !== "undefined")
|
|
1366
|
-
useEventListenerExt("keydown", handleKeyDown, window, true);
|
|
1367
|
-
|
|
1368
|
-
if (typeof window !== "undefined")
|
|
1369
|
-
useEventListenerExt(
|
|
1370
|
-
"click",
|
|
1371
|
-
() => {
|
|
1372
|
-
contextMenuRef.current?.close({});
|
|
1373
|
-
},
|
|
1374
|
-
window,
|
|
1375
|
-
true,
|
|
1376
|
-
);
|
|
1377
1298
|
const state = useMemo(
|
|
1378
1299
|
() => ({
|
|
1379
1300
|
page,
|
|
@@ -1425,8 +1346,6 @@ export function EditorClient({
|
|
|
1425
1346
|
if (currentOverlay !== "context-menu") contextMenuRef.current?.close({});
|
|
1426
1347
|
}, [currentOverlay]);
|
|
1427
1348
|
|
|
1428
|
-
const toast = useRef<Toast | null>(null);
|
|
1429
|
-
|
|
1430
1349
|
useEffect(() => {
|
|
1431
1350
|
loadItemVersions();
|
|
1432
1351
|
}, [currentItemDescriptor]);
|
|
@@ -1458,24 +1377,14 @@ export function EditorClient({
|
|
|
1458
1377
|
|
|
1459
1378
|
const showErrorToast = useCallback(
|
|
1460
1379
|
({ summary, details }: { summary?: string; details?: string }) => {
|
|
1461
|
-
toast.
|
|
1462
|
-
severity: "error",
|
|
1463
|
-
summary: summary || "Error",
|
|
1464
|
-
detail: details || "An error occurred",
|
|
1465
|
-
life: 3000,
|
|
1466
|
-
});
|
|
1380
|
+
toast.error(details || summary || "An error occurred");
|
|
1467
1381
|
},
|
|
1468
1382
|
[],
|
|
1469
1383
|
);
|
|
1470
1384
|
|
|
1471
1385
|
const showInfoToast = useCallback(
|
|
1472
1386
|
({ summary, details }: { summary?: string; details?: string }) => {
|
|
1473
|
-
toast.
|
|
1474
|
-
severity: "info",
|
|
1475
|
-
summary: summary || "Info",
|
|
1476
|
-
detail: details || "Information",
|
|
1477
|
-
life: 3000,
|
|
1478
|
-
});
|
|
1387
|
+
toast.info(details || summary || "Information");
|
|
1479
1388
|
},
|
|
1480
1389
|
[],
|
|
1481
1390
|
);
|
|
@@ -1648,6 +1557,32 @@ export function EditorClient({
|
|
|
1648
1557
|
|
|
1649
1558
|
const operations = operationsContext.ops;
|
|
1650
1559
|
|
|
1560
|
+
const { handleKeyDown } = useKeyboardNavigation({
|
|
1561
|
+
editContextRef,
|
|
1562
|
+
operations,
|
|
1563
|
+
pageViewContext,
|
|
1564
|
+
configuration,
|
|
1565
|
+
contentEditorItem,
|
|
1566
|
+
browseHistory,
|
|
1567
|
+
loadItem,
|
|
1568
|
+
showInfoToast,
|
|
1569
|
+
showErrorToast,
|
|
1570
|
+
executeCommand,
|
|
1571
|
+
});
|
|
1572
|
+
|
|
1573
|
+
if (typeof window !== "undefined")
|
|
1574
|
+
useEventListenerExt("keydown", handleKeyDown, window, true);
|
|
1575
|
+
|
|
1576
|
+
if (typeof window !== "undefined")
|
|
1577
|
+
useEventListenerExt(
|
|
1578
|
+
"click",
|
|
1579
|
+
() => {
|
|
1580
|
+
contextMenuRef.current?.close({});
|
|
1581
|
+
},
|
|
1582
|
+
window,
|
|
1583
|
+
true,
|
|
1584
|
+
);
|
|
1585
|
+
|
|
1651
1586
|
useEffect(() => {
|
|
1652
1587
|
if (mode === "suggestions") {
|
|
1653
1588
|
setShowSuggestedEdits(true);
|
|
@@ -1772,8 +1707,8 @@ export function EditorClient({
|
|
|
1772
1707
|
router.push(newUrl, { scroll: false });
|
|
1773
1708
|
},
|
|
1774
1709
|
selectMedia,
|
|
1775
|
-
showToast: (message:
|
|
1776
|
-
toast
|
|
1710
|
+
showToast: (message: string) => {
|
|
1711
|
+
toast(message);
|
|
1777
1712
|
},
|
|
1778
1713
|
scrollIntoView,
|
|
1779
1714
|
setScrollIntoView,
|
|
@@ -2153,6 +2088,8 @@ export function EditorClient({
|
|
|
2153
2088
|
userInfo: userInfo,
|
|
2154
2089
|
userPreferences,
|
|
2155
2090
|
setUserPreferences,
|
|
2091
|
+
favorites,
|
|
2092
|
+
loadFavorites,
|
|
2156
2093
|
};
|
|
2157
2094
|
}, [
|
|
2158
2095
|
operations,
|
|
@@ -2238,6 +2175,8 @@ export function EditorClient({
|
|
|
2238
2175
|
openDialog,
|
|
2239
2176
|
pageWizard,
|
|
2240
2177
|
webSocketMessages,
|
|
2178
|
+
favorites,
|
|
2179
|
+
loadFavorites,
|
|
2241
2180
|
]);
|
|
2242
2181
|
|
|
2243
2182
|
const modifiedFieldsContext = useMemo(() => {
|
|
@@ -2302,7 +2241,6 @@ export function EditorClient({
|
|
|
2302
2241
|
</>
|
|
2303
2242
|
) : (
|
|
2304
2243
|
<>
|
|
2305
|
-
<Toast ref={toast} />
|
|
2306
2244
|
<ConfirmationDialog ref={confirmationDialogRef} />
|
|
2307
2245
|
<EditContextMenu ref={contextMenuRef} />
|
|
2308
2246
|
<MainLayout
|
|
@@ -2352,6 +2290,7 @@ export function EditorClient({
|
|
|
2352
2290
|
</div>
|
|
2353
2291
|
)}
|
|
2354
2292
|
{dialog}
|
|
2293
|
+
<Toaster position="top-center" />
|
|
2355
2294
|
</EditContextProvider>
|
|
2356
2295
|
</ModifiedFieldsContextProvider>
|
|
2357
2296
|
</OperationsContextProvider>
|
|
@@ -7,7 +7,6 @@ import React, {
|
|
|
7
7
|
useEffect,
|
|
8
8
|
useRef,
|
|
9
9
|
} from "react";
|
|
10
|
-
import { ToastMessage } from "primereact/toast";
|
|
11
10
|
|
|
12
11
|
import { EditorConfiguration, EditorView } from "../../config/types";
|
|
13
12
|
import {
|
|
@@ -171,7 +170,7 @@ export type EditContextType = {
|
|
|
171
170
|
setShowSuggestedEditsDiff: React.Dispatch<React.SetStateAction<boolean>>;
|
|
172
171
|
setCenterPanelView: (view: ReactNode) => void;
|
|
173
172
|
configuration: EditorConfiguration;
|
|
174
|
-
showToast: (message:
|
|
173
|
+
showToast: (message: string) => void;
|
|
175
174
|
sessionId: string;
|
|
176
175
|
openSplashScreen: () => void;
|
|
177
176
|
getComponentCommands: (component: Component[]) => Promise<ComponentCommand[]>;
|
|
@@ -369,6 +368,8 @@ export type EditContextType = {
|
|
|
369
368
|
clearWebSocketMessages: () => void;
|
|
370
369
|
userInfo: UserInfo;
|
|
371
370
|
setUserPreferences: (preferences: Partial<UserPreferences>) => void;
|
|
371
|
+
favorites: any[];
|
|
372
|
+
loadFavorites: () => Promise<void>;
|
|
372
373
|
};
|
|
373
374
|
|
|
374
375
|
const EditContext = React.createContext<EditContextType | undefined>(undefined);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Command, CommandContext, CommandData } from "./commands";
|
|
2
2
|
import { FullItem, ItemDescriptor } from "../pageModel";
|
|
3
|
+
import { toast } from "sonner";
|
|
3
4
|
|
|
4
5
|
import { ItemNameDialog, ItemNameDialogProps } from "../ui/ItemNameDialogNew";
|
|
5
6
|
import {
|
|
@@ -357,6 +358,7 @@ export const publishItemCommand: ItemCommand = {
|
|
|
357
358
|
},
|
|
358
359
|
};
|
|
359
360
|
|
|
361
|
+
|
|
360
362
|
export const exportItemsCommand: ItemCommand = {
|
|
361
363
|
id: "exportItem",
|
|
362
364
|
label: "Export",
|
|
@@ -428,12 +430,9 @@ export const exportItemsCommand: ItemCommand = {
|
|
|
428
430
|
try {
|
|
429
431
|
await navigator.clipboard.writeText(result.yaml);
|
|
430
432
|
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
detail: `Successfully exported ${result.itemCount} item(s) to clipboard`,
|
|
435
|
-
life: 3000,
|
|
436
|
-
});
|
|
433
|
+
toast.success(
|
|
434
|
+
`Successfully exported ${result.itemCount} item(s) to clipboard`,
|
|
435
|
+
);
|
|
437
436
|
|
|
438
437
|
return true;
|
|
439
438
|
} catch (clipboardError) {
|
|
@@ -469,13 +468,9 @@ export const exportItemsCommand: ItemCommand = {
|
|
|
469
468
|
}
|
|
470
469
|
}
|
|
471
470
|
} catch (error) {
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
detail:
|
|
476
|
-
error instanceof Error ? error.message : "Unknown error occurred",
|
|
477
|
-
life: 5000,
|
|
478
|
-
});
|
|
471
|
+
toast.error(
|
|
472
|
+
error instanceof Error ? error.message : "Unknown error occurred",
|
|
473
|
+
);
|
|
479
474
|
}
|
|
480
475
|
|
|
481
476
|
return false;
|
|
@@ -583,12 +578,7 @@ export const importItemsCommand: ItemCommand = {
|
|
|
583
578
|
const result = response.data;
|
|
584
579
|
|
|
585
580
|
if (result && result.createdItems) {
|
|
586
|
-
|
|
587
|
-
severity: "success",
|
|
588
|
-
summary: "Import Complete",
|
|
589
|
-
detail: `Successfully imported ${result.itemCount} item(s)`,
|
|
590
|
-
life: 3000,
|
|
591
|
-
});
|
|
581
|
+
toast.success(`Successfully imported ${result.itemCount} item(s)`);
|
|
592
582
|
|
|
593
583
|
// Refresh by requesting a refresh
|
|
594
584
|
context.editContext.requestRefresh("immediate");
|
|
@@ -599,12 +589,7 @@ export const importItemsCommand: ItemCommand = {
|
|
|
599
589
|
const errorMessage =
|
|
600
590
|
error instanceof Error ? error.message : "Unknown error occurred";
|
|
601
591
|
|
|
602
|
-
|
|
603
|
-
severity: "error",
|
|
604
|
-
summary: "Import Failed",
|
|
605
|
-
detail: errorMessage,
|
|
606
|
-
life: 5000,
|
|
607
|
-
});
|
|
592
|
+
toast.error(errorMessage);
|
|
608
593
|
|
|
609
594
|
// Handle specific error cases
|
|
610
595
|
if (errorMessage.includes("already exist")) {
|
|
@@ -4,6 +4,7 @@ import { ComponentsDropdown } from "./ComponentsDropdown";
|
|
|
4
4
|
import { TemplateEditor } from "./TemplateEditor";
|
|
5
5
|
import { getSelectedComponents } from "../componentTreeHelper";
|
|
6
6
|
import { useEditContext } from "../client/editContext";
|
|
7
|
+
import { toast } from "sonner";
|
|
7
8
|
import {
|
|
8
9
|
Component,
|
|
9
10
|
loadComponentDetails,
|
|
@@ -34,8 +35,8 @@ export function ComponentEditor({
|
|
|
34
35
|
context.setComponentDesignerComponent(
|
|
35
36
|
await loadComponentDetails(
|
|
36
37
|
component.datasourceItem!.templateId,
|
|
37
|
-
context!.page!.item.id
|
|
38
|
-
)
|
|
38
|
+
context!.page!.item.id,
|
|
39
|
+
),
|
|
39
40
|
);
|
|
40
41
|
// if (component.rendering) {
|
|
41
42
|
// context.setComponentDesignerRendering(
|
|
@@ -57,8 +58,8 @@ export function ComponentEditor({
|
|
|
57
58
|
context.setComponentDesignerComponent(
|
|
58
59
|
await loadComponentDetails(
|
|
59
60
|
context.componentDesignerComponent.templateId,
|
|
60
|
-
context!.page!.item.id
|
|
61
|
-
)
|
|
61
|
+
context!.page!.item.id,
|
|
62
|
+
),
|
|
62
63
|
);
|
|
63
64
|
}
|
|
64
65
|
};
|
|
@@ -66,7 +67,7 @@ export function ComponentEditor({
|
|
|
66
67
|
}, [context.refreshCompletedFlag]);
|
|
67
68
|
|
|
68
69
|
return (
|
|
69
|
-
<div className="flex flex-col
|
|
70
|
+
<div className="flex h-full flex-col">
|
|
70
71
|
<Toolbar>
|
|
71
72
|
<ComponentsDropdown allComponents={allComponents} />{" "}
|
|
72
73
|
<Button
|
|
@@ -78,12 +79,9 @@ export function ComponentEditor({
|
|
|
78
79
|
const save = async () => {
|
|
79
80
|
await saveComponentDetails(
|
|
80
81
|
context.componentDesignerComponent!,
|
|
81
|
-
context.page!.item
|
|
82
|
+
context.page!.item,
|
|
82
83
|
);
|
|
83
|
-
|
|
84
|
-
content: "Component saved",
|
|
85
|
-
severity: "success",
|
|
86
|
-
});
|
|
84
|
+
toast.success("Component saved");
|
|
87
85
|
};
|
|
88
86
|
save();
|
|
89
87
|
}}
|
|
@@ -16,9 +16,11 @@ const RichTextEditorComponent = dynamic(
|
|
|
16
16
|
export function RichTextEditor({
|
|
17
17
|
field,
|
|
18
18
|
readOnly,
|
|
19
|
+
updateFieldValue,
|
|
19
20
|
}: {
|
|
20
21
|
field: RichTextField;
|
|
21
22
|
readOnly?: boolean;
|
|
23
|
+
updateFieldValue?: (value: string) => void;
|
|
22
24
|
}) {
|
|
23
25
|
const profilePath = field.customProperties?.profile;
|
|
24
26
|
|
|
@@ -46,5 +48,12 @@ export function RichTextEditor({
|
|
|
46
48
|
);
|
|
47
49
|
}
|
|
48
50
|
|
|
49
|
-
return
|
|
51
|
+
return (
|
|
52
|
+
<RichTextEditorComponent
|
|
53
|
+
field={field}
|
|
54
|
+
readOnly={readOnly}
|
|
55
|
+
profile={profile}
|
|
56
|
+
updateFieldValue={updateFieldValue}
|
|
57
|
+
/>
|
|
58
|
+
);
|
|
50
59
|
}
|
|
@@ -41,15 +41,18 @@ export function RichTextEditorComponent({
|
|
|
41
41
|
field,
|
|
42
42
|
readOnly,
|
|
43
43
|
profile,
|
|
44
|
+
updateFieldValue,
|
|
44
45
|
}: {
|
|
45
46
|
field: RichTextField;
|
|
46
47
|
readOnly?: boolean;
|
|
47
48
|
profile: RichTextEditorProfile | null;
|
|
49
|
+
updateFieldValue?: (value: string) => void;
|
|
48
50
|
}) {
|
|
49
51
|
const editContextRef = useEditContextRef();
|
|
50
52
|
const modifiedFieldsContext = useModifiedFieldsContext();
|
|
51
53
|
const [focused, setFocused] = useState(false);
|
|
52
54
|
const [value, setValue] = useState(field.value as string);
|
|
55
|
+
const editorRef = useRef<HTMLDivElement>(null);
|
|
53
56
|
|
|
54
57
|
if (!editContextRef.current) return null;
|
|
55
58
|
|
|
@@ -65,24 +68,35 @@ export function RichTextEditorComponent({
|
|
|
65
68
|
);
|
|
66
69
|
|
|
67
70
|
useEffect(() => {
|
|
68
|
-
if
|
|
69
|
-
|
|
70
|
-
|
|
71
|
+
// Only update if the editor is not currently being edited by the user
|
|
72
|
+
const isEditorActive = focused && editorRef.current?.contains(document.activeElement);
|
|
73
|
+
const newValue = field.isHistoric
|
|
74
|
+
? field.value as string
|
|
75
|
+
: modifiedField?.value ?? (field.value as string);
|
|
76
|
+
|
|
77
|
+
if (!isEditorActive && newValue !== value) {
|
|
78
|
+
setValue(newValue);
|
|
71
79
|
}
|
|
72
|
-
}, [field.value, modifiedFieldsContext?.modifiedFields]);
|
|
80
|
+
}, [field.value, modifiedFieldsContext?.modifiedFields, focused]);
|
|
73
81
|
|
|
74
82
|
const debouncedSetFieldvalue = useThrottledCallback((value) => {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
value
|
|
78
|
-
|
|
79
|
-
|
|
83
|
+
if (updateFieldValue) {
|
|
84
|
+
// Use the updateFieldValue prop when provided (WYSIWYG mode)
|
|
85
|
+
updateFieldValue(value);
|
|
86
|
+
} else {
|
|
87
|
+
// Use direct field editing when updateFieldValue is not provided (Editor mode)
|
|
88
|
+
editContextRef.current?.operations.editField({
|
|
89
|
+
field: field.descriptor,
|
|
90
|
+
value: value,
|
|
91
|
+
refresh: "none",
|
|
92
|
+
});
|
|
93
|
+
}
|
|
80
94
|
}, editContextRef.current?.configuration.debounceFieldEditsInterval);
|
|
81
95
|
|
|
82
96
|
const handleChange = (newValue: string) => {
|
|
83
97
|
// Skip empty content patterns for both paragraph and no-tag blocks
|
|
84
98
|
if ((newValue === "<p><br></p>" || newValue === "<br>" || newValue === "") && !field.value) return;
|
|
85
|
-
if (newValue !== value &&
|
|
99
|
+
if (newValue !== value && !readOnly) {
|
|
86
100
|
setValue(newValue);
|
|
87
101
|
debouncedSetFieldvalue(newValue);
|
|
88
102
|
}
|
|
@@ -95,7 +109,7 @@ export function RichTextEditorComponent({
|
|
|
95
109
|
// console.log(editorProfile);
|
|
96
110
|
|
|
97
111
|
return (
|
|
98
|
-
<div>
|
|
112
|
+
<div ref={editorRef}>
|
|
99
113
|
<ReactSlate
|
|
100
114
|
value={value}
|
|
101
115
|
onChange={handleChange}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
.editor-dropdown {
|
|
2
|
+
position: relative;
|
|
3
|
+
display: inline-block;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
.editor-dropdown-button {
|
|
7
|
+
padding: 5px 8px;
|
|
8
|
+
background: transparent;
|
|
9
|
+
border: 1px solid #ddd;
|
|
10
|
+
border-radius: 3px;
|
|
11
|
+
cursor: pointer;
|
|
12
|
+
display: flex;
|
|
13
|
+
align-items: center;
|
|
14
|
+
min-width: 60px;
|
|
15
|
+
justify-content: space-between;
|
|
16
|
+
font-size: 13px;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.editor-dropdown-button-content {
|
|
20
|
+
display: flex;
|
|
21
|
+
align-items: center;
|
|
22
|
+
overflow: hidden;
|
|
23
|
+
text-overflow: ellipsis;
|
|
24
|
+
white-space: nowrap;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.editor-dropdown-button-icon {
|
|
28
|
+
margin-right: 8px;
|
|
29
|
+
flex-shrink: 0;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.editor-dropdown-button-text {
|
|
33
|
+
overflow: hidden;
|
|
34
|
+
text-overflow: ellipsis;
|
|
35
|
+
white-space: nowrap;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.editor-dropdown-button-arrow {
|
|
39
|
+
margin-left: 5px;
|
|
40
|
+
flex-shrink: 0;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.editor-dropdown-menu {
|
|
44
|
+
position: absolute;
|
|
45
|
+
top: 100%;
|
|
46
|
+
left: 0;
|
|
47
|
+
z-index: 1000;
|
|
48
|
+
background: white;
|
|
49
|
+
border: 1px solid #ddd;
|
|
50
|
+
border-radius: 3px;
|
|
51
|
+
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.editor-dropdown-option {
|
|
55
|
+
padding: 8px 12px;
|
|
56
|
+
cursor: pointer;
|
|
57
|
+
background-color: transparent;
|
|
58
|
+
font-weight: normal;
|
|
59
|
+
display: flex;
|
|
60
|
+
align-items: center;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.editor-dropdown-option:hover {
|
|
64
|
+
background-color: #f5f5f5;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.editor-dropdown-option.active {
|
|
68
|
+
background-color: #f0f0f0;
|
|
69
|
+
font-weight: bold;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.editor-dropdown-option-icon {
|
|
73
|
+
margin-right: 8px;
|
|
74
|
+
flex-shrink: 0;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.editor-dropdown-option-text {
|
|
78
|
+
overflow: hidden;
|
|
79
|
+
text-overflow: ellipsis;
|
|
80
|
+
white-space: nowrap;
|
|
81
|
+
}
|