@alpaca-editor/core 1.0.3938 → 1.0.3939
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/editor/ContentTree.js +12 -8
- package/dist/editor/ContentTree.js.map +1 -1
- package/dist/editor/ContextMenu.d.ts +1 -1
- package/dist/editor/ContextMenu.js +17 -3
- package/dist/editor/ContextMenu.js.map +1 -1
- package/dist/editor/FieldActionsOverlay.d.ts +17 -0
- package/dist/editor/FieldActionsOverlay.js +148 -0
- package/dist/editor/FieldActionsOverlay.js.map +1 -0
- package/dist/editor/FieldHistory.d.ts +2 -1
- package/dist/editor/FieldHistory.js +11 -8
- package/dist/editor/FieldHistory.js.map +1 -1
- package/dist/editor/FieldListField.js +14 -17
- package/dist/editor/FieldListField.js.map +1 -1
- package/dist/editor/PictureEditor.js +28 -2
- package/dist/editor/PictureEditor.js.map +1 -1
- package/dist/editor/Titlebar.js +18 -9
- package/dist/editor/Titlebar.js.map +1 -1
- package/dist/editor/ai/AiTerminal.js +27 -41
- package/dist/editor/ai/AiTerminal.js.map +1 -1
- package/dist/editor/client/EditorClient.js +48 -18
- package/dist/editor/client/EditorClient.js.map +1 -1
- package/dist/editor/client/editContext.d.ts +1 -1
- package/dist/editor/client/editContext.js.map +1 -1
- package/dist/editor/client/itemsRepository.js +126 -90
- package/dist/editor/client/itemsRepository.js.map +1 -1
- package/dist/editor/menubar/BrowseHistory.js +3 -4
- package/dist/editor/menubar/BrowseHistory.js.map +1 -1
- package/dist/editor/menubar/PageSelector.js +37 -9
- package/dist/editor/menubar/PageSelector.js.map +1 -1
- package/dist/editor/page-editor-chrome/FieldActionIndicator.js +1 -1
- package/dist/editor/page-editor-chrome/FieldActionIndicator.js.map +1 -1
- package/dist/editor/page-viewer/PageViewerFrame.js +98 -2
- package/dist/editor/page-viewer/PageViewerFrame.js.map +1 -1
- package/dist/editor/pageModel.d.ts +14 -0
- package/dist/editor/reviews/Comment.js +3 -2
- package/dist/editor/reviews/Comment.js.map +1 -1
- package/dist/editor/services/editService.d.ts +1 -1
- package/dist/editor/services/editService.js +2 -1
- package/dist/editor/services/editService.js.map +1 -1
- package/dist/editor/ui/Icons.js +1 -1
- package/dist/editor/ui/Icons.js.map +1 -1
- package/dist/editor/ui/ItemList.d.ts +16 -0
- package/dist/editor/ui/ItemList.js +19 -0
- package/dist/editor/ui/ItemList.js.map +1 -0
- package/dist/editor/ui/ItemSearch.js +2 -12
- package/dist/editor/ui/ItemSearch.js.map +1 -1
- package/dist/editor/ui/SimpleTabs.js +1 -1
- package/dist/editor/ui/SimpleTabs.js.map +1 -1
- package/dist/revision.d.ts +2 -2
- package/dist/revision.js +2 -2
- package/dist/styles.css +3 -8
- package/package.json +1 -1
- package/src/editor/ContentTree.tsx +15 -12
- package/src/editor/ContextMenu.tsx +20 -2
- package/src/editor/FieldActionsOverlay.tsx +307 -0
- package/src/editor/FieldHistory.tsx +9 -8
- package/src/editor/FieldListField.tsx +29 -29
- package/src/editor/PictureEditor.tsx +66 -1
- package/src/editor/Titlebar.tsx +22 -11
- package/src/editor/ai/AiTerminal.tsx +42 -53
- package/src/editor/client/EditorClient.tsx +62 -18
- package/src/editor/client/editContext.ts +5 -1
- package/src/editor/client/itemsRepository.ts +151 -115
- package/src/editor/menubar/BrowseHistory.tsx +7 -16
- package/src/editor/menubar/PageSelector.tsx +91 -66
- package/src/editor/page-editor-chrome/FieldActionIndicator.tsx +1 -1
- package/src/editor/page-viewer/PageViewerFrame.tsx +143 -0
- package/src/editor/pageModel.ts +12 -0
- package/src/editor/reviews/Comment.tsx +5 -6
- package/src/editor/services/editService.ts +2 -0
- package/src/editor/ui/Icons.tsx +1 -0
- package/src/editor/ui/ItemList.tsx +76 -0
- package/src/editor/ui/ItemSearch.tsx +9 -46
- package/src/editor/ui/SimpleTabs.tsx +1 -1
- package/src/revision.ts +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SimpleTabs.js","sourceRoot":"","sources":["../../../src/editor/ui/SimpleTabs.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AASzC,MAAM,UAAU,UAAU,CAAC,EACzB,IAAI,EACJ,YAAY,EACZ,SAAS,EACT,SAAS,GAMV;IACC,IAAI,SAAS,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAChC,SAAS,GAAG,CAAC,CAAC;IAChB,CAAC;IAED,IAAI,SAAS,GAAG,CAAC,EAAE,CAAC;QAClB,SAAS,GAAG,CAAC,CAAC;IAChB,CAAC;IAED,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAEnC,OAAO,CACL,8BACE,cAAK,SAAS,EAAE,OAAO,CAAC,
|
|
1
|
+
{"version":3,"file":"SimpleTabs.js","sourceRoot":"","sources":["../../../src/editor/ui/SimpleTabs.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AASzC,MAAM,UAAU,UAAU,CAAC,EACzB,IAAI,EACJ,YAAY,EACZ,SAAS,EACT,SAAS,GAMV;IACC,IAAI,SAAS,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAChC,SAAS,GAAG,CAAC,CAAC;IAChB,CAAC;IAED,IAAI,SAAS,GAAG,CAAC,EAAE,CAAC;QAClB,SAAS,GAAG,CAAC,CAAC;IAChB,CAAC;IAED,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAEnC,OAAO,CACL,8BACE,cAAK,SAAS,EAAE,OAAO,CAAC,iBAAiB,EAAE,SAAS,CAAC,YAClD,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE,CAAC,CACxB,iBACE,EAAE,EAAE,GAAG,CAAC,EAAE,EACV,SAAS,EAAE,SAAS,KAAK,KAAK,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,gBAAgB,iBAEnD,GAAG,CAAC,MAAM,EACvB,OAAO,EAAE,GAAG,EAAE,CAAC,YAAY,CAAC,KAAK,CAAC,EAClC,KAAK,EAAE;wBACL,UAAU,EAAE,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ;wBACnD,YAAY,EAAE,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,MAAM;wBAC9D,YAAY,EAAE,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK;wBAC/C,KAAK,EAAE,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM;qBAC9C,YAEA,GAAG,CAAC,KAAK,IAVL,GAAG,CAAC,EAAE,CAWJ,CACV,CAAC,GACE,EACL,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,IACxB,CACJ,CAAC;AACJ,CAAC"}
|
package/dist/revision.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const version = "1.0.
|
|
2
|
-
export declare const buildDate = "2025-06-
|
|
1
|
+
export declare const version = "1.0.3939";
|
|
2
|
+
export declare const buildDate = "2025-06-07 12:23:08";
|
package/dist/revision.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export const version = "1.0.
|
|
2
|
-
export const buildDate = "2025-06-
|
|
1
|
+
export const version = "1.0.3939";
|
|
2
|
+
export const buildDate = "2025-06-07 12:23:08";
|
|
3
3
|
//# sourceMappingURL=revision.js.map
|
package/dist/styles.css
CHANGED
|
@@ -675,6 +675,9 @@
|
|
|
675
675
|
.min-w-64 {
|
|
676
676
|
min-width: calc(var(--spacing) * 64);
|
|
677
677
|
}
|
|
678
|
+
.min-w-96 {
|
|
679
|
+
min-width: calc(var(--spacing) * 96);
|
|
680
|
+
}
|
|
678
681
|
.min-w-\[8rem\] {
|
|
679
682
|
min-width: 8rem;
|
|
680
683
|
}
|
|
@@ -1450,9 +1453,6 @@
|
|
|
1450
1453
|
.pr-6 {
|
|
1451
1454
|
padding-right: calc(var(--spacing) * 6);
|
|
1452
1455
|
}
|
|
1453
|
-
.pr-8 {
|
|
1454
|
-
padding-right: calc(var(--spacing) * 8);
|
|
1455
|
-
}
|
|
1456
1456
|
.pb-0 {
|
|
1457
1457
|
padding-bottom: calc(var(--spacing) * 0);
|
|
1458
1458
|
}
|
|
@@ -2523,11 +2523,6 @@
|
|
|
2523
2523
|
padding-top: calc(var(--spacing) * 0);
|
|
2524
2524
|
}
|
|
2525
2525
|
}
|
|
2526
|
-
.md\:pb-3 {
|
|
2527
|
-
@media (width >= 48rem) {
|
|
2528
|
-
padding-bottom: calc(var(--spacing) * 3);
|
|
2529
|
-
}
|
|
2530
|
-
}
|
|
2531
2526
|
.md\:pb-4 {
|
|
2532
2527
|
@media (width >= 48rem) {
|
|
2533
2528
|
padding-bottom: calc(var(--spacing) * 4);
|
package/package.json
CHANGED
|
@@ -231,12 +231,6 @@ export default function ContentTree({
|
|
|
231
231
|
|
|
232
232
|
const refreshNode = useCallback(
|
|
233
233
|
async (node: TreeNode) => {
|
|
234
|
-
const tempNode = { ...node };
|
|
235
|
-
|
|
236
|
-
tempNode.children = undefined;
|
|
237
|
-
|
|
238
|
-
await doPreloadNodes(expandedKeys || [], [tempNode as CustomTreeNode]);
|
|
239
|
-
|
|
240
234
|
const item = await editContext?.itemsRepository.getItem(
|
|
241
235
|
node.data as ItemDescriptor,
|
|
242
236
|
);
|
|
@@ -256,16 +250,25 @@ export default function ContentTree({
|
|
|
256
250
|
});
|
|
257
251
|
customNode.selectable = !selectPagesOnly || item.hasLayout;
|
|
258
252
|
customNode.data = item;
|
|
259
|
-
|
|
260
|
-
// Preserve existing parent relationship - don't update it
|
|
261
|
-
}
|
|
253
|
+
// Don't set hasChildren yet - we'll determine it after loading children
|
|
262
254
|
|
|
263
|
-
|
|
255
|
+
// Always reload children to get the current state, regardless of expand state
|
|
256
|
+
const newChildren = await loadNodeChildren(customNode);
|
|
257
|
+
customNode.children = newChildren;
|
|
258
|
+
|
|
259
|
+
// Update hasChildren based on actual children count
|
|
260
|
+
customNode.hasChildren = newChildren.length > 0;
|
|
261
|
+
|
|
262
|
+
// If node is not expanded, clear children to save memory but keep hasChildren correct
|
|
263
|
+
if (!expandedKeys?.includes(node.key as string)) {
|
|
264
|
+
customNode.children = undefined;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
264
267
|
},
|
|
265
268
|
[
|
|
266
269
|
editContext?.itemsRepository,
|
|
267
270
|
expandedKeys,
|
|
268
|
-
|
|
271
|
+
loadNodeChildren,
|
|
269
272
|
isDraggable,
|
|
270
273
|
selectPagesOnly,
|
|
271
274
|
],
|
|
@@ -341,7 +344,7 @@ export default function ContentTree({
|
|
|
341
344
|
if (hasNewKeys) {
|
|
342
345
|
setExpandedKeys([...new Set([...expandedKeys, ...newExpandedKeys])]);
|
|
343
346
|
}
|
|
344
|
-
}, [expandIdPath,
|
|
347
|
+
}, [expandIdPath, rootItemId]);
|
|
345
348
|
|
|
346
349
|
useEffect(() => {
|
|
347
350
|
const newNodeDictionary: { [key: string]: CustomTreeNode } = {};
|
|
@@ -70,6 +70,12 @@ export async function showComponentContextMenu(
|
|
|
70
70
|
editContext: EditContextType,
|
|
71
71
|
field?: FieldDescriptor,
|
|
72
72
|
fieldButtons?: FieldButton[],
|
|
73
|
+
onParameterizedAction?: (
|
|
74
|
+
field: FieldDescriptor,
|
|
75
|
+
action: FieldButton,
|
|
76
|
+
allFieldButtons: FieldButton[],
|
|
77
|
+
event: any,
|
|
78
|
+
) => void,
|
|
73
79
|
) {
|
|
74
80
|
const componentCommandMenuItems = await getComponentMenuItems(
|
|
75
81
|
editContext,
|
|
@@ -89,8 +95,20 @@ export async function showComponentContextMenu(
|
|
|
89
95
|
menuItems.push({
|
|
90
96
|
id: button.id,
|
|
91
97
|
label: button.label,
|
|
92
|
-
command: async () => {
|
|
93
|
-
|
|
98
|
+
command: async (event) => {
|
|
99
|
+
// Check if the button has parameters
|
|
100
|
+
if (button.parameters && button.parameters.length > 0) {
|
|
101
|
+
// If we have a parameterized action handler, use it
|
|
102
|
+
if (onParameterizedAction) {
|
|
103
|
+
onParameterizedAction(field, button, fieldButtons, event);
|
|
104
|
+
} else {
|
|
105
|
+
// Fallback: execute without parameters (might not work well)
|
|
106
|
+
editContext!.triggerFieldAction(field, button);
|
|
107
|
+
}
|
|
108
|
+
} else {
|
|
109
|
+
// For simple actions, execute directly
|
|
110
|
+
editContext!.triggerFieldAction(field, button);
|
|
111
|
+
}
|
|
94
112
|
},
|
|
95
113
|
icon: button.icon ? <img src={button.icon} width={16} /> : undefined,
|
|
96
114
|
});
|
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
import React, { useState, useRef, useEffect } from "react";
|
|
2
|
+
import { OverlayPanel } from "primereact/overlaypanel";
|
|
3
|
+
import { FieldButton, FieldButtonParameter } from "./pageModel";
|
|
4
|
+
|
|
5
|
+
interface FieldActionsOverlayProps {
|
|
6
|
+
generatorButtons?: FieldButton[];
|
|
7
|
+
onActionClick: (action: FieldButton) => void;
|
|
8
|
+
onParameterizedActionExecute: (
|
|
9
|
+
action: FieldButton,
|
|
10
|
+
parameters: Record<string, string>,
|
|
11
|
+
) => void;
|
|
12
|
+
currentOverlay?: any;
|
|
13
|
+
fieldId: string;
|
|
14
|
+
setCurrentOverlay: (overlay: any) => void;
|
|
15
|
+
preSelectedAction?: FieldButton; // Auto-select this action when overlay opens
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const FieldActionsOverlay = React.forwardRef<
|
|
19
|
+
FieldActionsOverlayRef,
|
|
20
|
+
FieldActionsOverlayProps
|
|
21
|
+
>(
|
|
22
|
+
(
|
|
23
|
+
{
|
|
24
|
+
generatorButtons,
|
|
25
|
+
onActionClick,
|
|
26
|
+
onParameterizedActionExecute,
|
|
27
|
+
currentOverlay,
|
|
28
|
+
fieldId,
|
|
29
|
+
setCurrentOverlay,
|
|
30
|
+
preSelectedAction,
|
|
31
|
+
},
|
|
32
|
+
ref,
|
|
33
|
+
) => {
|
|
34
|
+
const overlayRef = useRef<OverlayPanel>(null);
|
|
35
|
+
const [selectedParameterizedAction, setSelectedParameterizedAction] =
|
|
36
|
+
useState<FieldButton | null>(null);
|
|
37
|
+
const [parameterValues, setParameterValues] = useState<
|
|
38
|
+
Record<string, string>
|
|
39
|
+
>({});
|
|
40
|
+
|
|
41
|
+
const overlayId = fieldId + "_generators";
|
|
42
|
+
|
|
43
|
+
useEffect(() => {
|
|
44
|
+
if (currentOverlay !== overlayId) {
|
|
45
|
+
overlayRef.current?.hide();
|
|
46
|
+
resetParameterizedAction();
|
|
47
|
+
}
|
|
48
|
+
}, [currentOverlay, overlayId]);
|
|
49
|
+
|
|
50
|
+
// Auto-select preSelectedAction if provided (removed from useEffect)
|
|
51
|
+
// Now handled in the show function
|
|
52
|
+
|
|
53
|
+
function resetParameterizedAction(): void {
|
|
54
|
+
setSelectedParameterizedAction(null);
|
|
55
|
+
setParameterValues({});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function handleActionClick(action: FieldButton): void {
|
|
59
|
+
if (action.parameters && action.parameters.length > 0) {
|
|
60
|
+
setSelectedParameterizedAction(action);
|
|
61
|
+
// Initialize parameter values with defaults
|
|
62
|
+
const initialValues: Record<string, string> = {};
|
|
63
|
+
action.parameters.forEach((param) => {
|
|
64
|
+
initialValues[param.id] = param.defaultValue || "";
|
|
65
|
+
});
|
|
66
|
+
setParameterValues(initialValues);
|
|
67
|
+
} else {
|
|
68
|
+
onActionClick(action);
|
|
69
|
+
overlayRef.current?.hide();
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function executeParameterizedAction(): void {
|
|
74
|
+
if (selectedParameterizedAction) {
|
|
75
|
+
onParameterizedActionExecute(
|
|
76
|
+
selectedParameterizedAction,
|
|
77
|
+
parameterValues,
|
|
78
|
+
);
|
|
79
|
+
resetParameterizedAction();
|
|
80
|
+
overlayRef.current?.hide();
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function goBackToActionList(): void {
|
|
85
|
+
resetParameterizedAction();
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function cancelParameterizedAction(): void {
|
|
89
|
+
resetParameterizedAction();
|
|
90
|
+
overlayRef.current?.hide();
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function updateParameterValue(paramId: string, value: string): void {
|
|
94
|
+
setParameterValues((prev) => ({ ...prev, [paramId]: value }));
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function areRequiredParametersFilled(): boolean {
|
|
98
|
+
if (!selectedParameterizedAction?.parameters) return true;
|
|
99
|
+
|
|
100
|
+
return selectedParameterizedAction.parameters.every((param) => {
|
|
101
|
+
if (!param.required) return true;
|
|
102
|
+
const value = parameterValues[param.id] || "";
|
|
103
|
+
return value.trim().length > 0;
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function renderParameterInput(
|
|
108
|
+
param: FieldButtonParameter,
|
|
109
|
+
shouldAutoFocus: boolean = false,
|
|
110
|
+
): React.ReactNode {
|
|
111
|
+
const value = parameterValues[param.id] || "";
|
|
112
|
+
const commonProps = {
|
|
113
|
+
value,
|
|
114
|
+
onChange: (
|
|
115
|
+
e: React.ChangeEvent<
|
|
116
|
+
HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement
|
|
117
|
+
>,
|
|
118
|
+
) => updateParameterValue(param.id, e.target.value),
|
|
119
|
+
onKeyDown: (e: React.KeyboardEvent) => {
|
|
120
|
+
if (e.key === "Enter" && (e.ctrlKey || e.metaKey)) {
|
|
121
|
+
e.preventDefault();
|
|
122
|
+
if (areRequiredParametersFilled()) {
|
|
123
|
+
executeParameterizedAction();
|
|
124
|
+
}
|
|
125
|
+
} else if (e.key === "Escape") {
|
|
126
|
+
e.preventDefault();
|
|
127
|
+
goBackToActionList();
|
|
128
|
+
}
|
|
129
|
+
},
|
|
130
|
+
className: "w-full rounded border p-2 text-xs",
|
|
131
|
+
placeholder: param.placeholder || "",
|
|
132
|
+
autoFocus: shouldAutoFocus,
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
switch (param.type) {
|
|
136
|
+
case "textarea":
|
|
137
|
+
return (
|
|
138
|
+
<textarea
|
|
139
|
+
{...commonProps}
|
|
140
|
+
rows={param.rows || 3}
|
|
141
|
+
className={commonProps.className + " resize-none"}
|
|
142
|
+
/>
|
|
143
|
+
);
|
|
144
|
+
case "number":
|
|
145
|
+
return <input {...commonProps} type="number" />;
|
|
146
|
+
case "select":
|
|
147
|
+
return (
|
|
148
|
+
<select {...commonProps}>
|
|
149
|
+
<option value="">
|
|
150
|
+
{param.placeholder || "Select an option..."}
|
|
151
|
+
</option>
|
|
152
|
+
{param.options?.map((option) => (
|
|
153
|
+
<option key={option.value} value={option.value}>
|
|
154
|
+
{option.label}
|
|
155
|
+
</option>
|
|
156
|
+
))}
|
|
157
|
+
</select>
|
|
158
|
+
);
|
|
159
|
+
case "text":
|
|
160
|
+
default:
|
|
161
|
+
return <input {...commonProps} type="text" />;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function show(event: any, actionToSelect?: FieldButton): void {
|
|
166
|
+
console.log("FieldActionsOverlay show called with:", {
|
|
167
|
+
event,
|
|
168
|
+
actionToSelect,
|
|
169
|
+
preSelectedAction,
|
|
170
|
+
overlayId,
|
|
171
|
+
isTrusted: event?.isTrusted,
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
// Set overlay state first, then show
|
|
175
|
+
setCurrentOverlay(overlayId);
|
|
176
|
+
|
|
177
|
+
// Check if this is a synthetic event (from context menu) or real event (from button click)
|
|
178
|
+
if (
|
|
179
|
+
event &&
|
|
180
|
+
event.isTrusted === false &&
|
|
181
|
+
event.target &&
|
|
182
|
+
event.target.style
|
|
183
|
+
) {
|
|
184
|
+
// This is likely our synthetic event with a positioned target element
|
|
185
|
+
console.log("Using synthetic event positioning");
|
|
186
|
+
overlayRef.current?.toggle(event, event.target);
|
|
187
|
+
} else {
|
|
188
|
+
// This is a normal event, use standard positioning
|
|
189
|
+
console.log("Using normal event positioning");
|
|
190
|
+
overlayRef.current?.toggle(event);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Use the passed actionToSelect or fall back to preSelectedAction prop
|
|
194
|
+
const actionToAutoSelect = actionToSelect || preSelectedAction;
|
|
195
|
+
|
|
196
|
+
// Auto-select the action after overlay is shown
|
|
197
|
+
if (
|
|
198
|
+
actionToAutoSelect &&
|
|
199
|
+
actionToAutoSelect.parameters &&
|
|
200
|
+
actionToAutoSelect.parameters.length > 0
|
|
201
|
+
) {
|
|
202
|
+
console.log("Auto-selecting action in 50ms:", actionToAutoSelect);
|
|
203
|
+
// Use longer timeout to ensure overlay is stable
|
|
204
|
+
setTimeout(() => {
|
|
205
|
+
console.log(
|
|
206
|
+
"Calling handleActionClick for action:",
|
|
207
|
+
actionToAutoSelect,
|
|
208
|
+
);
|
|
209
|
+
handleActionClick(actionToAutoSelect);
|
|
210
|
+
}, 50);
|
|
211
|
+
} else {
|
|
212
|
+
console.log(
|
|
213
|
+
"Not auto-selecting - actionToAutoSelect:",
|
|
214
|
+
actionToAutoSelect,
|
|
215
|
+
);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
function hide(): void {
|
|
220
|
+
overlayRef.current?.hide();
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
React.useImperativeHandle(ref, () => ({
|
|
224
|
+
show,
|
|
225
|
+
hide,
|
|
226
|
+
}));
|
|
227
|
+
|
|
228
|
+
return (
|
|
229
|
+
<OverlayPanel ref={overlayRef} className="p-1">
|
|
230
|
+
{selectedParameterizedAction ? (
|
|
231
|
+
<div className="min-w-64 p-2">
|
|
232
|
+
<div className="mb-2">
|
|
233
|
+
<div className="mb-2 flex items-center">
|
|
234
|
+
<button
|
|
235
|
+
className="mr-2 text-xs hover:text-gray-400"
|
|
236
|
+
onClick={goBackToActionList}
|
|
237
|
+
>
|
|
238
|
+
<i className="pi pi-arrow-left" />
|
|
239
|
+
</button>
|
|
240
|
+
<span className="text-xs font-semibold">
|
|
241
|
+
{selectedParameterizedAction.label}
|
|
242
|
+
</span>
|
|
243
|
+
</div>
|
|
244
|
+
<div className="mb-3 text-xs text-gray-600">
|
|
245
|
+
{selectedParameterizedAction.description}
|
|
246
|
+
</div>
|
|
247
|
+
|
|
248
|
+
{selectedParameterizedAction.parameters?.map((param, index) => (
|
|
249
|
+
<div key={param.id} className="mb-3">
|
|
250
|
+
<label className="mb-1 block text-xs font-medium">
|
|
251
|
+
{param.label}
|
|
252
|
+
{param.required && (
|
|
253
|
+
<span className="ml-1 text-red-500">*</span>
|
|
254
|
+
)}
|
|
255
|
+
</label>
|
|
256
|
+
{renderParameterInput(param, index === 0)}
|
|
257
|
+
</div>
|
|
258
|
+
))}
|
|
259
|
+
|
|
260
|
+
<div className="mt-1 text-xs text-gray-500">
|
|
261
|
+
Ctrl+Enter to execute, Esc to cancel
|
|
262
|
+
</div>
|
|
263
|
+
</div>
|
|
264
|
+
<div className="flex gap-2">
|
|
265
|
+
<button
|
|
266
|
+
className="rounded bg-blue-500 px-3 py-1 text-xs text-white hover:bg-blue-600 disabled:cursor-not-allowed disabled:opacity-50"
|
|
267
|
+
onClick={executeParameterizedAction}
|
|
268
|
+
disabled={!areRequiredParametersFilled()}
|
|
269
|
+
>
|
|
270
|
+
Execute
|
|
271
|
+
</button>
|
|
272
|
+
<button
|
|
273
|
+
className="rounded bg-gray-300 px-3 py-1 text-xs text-gray-700 hover:bg-gray-400"
|
|
274
|
+
onClick={cancelParameterizedAction}
|
|
275
|
+
>
|
|
276
|
+
Cancel
|
|
277
|
+
</button>
|
|
278
|
+
</div>
|
|
279
|
+
</div>
|
|
280
|
+
) : (
|
|
281
|
+
<>
|
|
282
|
+
{generatorButtons?.map((x) => (
|
|
283
|
+
<button
|
|
284
|
+
key={x.id}
|
|
285
|
+
className="block p-1 text-xs hover:text-gray-400"
|
|
286
|
+
onClick={() => handleActionClick(x)}
|
|
287
|
+
>
|
|
288
|
+
{x.icon && <i className={x.icon + " mr-2 text-xs"} />}
|
|
289
|
+
{x.label}
|
|
290
|
+
</button>
|
|
291
|
+
))}
|
|
292
|
+
</>
|
|
293
|
+
)}
|
|
294
|
+
</OverlayPanel>
|
|
295
|
+
);
|
|
296
|
+
},
|
|
297
|
+
);
|
|
298
|
+
|
|
299
|
+
// Export methods to be used by parent component
|
|
300
|
+
export interface FieldActionsOverlayRef {
|
|
301
|
+
show: (event: any, actionToSelect?: FieldButton) => void;
|
|
302
|
+
hide: () => void;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
FieldActionsOverlay.displayName = "FieldActionsOverlay";
|
|
306
|
+
|
|
307
|
+
export { FieldActionsOverlay };
|
|
@@ -12,9 +12,11 @@ import { SimpleIconButton } from "./ui/SimpleIconButton";
|
|
|
12
12
|
export function FieldHistory({
|
|
13
13
|
field,
|
|
14
14
|
onHover,
|
|
15
|
+
onRevert,
|
|
15
16
|
}: {
|
|
16
17
|
field: Field;
|
|
17
18
|
onHover: (historyEntry: FieldHistoryItem | undefined) => void;
|
|
19
|
+
onRevert?: () => void;
|
|
18
20
|
}) {
|
|
19
21
|
const [fieldHistory, setFieldHistory] = useState<FieldHistoryItem[]>([]);
|
|
20
22
|
const editContext = useEditContext();
|
|
@@ -30,13 +32,11 @@ export function FieldHistory({
|
|
|
30
32
|
}, [field]);
|
|
31
33
|
|
|
32
34
|
if (fieldHistory.length === 0)
|
|
33
|
-
return <div className="p-2 text-gray-500
|
|
35
|
+
return <div className="p-2 text-xs text-gray-500">No history</div>;
|
|
34
36
|
|
|
35
37
|
return (
|
|
36
38
|
<div>
|
|
37
|
-
<div className="
|
|
38
|
-
Field History
|
|
39
|
-
</div>
|
|
39
|
+
<div className="bg-gray-100 p-2 text-xs text-gray-500">Field History</div>
|
|
40
40
|
<div className="max-h-96 overflow-auto">
|
|
41
41
|
<SimpleTable
|
|
42
42
|
items={fieldHistory}
|
|
@@ -55,13 +55,14 @@ export function FieldHistory({
|
|
|
55
55
|
body: (x) => (
|
|
56
56
|
<SimpleIconButton
|
|
57
57
|
icon="pi pi-undo"
|
|
58
|
-
onClick={() =>
|
|
59
|
-
editContext.operations.editField({
|
|
58
|
+
onClick={async () => {
|
|
59
|
+
await editContext.operations.editField({
|
|
60
60
|
field: field.descriptor,
|
|
61
61
|
rawValue: x.rawValue,
|
|
62
62
|
refresh: "immediate",
|
|
63
|
-
})
|
|
64
|
-
|
|
63
|
+
});
|
|
64
|
+
onRevert?.();
|
|
65
|
+
}}
|
|
65
66
|
label="Revert"
|
|
66
67
|
/>
|
|
67
68
|
),
|
|
@@ -12,6 +12,10 @@ import { getSessionWithFieldLock } from "./utils";
|
|
|
12
12
|
|
|
13
13
|
import { loadFieldButtons } from "./services/editService";
|
|
14
14
|
import { Field, FieldButton } from "./pageModel";
|
|
15
|
+
import {
|
|
16
|
+
FieldActionsOverlay,
|
|
17
|
+
FieldActionsOverlayRef,
|
|
18
|
+
} from "./FieldActionsOverlay";
|
|
15
19
|
import { useThrottledCallback } from "use-debounce";
|
|
16
20
|
import { SimpleIconButton } from "./ui/SimpleIconButton";
|
|
17
21
|
import { FieldHistory } from "./FieldHistory";
|
|
@@ -43,15 +47,21 @@ export default function FieldListField({
|
|
|
43
47
|
const fieldItem = field.descriptor.item;
|
|
44
48
|
|
|
45
49
|
const [showRawValue, setShowRawValue] = useState(false);
|
|
46
|
-
const generatorsOverlay = useRef<
|
|
50
|
+
const generatorsOverlay = useRef<FieldActionsOverlayRef>(null);
|
|
47
51
|
const fieldHistoryOverlay = useRef<OverlayPanel>(null);
|
|
48
52
|
const [generatorButtons, setButtons] = useState<FieldButton[]>();
|
|
49
53
|
const [isModified, setIsModified] = useState(false);
|
|
50
54
|
const [isSaved, setIsSaved] = useState(false);
|
|
51
55
|
const [historyEntry, setHistoryEntry] = useState<FieldHistoryItem>();
|
|
56
|
+
async function handleActionClick(action: FieldButton): Promise<void> {
|
|
57
|
+
editContext?.triggerFieldAction(field.descriptor, action);
|
|
58
|
+
}
|
|
52
59
|
|
|
53
|
-
async function
|
|
54
|
-
|
|
60
|
+
async function handleParameterizedActionExecute(
|
|
61
|
+
action: FieldButton,
|
|
62
|
+
parameters: Record<string, string>,
|
|
63
|
+
): Promise<void> {
|
|
64
|
+
editContext?.triggerFieldAction(field.descriptor, action, parameters);
|
|
55
65
|
}
|
|
56
66
|
|
|
57
67
|
useEffect(() => {
|
|
@@ -148,24 +158,16 @@ export default function FieldListField({
|
|
|
148
158
|
}
|
|
149
159
|
}, [isFocusedField]);
|
|
150
160
|
|
|
151
|
-
useEffect(() => {
|
|
152
|
-
if (editContext.currentOverlay !== field.id + "_generators")
|
|
153
|
-
generatorsOverlay.current?.hide();
|
|
154
|
-
}, [editContext.currentOverlay]);
|
|
155
|
-
|
|
156
161
|
const renderGeneratorButtons = () => {
|
|
157
162
|
if (generatorButtons?.length || 0 > 0)
|
|
158
163
|
return (
|
|
159
164
|
<>
|
|
160
165
|
{(!executingAction || executingAction.state !== "running") && (
|
|
161
166
|
<SimpleIconButton
|
|
162
|
-
icon={<WizardIcon className="h-
|
|
167
|
+
icon={<WizardIcon className="h-5 w-5" />}
|
|
163
168
|
label="Generate"
|
|
164
169
|
onClick={(e: any) => {
|
|
165
|
-
generatorsOverlay.current?.
|
|
166
|
-
editContext.setCurrentOverlay(field.id + "_generators");
|
|
167
|
-
e.preventDefault();
|
|
168
|
-
e.stopPropagation();
|
|
170
|
+
generatorsOverlay.current?.show(e);
|
|
169
171
|
}}
|
|
170
172
|
></SimpleIconButton>
|
|
171
173
|
)}
|
|
@@ -175,21 +177,15 @@ export default function FieldListField({
|
|
|
175
177
|
{executingAction?.label}
|
|
176
178
|
</div>
|
|
177
179
|
)}
|
|
178
|
-
<
|
|
179
|
-
{
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
>
|
|
188
|
-
{x.icon && <i className={x.icon + " mr-2 text-xs"} />}
|
|
189
|
-
{x.label}
|
|
190
|
-
</button>
|
|
191
|
-
))}
|
|
192
|
-
</OverlayPanel>
|
|
180
|
+
<FieldActionsOverlay
|
|
181
|
+
ref={generatorsOverlay}
|
|
182
|
+
generatorButtons={generatorButtons}
|
|
183
|
+
onActionClick={handleActionClick}
|
|
184
|
+
onParameterizedActionExecute={handleParameterizedActionExecute}
|
|
185
|
+
currentOverlay={editContext.currentOverlay}
|
|
186
|
+
fieldId={field.id}
|
|
187
|
+
setCurrentOverlay={editContext.setCurrentOverlay}
|
|
188
|
+
/>
|
|
193
189
|
</>
|
|
194
190
|
);
|
|
195
191
|
return null;
|
|
@@ -245,7 +241,10 @@ export default function FieldListField({
|
|
|
245
241
|
{field.isShared && (
|
|
246
242
|
<span className="text-xs text-gray-400">[Shared]</span>
|
|
247
243
|
)}
|
|
248
|
-
|
|
244
|
+
{((!field.isFallback && field.rawValue !== null) ||
|
|
245
|
+
showFallbackButton ||
|
|
246
|
+
(config?.buttons && config.buttons.length > 0) ||
|
|
247
|
+
!simplified) && <span className="text-xs">·</span>}
|
|
249
248
|
{!field.isFallback && field.rawValue !== null ? (
|
|
250
249
|
<button
|
|
251
250
|
className="p-0 text-xs"
|
|
@@ -313,6 +312,7 @@ export default function FieldListField({
|
|
|
313
312
|
<FieldHistory
|
|
314
313
|
field={field}
|
|
315
314
|
onHover={(x) => setHistoryEntry(x)}
|
|
315
|
+
onRevert={() => fieldHistoryOverlay.current?.hide()}
|
|
316
316
|
/>
|
|
317
317
|
</OverlayPanel>
|
|
318
318
|
</div>
|