@parhelia/core 0.1.12601 → 0.1.12612
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/client/EditorShell.js +117 -26
- package/dist/editor/client/EditorShell.js.map +1 -1
- package/dist/editor/client/editContext.d.ts +12 -0
- package/dist/editor/client/editContext.js.map +1 -1
- package/dist/editor/client/helpers.js +6 -11
- package/dist/editor/client/helpers.js.map +1 -1
- package/dist/editor/menubar/toolbar-sections/ViewportControls.js +12 -2
- package/dist/editor/menubar/toolbar-sections/ViewportControls.js.map +1 -1
- package/dist/editor/page-viewer/EditorFormHintPopover.d.ts +7 -0
- package/dist/editor/page-viewer/EditorFormHintPopover.js +55 -0
- package/dist/editor/page-viewer/EditorFormHintPopover.js.map +1 -0
- package/dist/editor/page-viewer/MiniMap.js +92 -5
- package/dist/editor/page-viewer/MiniMap.js.map +1 -1
- package/dist/editor/page-viewer/PageViewer.js +36 -94
- package/dist/editor/page-viewer/PageViewer.js.map +1 -1
- package/dist/editor/services/editService.js +27 -11
- package/dist/editor/services/editService.js.map +1 -1
- package/dist/editor/services/serviceHelper.js +62 -2
- package/dist/editor/services/serviceHelper.js.map +1 -1
- package/dist/revision.d.ts +2 -2
- package/dist/revision.js +2 -2
- package/dist/task-board/services/taskService.js +10 -3
- package/dist/task-board/services/taskService.js.map +1 -1
- package/dist/types.d.ts +4 -0
- package/package.json +1 -1
|
@@ -21,6 +21,7 @@ import ConfirmationDialog from "../ConfirmationDialog";
|
|
|
21
21
|
import { getItemDescriptor } from "../utils";
|
|
22
22
|
import { EditContextMenu } from "../ContextMenu";
|
|
23
23
|
import { InlineAiTrigger } from "../ai/InlineAiTrigger";
|
|
24
|
+
import { EditorFormHintPopover } from "../page-viewer/EditorFormHintPopover";
|
|
24
25
|
import { FieldEditorPopup } from "../FieldEditorPopup";
|
|
25
26
|
import { ConcurrentUserLimitDialog } from "../ConcurrentUserLimitDialog";
|
|
26
27
|
import { post } from "../services/serviceHelper";
|
|
@@ -54,6 +55,11 @@ import { useMediaSelector } from "./hooks/useMediaSelector";
|
|
|
54
55
|
import { useGlobalEditorKeyDown } from "./hooks/useGlobalEditorKeyDown";
|
|
55
56
|
import { useStartupChecks } from "../settings/status/index";
|
|
56
57
|
import { FeatureGate, LicenseFeatures, LicenseProvider, LicenseOverlay, } from "../../licensing";
|
|
58
|
+
// Sentinel written to the `sidebar` URL param when the user has explicitly closed
|
|
59
|
+
// every sidebar. Distinguishes "no preference yet" (param absent) from "user wants
|
|
60
|
+
// nothing open" (param present with this value) so reload can honor the user's intent.
|
|
61
|
+
const SIDEBAR_NONE_SENTINEL = "none";
|
|
62
|
+
const sidebarUrlValue = (ids) => ids.length ? ids.join(",") : SIDEBAR_NONE_SENTINEL;
|
|
57
63
|
function AgentsSlotContextBridge({ slot }) {
|
|
58
64
|
const editContext = useEditContext();
|
|
59
65
|
const slotContext = useEditorSlotContext({
|
|
@@ -178,8 +184,12 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
178
184
|
const [openSidebars, setOpenSidebars] = useState(() => {
|
|
179
185
|
const sidebarParam = searchParams.get("sidebar");
|
|
180
186
|
let sidebars = [];
|
|
181
|
-
|
|
182
|
-
|
|
187
|
+
// Presence check (not truthiness) so the sentinel "none" is respected across reloads.
|
|
188
|
+
if (sidebarParam !== null) {
|
|
189
|
+
sidebars =
|
|
190
|
+
sidebarParam === SIDEBAR_NONE_SENTINEL
|
|
191
|
+
? []
|
|
192
|
+
: sidebarParam.split(",").filter(Boolean);
|
|
183
193
|
}
|
|
184
194
|
else {
|
|
185
195
|
sidebars = [...(configuration.editor.defaultOpenSidebars ?? [])];
|
|
@@ -504,6 +514,10 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
504
514
|
});
|
|
505
515
|
}, [editorSlots, showComponentNavigatorDefault]);
|
|
506
516
|
const [showAgentsPanel, setShowAgentsPanel] = useState(userPreferences.showAgentsPanel ?? false);
|
|
517
|
+
const [editorFormHidden, setEditorFormHiddenState] = useState(userPreferences.editorFormHidden ?? false);
|
|
518
|
+
const [editorFormHintSeen, setEditorFormHintSeenState] = useState(userPreferences.editorFormHintSeen ?? false);
|
|
519
|
+
const [editorFormHintVisible, setEditorFormHintVisible] = useState(false);
|
|
520
|
+
const editorFormToggleButtonRef = useRef(null);
|
|
507
521
|
const [showMinimap, setShowMinimap] = useState(userPreferences.showMinimap ?? true);
|
|
508
522
|
const [showHelpTerminal, setShowHelpTerminal] = useState(false);
|
|
509
523
|
const [helpTerminalInitialPrompt, setHelpTerminalInitialPrompt] = useState(undefined);
|
|
@@ -978,6 +992,26 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
978
992
|
setShowMinimap(newValue);
|
|
979
993
|
setUserPreferences({ showMinimap: newValue });
|
|
980
994
|
}, [showMinimap, setUserPreferences]);
|
|
995
|
+
const handleSetEditorFormHidden = useCallback((value) => {
|
|
996
|
+
setEditorFormHiddenState(value);
|
|
997
|
+
setUserPreferences({ editorFormHidden: value });
|
|
998
|
+
}, [setUserPreferences]);
|
|
999
|
+
const markEditorFormHintSeen = useCallback(() => {
|
|
1000
|
+
setEditorFormHintSeenState(true);
|
|
1001
|
+
setUserPreferences({ editorFormHintSeen: true });
|
|
1002
|
+
}, [setUserPreferences]);
|
|
1003
|
+
const showEditorFormHint = useCallback(() => {
|
|
1004
|
+
setEditorFormHintVisible(true);
|
|
1005
|
+
}, []);
|
|
1006
|
+
const dismissEditorFormHint = useCallback(() => {
|
|
1007
|
+
setEditorFormHintVisible(false);
|
|
1008
|
+
setEditorFormHintSeenState((prev) => {
|
|
1009
|
+
if (prev)
|
|
1010
|
+
return prev;
|
|
1011
|
+
setUserPreferences({ editorFormHintSeen: true });
|
|
1012
|
+
return true;
|
|
1013
|
+
});
|
|
1014
|
+
}, [setUserPreferences]);
|
|
981
1015
|
const handleSetShowHelpTerminal = useCallback((value) => {
|
|
982
1016
|
const newValue = typeof value === "function" ? value(showHelpTerminal) : value;
|
|
983
1017
|
setShowHelpTerminal(newValue);
|
|
@@ -1094,7 +1128,10 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
1094
1128
|
lastUrlRef.current = window.location.href;
|
|
1095
1129
|
const keepAliveUrl = "/parhelia/keepalive";
|
|
1096
1130
|
const runSessionCheck = () => {
|
|
1097
|
-
fetch(keepAliveUrl + "?ts=" + Date.now()
|
|
1131
|
+
fetch(keepAliveUrl + "?ts=" + Date.now(), {
|
|
1132
|
+
credentials: "include",
|
|
1133
|
+
headers: { "Cache-Control": "no-cache" },
|
|
1134
|
+
})
|
|
1098
1135
|
.then((response) => {
|
|
1099
1136
|
if (response.headers.get("X-Parhelia-Session-Revoked") === "true") {
|
|
1100
1137
|
window.dispatchEvent(new CustomEvent("parhelia:session-revoked", {
|
|
@@ -1102,15 +1139,23 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
1102
1139
|
}));
|
|
1103
1140
|
return;
|
|
1104
1141
|
}
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1142
|
+
// A redirected response (e.g. to /sitecore/login) or an explicit
|
|
1143
|
+
// 401/403 both mean the user is no longer authenticated. Let a
|
|
1144
|
+
// single event-driven toast handle the UI.
|
|
1145
|
+
const finalUrl = response.url || "";
|
|
1146
|
+
const redirectedToLogin = response.redirected &&
|
|
1147
|
+
(/\/sitecore\/login/i.test(finalUrl) ||
|
|
1148
|
+
/[?&]returnUrl=/i.test(finalUrl));
|
|
1149
|
+
if (redirectedToLogin ||
|
|
1150
|
+
response.status === 401 ||
|
|
1151
|
+
response.status === 403) {
|
|
1152
|
+
window.dispatchEvent(new CustomEvent("parhelia:session-expired", {
|
|
1153
|
+
detail: {
|
|
1154
|
+
reason: redirectedToLogin
|
|
1155
|
+
? "login-redirect"
|
|
1156
|
+
: `status-${response.status}`,
|
|
1111
1157
|
},
|
|
1112
|
-
|
|
1113
|
-
});
|
|
1158
|
+
}));
|
|
1114
1159
|
}
|
|
1115
1160
|
})
|
|
1116
1161
|
.catch((error) => console.error("Keep Alive error:", error));
|
|
@@ -1974,16 +2019,12 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
1974
2019
|
if (!isWorkspaceTransitioning && current.get("workspace") !== viewName) {
|
|
1975
2020
|
current.set("workspace", viewName);
|
|
1976
2021
|
}
|
|
1977
|
-
// Sync sidebar state
|
|
2022
|
+
// Sync sidebar state. Always write a value (sentinel when empty) so that an
|
|
2023
|
+
// explicit "user closed everything" state survives a reload.
|
|
1978
2024
|
const currentSidebars = current.get("sidebar") ?? "";
|
|
1979
|
-
const newSidebars = openSidebars
|
|
2025
|
+
const newSidebars = sidebarUrlValue(openSidebars);
|
|
1980
2026
|
if (currentSidebars !== newSidebars) {
|
|
1981
|
-
|
|
1982
|
-
current.set("sidebar", newSidebars);
|
|
1983
|
-
}
|
|
1984
|
-
else {
|
|
1985
|
-
current.delete("sidebar");
|
|
1986
|
-
}
|
|
2027
|
+
current.set("sidebar", newSidebars);
|
|
1987
2028
|
}
|
|
1988
2029
|
if (showHelpTerminal) {
|
|
1989
2030
|
current.set("help", selectedHelpSectionId ?? "contents");
|
|
@@ -2679,6 +2720,31 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
2679
2720
|
window.removeEventListener("parhelia:session-revoked", handleRevoked);
|
|
2680
2721
|
};
|
|
2681
2722
|
}, [promptSessionReconnect]);
|
|
2723
|
+
// Show a single "session expired" toast with a Login action when any
|
|
2724
|
+
// service call (or the keepalive check) detects that the user is no
|
|
2725
|
+
// longer authenticated. Using a stable toast id coalesces the toast so a
|
|
2726
|
+
// burst of failing calls does not spam the UI with duplicate toasts.
|
|
2727
|
+
useEffect(() => {
|
|
2728
|
+
if (typeof window === "undefined")
|
|
2729
|
+
return;
|
|
2730
|
+
const handleExpired = () => {
|
|
2731
|
+
toast.error("Your session has expired", {
|
|
2732
|
+
id: "session-expired",
|
|
2733
|
+
description: "Please login again to continue editing.",
|
|
2734
|
+
action: {
|
|
2735
|
+
label: "Login",
|
|
2736
|
+
onClick: () => {
|
|
2737
|
+
window.location.href = "/sitecore/login";
|
|
2738
|
+
},
|
|
2739
|
+
},
|
|
2740
|
+
duration: Infinity,
|
|
2741
|
+
});
|
|
2742
|
+
};
|
|
2743
|
+
window.addEventListener("parhelia:session-expired", handleExpired);
|
|
2744
|
+
return () => {
|
|
2745
|
+
window.removeEventListener("parhelia:session-expired", handleExpired);
|
|
2746
|
+
};
|
|
2747
|
+
}, []);
|
|
2682
2748
|
const sendSocketMessage = useCallback((message) => {
|
|
2683
2749
|
if (socketInstanceRef.current &&
|
|
2684
2750
|
socketInstanceRef.current.readyState === WebSocket.OPEN) {
|
|
@@ -2795,7 +2861,7 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
2795
2861
|
setUserPreferences({ showAgentsPanel: false });
|
|
2796
2862
|
}
|
|
2797
2863
|
startTransition(() => {
|
|
2798
|
-
updateUrl({ sidebar: newSidebars
|
|
2864
|
+
updateUrl({ sidebar: sidebarUrlValue(newSidebars) });
|
|
2799
2865
|
});
|
|
2800
2866
|
return;
|
|
2801
2867
|
}
|
|
@@ -2818,7 +2884,7 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
2818
2884
|
setMobileEditorPanelOpenRaw(false);
|
|
2819
2885
|
}
|
|
2820
2886
|
startTransition(() => {
|
|
2821
|
-
updateUrl({ sidebar: newSidebars
|
|
2887
|
+
updateUrl({ sidebar: sidebarUrlValue(newSidebars) });
|
|
2822
2888
|
});
|
|
2823
2889
|
}, [
|
|
2824
2890
|
updateUrl,
|
|
@@ -2856,7 +2922,7 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
2856
2922
|
setMobileEditorPanelOpenRaw(false);
|
|
2857
2923
|
}
|
|
2858
2924
|
startTransition(() => {
|
|
2859
|
-
updateUrl({ sidebar: newSidebars
|
|
2925
|
+
updateUrl({ sidebar: sidebarUrlValue(newSidebars) });
|
|
2860
2926
|
});
|
|
2861
2927
|
}, [
|
|
2862
2928
|
updateUrl,
|
|
@@ -2936,7 +3002,7 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
2936
3002
|
openSidebarsRef.current = nextOpen;
|
|
2937
3003
|
setOpenSidebars(nextOpen);
|
|
2938
3004
|
startTransition(() => {
|
|
2939
|
-
updateUrl({ sidebar: nextOpen
|
|
3005
|
+
updateUrl({ sidebar: sidebarUrlValue(nextOpen) });
|
|
2940
3006
|
});
|
|
2941
3007
|
setSidebarStacks((prev) => {
|
|
2942
3008
|
const normalized = normalizeSidebarStacks(nextOpen, prev);
|
|
@@ -3039,14 +3105,23 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
3039
3105
|
panels: resolvedPanels,
|
|
3040
3106
|
};
|
|
3041
3107
|
}, [getSidebarsForWorkspace, workspaceId]);
|
|
3108
|
+
// Track the last workspaceId this effect saw so we only auto-apply
|
|
3109
|
+
// `currentWorkspace.defaultSidebars` on an actual workspace change. On initial mount
|
|
3110
|
+
// the user's explicit empty state (sidebar=none in URL) must not be overwritten.
|
|
3111
|
+
const prevWorkspaceIdForDefaultsRef = useRef(null);
|
|
3042
3112
|
useEffect(() => {
|
|
3043
3113
|
if (!currentWorkspace.supportsSidebars) {
|
|
3044
3114
|
return;
|
|
3045
3115
|
}
|
|
3116
|
+
const prev = prevWorkspaceIdForDefaultsRef.current;
|
|
3117
|
+
prevWorkspaceIdForDefaultsRef.current = workspaceId;
|
|
3118
|
+
const isWorkspaceChange = prev !== null && prev !== workspaceId;
|
|
3046
3119
|
const allowedIds = new Set(getSidebarsForWorkspace(workspaceId).map((sidebar) => sidebar.id));
|
|
3047
3120
|
const currentOpen = openSidebarsRef.current;
|
|
3048
3121
|
let nextOpen = currentOpen.filter((id) => allowedIds.has(id));
|
|
3049
|
-
if (
|
|
3122
|
+
if (isWorkspaceChange &&
|
|
3123
|
+
nextOpen.length === 0 &&
|
|
3124
|
+
currentWorkspace.defaultSidebars?.length) {
|
|
3050
3125
|
nextOpen = currentWorkspace.defaultSidebars.filter((id) => allowedIds.has(id));
|
|
3051
3126
|
}
|
|
3052
3127
|
const unchanged = nextOpen.length === currentOpen.length &&
|
|
@@ -3058,7 +3133,7 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
3058
3133
|
setOpenSidebars(nextOpen);
|
|
3059
3134
|
setSidebarStacks((prev) => normalizeSidebarStacks(nextOpen, prev));
|
|
3060
3135
|
startTransition(() => {
|
|
3061
|
-
updateUrl({ sidebar: nextOpen
|
|
3136
|
+
updateUrl({ sidebar: sidebarUrlValue(nextOpen) });
|
|
3062
3137
|
});
|
|
3063
3138
|
}, [
|
|
3064
3139
|
currentWorkspace,
|
|
@@ -4247,6 +4322,14 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
4247
4322
|
setComponentNavigatorOpenForSlot,
|
|
4248
4323
|
showAgentsPanel,
|
|
4249
4324
|
setShowAgentsPanel: handleSetShowAgentsPanel,
|
|
4325
|
+
editorFormHidden,
|
|
4326
|
+
setEditorFormHidden: handleSetEditorFormHidden,
|
|
4327
|
+
editorFormHintSeen,
|
|
4328
|
+
markEditorFormHintSeen,
|
|
4329
|
+
editorFormHintVisible,
|
|
4330
|
+
showEditorFormHint,
|
|
4331
|
+
dismissEditorFormHint,
|
|
4332
|
+
editorFormToggleButtonRef,
|
|
4250
4333
|
showMinimap,
|
|
4251
4334
|
setShowMinimap: handleSetShowMinimap,
|
|
4252
4335
|
showHelpTerminal,
|
|
@@ -4410,6 +4493,14 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
4410
4493
|
handleSetShowComponentNavigator,
|
|
4411
4494
|
showAgentsPanel,
|
|
4412
4495
|
handleSetShowAgentsPanel,
|
|
4496
|
+
editorFormHidden,
|
|
4497
|
+
handleSetEditorFormHidden,
|
|
4498
|
+
editorFormHintSeen,
|
|
4499
|
+
markEditorFormHintSeen,
|
|
4500
|
+
editorFormHintVisible,
|
|
4501
|
+
showEditorFormHint,
|
|
4502
|
+
dismissEditorFormHint,
|
|
4503
|
+
editorFormToggleButtonRef,
|
|
4413
4504
|
showMinimap,
|
|
4414
4505
|
handleSetShowMinimap,
|
|
4415
4506
|
showHelpTerminal,
|
|
@@ -4716,6 +4807,6 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
4716
4807
|
if (!open) {
|
|
4717
4808
|
setConcurrentUserLimitError(null);
|
|
4718
4809
|
}
|
|
4719
|
-
}, 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 }), _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, {})] }) }) }) }) }));
|
|
4810
|
+
}, 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 }), _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, {})] }) }) }) }) }));
|
|
4720
4811
|
}
|
|
4721
4812
|
//# sourceMappingURL=EditorShell.js.map
|