@alpaca-editor/core 1.0.4014 → 1.0.4017
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/calendar.js +2 -6
- package/dist/components/ui/calendar.js.map +1 -1
- package/dist/components/ui/card.d.ts +2 -1
- package/dist/components/ui/card.js +2 -2
- package/dist/components/ui/card.js.map +1 -1
- package/dist/components/ui/copy-button.js +31 -3
- package/dist/components/ui/copy-button.js.map +1 -1
- package/dist/components/ui/popover.js +6 -3
- package/dist/components/ui/popover.js.map +1 -1
- package/dist/config/config.js +20 -13
- package/dist/config/config.js.map +1 -1
- package/dist/editor/FieldList.js +1 -1
- package/dist/editor/FieldList.js.map +1 -1
- package/dist/editor/FieldListField.js +1 -1
- package/dist/editor/FieldListField.js.map +1 -1
- package/dist/editor/ScrollingContentTree.d.ts +2 -1
- package/dist/editor/ScrollingContentTree.js +2 -2
- package/dist/editor/ScrollingContentTree.js.map +1 -1
- package/dist/editor/client/editContext.d.ts +1 -0
- package/dist/editor/client/editContext.js.map +1 -1
- package/dist/editor/client/itemsRepository.d.ts +2 -2
- package/dist/editor/client/itemsRepository.js +15 -5
- package/dist/editor/client/itemsRepository.js.map +1 -1
- package/dist/editor/client/operations.js +18 -6
- package/dist/editor/client/operations.js.map +1 -1
- package/dist/editor/client/pageModelBuilder.js +2 -1
- package/dist/editor/client/pageModelBuilder.js.map +1 -1
- package/dist/editor/context-menu/InsertMenu.js +45 -12
- package/dist/editor/context-menu/InsertMenu.js.map +1 -1
- package/dist/editor/field-types/DateFieldEditor.js +1 -1
- package/dist/editor/field-types/DateFieldEditor.js.map +1 -1
- package/dist/editor/field-types/DateTimeFieldEditor.d.ts +5 -0
- package/dist/editor/field-types/DateTimeFieldEditor.js +151 -0
- package/dist/editor/field-types/DateTimeFieldEditor.js.map +1 -0
- package/dist/editor/field-types/InternalLinkFieldEditor.js +1 -1
- package/dist/editor/field-types/InternalLinkFieldEditor.js.map +1 -1
- package/dist/editor/field-types/TreeListEditor.js +17 -6
- package/dist/editor/field-types/TreeListEditor.js.map +1 -1
- package/dist/editor/fieldTypes.d.ts +6 -0
- package/dist/editor/menubar/ToolbarFactory.js +1 -1
- package/dist/editor/menubar/ToolbarFactory.js.map +1 -1
- package/dist/editor/menubar/toolbar-sections/EditControls.d.ts +7 -1
- package/dist/editor/menubar/toolbar-sections/EditControls.js +2 -2
- package/dist/editor/menubar/toolbar-sections/EditControls.js.map +1 -1
- package/dist/editor/page-viewer/EditorForm.js +3 -1
- package/dist/editor/page-viewer/EditorForm.js.map +1 -1
- package/dist/editor/page-viewer/PageViewer.d.ts +2 -1
- package/dist/editor/page-viewer/PageViewer.js +7 -5
- package/dist/editor/page-viewer/PageViewer.js.map +1 -1
- package/dist/editor/page-viewer/PageViewerFrame.d.ts +2 -1
- package/dist/editor/page-viewer/PageViewerFrame.js +3 -2
- package/dist/editor/page-viewer/PageViewerFrame.js.map +1 -1
- package/dist/editor/sidebar/ComponentPalette.js +28 -1
- package/dist/editor/sidebar/ComponentPalette.js.map +1 -1
- package/dist/editor/sidebar/Debug.js +13 -3
- package/dist/editor/sidebar/Debug.js.map +1 -1
- package/dist/editor/ui/ItemSearch.d.ts +1 -0
- package/dist/editor/ui/ItemSearch.js +5 -5
- package/dist/editor/ui/ItemSearch.js.map +1 -1
- package/dist/editor/ui/SimpleTabs.d.ts +2 -1
- package/dist/editor/ui/SimpleTabs.js +8 -7
- package/dist/editor/ui/SimpleTabs.js.map +1 -1
- package/dist/editor/ui/Spinner.d.ts +1 -1
- package/dist/page-wizard/WizardSteps.js +5 -4
- package/dist/page-wizard/WizardSteps.js.map +1 -1
- package/dist/page-wizard/steps/CollectStep.js +1 -1
- package/dist/page-wizard/steps/CollectStep.js.map +1 -1
- package/dist/page-wizard/steps/ContentStep.js +4 -3
- package/dist/page-wizard/steps/ContentStep.js.map +1 -1
- package/dist/page-wizard/steps/FindItemsStep.js +2 -13
- package/dist/page-wizard/steps/FindItemsStep.js.map +1 -1
- package/dist/page-wizard/steps/usePageCreator.js +2 -4
- package/dist/page-wizard/steps/usePageCreator.js.map +1 -1
- package/dist/revision.d.ts +2 -2
- package/dist/revision.js +2 -2
- package/dist/styles.css +357 -60
- package/package.json +1 -1
- package/src/components/ui/calendar.tsx +2 -18
- package/src/components/ui/card.tsx +5 -0
- package/src/components/ui/copy-button.tsx +32 -3
- package/src/components/ui/popover.tsx +6 -3
- package/src/config/config.tsx +21 -14
- package/src/editor/FieldList.tsx +1 -1
- package/src/editor/FieldListField.tsx +1 -1
- package/src/editor/ScrollingContentTree.tsx +3 -0
- package/src/editor/client/editContext.ts +1 -0
- package/src/editor/client/itemsRepository.ts +25 -7
- package/src/editor/client/operations.ts +19 -5
- package/src/editor/client/pageModelBuilder.ts +1 -1
- package/src/editor/context-menu/InsertMenu.tsx +77 -30
- package/src/editor/field-types/DateFieldEditor.tsx +8 -2
- package/src/editor/field-types/DateTimeFieldEditor.tsx +281 -0
- package/src/editor/field-types/InternalLinkFieldEditor.tsx +1 -1
- package/src/editor/field-types/TreeListEditor.tsx +41 -8
- package/src/editor/fieldTypes.ts +8 -0
- package/src/editor/menubar/ToolbarFactory.tsx +2 -1
- package/src/editor/menubar/toolbar-sections/EditControls.tsx +37 -23
- package/src/editor/page-editor-chrome/PlaceholderDropZone.tsx +1 -1
- package/src/editor/page-viewer/EditorForm.tsx +3 -1
- package/src/editor/page-viewer/PageViewer.tsx +18 -15
- package/src/editor/page-viewer/PageViewerFrame.tsx +11 -2
- package/src/editor/sidebar/ComponentPalette.tsx +36 -1
- package/src/editor/sidebar/Debug.tsx +14 -6
- package/src/editor/ui/ItemSearch.tsx +6 -3
- package/src/editor/ui/SimpleTabs.tsx +10 -1
- package/src/editor/ui/Spinner.tsx +1 -1
- package/src/page-wizard/WizardSteps.tsx +2 -3
- package/src/page-wizard/steps/CollectStep.tsx +1 -1
- package/src/page-wizard/steps/ContentStep.tsx +18 -12
- package/src/page-wizard/steps/FindItemsStep.tsx +1 -50
- package/src/page-wizard/steps/usePageCreator.ts +2 -3
- package/src/revision.ts +2 -2
- package/styles.css +1 -0
package/src/config/config.tsx
CHANGED
|
@@ -16,6 +16,7 @@ import { DropListEditor } from "../editor/field-types/DropListEditor";
|
|
|
16
16
|
import { RawEditor } from "../editor/field-types/RawEditor";
|
|
17
17
|
import { CheckboxEditor } from "../editor/field-types/CheckboxEditor";
|
|
18
18
|
import { DateFieldEditor } from "../editor/field-types/DateFieldEditor";
|
|
19
|
+
import { DateTimeFieldEditor } from "../editor/field-types/DateTimeFieldEditor";
|
|
19
20
|
|
|
20
21
|
import { ItemLocked } from "../editor/editor-warnings/ItemLocked";
|
|
21
22
|
import { NoWriteAccess } from "../editor/editor-warnings/NoWriteAccess";
|
|
@@ -116,6 +117,7 @@ import {
|
|
|
116
117
|
Bug,
|
|
117
118
|
Timer,
|
|
118
119
|
WandSparkles,
|
|
120
|
+
BadgeCheck,
|
|
119
121
|
} from "lucide-react";
|
|
120
122
|
|
|
121
123
|
import { Completions } from "../editor/sidebar/Completions";
|
|
@@ -284,6 +286,9 @@ export const getConfiguration = (): EditorConfiguration => {
|
|
|
284
286
|
date: {
|
|
285
287
|
editor: DateFieldEditor,
|
|
286
288
|
},
|
|
289
|
+
datetime: {
|
|
290
|
+
editor: DateTimeFieldEditor,
|
|
291
|
+
},
|
|
287
292
|
droptree: {
|
|
288
293
|
editor: InternalLinkFieldEditor,
|
|
289
294
|
},
|
|
@@ -499,8 +504,8 @@ export const getConfiguration = (): EditorConfiguration => {
|
|
|
499
504
|
...pageEditorViewBase,
|
|
500
505
|
},
|
|
501
506
|
{
|
|
502
|
-
name: "
|
|
503
|
-
title: "
|
|
507
|
+
name: "comments",
|
|
508
|
+
title: "Comments",
|
|
504
509
|
icon: <MessageCircleMore strokeWidth={1} />,
|
|
505
510
|
leftSidebar: {
|
|
506
511
|
panels: [
|
|
@@ -509,15 +514,25 @@ export const getConfiguration = (): EditorConfiguration => {
|
|
|
509
514
|
icon: "pi pi-comments",
|
|
510
515
|
title: "Comments & Suggestions",
|
|
511
516
|
content: <Comments />,
|
|
512
|
-
initialSize:
|
|
517
|
+
initialSize: 100,
|
|
513
518
|
noOverflow: true,
|
|
514
519
|
},
|
|
520
|
+
],
|
|
521
|
+
},
|
|
522
|
+
...pageEditorViewBase,
|
|
523
|
+
},
|
|
524
|
+
{
|
|
525
|
+
name: "reviews",
|
|
526
|
+
title: "Reviews",
|
|
527
|
+
icon: <BadgeCheck strokeWidth={1} />,
|
|
528
|
+
leftSidebar: {
|
|
529
|
+
panels: [
|
|
515
530
|
{
|
|
516
531
|
name: "reviews",
|
|
517
|
-
|
|
532
|
+
|
|
518
533
|
title: "Reviews",
|
|
519
534
|
content: <Reviews />,
|
|
520
|
-
initialSize:
|
|
535
|
+
initialSize: 100,
|
|
521
536
|
noOverflow: true,
|
|
522
537
|
},
|
|
523
538
|
],
|
|
@@ -947,18 +962,10 @@ export function configureForUser(
|
|
|
947
962
|
editor: {
|
|
948
963
|
...configuration.editor,
|
|
949
964
|
views: configuration.editor.views
|
|
950
|
-
.filter((x) => x.name === "reviews")
|
|
965
|
+
.filter((x) => x.name === "comments" || x.name === "reviews")
|
|
951
966
|
.map((x) => {
|
|
952
967
|
return {
|
|
953
968
|
...x,
|
|
954
|
-
leftSidebar: {
|
|
955
|
-
...x.leftSidebar,
|
|
956
|
-
panels: [
|
|
957
|
-
...(x.leftSidebar?.panels ?? []).filter(
|
|
958
|
-
(x) => x.name !== "reviews",
|
|
959
|
-
),
|
|
960
|
-
],
|
|
961
|
-
},
|
|
962
969
|
toolbarFactory: previewToolbar,
|
|
963
970
|
};
|
|
964
971
|
}),
|
package/src/editor/FieldList.tsx
CHANGED
|
@@ -55,7 +55,7 @@ export function FieldList({
|
|
|
55
55
|
|
|
56
56
|
return (
|
|
57
57
|
<div className="text-dark">
|
|
58
|
-
<div className="tour-field-list sticky top-0 z-10
|
|
58
|
+
<div className="tour-field-list sticky top-0 z-10 flex items-center gap-2 border-b border-gray-200 bg-white p-2">
|
|
59
59
|
<FilterInput
|
|
60
60
|
className="flex-1"
|
|
61
61
|
value={searchFilter}
|
|
@@ -402,7 +402,7 @@ export default function FieldListField({
|
|
|
402
402
|
<span className="font-medium">Field JSON</span>
|
|
403
403
|
<CopyButton textToCopy={JSON.stringify(field, null, 2)} />
|
|
404
404
|
</div>
|
|
405
|
-
<pre className="max-h-40 overflow-auto text-xs whitespace-pre-wrap">
|
|
405
|
+
<pre className="max-h-40 overflow-auto text-xs whitespace-pre-wrap select-text">
|
|
406
406
|
{JSON.stringify(field, null, 2)}
|
|
407
407
|
</pre>
|
|
408
408
|
</div>
|
|
@@ -10,12 +10,14 @@ export function ScrollingContentTree({
|
|
|
10
10
|
selectedItemId,
|
|
11
11
|
onSelectionChange,
|
|
12
12
|
rootItemId,
|
|
13
|
+
rootItemIds,
|
|
13
14
|
expandedItemId,
|
|
14
15
|
scrollToSelected = true,
|
|
15
16
|
}: {
|
|
16
17
|
selectedItemId?: string;
|
|
17
18
|
onSelectionChange?: (itemIds: ItemTreeNodeData[]) => void;
|
|
18
19
|
rootItemId?: string;
|
|
20
|
+
rootItemIds?: string[];
|
|
19
21
|
expandedItemId?: string;
|
|
20
22
|
scrollToSelected?: boolean;
|
|
21
23
|
}) {
|
|
@@ -62,6 +64,7 @@ export function ScrollingContentTree({
|
|
|
62
64
|
<ContentTree
|
|
63
65
|
language={editContext!.currentItemDescriptor?.language ?? "en"}
|
|
64
66
|
rootItemId={rootItemId ?? contentItemId}
|
|
67
|
+
rootItemIds={rootItemIds}
|
|
65
68
|
expandIdPath={expandedItem?.idPath}
|
|
66
69
|
selectedItemIds={selectedItemIds}
|
|
67
70
|
selectionMode="single"
|
|
@@ -31,11 +31,15 @@ export type ItemsRepository = {
|
|
|
31
31
|
isDirty: boolean,
|
|
32
32
|
value: any | null,
|
|
33
33
|
rawValue?: string | null,
|
|
34
|
-
) =>
|
|
34
|
+
) => Promise<number>;
|
|
35
35
|
|
|
36
36
|
refreshItems: (items: ItemDescriptor[]) => Promise<void>;
|
|
37
37
|
revision: number;
|
|
38
|
-
onFieldSaved: (
|
|
38
|
+
onFieldSaved: (
|
|
39
|
+
field: FieldDescriptor,
|
|
40
|
+
value: string | null,
|
|
41
|
+
saveSequence: number,
|
|
42
|
+
) => void;
|
|
39
43
|
onItemsDeleted: (items: DeletedItem[]) => void;
|
|
40
44
|
//addToModifiedFields: (fieldDescriptors: FieldDescriptor[]) => void;
|
|
41
45
|
subscribeItemsChanged: (
|
|
@@ -101,6 +105,7 @@ export function useItemsRepository(
|
|
|
101
105
|
);
|
|
102
106
|
const pendingRequests = useRef<Map<string, Promise<void>>>(new Map());
|
|
103
107
|
const pendingStubsRequests = useRef<Map<string, Promise<void>>>(new Map());
|
|
108
|
+
const saveSequenceCounter = useRef<number>(0);
|
|
104
109
|
|
|
105
110
|
const [revision, setRevision] = useState(0);
|
|
106
111
|
const itemsChangedListeners = useRef<Set<(changes: ItemChange[]) => void>>(
|
|
@@ -366,10 +371,10 @@ export function useItemsRepository(
|
|
|
366
371
|
rawValue?: string | null,
|
|
367
372
|
) => {
|
|
368
373
|
const item = await getItem(field.item);
|
|
369
|
-
if (!item) return;
|
|
374
|
+
if (!item) return 0;
|
|
370
375
|
|
|
371
376
|
const fieldToUpdate = item.fields.find((x) => x.id === field.fieldId);
|
|
372
|
-
if (!fieldToUpdate) return;
|
|
377
|
+
if (!fieldToUpdate) return 0;
|
|
373
378
|
|
|
374
379
|
// Update the field value in the item copy
|
|
375
380
|
const updatedItem = {
|
|
@@ -387,8 +392,10 @@ export function useItemsRepository(
|
|
|
387
392
|
|
|
388
393
|
itemsMap.current.set(generateKey(field.item), updatedItem);
|
|
389
394
|
|
|
395
|
+
const val = rawValue !== undefined ? rawValue : value;
|
|
396
|
+
const currentSaveSequence = ++saveSequenceCounter.current;
|
|
397
|
+
|
|
390
398
|
setModifiedFields((prevModifiedFields) => {
|
|
391
|
-
const val = rawValue !== undefined ? rawValue : value;
|
|
392
399
|
const modifiedField = prevModifiedFields.find(
|
|
393
400
|
(x) =>
|
|
394
401
|
x.fieldId === field.fieldId &&
|
|
@@ -405,6 +412,7 @@ export function useItemsRepository(
|
|
|
405
412
|
isDirty: isDirty,
|
|
406
413
|
modifiedBy: user,
|
|
407
414
|
timestamp: Date.now(),
|
|
415
|
+
saveSequence: currentSaveSequence,
|
|
408
416
|
},
|
|
409
417
|
];
|
|
410
418
|
} else {
|
|
@@ -412,6 +420,7 @@ export function useItemsRepository(
|
|
|
412
420
|
modifiedField.value = val;
|
|
413
421
|
modifiedField.modifiedBy = user;
|
|
414
422
|
modifiedField.timestamp = Date.now();
|
|
423
|
+
modifiedField.saveSequence = currentSaveSequence;
|
|
415
424
|
}
|
|
416
425
|
|
|
417
426
|
return [...prevModifiedFields];
|
|
@@ -432,6 +441,7 @@ export function useItemsRepository(
|
|
|
432
441
|
});
|
|
433
442
|
|
|
434
443
|
// setRevision((prev) => prev + 1);
|
|
444
|
+
return currentSaveSequence;
|
|
435
445
|
},
|
|
436
446
|
[getItem, setModifiedFields, setLastEditedFields],
|
|
437
447
|
);
|
|
@@ -510,7 +520,7 @@ export function useItemsRepository(
|
|
|
510
520
|
);
|
|
511
521
|
|
|
512
522
|
const onFieldSaved = useCallback(
|
|
513
|
-
(field: FieldDescriptor, value: string | null) => {
|
|
523
|
+
(field: FieldDescriptor, value: string | null, saveSequence: number) => {
|
|
514
524
|
setModifiedFields((prevModifiedFields) => {
|
|
515
525
|
const modifiedField = prevModifiedFields.find(
|
|
516
526
|
(x) =>
|
|
@@ -520,7 +530,15 @@ export function useItemsRepository(
|
|
|
520
530
|
x.item.version === field.item.version,
|
|
521
531
|
);
|
|
522
532
|
if (modifiedField) {
|
|
523
|
-
if
|
|
533
|
+
// Only mark as not dirty if this save operation corresponds to the most recent edit
|
|
534
|
+
// or if the value matches and this is the latest save operation
|
|
535
|
+
if (
|
|
536
|
+
modifiedField.saveSequence === saveSequence ||
|
|
537
|
+
(modifiedField.value === value &&
|
|
538
|
+
modifiedField.saveSequence <= saveSequence)
|
|
539
|
+
) {
|
|
540
|
+
modifiedField.isDirty = false;
|
|
541
|
+
}
|
|
524
542
|
return [...prevModifiedFields];
|
|
525
543
|
}
|
|
526
544
|
return prevModifiedFields;
|
|
@@ -344,7 +344,7 @@ export function getOperationsContext(
|
|
|
344
344
|
return;
|
|
345
345
|
}
|
|
346
346
|
|
|
347
|
-
state.itemsRepository.updateFieldValue(
|
|
347
|
+
const saveSequence = await state.itemsRepository.updateFieldValue(
|
|
348
348
|
field,
|
|
349
349
|
state.user ?? { name: "unknown", ai: false },
|
|
350
350
|
true,
|
|
@@ -353,7 +353,13 @@ export function getOperationsContext(
|
|
|
353
353
|
);
|
|
354
354
|
|
|
355
355
|
if (refresh === "immediate") {
|
|
356
|
-
return editFieldImmediate({
|
|
356
|
+
return editFieldImmediate({
|
|
357
|
+
field,
|
|
358
|
+
value,
|
|
359
|
+
rawValue,
|
|
360
|
+
refresh,
|
|
361
|
+
saveSequence,
|
|
362
|
+
});
|
|
357
363
|
}
|
|
358
364
|
if (
|
|
359
365
|
lastEditField.current?.fieldId !== field.fieldId ||
|
|
@@ -382,11 +388,13 @@ export function getOperationsContext(
|
|
|
382
388
|
value,
|
|
383
389
|
rawValue,
|
|
384
390
|
refresh = "immediate",
|
|
391
|
+
saveSequence,
|
|
385
392
|
}: {
|
|
386
393
|
field: FieldDescriptor;
|
|
387
394
|
value?: string;
|
|
388
395
|
rawValue?: string | null;
|
|
389
396
|
refresh?: "none" | "immediate" | "delayed" | "waitForQuietPeriod";
|
|
397
|
+
saveSequence?: number;
|
|
390
398
|
}): Promise<void> => {
|
|
391
399
|
// state.itemsRepository.updateFieldValue(
|
|
392
400
|
// field,
|
|
@@ -404,7 +412,7 @@ export function getOperationsContext(
|
|
|
404
412
|
if (op) {
|
|
405
413
|
await executeOp(op, { refresh });
|
|
406
414
|
await state.itemsRepository.refreshItems([field.item]);
|
|
407
|
-
state.itemsRepository.onFieldSaved(field, val);
|
|
415
|
+
state.itemsRepository.onFieldSaved(field, val, saveSequence || 0);
|
|
408
416
|
}
|
|
409
417
|
},
|
|
410
418
|
[state.itemsRepository, executeOp],
|
|
@@ -422,14 +430,20 @@ export function getOperationsContext(
|
|
|
422
430
|
rawValue?: string | null;
|
|
423
431
|
refresh?: "none" | "immediate" | "delayed" | "waitForQuietPeriod";
|
|
424
432
|
}) => {
|
|
425
|
-
state.itemsRepository.updateFieldValue(
|
|
433
|
+
const saveSequence = await state.itemsRepository.updateFieldValue(
|
|
426
434
|
field,
|
|
427
435
|
state.user ?? { name: "unknown", ai: false },
|
|
428
436
|
true,
|
|
429
437
|
value,
|
|
430
438
|
rawValue,
|
|
431
439
|
);
|
|
432
|
-
return editFieldImmediate({
|
|
440
|
+
return editFieldImmediate({
|
|
441
|
+
field,
|
|
442
|
+
value,
|
|
443
|
+
rawValue,
|
|
444
|
+
refresh,
|
|
445
|
+
saveSequence,
|
|
446
|
+
});
|
|
433
447
|
},
|
|
434
448
|
state.configuration.debounceFieldEditsInterval * 2,
|
|
435
449
|
{ trailing: true },
|
|
@@ -31,24 +31,42 @@ export const InsertMenuTemplate = ({
|
|
|
31
31
|
}, [activeTab]);
|
|
32
32
|
|
|
33
33
|
const [recentTemplates, setRecentTemplates] = useState<string[]>([]);
|
|
34
|
-
|
|
35
34
|
const [recentItems, setRecentItems] = useState<FullItem[]>([]);
|
|
36
35
|
const [hoveredItem, setHoveredItem] = useState<ResultItem>();
|
|
37
36
|
const [wizards, setWizards] = useState<Wizard[]>([]);
|
|
38
37
|
|
|
38
|
+
// Loading states
|
|
39
|
+
const [isLoadingRecent, setIsLoadingRecent] = useState(false);
|
|
40
|
+
const [isLoadingWizards, setIsLoadingWizards] = useState(false);
|
|
41
|
+
|
|
39
42
|
const hideTimeoutRef = useRef<NodeJS.Timeout>(undefined);
|
|
40
43
|
const opRef = useRef<HTMLDivElement>(null);
|
|
44
|
+
|
|
41
45
|
useEffect(() => {
|
|
42
46
|
const loadRecentItems = async () => {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
47
|
+
if (recentTemplates.length === 0) return;
|
|
48
|
+
|
|
49
|
+
setIsLoadingRecent(true);
|
|
50
|
+
try {
|
|
51
|
+
const items = await editContext?.itemsRepository.getItems(
|
|
52
|
+
recentTemplates.map((id) => ({
|
|
53
|
+
id,
|
|
54
|
+
version: 0,
|
|
55
|
+
language: "en",
|
|
56
|
+
})),
|
|
57
|
+
);
|
|
50
58
|
|
|
51
|
-
|
|
59
|
+
if (items) {
|
|
60
|
+
// Remove duplicates based on item.id to prevent React key conflicts
|
|
61
|
+
const uniqueItems = items.filter(
|
|
62
|
+
(item, index, self) =>
|
|
63
|
+
self.findIndex((i) => i.id === item.id) === index,
|
|
64
|
+
);
|
|
65
|
+
setRecentItems(uniqueItems);
|
|
66
|
+
}
|
|
67
|
+
} finally {
|
|
68
|
+
setIsLoadingRecent(false);
|
|
69
|
+
}
|
|
52
70
|
};
|
|
53
71
|
loadRecentItems();
|
|
54
72
|
}, [recentTemplates]);
|
|
@@ -57,16 +75,37 @@ export const InsertMenuTemplate = ({
|
|
|
57
75
|
const stored = localStorage.getItem("editor.recentTemplates");
|
|
58
76
|
if (stored) {
|
|
59
77
|
const parsed = JSON.parse(stored);
|
|
60
|
-
|
|
78
|
+
// Ensure the parsed data is a string array and remove duplicates
|
|
79
|
+
const templateIds = Array.isArray(parsed)
|
|
80
|
+
? parsed.filter((id): id is string => typeof id === "string")
|
|
81
|
+
: [];
|
|
82
|
+
const uniqueTemplates = [...new Set(templateIds)];
|
|
83
|
+
setRecentTemplates(uniqueTemplates);
|
|
84
|
+
|
|
85
|
+
// Update localStorage if duplicates were found or invalid data was cleaned
|
|
86
|
+
if (
|
|
87
|
+
uniqueTemplates.length !== templateIds.length ||
|
|
88
|
+
templateIds.length !== parsed.length
|
|
89
|
+
) {
|
|
90
|
+
localStorage.setItem(
|
|
91
|
+
"editor.recentTemplates",
|
|
92
|
+
JSON.stringify(uniqueTemplates),
|
|
93
|
+
);
|
|
94
|
+
}
|
|
61
95
|
}
|
|
62
96
|
}, [insertOptions]);
|
|
63
97
|
|
|
64
98
|
useEffect(() => {
|
|
65
99
|
const loadWizards = async () => {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
100
|
+
setIsLoadingWizards(true);
|
|
101
|
+
try {
|
|
102
|
+
const wizards = await editContext?.configuration.pageWizard.getWizards(
|
|
103
|
+
item.descriptor,
|
|
104
|
+
);
|
|
105
|
+
setWizards(wizards ?? []);
|
|
106
|
+
} finally {
|
|
107
|
+
setIsLoadingWizards(false);
|
|
108
|
+
}
|
|
70
109
|
};
|
|
71
110
|
loadWizards();
|
|
72
111
|
}, [item]);
|
|
@@ -106,21 +145,26 @@ export const InsertMenuTemplate = ({
|
|
|
106
145
|
const options =
|
|
107
146
|
insertOptions.length === 0
|
|
108
147
|
? undefined
|
|
109
|
-
: insertOptions
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
148
|
+
: insertOptions
|
|
149
|
+
.filter(
|
|
150
|
+
(x, index, self) =>
|
|
151
|
+
self.findIndex((item) => item.id === x.id) === index,
|
|
152
|
+
) // Remove duplicates
|
|
153
|
+
.map((x) => ({
|
|
154
|
+
label: x.name,
|
|
155
|
+
id: x.id,
|
|
156
|
+
icon: (
|
|
157
|
+
<img
|
|
158
|
+
className="p-menuitem-icon"
|
|
159
|
+
src={x.icon}
|
|
160
|
+
style={{ height: "16px" }}
|
|
161
|
+
width="16"
|
|
162
|
+
height="16"
|
|
163
|
+
onDragStart={(e) => e.preventDefault()}
|
|
164
|
+
></img>
|
|
165
|
+
),
|
|
166
|
+
command: getCommand(x),
|
|
167
|
+
}));
|
|
124
168
|
|
|
125
169
|
const tabs: Tab[] = [
|
|
126
170
|
{
|
|
@@ -283,6 +327,8 @@ export const InsertMenuTemplate = ({
|
|
|
283
327
|
});
|
|
284
328
|
}
|
|
285
329
|
|
|
330
|
+
const isAnyTabLoading = isLoadingRecent || isLoadingWizards;
|
|
331
|
+
|
|
286
332
|
return (
|
|
287
333
|
<div
|
|
288
334
|
className="p-2"
|
|
@@ -331,7 +377,8 @@ export const InsertMenuTemplate = ({
|
|
|
331
377
|
tabs={tabs}
|
|
332
378
|
setActiveTab={setActiveTab}
|
|
333
379
|
activeTab={activeTab}
|
|
334
|
-
|
|
380
|
+
isLoading={isAnyTabLoading}
|
|
381
|
+
/>
|
|
335
382
|
</div>
|
|
336
383
|
</div>
|
|
337
384
|
</div>
|
|
@@ -109,7 +109,7 @@ export function DateFieldEditor({
|
|
|
109
109
|
};
|
|
110
110
|
|
|
111
111
|
return (
|
|
112
|
-
<Popover>
|
|
112
|
+
<Popover enableIframeClickDetection={false}>
|
|
113
113
|
<PopoverTrigger asChild>
|
|
114
114
|
<Button
|
|
115
115
|
variant="outline"
|
|
@@ -125,7 +125,13 @@ export function DateFieldEditor({
|
|
|
125
125
|
</Button>
|
|
126
126
|
</PopoverTrigger>
|
|
127
127
|
<PopoverContent className="w-auto p-0" align="start">
|
|
128
|
-
<
|
|
128
|
+
<div
|
|
129
|
+
className="p-3"
|
|
130
|
+
onMouseDown={(e) => e.stopPropagation()}
|
|
131
|
+
onClick={(e) => e.stopPropagation()}
|
|
132
|
+
>
|
|
133
|
+
<Calendar mode="single" selected={date} onSelect={handleDateSelect} />
|
|
134
|
+
</div>
|
|
129
135
|
</PopoverContent>
|
|
130
136
|
</Popover>
|
|
131
137
|
);
|