@parhelia/core 0.1.12927 → 0.1.12928
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/client-components/index.d.ts +1 -1
- package/dist/client-components/index.js +1 -1
- package/dist/client-components/index.js.map +1 -1
- package/dist/editor/FieldListField.js +8 -0
- package/dist/editor/FieldListField.js.map +1 -1
- package/dist/editor/MainLayout.js +2 -1
- package/dist/editor/MainLayout.js.map +1 -1
- package/dist/editor/PerfProfiler.d.ts +11 -0
- package/dist/editor/PerfProfiler.js +29 -0
- package/dist/editor/PerfProfiler.js.map +1 -0
- package/dist/editor/ai/GuidanceOverlay.js +4 -9
- package/dist/editor/ai/GuidanceOverlay.js.map +1 -1
- package/dist/editor/ai/InlineAiDialog.js +2 -2
- package/dist/editor/ai/InlineAiDialog.js.map +1 -1
- package/dist/editor/ai/dialogs/capturePageScreenshot.js +1 -1
- package/dist/editor/ai/dialogs/capturePageScreenshot.js.map +1 -1
- package/dist/editor/ai/terminal/components/AgentSettingsContent.d.ts +2 -1
- package/dist/editor/ai/terminal/components/AgentSettingsContent.js.map +1 -1
- package/dist/editor/ai/terminal/components/AgentSettingsSections.d.ts +2 -1
- package/dist/editor/ai/terminal/components/AgentSettingsSections.js +9 -2
- package/dist/editor/ai/terminal/components/AgentSettingsSections.js.map +1 -1
- package/dist/editor/ai/terminal/components/ContextInfoBar.js +4 -3
- package/dist/editor/ai/terminal/components/ContextInfoBar.js.map +1 -1
- package/dist/editor/ai/terminal/useAgentSettingsData.d.ts +8 -1
- package/dist/editor/ai/terminal/useAgentSettingsData.js +42 -3
- package/dist/editor/ai/terminal/useAgentSettingsData.js.map +1 -1
- package/dist/editor/ai/terminal/useAgentSettingsPanel.d.ts +1 -1
- package/dist/editor/bridge/BridgeClient.js +9 -1
- package/dist/editor/bridge/BridgeClient.js.map +1 -1
- package/dist/editor/bridge/protocol.d.ts +19 -0
- package/dist/editor/bridge/protocol.js +1 -1
- package/dist/editor/bridge/protocol.js.map +1 -1
- package/dist/editor/client/EditorShell.js +156 -20
- package/dist/editor/client/EditorShell.js.map +1 -1
- package/dist/editor/client/editContext.d.ts +32 -1
- package/dist/editor/client/editContext.js +8 -0
- package/dist/editor/client/editContext.js.map +1 -1
- package/dist/editor/client/fieldModificationStore.js +64 -0
- package/dist/editor/client/fieldModificationStore.js.map +1 -1
- package/dist/editor/client/itemsRepository.js +95 -3
- package/dist/editor/client/itemsRepository.js.map +1 -1
- package/dist/editor/client/operations.d.ts +1 -0
- package/dist/editor/client/operations.js +147 -13
- package/dist/editor/client/operations.js.map +1 -1
- package/dist/editor/client/ui/EditorChrome.js +6 -5
- package/dist/editor/client/ui/EditorChrome.js.map +1 -1
- package/dist/editor/commands/keyboardCommands.js +1 -1
- package/dist/editor/commands/keyboardCommands.js.map +1 -1
- package/dist/editor/componentTreeHelper.js +15 -5
- package/dist/editor/componentTreeHelper.js.map +1 -1
- package/dist/editor/field-types/SingleLineText.js +79 -9
- package/dist/editor/field-types/SingleLineText.js.map +1 -1
- package/dist/editor/fieldValueDiagnostics.d.ts +79 -0
- package/dist/editor/fieldValueDiagnostics.js +133 -0
- package/dist/editor/fieldValueDiagnostics.js.map +1 -0
- package/dist/editor/page-editor-chrome/DragInsertionOverlay.js +51 -19
- package/dist/editor/page-editor-chrome/DragInsertionOverlay.js.map +1 -1
- package/dist/editor/page-editor-chrome/FrameMenu.d.ts +2 -0
- package/dist/editor/page-editor-chrome/FrameMenu.js +8 -6
- package/dist/editor/page-editor-chrome/FrameMenu.js.map +1 -1
- package/dist/editor/page-editor-chrome/FrameMenus.d.ts +3 -1
- package/dist/editor/page-editor-chrome/FrameMenus.js +4 -4
- package/dist/editor/page-editor-chrome/FrameMenus.js.map +1 -1
- package/dist/editor/page-editor-chrome/PageEditorChrome.js +17 -4
- package/dist/editor/page-editor-chrome/PageEditorChrome.js.map +1 -1
- package/dist/editor/page-editor-chrome/PictureEditorOverlay.js +4 -7
- package/dist/editor/page-editor-chrome/PictureEditorOverlay.js.map +1 -1
- package/dist/editor/page-editor-chrome/PlaceholderDropZone.d.ts +8 -1
- package/dist/editor/page-editor-chrome/PlaceholderDropZone.js +14 -3
- package/dist/editor/page-editor-chrome/PlaceholderDropZone.js.map +1 -1
- package/dist/editor/page-editor-chrome/PlaceholderDropZones.d.ts +3 -1
- package/dist/editor/page-editor-chrome/PlaceholderDropZones.js +2 -2
- package/dist/editor/page-editor-chrome/PlaceholderDropZones.js.map +1 -1
- package/dist/editor/page-editor-chrome/overlay/placeholderZones.js +43 -1
- package/dist/editor/page-editor-chrome/overlay/placeholderZones.js.map +1 -1
- package/dist/editor/page-editor-chrome/useBridgeInlineEditing.js +121 -48
- package/dist/editor/page-editor-chrome/useBridgeInlineEditing.js.map +1 -1
- package/dist/editor/page-viewer/EditorForm.js +54 -5
- package/dist/editor/page-viewer/EditorForm.js.map +1 -1
- package/dist/editor/page-viewer/MiniMap.js +4 -4
- package/dist/editor/page-viewer/MiniMap.js.map +1 -1
- package/dist/editor/page-viewer/PageViewer.js +9 -7
- package/dist/editor/page-viewer/PageViewer.js.map +1 -1
- package/dist/editor/page-viewer/PageViewerFrame.js +267 -25
- package/dist/editor/page-viewer/PageViewerFrame.js.map +1 -1
- package/dist/editor/page-viewer/bridgeFieldPatch.js +49 -2
- package/dist/editor/page-viewer/bridgeFieldPatch.js.map +1 -1
- package/dist/editor/page-viewer/pageViewContext.d.ts +1 -0
- package/dist/editor/page-viewer/pageViewContext.js +7 -0
- package/dist/editor/page-viewer/pageViewContext.js.map +1 -1
- package/dist/editor/perfTrace.d.ts +46 -0
- package/dist/editor/perfTrace.js +213 -0
- package/dist/editor/perfTrace.js.map +1 -0
- package/dist/editor/reviews/CommentPopover.js +2 -3
- package/dist/editor/reviews/CommentPopover.js.map +1 -1
- package/dist/editor/reviews/commentAi.js +1 -1
- package/dist/editor/reviews/commentAi.js.map +1 -1
- package/dist/editor/services/agentService.d.ts +2 -0
- package/dist/editor/services/agentService.js.map +1 -1
- package/dist/editor/services/aiService.d.ts +1 -0
- package/dist/editor/services/aiService.js.map +1 -1
- package/dist/editor/sidebar/ComponentTree.js +10 -9
- package/dist/editor/sidebar/ComponentTree.js.map +1 -1
- package/dist/editor/sidebar/ContentTreePanel.d.ts +2 -2
- package/dist/editor/sidebar/ContentTreePanel.js +6 -2
- package/dist/editor/sidebar/ContentTreePanel.js.map +1 -1
- package/dist/editor/sidebar/MainContentTree.js +3 -2
- package/dist/editor/sidebar/MainContentTree.js.map +1 -1
- package/dist/editor/utils/keyboardNavigation.js +2 -2
- package/dist/editor/utils/keyboardNavigation.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/revision.d.ts +2 -2
- package/dist/revision.js +2 -2
- package/package.json +1 -1
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
import React, { useState, useEffect, useRef, useCallback, useMemo, startTransition, } from "react";
|
|
3
|
+
import React, { useState, useEffect, useLayoutEffect, useRef, useCallback, useMemo, startTransition, } from "react";
|
|
4
4
|
import { toast } from "sonner";
|
|
5
|
-
import {
|
|
5
|
+
import { isPerfTraceActive, perfTracePaintStep, perfTraceStep, } from "../perfTrace";
|
|
6
|
+
import { EditContextProvider, FieldsEditContextProvider, OperationsContextProvider, SelectionContextProvider, useEditContext, } from "./editContext";
|
|
6
7
|
import { aggregateModifiedFieldsFromStores, areModifiedFieldSnapshotsEqual, FieldModificationStore, } from "./fieldModificationStore";
|
|
7
8
|
import { SplashScreenAgentProvider } from "../../splash-screen/SplashScreenAgentContext";
|
|
8
9
|
import { useRouter, useSearchParams, usePathname } from "./navigation";
|
|
9
10
|
import { findComponent, getComponentById } from "../componentTreeHelper";
|
|
10
11
|
import { getOperationsContext } from "./operations";
|
|
11
12
|
import { handleErrorResult } from "./helpers";
|
|
12
|
-
import { showExpandableErrorToast
|
|
13
|
+
import { showExpandableErrorToast } from "./errorToast";
|
|
13
14
|
import { isManualShowMeFocusTransfer, isManualShowMeTarget, } from "./manualShowMeFocus";
|
|
14
15
|
import { executeFieldAction as executeFieldServerAction, connectSocket, getEditHistory, getRunningOperations, reconnectSession, releaseFieldLocks, validateItems, } from "../services/editService";
|
|
15
16
|
import { emitAgentDocumentsChanged } from "../services/agentService";
|
|
@@ -37,6 +38,7 @@ import { post } from "../services/serviceHelper";
|
|
|
37
38
|
import { CONTENT_TREE_SIDEBAR_ID } from "../sidebar/contentTreeConstants";
|
|
38
39
|
import { PageViewerFrame } from "../page-viewer/PageViewerFrame";
|
|
39
40
|
import { useItemsRepository } from "./itemsRepository";
|
|
41
|
+
import { logFieldValueDiagnostic, summarizeFieldDescriptor, } from "../fieldValueDiagnostics";
|
|
40
42
|
import { Spinner } from "../ui/Spinner";
|
|
41
43
|
import { createSettleRegistry } from "../ui/animationSettle";
|
|
42
44
|
import { cleanId } from "../utils/id-helper";
|
|
@@ -47,7 +49,7 @@ import { Tour } from "../../tour/Tour";
|
|
|
47
49
|
import { GuidanceOverlay } from "../ai/GuidanceOverlay";
|
|
48
50
|
import { AgentDialogHandler } from "../ai/dialogs";
|
|
49
51
|
import { setActiveAgentConversation } from "../ai/useActiveAgentConversation";
|
|
50
|
-
import { usePageViewContext, } from "../page-viewer/pageViewContext";
|
|
52
|
+
import { CANVAS_REFRESH_COMPLETED_EVENT, usePageViewContext, } from "../page-viewer/pageViewContext";
|
|
51
53
|
import { QuickItemSwitcher } from "../QuickItemSwitcher";
|
|
52
54
|
import { useEditorSlotContext, } from "../views/editorSlotContext";
|
|
53
55
|
import { getComments, getAvailableCommentTags, } from "../services/reviewsService";
|
|
@@ -176,6 +178,10 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
176
178
|
const parheliaSettingsRefreshInFlightRef = useRef(null);
|
|
177
179
|
const minimapEnabledInSettings = effectiveParheliaSettings?.showMinimap !== false;
|
|
178
180
|
const [selection, setSelection] = useState([]);
|
|
181
|
+
// Current selection for event-time reads (select() early-bail, getSelection)
|
|
182
|
+
// without making callers depend on the reactive value.
|
|
183
|
+
const selectionRef = useRef(selection);
|
|
184
|
+
selectionRef.current = selection;
|
|
179
185
|
const [contentTreeSelection, setContentTreeSelection] = useState([]);
|
|
180
186
|
const [selectedForInsertion, setSelectedForInsertion] = useState("");
|
|
181
187
|
const [refreshCompletedFlag, setRefreshCompletedFlag] = useState(false);
|
|
@@ -230,6 +236,51 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
230
236
|
const [inserting, setInserting] = useState();
|
|
231
237
|
const [removingComponentIds, setRemovingComponentIds] = useState([]);
|
|
232
238
|
const insertingSequenceRef = useRef(0);
|
|
239
|
+
// Armed by selectWithoutAutoScroll for programmatic selections (drop
|
|
240
|
+
// target's parent, post-operation focus): the canvas selection-scroll
|
|
241
|
+
// effect consumes it and skips exactly that change. Deterministic — unlike
|
|
242
|
+
// a time window, it cannot expire while a slow operation or a frozen host
|
|
243
|
+
// delays the effect flush.
|
|
244
|
+
const suppressNextSelectionAutoScrollRef = useRef(false);
|
|
245
|
+
const selectWithoutAutoScroll = useCallback((ids) => {
|
|
246
|
+
const current = selectionRef.current;
|
|
247
|
+
if (ids.length === current.length &&
|
|
248
|
+
ids.every((id, index) => id === current[index])) {
|
|
249
|
+
// No state change: nothing renders, so don't leave the suppression
|
|
250
|
+
// armed for an unrelated later selection.
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
suppressNextSelectionAutoScrollRef.current = true;
|
|
254
|
+
setSelection(ids);
|
|
255
|
+
}, []);
|
|
256
|
+
const consumeNextSelectionAutoScrollSuppression = useCallback(() => {
|
|
257
|
+
const suppressed = suppressNextSelectionAutoScrollRef.current;
|
|
258
|
+
suppressNextSelectionAutoScrollRef.current = false;
|
|
259
|
+
return suppressed;
|
|
260
|
+
}, []);
|
|
261
|
+
const insertingHoldCleanupRef = useRef(null);
|
|
262
|
+
// The drop operation's HTTP resolve only means the server accepted it — the
|
|
263
|
+
// canvas re-render (fetch + DOM patch) lands seconds later. Keep the
|
|
264
|
+
// inserting indicator up until the first canvas refresh after the operation
|
|
265
|
+
// completes, so it visually hands off to the component actually appearing,
|
|
266
|
+
// with a timeout backstop for hosts that never report a refresh.
|
|
267
|
+
const holdInsertingUntilCanvasRefresh = useCallback((sequence) => {
|
|
268
|
+
insertingHoldCleanupRef.current?.();
|
|
269
|
+
const finish = () => {
|
|
270
|
+
insertingHoldCleanupRef.current = null;
|
|
271
|
+
window.removeEventListener(CANVAS_REFRESH_COMPLETED_EVENT, finish);
|
|
272
|
+
window.clearTimeout(timeoutId);
|
|
273
|
+
if (insertingSequenceRef.current === sequence) {
|
|
274
|
+
setInserting(undefined);
|
|
275
|
+
}
|
|
276
|
+
};
|
|
277
|
+
const timeoutId = window.setTimeout(finish, 15000);
|
|
278
|
+
window.addEventListener(CANVAS_REFRESH_COMPLETED_EVENT, finish);
|
|
279
|
+
insertingHoldCleanupRef.current = finish;
|
|
280
|
+
}, []);
|
|
281
|
+
useEffect(() => () => {
|
|
282
|
+
insertingHoldCleanupRef.current?.();
|
|
283
|
+
}, []);
|
|
233
284
|
const [showFullscreenHint, setShowFullscreenHint] = useState(false);
|
|
234
285
|
// Fullscreen is a shell-level UI mode. Keep it in EditorShell state so the shell can rerender
|
|
235
286
|
// immediately when toggled, while still syncing the active slot's PageViewContext.fullscreen.
|
|
@@ -873,6 +924,15 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
873
924
|
setSelectedHelpSectionId(helpParam === "contents" || helpParam === "true" ? null : helpParam);
|
|
874
925
|
}
|
|
875
926
|
}, [searchParams, isInitialLoad]);
|
|
927
|
+
// Perf probe: the gap between shell:setSelection-state-update and
|
|
928
|
+
// shell:selection-render-committed is the React render of the entire shell
|
|
929
|
+
// tree (every editContext consumer); the paint step adds compositor time.
|
|
930
|
+
useLayoutEffect(() => {
|
|
931
|
+
if (!isPerfTraceActive())
|
|
932
|
+
return;
|
|
933
|
+
perfTraceStep("shell:selection-render-committed", { ids: selection });
|
|
934
|
+
perfTracePaintStep("shell:selection-painted");
|
|
935
|
+
}, [selection]);
|
|
876
936
|
useEffect(() => {
|
|
877
937
|
if (focusedField &&
|
|
878
938
|
selection.length > 0 &&
|
|
@@ -3054,6 +3114,7 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
3054
3114
|
configuration,
|
|
3055
3115
|
selection,
|
|
3056
3116
|
setSelection,
|
|
3117
|
+
selectWithoutAutoScroll,
|
|
3057
3118
|
loadItem,
|
|
3058
3119
|
addToEditHistory,
|
|
3059
3120
|
setLockedField,
|
|
@@ -4030,6 +4091,13 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
4030
4091
|
}, [operationsContext.cleanup]);
|
|
4031
4092
|
// Shared focused field setter with lock handling (used in both contexts)
|
|
4032
4093
|
const setFocusedFieldWithLock = useCallback(async (field, requestLock) => {
|
|
4094
|
+
logFieldValueDiagnostic("focused-field", "setFocusedField requested", {
|
|
4095
|
+
field: summarizeFieldDescriptor(field),
|
|
4096
|
+
requestLock,
|
|
4097
|
+
ignoreBlur,
|
|
4098
|
+
currentFocusedField: summarizeFieldDescriptor(focusedFieldRef.current),
|
|
4099
|
+
lockedField: summarizeFieldDescriptor(lockedField),
|
|
4100
|
+
});
|
|
4033
4101
|
if (field) {
|
|
4034
4102
|
setIgnoreBlur(true);
|
|
4035
4103
|
setTimeout(() => {
|
|
@@ -4038,12 +4106,25 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
4038
4106
|
if (requestLock) {
|
|
4039
4107
|
const lockResult = (await operations.ensureLock(field)) || false;
|
|
4040
4108
|
if (!lockResult) {
|
|
4109
|
+
logFieldValueDiagnostic("focused-field", "lock failed", {
|
|
4110
|
+
field: summarizeFieldDescriptor(field),
|
|
4111
|
+
requestLock,
|
|
4112
|
+
});
|
|
4041
4113
|
return false;
|
|
4042
4114
|
}
|
|
4043
4115
|
setFocusedField({ ...field });
|
|
4116
|
+
logFieldValueDiagnostic("focused-field", "focused field set", {
|
|
4117
|
+
field: summarizeFieldDescriptor(field),
|
|
4118
|
+
requestLock,
|
|
4119
|
+
lockResult,
|
|
4120
|
+
});
|
|
4044
4121
|
return true;
|
|
4045
4122
|
}
|
|
4046
4123
|
setFocusedField({ ...field });
|
|
4124
|
+
logFieldValueDiagnostic("focused-field", "focused field set", {
|
|
4125
|
+
field: summarizeFieldDescriptor(field),
|
|
4126
|
+
requestLock,
|
|
4127
|
+
});
|
|
4047
4128
|
}
|
|
4048
4129
|
else {
|
|
4049
4130
|
// Keep the field selected when the blur was caused by clicking a User
|
|
@@ -4060,13 +4141,25 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
4060
4141
|
now: Date.now(),
|
|
4061
4142
|
});
|
|
4062
4143
|
if (!ignoreBlur && !focusMovedToShowMe) {
|
|
4144
|
+
logFieldValueDiagnostic("focused-field", "clearing focused field", {
|
|
4145
|
+
previousFocusedField: summarizeFieldDescriptor(focusedFieldRef.current),
|
|
4146
|
+
lockedField: summarizeFieldDescriptor(lockedField),
|
|
4147
|
+
sessionId,
|
|
4148
|
+
});
|
|
4063
4149
|
setFocusedField(undefined);
|
|
4064
4150
|
setLockedField(undefined); // Clear client-side lock state
|
|
4065
4151
|
releaseFieldLocks(sessionId);
|
|
4066
4152
|
}
|
|
4153
|
+
else {
|
|
4154
|
+
logFieldValueDiagnostic("focused-field", "clear skipped", {
|
|
4155
|
+
reason: ignoreBlur ? "ignoreBlur" : "manual show-me focus transfer",
|
|
4156
|
+
previousFocusedField: summarizeFieldDescriptor(focusedFieldRef.current),
|
|
4157
|
+
focusMovedToShowMe,
|
|
4158
|
+
});
|
|
4159
|
+
}
|
|
4067
4160
|
}
|
|
4068
4161
|
return true;
|
|
4069
|
-
}, [operations, ignoreBlur, sessionId]);
|
|
4162
|
+
}, [operations, ignoreBlur, sessionId, lockedField]);
|
|
4070
4163
|
const quickSwitcherEntries = useMemo(() => {
|
|
4071
4164
|
const entries = [];
|
|
4072
4165
|
const seen = new Set();
|
|
@@ -4552,10 +4645,21 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
4552
4645
|
loadItemVersions,
|
|
4553
4646
|
sessionId: sessionId,
|
|
4554
4647
|
readonly: isReadOnly,
|
|
4555
|
-
|
|
4648
|
+
getSelection: () => selectionRef.current,
|
|
4556
4649
|
select: (ids) => {
|
|
4650
|
+
// Re-selecting the same components is a no-op: without this bail a
|
|
4651
|
+
// fresh array identity re-renders every selection consumer.
|
|
4652
|
+
const current = selectionRef.current;
|
|
4653
|
+
if (ids.length === current.length &&
|
|
4654
|
+
ids.every((id, index) => id === current[index])) {
|
|
4655
|
+
perfTraceStep("shell:setSelection-bailed (unchanged)", { ids });
|
|
4656
|
+
return;
|
|
4657
|
+
}
|
|
4658
|
+
perfTraceStep("shell:setSelection-state-update", { ids });
|
|
4557
4659
|
setSelection(ids);
|
|
4558
4660
|
},
|
|
4661
|
+
selectWithoutAutoScroll,
|
|
4662
|
+
consumeNextSelectionAutoScrollSuppression,
|
|
4559
4663
|
contentTreeSelection,
|
|
4560
4664
|
setContentTreeSelection,
|
|
4561
4665
|
selectedForInsertion,
|
|
@@ -4597,6 +4701,10 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
4597
4701
|
return await getComponentCommands(components, editContext, providerContext);
|
|
4598
4702
|
},
|
|
4599
4703
|
dragStart: (dragObject) => {
|
|
4704
|
+
// A drag supersedes any unresolved scroll request (e.g. a comment
|
|
4705
|
+
// target still waiting for geometry). Left pending, it would replay
|
|
4706
|
+
// against the post-drop refresh and yank the canvas to a stale spot.
|
|
4707
|
+
setScrollIntoView(undefined);
|
|
4600
4708
|
setDragObject(dragObject);
|
|
4601
4709
|
},
|
|
4602
4710
|
dragEnd: () => {
|
|
@@ -4611,8 +4719,11 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
4611
4719
|
const parentId = placeholderKeyComponents.length === 1
|
|
4612
4720
|
? undefined
|
|
4613
4721
|
: placeholderKeyComponents[1];
|
|
4722
|
+
// Without auto-scroll: the parent is selected for context, not to be
|
|
4723
|
+
// shown — scrolling would move the page away from the drop point
|
|
4724
|
+
// (and, before the refresh lands, toward stale pre-move geometry).
|
|
4614
4725
|
if (parentId)
|
|
4615
|
-
|
|
4726
|
+
selectWithoutAutoScroll([parentId]);
|
|
4616
4727
|
let op;
|
|
4617
4728
|
if (!currentItemDescriptorRef.current)
|
|
4618
4729
|
return;
|
|
@@ -4689,16 +4800,29 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
4689
4800
|
}
|
|
4690
4801
|
return;
|
|
4691
4802
|
}
|
|
4803
|
+
let operationFailed = false;
|
|
4692
4804
|
try {
|
|
4693
|
-
|
|
4805
|
+
// executeOp resolves (instead of throwing) with a failed status when
|
|
4806
|
+
// the server rejects the operation — no refresh follows then.
|
|
4807
|
+
const result = (await operationPromise);
|
|
4808
|
+
operationFailed = result?.executionStatus === "failed";
|
|
4694
4809
|
}
|
|
4695
4810
|
catch (err) {
|
|
4811
|
+
operationFailed = true;
|
|
4696
4812
|
console.error("Failed to drop component in placeholder", err);
|
|
4697
4813
|
}
|
|
4698
4814
|
finally {
|
|
4699
4815
|
if (insertionSequence !== undefined &&
|
|
4700
4816
|
insertingSequenceRef.current === insertionSequence) {
|
|
4701
|
-
|
|
4817
|
+
if (operationFailed) {
|
|
4818
|
+
setInserting(undefined);
|
|
4819
|
+
}
|
|
4820
|
+
else {
|
|
4821
|
+
// The server accepted the drop; the canvas has not repainted
|
|
4822
|
+
// yet. Hold the indicator until the refresh lands so it stops
|
|
4823
|
+
// when the component actually appears, not seconds earlier.
|
|
4824
|
+
holdInsertingUntilCanvasRefresh(insertionSequence);
|
|
4825
|
+
}
|
|
4702
4826
|
}
|
|
4703
4827
|
}
|
|
4704
4828
|
},
|
|
@@ -5200,7 +5324,6 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
5200
5324
|
loadItemVersions,
|
|
5201
5325
|
sessionId,
|
|
5202
5326
|
isReadOnly,
|
|
5203
|
-
selection,
|
|
5204
5327
|
contentTreeSelection,
|
|
5205
5328
|
selectedForInsertion,
|
|
5206
5329
|
dragObject,
|
|
@@ -5348,7 +5471,13 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
5348
5471
|
// This ensures editContextRef.current always has the latest value when executeCommand is called
|
|
5349
5472
|
// Using useEffect would create a timing window where the ref is stale
|
|
5350
5473
|
editContextRef.current = editContext;
|
|
5351
|
-
|
|
5474
|
+
// Selection is deliberately NOT part of editContext (see SelectionContext):
|
|
5475
|
+
// a canvas click would otherwise rebuild the context and re-render every
|
|
5476
|
+
// consumer. Only SelectionContext subscribers re-render on selection change.
|
|
5477
|
+
const selectionContextValue = useMemo(() => ({ selection }), [selection]);
|
|
5478
|
+
// Memoized: a fresh identity here re-renders every FieldsEditContext
|
|
5479
|
+
// consumer on every shell render (same churn class as SelectionContext).
|
|
5480
|
+
const fieldsEditContext = useMemo(() => ({
|
|
5352
5481
|
modifiedFields,
|
|
5353
5482
|
recentEdits,
|
|
5354
5483
|
clearRecentEdits: () => {
|
|
@@ -5361,7 +5490,14 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
5361
5490
|
setLockedField(undefined); // Clear client-side lock state
|
|
5362
5491
|
await releaseFieldLocks(sessionId);
|
|
5363
5492
|
},
|
|
5364
|
-
}
|
|
5493
|
+
}), [
|
|
5494
|
+
modifiedFields,
|
|
5495
|
+
recentEdits,
|
|
5496
|
+
addRecentEdit,
|
|
5497
|
+
focusedField,
|
|
5498
|
+
setFocusedFieldWithLock,
|
|
5499
|
+
sessionId,
|
|
5500
|
+
]);
|
|
5365
5501
|
// Debug: Track editContext changes
|
|
5366
5502
|
// const prevDependencies = useRef<any[]>([]);
|
|
5367
5503
|
// useEffect(() => {
|
|
@@ -5615,13 +5751,13 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
5615
5751
|
window.history.replaceState(getCurrentHistoryState(), "", newUrl);
|
|
5616
5752
|
}, configuration: configuration, restoredFromUrl: tourRestoredRef.current })), _jsx(FeatureGate, { feature: LicenseFeatures.AI, children: _jsx(GuidanceOverlay, {}) }), _jsx(FeatureGate, { feature: LicenseFeatures.AI, children: _jsx(AgentDialogHandler, {}) })] }));
|
|
5617
5753
|
const showRefreshSpinner = editContext.isRefreshing && !activePageViewContext.iframeSupportsRefresh;
|
|
5618
|
-
return (_jsx(LicenseProvider, { initialLicenseStatus: initialLicenseStatus, initialStatusLoaded: initialLicenseStatusLoaded, children: _jsx("div", { className: `editor h-full w-full`, children: _jsx(OperationsContextProvider, { value: operationsContext.context, children: _jsx(FieldsEditContextProvider, { value: fieldsEditContext, children: _jsx(EditContextProvider, { value: editContext, children: _jsxs(SplashScreenAgentProvider, { children: [_jsx(DevModeIndicator, {}), startupChecks.state === "loading" && _jsx(EditorLoadingOverlay, {}), showRefreshSpinner && (_jsx("div", { className: "text-neutral-grey-50 pointer-events-none fixed right-0 bottom-0 flex h-24 w-24 items-center justify-center opacity-50 select-none", children: _jsx(Spinner, {}) })), (currentWorkspace.id === "agents" ||
|
|
5619
|
-
|
|
5620
|
-
|
|
5621
|
-
|
|
5622
|
-
|
|
5623
|
-
|
|
5624
|
-
|
|
5625
|
-
|
|
5754
|
+
return (_jsx(LicenseProvider, { initialLicenseStatus: initialLicenseStatus, initialStatusLoaded: initialLicenseStatusLoaded, children: _jsx("div", { className: `editor h-full w-full`, children: _jsx(OperationsContextProvider, { value: operationsContext.context, children: _jsx(FieldsEditContextProvider, { value: fieldsEditContext, children: _jsx(EditContextProvider, { value: editContext, children: _jsx(SelectionContextProvider, { value: selectionContextValue, children: _jsxs(SplashScreenAgentProvider, { children: [_jsx(DevModeIndicator, {}), startupChecks.state === "loading" && (_jsx(EditorLoadingOverlay, {})), showRefreshSpinner && (_jsx("div", { className: "text-neutral-grey-50 pointer-events-none fixed right-0 bottom-0 flex h-24 w-24 items-center justify-center opacity-50 select-none", children: _jsx(Spinner, {}) })), (currentWorkspace.id === "agents" ||
|
|
5755
|
+
currentWorkspace.id === "taskboard" ||
|
|
5756
|
+
currentWorkspace.id === "translation-management") &&
|
|
5757
|
+
showAgentsWorkspaceEditor && (_jsx(AgentsSlotContextBridgeHost, { slots: editorSlots })), startupChecks.state !== "loading" && (children || editorUi), startupChecks.state !== "loading" && dialog, _jsx(Toaster, { position: "top-center" }), " ", _jsx(ConfirmationDialog, { ref: confirmationDialogRef }), _jsx(ConcurrentUserLimitDialog, { open: concurrentUserLimitError !== null, onOpenChange: (open) => {
|
|
5758
|
+
if (!open) {
|
|
5759
|
+
setConcurrentUserLimitError(null);
|
|
5760
|
+
}
|
|
5761
|
+
}, sessionId: sessionId, currentUsers: concurrentUserLimitError?.currentUsers ?? 0, maxUsers: concurrentUserLimitError?.maxUsers ?? 0, message: concurrentUserLimitError?.message ?? "", onRetry: handleRetryConnection, isAdministrator: userInfo.user.isAdministrator === true }), _jsx(QuickItemSwitcher, { visible: quickSwitcherVisible, entries: quickSwitcherEntries.slice(0, 5), selectedIndex: quickSwitcherSelectedIndex, onSelect: handleQuickSwitcherSelect, onClose: () => setQuickSwitcherVisible(false) }), _jsx(EditContextMenu, { ref: contextMenuRef, onOpenChange: handleContextMenuOpenChange }), _jsx(EditorFormHintPopover, {}), _jsx(FeatureGate, { feature: LicenseFeatures.AI, children: _jsx(InlineAiTrigger, {}) }), media.mediaSelectorVisible && (_jsx(MediaSelector, { language: editContext.currentItemDescriptor.language, visible: media.mediaSelectorVisible, onHide: media.handleHide, onMediaSelected: media.onMediaSelect, selectedIdPath: media.selectedMediaIdPath, mode: media.mediaSelectorMode, initialSearchTerm: media.initialSearchTerm })), _jsx(FieldEditorPopup, { ref: fieldEditorPopupRef }), _jsx(LicenseOverlay, {}), _jsx(SessionExpiredOverlay, {})] }) }) }) }) }) }) }));
|
|
5626
5762
|
}
|
|
5627
5763
|
//# sourceMappingURL=EditorShell.js.map
|