@parhelia/core 0.1.12565 → 0.1.12570
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/agents-view/AgentCard.d.ts +4 -6
- package/dist/agents-view/AgentCard.js +24 -143
- package/dist/agents-view/AgentCard.js.map +1 -1
- package/dist/agents-view/AgentsInbox.d.ts +1 -1
- package/dist/agents-view/AgentsInbox.js +92 -7
- package/dist/agents-view/AgentsInbox.js.map +1 -1
- package/dist/agents-view/AgentsTitlebar.js +2 -3
- package/dist/agents-view/AgentsTitlebar.js.map +1 -1
- package/dist/agents-view/AgentsView.d.ts +7 -6
- package/dist/agents-view/AgentsView.js +99 -191
- package/dist/agents-view/AgentsView.js.map +1 -1
- package/dist/agents-view/AgentsWorkspaceView.d.ts +6 -2
- package/dist/agents-view/AgentsWorkspaceView.js +113 -266
- package/dist/agents-view/AgentsWorkspaceView.js.map +1 -1
- package/dist/agents-view/ProfileAgentsGroup.d.ts +1 -2
- package/dist/agents-view/ProfileAgentsGroup.js +3 -4
- package/dist/agents-view/ProfileAgentsGroup.js.map +1 -1
- package/dist/components/ActionButton.d.ts +1 -1
- package/dist/components/ActionButton.js.map +1 -1
- package/dist/components/FilterInput.d.ts +1 -1
- package/dist/components/FilterInput.js +1 -1
- package/dist/components/FilterInput.js.map +1 -1
- package/dist/components/ui/LanguageSelector.js +4 -2
- package/dist/components/ui/LanguageSelector.js.map +1 -1
- package/dist/components/ui/PlaceholderInput.js +3 -3
- package/dist/components/ui/PlaceholderInput.js.map +1 -1
- package/dist/components/ui/PlaceholderInputTypes.js +1 -1
- package/dist/components/ui/PlaceholderInputTypes.js.map +1 -1
- package/dist/components/ui/alert-dialog.d.ts +1 -1
- package/dist/components/ui/alert-dialog.js +10 -6
- package/dist/components/ui/alert-dialog.js.map +1 -1
- package/dist/components/ui/button.d.ts +4 -4
- package/dist/components/ui/button.js +1 -4
- package/dist/components/ui/button.js.map +1 -1
- package/dist/components/ui/context-menu.d.ts +1 -1
- package/dist/components/ui/context-menu.js +4 -12
- package/dist/components/ui/context-menu.js.map +1 -1
- package/dist/components/ui/copy-button.d.ts +1 -2
- package/dist/components/ui/copy-button.js +2 -2
- package/dist/components/ui/copy-button.js.map +1 -1
- package/dist/components/ui/dialog.d.ts +1 -1
- package/dist/components/ui/dialog.js +126 -21
- package/dist/components/ui/dialog.js.map +1 -1
- package/dist/components/ui/input.d.ts +1 -1
- package/dist/components/ui/input.js +3 -5
- package/dist/components/ui/input.js.map +1 -1
- package/dist/components/ui/paste-button.d.ts +1 -2
- package/dist/components/ui/paste-button.js +2 -2
- package/dist/components/ui/paste-button.js.map +1 -1
- package/dist/components/ui/popover.js +9 -1
- package/dist/components/ui/popover.js.map +1 -1
- package/dist/components/ui/select.js +1 -1
- package/dist/components/ui/select.js.map +1 -1
- package/dist/components/ui/styled-dialog-title.js +1 -1
- package/dist/components/ui/styled-dialog-title.js.map +1 -1
- package/dist/components/ui/tabs.d.ts +1 -1
- package/dist/components/ui/tabs.js +11 -4
- package/dist/components/ui/tabs.js.map +1 -1
- package/dist/config/config.d.ts +2 -4
- package/dist/config/config.js +70 -250
- package/dist/config/config.js.map +1 -1
- package/dist/config/types/workspace.d.ts +0 -6
- package/dist/config/types.d.ts +12 -63
- package/dist/config/types.js.map +1 -1
- package/dist/editor/ComponentInfo.d.ts +4 -0
- package/dist/editor/ComponentInfo.js +41 -0
- package/dist/editor/ComponentInfo.js.map +1 -0
- package/dist/editor/ConfirmationDialog.js +4 -20
- package/dist/editor/ConfirmationDialog.js.map +1 -1
- package/dist/editor/ContentTree.d.ts +1 -2
- package/dist/editor/ContentTree.js +32 -93
- package/dist/editor/ContentTree.js.map +1 -1
- package/dist/editor/Editor.js +22 -87
- package/dist/editor/Editor.js.map +1 -1
- package/dist/editor/FieldHistory.js +36 -84
- package/dist/editor/FieldHistory.js.map +1 -1
- package/dist/editor/FieldListField.js +9 -21
- package/dist/editor/FieldListField.js.map +1 -1
- package/dist/editor/FieldListFieldWithFallbacks.js +2 -23
- package/dist/editor/FieldListFieldWithFallbacks.js.map +1 -1
- package/dist/editor/GlobalMenuBar.js +2 -29
- package/dist/editor/GlobalMenuBar.js.map +1 -1
- package/dist/editor/ImageEditor.js +2 -5
- package/dist/editor/ImageEditor.js.map +1 -1
- package/dist/editor/ItemInfo.js +1 -36
- package/dist/editor/ItemInfo.js.map +1 -1
- package/dist/editor/LinkEditorDialog.js +0 -3
- package/dist/editor/LinkEditorDialog.js.map +1 -1
- package/dist/editor/MainLayout.d.ts +2 -0
- package/dist/editor/MainLayout.js +8 -65
- package/dist/editor/MainLayout.js.map +1 -1
- package/dist/editor/MigrationsView.js +5 -29
- package/dist/editor/MigrationsView.js.map +1 -1
- package/dist/editor/MobileLayout.js +12 -37
- package/dist/editor/MobileLayout.js.map +1 -1
- package/dist/editor/PictureCropper.js +45 -54
- package/dist/editor/PictureCropper.js.map +1 -1
- package/dist/editor/PictureEditor.js +15 -17
- package/dist/editor/PictureEditor.js.map +1 -1
- package/dist/editor/QuickItemSwitcher.js +21 -21
- package/dist/editor/QuickItemSwitcher.js.map +1 -1
- package/dist/editor/SetupWizard.js +12 -52
- package/dist/editor/SetupWizard.js.map +1 -1
- package/dist/editor/Titlebar.js +2 -7
- package/dist/editor/Titlebar.js.map +1 -1
- package/dist/editor/ai/AgentCostDisplay.d.ts +0 -1
- package/dist/editor/ai/AgentCostDisplay.js +1 -1
- package/dist/editor/ai/AgentCostDisplay.js.map +1 -1
- package/dist/editor/ai/AgentDocumentList.js +14 -32
- package/dist/editor/ai/AgentDocumentList.js.map +1 -1
- package/dist/editor/ai/AgentGreeting.js +2 -3
- package/dist/editor/ai/AgentGreeting.js.map +1 -1
- package/dist/editor/ai/AgentProfileSelector.js +1 -2
- package/dist/editor/ai/AgentProfileSelector.js.map +1 -1
- package/dist/editor/ai/AgentStatusBadge.d.ts +5 -0
- package/dist/editor/ai/AgentStatusBadge.js +65 -67
- package/dist/editor/ai/AgentStatusBadge.js.map +1 -1
- package/dist/editor/ai/AgentTerminal.d.ts +2 -14
- package/dist/editor/ai/AgentTerminal.js +496 -2406
- package/dist/editor/ai/AgentTerminal.js.map +1 -1
- package/dist/editor/ai/AgentTerminalStatusBar.d.ts +3 -8
- package/dist/editor/ai/AgentTerminalStatusBar.js +56 -481
- package/dist/editor/ai/AgentTerminalStatusBar.js.map +1 -1
- package/dist/editor/ai/Agents.js +113 -161
- package/dist/editor/ai/Agents.js.map +1 -1
- package/dist/editor/ai/AiResponseMessage.d.ts +1 -10
- package/dist/editor/ai/AiResponseMessage.js +26 -267
- package/dist/editor/ai/AiResponseMessage.js.map +1 -1
- package/dist/editor/ai/ContextInfoBar.d.ts +3 -2
- package/dist/editor/ai/ContextInfoBar.js +7 -64
- package/dist/editor/ai/ContextInfoBar.js.map +1 -1
- package/dist/editor/ai/GuidanceOverlay.js +11 -17
- package/dist/editor/ai/GuidanceOverlay.js.map +1 -1
- package/dist/editor/ai/HelpTerminal.d.ts +5 -0
- package/dist/editor/ai/HelpTerminal.js +166 -0
- package/dist/editor/ai/HelpTerminal.js.map +1 -0
- package/dist/editor/ai/InlineAiDialog.d.ts +1 -1
- package/dist/editor/ai/InlineAiDialog.js +192 -514
- package/dist/editor/ai/InlineAiDialog.js.map +1 -1
- package/dist/editor/ai/InlineAiTrigger.js +12 -115
- package/dist/editor/ai/InlineAiTrigger.js.map +1 -1
- package/dist/editor/ai/MediaImage.js +8 -40
- package/dist/editor/ai/MediaImage.js.map +1 -1
- package/dist/editor/ai/SpawnedAgentsPanel.js +12 -10
- package/dist/editor/ai/SpawnedAgentsPanel.js.map +1 -1
- package/dist/editor/ai/ToolCallDisplay.d.ts +2 -22
- package/dist/editor/ai/ToolCallDisplay.js +150 -542
- package/dist/editor/ai/ToolCallDisplay.js.map +1 -1
- package/dist/editor/ai/dialogs/AgentDialogHandler.d.ts +8 -1
- package/dist/editor/ai/dialogs/AgentDialogHandler.js +42 -379
- package/dist/editor/ai/dialogs/AgentDialogHandler.js.map +1 -1
- package/dist/editor/ai/dialogs/QuestionnaireInline.d.ts +1 -5
- package/dist/editor/ai/dialogs/QuestionnaireInline.js +60 -628
- package/dist/editor/ai/dialogs/QuestionnaireInline.js.map +1 -1
- package/dist/editor/ai/dialogs/agentDialogTypes.d.ts +0 -115
- package/dist/editor/ai/dialogs/agentDialogTypes.js +0 -2
- package/dist/editor/ai/dialogs/agentDialogTypes.js.map +1 -1
- package/dist/editor/ai/types.d.ts +1 -3
- package/dist/editor/ai/useAgentStatus.d.ts +1 -2
- package/dist/editor/ai/useAgentStatus.js +100 -90
- package/dist/editor/ai/useAgentStatus.js.map +1 -1
- package/dist/editor/ai/useInlineAiPosition.js +5 -45
- package/dist/editor/ai/useInlineAiPosition.js.map +1 -1
- package/dist/editor/client/AboutDialog.js +2 -4
- package/dist/editor/client/AboutDialog.js.map +1 -1
- package/dist/editor/client/EditorShell.d.ts +1 -4
- package/dist/editor/client/EditorShell.js +237 -770
- package/dist/editor/client/EditorShell.js.map +1 -1
- package/dist/editor/client/editContext.d.ts +19 -33
- package/dist/editor/client/editContext.js.map +1 -1
- package/dist/editor/client/helpers.js +0 -6
- package/dist/editor/client/helpers.js.map +1 -1
- package/dist/editor/client/hooks/useEditorUrlSync.js +2 -1
- package/dist/editor/client/hooks/useEditorUrlSync.js.map +1 -1
- package/dist/editor/client/hooks/useEditorWebSocket.d.ts +0 -10
- package/dist/editor/client/hooks/useEditorWebSocket.js +14 -209
- package/dist/editor/client/hooks/useEditorWebSocket.js.map +1 -1
- package/dist/editor/client/hooks/useQuota.d.ts +0 -8
- package/dist/editor/client/hooks/useQuota.js.map +1 -1
- package/dist/editor/client/hooks/useSocketMessageHandler.js +15 -73
- package/dist/editor/client/hooks/useSocketMessageHandler.js.map +1 -1
- package/dist/editor/client/itemsRepository.js +6 -10
- package/dist/editor/client/itemsRepository.js.map +1 -1
- package/dist/editor/client/operations.d.ts +3 -6
- package/dist/editor/client/operations.js +30 -208
- package/dist/editor/client/operations.js.map +1 -1
- package/dist/editor/client/pageModelBuilder.js +31 -4
- package/dist/editor/client/pageModelBuilder.js.map +1 -1
- package/dist/editor/client/ui/DevModeIndicator.js +2 -2
- package/dist/editor/client/ui/DevModeIndicator.js.map +1 -1
- package/dist/editor/client/ui/EditorChrome.d.ts +6 -0
- package/dist/editor/client/ui/EditorChrome.js +72 -55
- package/dist/editor/client/ui/EditorChrome.js.map +1 -1
- package/dist/editor/client/ui/FullscreenControls.js +3 -5
- package/dist/editor/client/ui/FullscreenControls.js.map +1 -1
- package/dist/editor/commands/commands.d.ts +1 -11
- package/dist/editor/commands/commands.js +1 -12
- package/dist/editor/commands/commands.js.map +1 -1
- package/dist/editor/commands/componentCommands.js +55 -109
- package/dist/editor/commands/componentCommands.js.map +1 -1
- package/dist/editor/commands/customCommandConverter.d.ts +1 -8
- package/dist/editor/commands/customCommandConverter.js +5 -35
- package/dist/editor/commands/customCommandConverter.js.map +1 -1
- package/dist/editor/commands/handlers/agentHandler.js +1 -2
- package/dist/editor/commands/handlers/agentHandler.js.map +1 -1
- package/dist/editor/commands/itemCommands.d.ts +0 -3
- package/dist/editor/commands/itemCommands.js +10 -93
- package/dist/editor/commands/itemCommands.js.map +1 -1
- package/dist/editor/commands/undo.d.ts +15 -9
- package/dist/editor/commands/undo.js +0 -24
- package/dist/editor/commands/undo.js.map +1 -1
- package/dist/editor/context-menu/InsertMenu.js +39 -83
- package/dist/editor/context-menu/InsertMenu.js.map +1 -1
- package/dist/editor/field-types/MultiLineText.js +1 -1
- package/dist/editor/field-types/MultiLineText.js.map +1 -1
- package/dist/editor/field-types/RawEditor.js +1 -1
- package/dist/editor/field-types/ReactQuill.d.ts +125 -0
- package/dist/editor/field-types/ReactQuill.js +385 -0
- package/dist/editor/field-types/ReactQuill.js.map +1 -0
- package/dist/editor/field-types/RichTextEditor.js +5 -13
- package/dist/editor/field-types/RichTextEditor.js.map +1 -1
- package/dist/editor/field-types/RichTextEditorComponent.js +3 -37
- package/dist/editor/field-types/RichTextEditorComponent.js.map +1 -1
- package/dist/editor/field-types/SingleLineText.js +1 -1
- package/dist/editor/field-types/TreeListEditor.js +2 -3
- package/dist/editor/field-types/TreeListEditor.js.map +1 -1
- package/dist/editor/field-types/richtext/components/ReactSlate.css +5 -23
- package/dist/editor/field-types/richtext/components/ReactSlate.d.ts +0 -2
- package/dist/editor/field-types/richtext/components/ReactSlate.js +4 -28
- package/dist/editor/field-types/richtext/components/ReactSlate.js.map +1 -1
- package/dist/editor/field-types/richtext/components/ToolbarButton.js +2 -4
- package/dist/editor/field-types/richtext/components/ToolbarButton.js.map +1 -1
- package/dist/editor/field-types/richtext/contextMenuFactory.d.ts +0 -13
- package/dist/editor/field-types/richtext/contextMenuFactory.js +24 -181
- package/dist/editor/field-types/richtext/contextMenuFactory.js.map +1 -1
- package/dist/editor/field-types/richtext/types.d.ts +0 -2
- package/dist/editor/field-types/richtext/types.js.map +1 -1
- package/dist/editor/field-types/richtext/utils/plugins.js +0 -4
- package/dist/editor/field-types/richtext/utils/plugins.js.map +1 -1
- package/dist/editor/field-types/textContextMenuFactory.js +2 -3
- package/dist/editor/field-types/textContextMenuFactory.js.map +1 -1
- package/dist/editor/media-selector/AiImageSearchPrompt.js +2 -4
- package/dist/editor/media-selector/AiImageSearchPrompt.js.map +1 -1
- package/dist/editor/media-selector/MediaFolderBrowser.js +1 -1
- package/dist/editor/media-selector/MediaFolderBrowser.js.map +1 -1
- package/dist/editor/media-selector/MediaSelector.js +1 -7
- package/dist/editor/media-selector/MediaSelector.js.map +1 -1
- package/dist/editor/media-selector/TreeSelector.js +35 -40
- package/dist/editor/media-selector/TreeSelector.js.map +1 -1
- package/dist/editor/menubar/ActiveUsers.js +1 -1
- package/dist/editor/menubar/ActiveUsers.js.map +1 -1
- package/dist/editor/menubar/GenericToolbar.js +2 -4
- package/dist/editor/menubar/GenericToolbar.js.map +1 -1
- package/dist/editor/menubar/ItemLanguageVersion.js +2 -2
- package/dist/editor/menubar/ItemLanguageVersion.js.map +1 -1
- package/dist/editor/menubar/PageSelector.js +147 -26
- package/dist/editor/menubar/PageSelector.js.map +1 -1
- package/dist/editor/menubar/Separator.js +1 -1
- package/dist/editor/menubar/VersionSelector.js +4 -2
- package/dist/editor/menubar/VersionSelector.js.map +1 -1
- package/dist/editor/menubar/WorkflowButton.js +12 -39
- package/dist/editor/menubar/WorkflowButton.js.map +1 -1
- package/dist/editor/menubar/toolbar-sections/CustomCommandsToolbar.js +38 -16
- package/dist/editor/menubar/toolbar-sections/CustomCommandsToolbar.js.map +1 -1
- package/dist/editor/menubar/toolbar-sections/EditControls.js +3 -3
- package/dist/editor/menubar/toolbar-sections/EditControls.js.map +1 -1
- package/dist/editor/menubar/toolbar-sections/HelpButton.js +0 -1
- package/dist/editor/menubar/toolbar-sections/HelpButton.js.map +1 -1
- package/dist/editor/menubar/toolbar-sections/ManualBrowser.d.ts +10 -6
- package/dist/editor/menubar/toolbar-sections/ManualBrowser.js +220 -597
- package/dist/editor/menubar/toolbar-sections/ManualBrowser.js.map +1 -1
- package/dist/editor/menubar/toolbar-sections/UtilityControls.js +2 -13
- package/dist/editor/menubar/toolbar-sections/UtilityControls.js.map +1 -1
- package/dist/editor/page-editor-chrome/CommentHighlighting.js +1 -42
- package/dist/editor/page-editor-chrome/CommentHighlighting.js.map +1 -1
- package/dist/editor/page-editor-chrome/FrameMenu.js +1 -1
- package/dist/editor/page-editor-chrome/FrameMenu.js.map +1 -1
- package/dist/editor/page-editor-chrome/InlineEditor.js +48 -97
- package/dist/editor/page-editor-chrome/InlineEditor.js.map +1 -1
- package/dist/editor/page-editor-chrome/PlaceholderDropZone.js +17 -38
- package/dist/editor/page-editor-chrome/PlaceholderDropZone.js.map +1 -1
- package/dist/editor/page-editor-chrome/PlaceholderDropZones.js +11 -17
- package/dist/editor/page-editor-chrome/PlaceholderDropZones.js.map +1 -1
- package/dist/editor/page-editor-chrome/useInlineAICompletion.js +301 -301
- package/dist/editor/page-editor-chrome/useInlineAICompletion.js.map +1 -1
- package/dist/editor/page-viewer/DeviceToolbar.js +1 -1
- package/dist/editor/page-viewer/DeviceToolbar.js.map +1 -1
- package/dist/editor/page-viewer/EditorForm.js +11 -69
- package/dist/editor/page-viewer/EditorForm.js.map +1 -1
- package/dist/editor/page-viewer/MiniMap.d.ts +4 -2
- package/dist/editor/page-viewer/MiniMap.js +28 -91
- package/dist/editor/page-viewer/MiniMap.js.map +1 -1
- package/dist/editor/page-viewer/PageViewer.d.ts +1 -3
- package/dist/editor/page-viewer/PageViewer.js +19 -92
- package/dist/editor/page-viewer/PageViewer.js.map +1 -1
- package/dist/editor/page-viewer/PageViewerFrame.d.ts +1 -2
- package/dist/editor/page-viewer/PageViewerFrame.js +115 -348
- package/dist/editor/page-viewer/PageViewerFrame.js.map +1 -1
- package/dist/editor/page-viewer/pageModelSkeletonBuilder.js +49 -114
- package/dist/editor/page-viewer/pageModelSkeletonBuilder.js.map +1 -1
- package/dist/editor/page-viewer/pageViewContext.d.ts +0 -1
- package/dist/editor/page-viewer/pageViewContext.js +14 -51
- package/dist/editor/page-viewer/pageViewContext.js.map +1 -1
- package/dist/editor/pageModel.d.ts +1 -14
- package/dist/editor/reviews/Comment.js +12 -26
- package/dist/editor/reviews/Comment.js.map +1 -1
- package/dist/editor/reviews/CommentDisplayPopover.js +5 -7
- package/dist/editor/reviews/CommentDisplayPopover.js.map +1 -1
- package/dist/editor/reviews/CommentView.js +4 -19
- package/dist/editor/reviews/CommentView.js.map +1 -1
- package/dist/editor/reviews/Comments.js +72 -89
- package/dist/editor/reviews/Comments.js.map +1 -1
- package/dist/editor/reviews/CreateReviewDialog.js +177 -281
- package/dist/editor/reviews/CreateReviewDialog.js.map +1 -1
- package/dist/editor/reviews/DecisionsMatrix.js +25 -96
- package/dist/editor/reviews/DecisionsMatrix.js.map +1 -1
- package/dist/editor/reviews/DiffView.js +14 -7
- package/dist/editor/reviews/DiffView.js.map +1 -1
- package/dist/editor/reviews/EditReviewSettingsDialog.js +4 -6
- package/dist/editor/reviews/EditReviewSettingsDialog.js.map +1 -1
- package/dist/editor/reviews/MultiReviewManager.js +3 -25
- package/dist/editor/reviews/MultiReviewManager.js.map +1 -1
- package/dist/editor/reviews/PagesPanel.js +15 -31
- package/dist/editor/reviews/PagesPanel.js.map +1 -1
- package/dist/editor/reviews/PreviewInfo.js +4 -1
- package/dist/editor/reviews/PreviewInfo.js.map +1 -1
- package/dist/editor/reviews/ReviewCard.js +7 -13
- package/dist/editor/reviews/ReviewCard.js.map +1 -1
- package/dist/editor/reviews/ReviewDetail.js +2 -3
- package/dist/editor/reviews/ReviewDetail.js.map +1 -1
- package/dist/editor/reviews/ReviewsList.js +3 -7
- package/dist/editor/reviews/ReviewsList.js.map +1 -1
- package/dist/editor/reviews/SuggestedEdit.js +3 -34
- package/dist/editor/reviews/SuggestedEdit.js.map +1 -1
- package/dist/editor/reviews/SuggestionDisplayPopover.js +5 -31
- package/dist/editor/reviews/SuggestionDisplayPopover.js.map +1 -1
- package/dist/editor/reviews/commentAi.js +6 -25
- package/dist/editor/reviews/commentAi.js.map +1 -1
- package/dist/editor/reviews/reviewCommands.js +1 -4
- package/dist/editor/reviews/reviewCommands.js.map +1 -1
- package/dist/editor/reviews/useMultiReview.js +2 -2
- package/dist/editor/reviews/useMultiReview.js.map +1 -1
- package/dist/editor/reviews/useReviews.d.ts +2 -2
- package/dist/editor/reviews/useReviews.js +30 -12
- package/dist/editor/reviews/useReviews.js.map +1 -1
- package/dist/editor/services/agentService.d.ts +5 -229
- package/dist/editor/services/agentService.js +39 -292
- package/dist/editor/services/agentService.js.map +1 -1
- package/dist/editor/services/aiService.d.ts +1 -57
- package/dist/editor/services/aiService.js +6 -79
- package/dist/editor/services/aiService.js.map +1 -1
- package/dist/editor/services/contentService.d.ts +3 -6
- package/dist/editor/services/contentService.js +12 -13
- package/dist/editor/services/contentService.js.map +1 -1
- package/dist/editor/services/editService.d.ts +1 -52
- package/dist/editor/services/editService.js +2 -94
- package/dist/editor/services/editService.js.map +1 -1
- package/dist/editor/services/indexService.js +1 -1
- package/dist/editor/services/indexService.js.map +1 -1
- package/dist/editor/services/reviewsService.d.ts +6 -3
- package/dist/editor/services/reviewsService.js +11 -2
- package/dist/editor/services/reviewsService.js.map +1 -1
- package/dist/editor/services/serviceHelper.d.ts +1 -2
- package/dist/editor/services/serviceHelper.js +20 -112
- package/dist/editor/services/serviceHelper.js.map +1 -1
- package/dist/editor/services/systemService.d.ts +1 -2
- package/dist/editor/services/systemService.js +0 -3
- package/dist/editor/services/systemService.js.map +1 -1
- package/dist/editor/services-server/api.d.ts +2 -1
- package/dist/editor/services-server/api.js +6 -11
- package/dist/editor/services-server/api.js.map +1 -1
- package/dist/editor/services-server/graphQL.d.ts +29 -0
- package/dist/editor/services-server/graphQL.js +53 -0
- package/dist/editor/services-server/graphQL.js.map +1 -0
- package/dist/editor/settings/About.js +3 -317
- package/dist/editor/settings/About.js.map +1 -1
- package/dist/editor/settings/AllAgentsPanel.d.ts +5 -0
- package/dist/editor/settings/AllAgentsPanel.js +139 -0
- package/dist/editor/settings/AllAgentsPanel.js.map +1 -0
- package/dist/editor/settings/LatestFeedback.d.ts +1 -0
- package/dist/editor/settings/LatestFeedback.js +136 -0
- package/dist/editor/settings/LatestFeedback.js.map +1 -0
- package/dist/editor/settings/QuotaInfo.js +4 -210
- package/dist/editor/settings/QuotaInfo.js.map +1 -1
- package/dist/editor/settings/SettingsView.js +23 -25
- package/dist/editor/settings/SettingsView.js.map +1 -1
- package/dist/editor/settings/Setup.d.ts +1 -0
- package/dist/editor/settings/Setup.js +211 -0
- package/dist/editor/settings/Setup.js.map +1 -0
- package/dist/editor/settings/Status.js +6 -7
- package/dist/editor/settings/Status.js.map +1 -1
- package/dist/editor/settings/index/useIndexStatus.js +22 -20
- package/dist/editor/settings/index/useIndexStatus.js.map +1 -1
- package/dist/editor/settings/panels/AgentsPanel.d.ts +4 -0
- package/dist/editor/settings/panels/AgentsPanel.js +121 -95
- package/dist/editor/settings/panels/AgentsPanel.js.map +1 -1
- package/dist/editor/settings/panels/DatabasePanel.d.ts +6 -0
- package/dist/editor/settings/panels/DatabasePanel.js +50 -0
- package/dist/editor/settings/panels/DatabasePanel.js.map +1 -0
- package/dist/editor/settings/panels/ModelsPanel.js +108 -329
- package/dist/editor/settings/panels/ModelsPanel.js.map +1 -1
- package/dist/editor/settings/panels/ProvidersPanel.d.ts +1 -1
- package/dist/editor/settings/panels/ProvidersPanel.js +59 -86
- package/dist/editor/settings/panels/ProvidersPanel.js.map +1 -1
- package/dist/editor/settings/panels/SearchConfigPanel.js +4 -4
- package/dist/editor/settings/panels/SearchConfigPanel.js.map +1 -1
- package/dist/editor/settings/panels/index.d.ts +2 -3
- package/dist/editor/settings/panels/index.js +2 -3
- package/dist/editor/settings/panels/index.js.map +1 -1
- package/dist/editor/settings/setup-steps/AiSetupStep/EmbeddingsModelSection.d.ts +2 -0
- package/dist/editor/settings/setup-steps/AiSetupStep/EmbeddingsModelSection.js +195 -0
- package/dist/editor/settings/setup-steps/AiSetupStep/EmbeddingsModelSection.js.map +1 -0
- package/dist/editor/settings/setup-steps/AiSetupStep/index.d.ts +2 -0
- package/dist/editor/settings/setup-steps/AiSetupStep/index.js +21 -0
- package/dist/editor/settings/setup-steps/AiSetupStep/index.js.map +1 -0
- package/dist/editor/settings/setup-steps/AiSetupStep/provider/ProviderSection.d.ts +1 -0
- package/dist/editor/settings/setup-steps/AiSetupStep/provider/ProviderSection.js +233 -0
- package/dist/editor/settings/setup-steps/AiSetupStep/provider/ProviderSection.js.map +1 -0
- package/dist/editor/settings/setup-steps/AiSetupStep/required-containers/RequiredContainersList.d.ts +15 -0
- package/dist/editor/settings/setup-steps/AiSetupStep/required-containers/RequiredContainersList.js +14 -0
- package/dist/editor/settings/setup-steps/AiSetupStep/required-containers/RequiredContainersList.js.map +1 -0
- package/dist/editor/settings/setup-steps/AiSetupStep/required-containers/RequiredContainersSection.d.ts +1 -0
- package/dist/editor/settings/setup-steps/AiSetupStep/required-containers/RequiredContainersSection.js +94 -0
- package/dist/editor/settings/setup-steps/AiSetupStep/required-containers/RequiredContainersSection.js.map +1 -0
- package/dist/editor/settings/setup-steps/AiSetupStep/types.d.ts +1 -0
- package/dist/editor/settings/setup-steps/AiSetupStep/types.js +2 -0
- package/dist/editor/settings/setup-steps/AiSetupStep/types.js.map +1 -0
- package/dist/editor/settings/setup-steps/AiSetupStep/utils.d.ts +5 -0
- package/dist/editor/settings/setup-steps/AiSetupStep/utils.js +44 -0
- package/dist/editor/settings/setup-steps/AiSetupStep/utils.js.map +1 -0
- package/dist/editor/settings/setup-steps/IndexSetupStep.d.ts +2 -0
- package/dist/editor/settings/setup-steps/IndexSetupStep.js +36 -0
- package/dist/editor/settings/setup-steps/IndexSetupStep.js.map +1 -0
- package/dist/editor/settings/setup-steps/SettingsSetupStep.d.ts +2 -0
- package/dist/editor/settings/setup-steps/SettingsSetupStep.js +111 -0
- package/dist/editor/settings/setup-steps/SettingsSetupStep.js.map +1 -0
- package/dist/editor/settings/setup-steps/SetupOverview.d.ts +14 -0
- package/dist/editor/settings/setup-steps/SetupOverview.js +38 -0
- package/dist/editor/settings/setup-steps/SetupOverview.js.map +1 -0
- package/dist/editor/settings/status/coreStatusChecks.js +19 -124
- package/dist/editor/settings/status/coreStatusChecks.js.map +1 -1
- package/dist/editor/settings/status/useStartupChecks.d.ts +1 -3
- package/dist/editor/settings/status/useStartupChecks.js +5 -9
- package/dist/editor/settings/status/useStartupChecks.js.map +1 -1
- package/dist/editor/setup-wizard/steps/CompleteStep.d.ts +1 -2
- package/dist/editor/setup-wizard/steps/CompleteStep.js +1 -2
- package/dist/editor/setup-wizard/steps/CompleteStep.js.map +1 -1
- package/dist/editor/sidebar/ComponentPalette.js +1 -2
- package/dist/editor/sidebar/ComponentPalette.js.map +1 -1
- package/dist/editor/sidebar/ComponentTree.d.ts +1 -8
- package/dist/editor/sidebar/ComponentTree.js +69 -216
- package/dist/editor/sidebar/ComponentTree.js.map +1 -1
- package/dist/editor/sidebar/Debug.d.ts +1 -0
- package/dist/editor/sidebar/Debug.js +70 -0
- package/dist/editor/sidebar/Debug.js.map +1 -0
- package/dist/editor/sidebar/EditHistory.js +46 -22
- package/dist/editor/sidebar/EditHistory.js.map +1 -1
- package/dist/editor/sidebar/Favorites.js +8 -4
- package/dist/editor/sidebar/Favorites.js.map +1 -1
- package/dist/editor/sidebar/GraphQL.d.ts +2 -0
- package/dist/editor/sidebar/GraphQL.js +234 -0
- package/dist/editor/sidebar/GraphQL.js.map +1 -0
- package/dist/editor/sidebar/LeftToolbar.d.ts +1 -0
- package/dist/editor/sidebar/LeftToolbar.js +12 -0
- package/dist/editor/sidebar/LeftToolbar.js.map +1 -0
- package/dist/editor/sidebar/MainContentTree.js +3 -4
- package/dist/editor/sidebar/MainContentTree.js.map +1 -1
- package/dist/editor/sidebar/NavigationSidebar.d.ts +4 -0
- package/dist/editor/sidebar/NavigationSidebar.js +254 -0
- package/dist/editor/sidebar/NavigationSidebar.js.map +1 -0
- package/dist/editor/sidebar/OperationItem.js +7 -21
- package/dist/editor/sidebar/OperationItem.js.map +1 -1
- package/dist/editor/sidebar/SidebarPanel.d.ts +1 -3
- package/dist/editor/sidebar/SidebarPanel.js +12 -44
- package/dist/editor/sidebar/SidebarPanel.js.map +1 -1
- package/dist/editor/sidebar/SidebarStack.d.ts +1 -2
- package/dist/editor/sidebar/SidebarStack.js +3 -4
- package/dist/editor/sidebar/SidebarStack.js.map +1 -1
- package/dist/editor/sidebar/Validation.js +12 -24
- package/dist/editor/sidebar/Validation.js.map +1 -1
- package/dist/editor/sidebar/Workbox.js +3 -53
- package/dist/editor/sidebar/Workbox.js.map +1 -1
- package/dist/editor/sidebar/WorkspaceRail.d.ts +1 -0
- package/dist/editor/sidebar/WorkspaceRail.js +167 -56
- package/dist/editor/sidebar/WorkspaceRail.js.map +1 -1
- package/dist/editor/tree-indicators/GutterColumns.d.ts +1 -3
- package/dist/editor/tree-indicators/GutterColumns.js +5 -26
- package/dist/editor/tree-indicators/GutterColumns.js.map +1 -1
- package/dist/editor/tree-indicators/GutterContext.d.ts +0 -4
- package/dist/editor/tree-indicators/GutterContext.js +0 -23
- package/dist/editor/tree-indicators/GutterContext.js.map +1 -1
- package/dist/editor/tree-indicators/GutterSelector.d.ts +5 -0
- package/dist/editor/tree-indicators/GutterSelector.js +91 -0
- package/dist/editor/tree-indicators/GutterSelector.js.map +1 -0
- package/dist/editor/tree-indicators/index.d.ts +1 -0
- package/dist/editor/tree-indicators/index.js +1 -0
- package/dist/editor/tree-indicators/index.js.map +1 -1
- package/dist/editor/tree-indicators/types.d.ts +1 -12
- package/dist/editor/ui/CopyMoveTargetSelectorDialog.js +1 -1
- package/dist/editor/ui/CopyMoveTargetSelectorDialog.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/ItemNameDialogNew.d.ts +0 -2
- package/dist/editor/ui/ItemNameDialogNew.js +17 -33
- package/dist/editor/ui/ItemNameDialogNew.js.map +1 -1
- package/dist/editor/ui/ItemSearch.js +11 -7
- package/dist/editor/ui/ItemSearch.js.map +1 -1
- package/dist/editor/ui/SimpleIconButton.js +1 -1
- package/dist/editor/ui/SimpleIconButton.js.map +1 -1
- package/dist/editor/ui/SimpleTabs.d.ts +0 -1
- package/dist/editor/ui/SimpleTabs.js +25 -45
- package/dist/editor/ui/SimpleTabs.js.map +1 -1
- package/dist/editor/ui/Splitter.d.ts +0 -1
- package/dist/editor/ui/Splitter.js +86 -102
- package/dist/editor/ui/Splitter.js.map +1 -1
- package/dist/editor/ui/TemplateSelectorDialog.js +4 -4
- package/dist/editor/ui/TemplateSelectorDialog.js.map +1 -1
- package/dist/editor/ui/TreeListSelector.d.ts +1 -6
- package/dist/editor/ui/TreeListSelector.js +2 -2
- package/dist/editor/ui/TreeListSelector.js.map +1 -1
- package/dist/editor/utils/keyboardNavigation.d.ts +20 -6
- package/dist/editor/utils/keyboardNavigation.js +140 -48
- package/dist/editor/utils/keyboardNavigation.js.map +1 -1
- package/dist/editor/utils.js +9 -19
- package/dist/editor/utils.js.map +1 -1
- package/dist/editor/views/CompareView.d.ts +1 -3
- package/dist/editor/views/CompareView.js +5 -7
- package/dist/editor/views/CompareView.js.map +1 -1
- package/dist/editor/views/EditView.js +1 -1
- package/dist/editor/views/EditView.js.map +1 -1
- package/dist/editor/views/EditorSlot.js +34 -27
- package/dist/editor/views/EditorSlot.js.map +1 -1
- package/dist/editor/views/ItemEditor.js +3 -7
- package/dist/editor/views/ItemEditor.js.map +1 -1
- package/dist/editor/views/MediaFolderEditView.js +1 -1
- package/dist/editor/views/MediaFolderEditView.js.map +1 -1
- package/dist/editor/views/ParheliaView.js +6 -5
- package/dist/editor/views/ParheliaView.js.map +1 -1
- package/dist/editor/views/SingleEditView.d.ts +1 -2
- package/dist/editor/views/SingleEditView.js +8 -10
- package/dist/editor/views/SingleEditView.js.map +1 -1
- package/dist/editor/views/editorSlotContext.js +6 -35
- package/dist/editor/views/editorSlotContext.js.map +1 -1
- package/dist/index.d.ts +2 -16
- package/dist/index.js +0 -11
- package/dist/index.js.map +1 -1
- package/dist/revision.d.ts +2 -2
- package/dist/revision.js +2 -2
- package/dist/setup/services/setupWizardService.d.ts +13 -40
- package/dist/setup/services/setupWizardService.js +17 -32
- package/dist/setup/services/setupWizardService.js.map +1 -1
- package/dist/setup/wizard/steps/AddModelDialog.js +3 -12
- package/dist/setup/wizard/steps/AddModelDialog.js.map +1 -1
- package/dist/setup/wizard/steps/ImportModelDialog.js +22 -39
- package/dist/setup/wizard/steps/ImportModelDialog.js.map +1 -1
- package/dist/splash-screen/ModernSplashScreen.js +32 -112
- package/dist/splash-screen/ModernSplashScreen.js.map +1 -1
- package/dist/splash-screen/NewPage.js +50 -33
- package/dist/splash-screen/NewPage.js.map +1 -1
- package/dist/splash-screen/OpenPage.js +6 -2
- package/dist/splash-screen/OpenPage.js.map +1 -1
- package/dist/splash-screen/ParheliaAssistantChat.js +29 -12
- package/dist/splash-screen/ParheliaAssistantChat.js.map +1 -1
- package/dist/splash-screen/ParheliaLogo.js +37 -87
- package/dist/splash-screen/ParheliaLogo.js.map +1 -1
- package/dist/splash-screen/RecentPages.js +3 -3
- package/dist/splash-screen/RecentPages.js.map +1 -1
- package/dist/tour/Tour.d.ts +1 -2
- package/dist/tour/Tour.js +75 -256
- package/dist/tour/Tour.js.map +1 -1
- package/dist/tour/default-tour.js +96 -222
- package/dist/tour/default-tour.js.map +1 -1
- package/dist/types.d.ts +29 -63
- package/package.json +15 -19
- package/styles.css +10 -39
|
@@ -1,17 +1,15 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { jsx as _jsx,
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
3
|
import React, { useState, useEffect, useRef, useCallback, useSyncExternalStore, useMemo, startTransition, } from "react";
|
|
4
4
|
import { toast } from "sonner";
|
|
5
|
-
import { EditContextProvider, FieldsEditContextProvider, OperationsContextProvider,
|
|
5
|
+
import { EditContextProvider, FieldsEditContextProvider, OperationsContextProvider, } from "./editContext";
|
|
6
6
|
import { fieldModificationStore } from "./fieldModificationStore";
|
|
7
|
-
import { useRouter, useSearchParams, usePathname } from "
|
|
7
|
+
import { useRouter, useSearchParams, usePathname } from "next/navigation";
|
|
8
8
|
import { findComponent, getComponentById } from "../componentTreeHelper";
|
|
9
9
|
import { getOperationsContext } from "./operations";
|
|
10
10
|
import { handleErrorResult } from "./helpers";
|
|
11
|
-
import { executeFieldAction as executeFieldServerAction, connectSocket, getEditHistory, getRunningOperations,
|
|
11
|
+
import { executeFieldAction as executeFieldServerAction, connectSocket, getEditHistory, getRunningOperations, releaseFieldLocks, validateItems, } from "../services/editService";
|
|
12
12
|
import { useEditorWebSocket } from "./hooks/useEditorWebSocket";
|
|
13
|
-
import { createEditorSocketDiagnostics, } from "./socketDiagnostics";
|
|
14
|
-
import { localStorageService } from "../services/localStorageService";
|
|
15
13
|
import { useSocketMessageHandler } from "./hooks/useSocketMessageHandler";
|
|
16
14
|
import "react-json-view-lite/dist/index.css";
|
|
17
15
|
import { MediaSelector, } from "../media-selector/MediaSelector";
|
|
@@ -22,7 +20,6 @@ import { getItemDescriptor } from "../utils";
|
|
|
22
20
|
import { EditContextMenu } from "../ContextMenu";
|
|
23
21
|
import { InlineAiTrigger } from "../ai/InlineAiTrigger";
|
|
24
22
|
import { FieldEditorPopup } from "../FieldEditorPopup";
|
|
25
|
-
import { ConcurrentUserLimitDialog } from "../ConcurrentUserLimitDialog";
|
|
26
23
|
import { post } from "../services/serviceHelper";
|
|
27
24
|
import { PageViewerFrame } from "../page-viewer/PageViewerFrame";
|
|
28
25
|
import { useItemsRepository } from "./itemsRepository";
|
|
@@ -36,7 +33,6 @@ import { GuidanceOverlay } from "../ai/GuidanceOverlay";
|
|
|
36
33
|
import { AgentDialogHandler } from "../ai/dialogs";
|
|
37
34
|
import { usePageViewContext, } from "../page-viewer/pageViewContext";
|
|
38
35
|
import { QuickItemSwitcher } from "../QuickItemSwitcher";
|
|
39
|
-
import { useEditorSlotContext, } from "../views/editorSlotContext";
|
|
40
36
|
import { getComments, getAvailableCommentTags, } from "../services/reviewsService";
|
|
41
37
|
import { useReviews } from "../reviews/useReviews";
|
|
42
38
|
import uuid from "react-uuid";
|
|
@@ -53,33 +49,7 @@ import { useWorkbox } from "./hooks/useWorkbox";
|
|
|
53
49
|
import { useMediaSelector } from "./hooks/useMediaSelector";
|
|
54
50
|
import { useGlobalEditorKeyDown } from "./hooks/useGlobalEditorKeyDown";
|
|
55
51
|
import { useStartupChecks } from "../settings/status/index";
|
|
56
|
-
|
|
57
|
-
function AgentsSlotContextBridge({ slot }) {
|
|
58
|
-
const editContext = useEditContext();
|
|
59
|
-
const slotContext = useEditorSlotContext({
|
|
60
|
-
slotId: slot.slotId,
|
|
61
|
-
itemDescriptor: slot.itemDescriptor,
|
|
62
|
-
refreshToken: slot.refreshToken,
|
|
63
|
-
});
|
|
64
|
-
if (!editContext || !slotContext)
|
|
65
|
-
return null;
|
|
66
|
-
useEffect(() => {
|
|
67
|
-
editContext.registerSlotContext(slot.slotId, slotContext);
|
|
68
|
-
return () => {
|
|
69
|
-
editContext.unregisterSlotContext(slot.slotId);
|
|
70
|
-
};
|
|
71
|
-
}, [
|
|
72
|
-
slot.slotId,
|
|
73
|
-
slotContext,
|
|
74
|
-
editContext.registerSlotContext,
|
|
75
|
-
editContext.unregisterSlotContext,
|
|
76
|
-
]);
|
|
77
|
-
return null;
|
|
78
|
-
}
|
|
79
|
-
function AgentsSlotContextBridgeHost({ slots }) {
|
|
80
|
-
return (_jsx(_Fragment, { children: slots.map((slot) => (_jsx(AgentsSlotContextBridge, { slot: slot }, `agents-slot-bridge-${slot.slotId}`))) }));
|
|
81
|
-
}
|
|
82
|
-
export function EditorShell({ configuration, className, item: loadItemDescriptor, sessionId, userInfo, userPreferences, initialLicenseStatus, initialLicenseStatusLoaded, parheliaSettings, setUserPreferences, children, }) {
|
|
52
|
+
export function EditorShell({ configuration, className, item: loadItemDescriptor, sessionId, userInfo, userPreferences, parheliaSettings, setUserPreferences, children, }) {
|
|
83
53
|
const router = useRouter();
|
|
84
54
|
const pathname = usePathname();
|
|
85
55
|
const searchParams = useSearchParams();
|
|
@@ -127,7 +97,6 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
127
97
|
const [historyMode, setHistoryMode] = useState("global");
|
|
128
98
|
const [showOnlyMyChanges, setShowOnlyMyChanges] = useState(true);
|
|
129
99
|
const [filterByCurrentLanguage, setFilterByCurrentLanguage] = useState(true);
|
|
130
|
-
const [historySearchQuery, setHistorySearchQuery] = useState("");
|
|
131
100
|
const [recentEdits, setRecentEdits] = useState([]);
|
|
132
101
|
const addRecentEdit = useCallback((edit) => {
|
|
133
102
|
setRecentEdits((prevEditedFields) => {
|
|
@@ -155,14 +124,14 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
155
124
|
if (typeof window !== "undefined")
|
|
156
125
|
sessionStorage?.setItem("sessionId", sessionId);
|
|
157
126
|
// Workspace state
|
|
158
|
-
// Note: "reviews" is a sidebar, not a workspace. If workspace=reviews, we should
|
|
127
|
+
// Note: "reviews" is a sidebar, not a workspace. If view/workspace=reviews, we should
|
|
159
128
|
// set workspace to "editor" and open the reviews sidebar instead.
|
|
160
129
|
// Memoize searchParams reads to avoid triggering Router state updates during render
|
|
161
130
|
// (Next.js App Router uses startTransition internally for URL changes)
|
|
162
|
-
const rawWorkspace = useMemo(() => searchParams.get("workspace"), [searchParams]);
|
|
131
|
+
const rawWorkspace = useMemo(() => searchParams.get("workspace") ?? searchParams.get("view"), [searchParams]);
|
|
163
132
|
const isReviewsSidebarRequest = rawWorkspace === "reviews";
|
|
164
133
|
const [workspaceId, setWorkspaceId] = useState(
|
|
165
|
-
// If
|
|
134
|
+
// If view=reviews, use "editor" workspace (reviews is a sidebar, not a workspace)
|
|
166
135
|
isReviewsSidebarRequest
|
|
167
136
|
? "editor"
|
|
168
137
|
: (rawWorkspace ??
|
|
@@ -184,7 +153,7 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
184
153
|
else {
|
|
185
154
|
sidebars = [...(configuration.editor.defaultOpenSidebars ?? [])];
|
|
186
155
|
}
|
|
187
|
-
// If workspace=reviews was requested, ensure reviews sidebar is open
|
|
156
|
+
// If view/workspace=reviews was requested, ensure reviews sidebar is open
|
|
188
157
|
if (isReviewsSidebarRequest && !sidebars.includes("reviews")) {
|
|
189
158
|
sidebars.push("reviews");
|
|
190
159
|
}
|
|
@@ -192,11 +161,17 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
192
161
|
});
|
|
193
162
|
// Toolbar pinned sidebars - icons always visible in toolbar (defined early so callbacks can access)
|
|
194
163
|
const [pinnedSidebars, setPinnedSidebars] = useState(userInfo.preferences?.pinnedSidebars || []);
|
|
195
|
-
const pinnedSidebarsRef = useRef(pinnedSidebars);
|
|
196
164
|
// Locked sidebars - open panels that stay visible when selecting another sidebar
|
|
197
165
|
const [lockedSidebars, setLockedSidebars] = useState(() => {
|
|
166
|
+
if (typeof window === "undefined") {
|
|
167
|
+
return [];
|
|
168
|
+
}
|
|
198
169
|
try {
|
|
199
|
-
const
|
|
170
|
+
const stored = window.localStorage.getItem("editor.lockedSidebars");
|
|
171
|
+
if (!stored) {
|
|
172
|
+
return [];
|
|
173
|
+
}
|
|
174
|
+
const parsed = JSON.parse(stored);
|
|
200
175
|
if (!Array.isArray(parsed) ||
|
|
201
176
|
!parsed.every((id) => typeof id === "string")) {
|
|
202
177
|
return [];
|
|
@@ -212,9 +187,6 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
212
187
|
useEffect(() => {
|
|
213
188
|
lockedSidebarsRef.current = lockedSidebars;
|
|
214
189
|
}, [lockedSidebars]);
|
|
215
|
-
useEffect(() => {
|
|
216
|
-
pinnedSidebarsRef.current = pinnedSidebars;
|
|
217
|
-
}, [pinnedSidebars]);
|
|
218
190
|
// Filter locked sidebars to only include currently open sidebars
|
|
219
191
|
useEffect(() => {
|
|
220
192
|
const openSet = new Set(openSidebars);
|
|
@@ -276,11 +248,15 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
276
248
|
// Group open sidebars into vertical stacks (each stack shares one left column).
|
|
277
249
|
const [sidebarStacks, setSidebarStacks] = useState(() => {
|
|
278
250
|
const defaultStacks = openSidebars.map((id) => [id]);
|
|
251
|
+
if (typeof window === "undefined") {
|
|
252
|
+
return normalizeSidebarStacks(openSidebars, defaultStacks);
|
|
253
|
+
}
|
|
279
254
|
try {
|
|
280
|
-
const
|
|
281
|
-
if (!
|
|
255
|
+
const stored = window.localStorage.getItem("editor.sidebarStacks");
|
|
256
|
+
if (!stored) {
|
|
282
257
|
return normalizeSidebarStacks(openSidebars, defaultStacks);
|
|
283
258
|
}
|
|
259
|
+
const parsed = JSON.parse(stored);
|
|
284
260
|
if (!Array.isArray(parsed) ||
|
|
285
261
|
!parsed.every((x) => Array.isArray(x) && x.every((id) => typeof id === "string"))) {
|
|
286
262
|
return normalizeSidebarStacks(openSidebars, defaultStacks);
|
|
@@ -302,19 +278,28 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
302
278
|
}, [openSidebars, normalizeSidebarStacks]);
|
|
303
279
|
// Persist stacks independently of the URL (user layout preference).
|
|
304
280
|
useEffect(() => {
|
|
281
|
+
if (typeof window === "undefined")
|
|
282
|
+
return;
|
|
305
283
|
try {
|
|
306
|
-
|
|
284
|
+
window.localStorage.setItem("editor.sidebarStacks", JSON.stringify(sidebarStacks));
|
|
307
285
|
}
|
|
308
286
|
catch { }
|
|
309
287
|
}, [sidebarStacks]);
|
|
310
288
|
// Persist locked sidebars to localStorage.
|
|
311
289
|
useEffect(() => {
|
|
290
|
+
if (typeof window === "undefined")
|
|
291
|
+
return;
|
|
312
292
|
try {
|
|
313
|
-
|
|
293
|
+
window.localStorage.setItem("editor.lockedSidebars", JSON.stringify(lockedSidebars));
|
|
314
294
|
}
|
|
315
295
|
catch { }
|
|
316
296
|
}, [lockedSidebars]);
|
|
297
|
+
// Legacy aliases for backwards compatibility
|
|
317
298
|
const viewName = workspaceId;
|
|
299
|
+
const setViewName = setWorkspaceId;
|
|
300
|
+
const viewNameRef = workspaceIdRef;
|
|
301
|
+
const previousViewName = previousWorkspaceId;
|
|
302
|
+
const setPreviousViewName = setPreviousWorkspaceId;
|
|
318
303
|
const [compareMode, setCompareModeState] = useState(false);
|
|
319
304
|
const [componentDesignerComponent, setComponentDesignerComponent] = useState();
|
|
320
305
|
const [componentDesignerRendering, setComponentDesignerRendering] = useState();
|
|
@@ -322,7 +307,6 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
322
307
|
const [ignoreBlur, setIgnoreBlur] = useState(false);
|
|
323
308
|
const [currentItemDescriptor, setCurrentItemDescriptor] = useState();
|
|
324
309
|
const currentItemDescriptorRef = useRef(undefined);
|
|
325
|
-
const latestGlobalLoadKeyRef = useRef(null);
|
|
326
310
|
const [editorSlots, setEditorSlots] = useState(() => {
|
|
327
311
|
// Always start with empty slots - don't persist the number of slots
|
|
328
312
|
return [];
|
|
@@ -342,29 +326,6 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
342
326
|
activeSlotIdRef.current = activeSlotId;
|
|
343
327
|
}, [activeSlotId]);
|
|
344
328
|
const [slotContexts, setSlotContexts] = useState(() => new Map());
|
|
345
|
-
const promptSessionReconnect = useCallback((reason) => {
|
|
346
|
-
const description = reason && reason !== "session-revoked"
|
|
347
|
-
? `${reason}. Click reconnect to continue in this browser.`
|
|
348
|
-
: "You were disconnected because this account is active in another browser.";
|
|
349
|
-
toast.error("Session disconnected", {
|
|
350
|
-
id: "session-revoked",
|
|
351
|
-
description,
|
|
352
|
-
action: {
|
|
353
|
-
label: "Reconnect",
|
|
354
|
-
onClick: async () => {
|
|
355
|
-
const result = await reconnectSession(sessionId);
|
|
356
|
-
if (result.type === "success") {
|
|
357
|
-
window.location.reload();
|
|
358
|
-
return;
|
|
359
|
-
}
|
|
360
|
-
toast.error("Reconnect failed", {
|
|
361
|
-
description: "Could not claim this browser session. Try again.",
|
|
362
|
-
});
|
|
363
|
-
},
|
|
364
|
-
},
|
|
365
|
-
duration: Infinity,
|
|
366
|
-
});
|
|
367
|
-
}, [sessionId]);
|
|
368
329
|
// Track previous item ID to detect actual navigation between pages
|
|
369
330
|
const previousItemIdRef = useRef(undefined);
|
|
370
331
|
useEffect(() => {
|
|
@@ -393,9 +354,6 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
393
354
|
// Ref to track when we're handling a popstate event (browser back/forward)
|
|
394
355
|
// This prevents the URL sync effect from pushing new history entries during back navigation
|
|
395
356
|
const isHandlingPopStateRef = useRef(false);
|
|
396
|
-
// When switchWorkspace already pushed a URL entry, the follow-up URL sync
|
|
397
|
-
// effect should only *replace* that entry (not push a second one).
|
|
398
|
-
const switchWorkspacePushedRef = useRef(false);
|
|
399
357
|
// Ref to track the last known URL for the popstate handler
|
|
400
358
|
// This is updated both when the popstate handler runs AND when the URL sync effect pushes a new URL
|
|
401
359
|
// Without this, the popstate handler would have a stale lastUrl value after pushState calls
|
|
@@ -412,16 +370,26 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
412
370
|
const [showSuggestedEditsDiff, setShowSuggestedEditsDiff] = useState(false);
|
|
413
371
|
const [availableCommentTags, setAvailableCommentTags] = useState([]);
|
|
414
372
|
const [showComments, setShowComments] = useState(() => {
|
|
415
|
-
|
|
373
|
+
const savedShowComments = typeof window !== "undefined"
|
|
374
|
+
? localStorage.getItem("editor.showComments")
|
|
375
|
+
: null;
|
|
376
|
+
return savedShowComments ? JSON.parse(savedShowComments) : true;
|
|
416
377
|
});
|
|
417
378
|
useEffect(() => {
|
|
418
|
-
|
|
379
|
+
if (typeof window !== "undefined") {
|
|
380
|
+
localStorage.setItem("editor.showComments", JSON.stringify(showComments));
|
|
381
|
+
}
|
|
419
382
|
}, [showComments]);
|
|
420
383
|
const [showResolvedComments, setShowResolvedComments] = useState(() => {
|
|
421
|
-
|
|
384
|
+
const saved = typeof window !== "undefined"
|
|
385
|
+
? localStorage.getItem("editor.showResolvedComments")
|
|
386
|
+
: null;
|
|
387
|
+
return saved ? JSON.parse(saved) : false;
|
|
422
388
|
});
|
|
423
389
|
useEffect(() => {
|
|
424
|
-
|
|
390
|
+
if (typeof window !== "undefined") {
|
|
391
|
+
localStorage.setItem("editor.showResolvedComments", JSON.stringify(showResolvedComments));
|
|
392
|
+
}
|
|
425
393
|
}, [showResolvedComments]);
|
|
426
394
|
const [selectedComment, setSelectedComment] = useState();
|
|
427
395
|
const [browseHistory, setBrowseHistory] = useState(() => {
|
|
@@ -440,12 +408,13 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
440
408
|
visitedAt: entry.visitedAt,
|
|
441
409
|
}));
|
|
442
410
|
});
|
|
443
|
-
// Navigation history for browser history (
|
|
411
|
+
// Navigation history for browser history (view + item combinations)
|
|
444
412
|
const [navigationHistory, setNavigationHistory] = useState(() => {
|
|
445
|
-
// Initialize from browse history with
|
|
413
|
+
// Initialize from browse history with current view
|
|
446
414
|
if (!userInfo.browseHistory)
|
|
447
415
|
return [];
|
|
448
416
|
const defaultWorkspaceId = searchParams.get("workspace") ??
|
|
417
|
+
searchParams.get("view") ??
|
|
449
418
|
configuration.editor.defaultWorkspace ??
|
|
450
419
|
configuration.editor.workspaces?.[0]?.id ??
|
|
451
420
|
"editor";
|
|
@@ -477,43 +446,20 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
477
446
|
const [statusMessage, setStatusMessage] = useState("");
|
|
478
447
|
const [focusFieldComponentId, setFocusFieldComponentId] = useState();
|
|
479
448
|
const [enableCompletions, setEnableCompletions] = useState(false);
|
|
480
|
-
const [
|
|
481
|
-
const [slotComponentNavigatorVisibility, setSlotComponentNavigatorVisibility] = useState({});
|
|
482
|
-
useEffect(() => {
|
|
483
|
-
setSlotComponentNavigatorVisibility((prev) => {
|
|
484
|
-
const next = {};
|
|
485
|
-
let changed = false;
|
|
486
|
-
for (const slot of editorSlots) {
|
|
487
|
-
if (Object.prototype.hasOwnProperty.call(prev, slot.slotId)) {
|
|
488
|
-
next[slot.slotId] = prev[slot.slotId];
|
|
489
|
-
}
|
|
490
|
-
else {
|
|
491
|
-
next[slot.slotId] = showComponentNavigatorDefault;
|
|
492
|
-
changed = true;
|
|
493
|
-
}
|
|
494
|
-
}
|
|
495
|
-
if (Object.keys(prev).length !== editorSlots.length) {
|
|
496
|
-
changed = true;
|
|
497
|
-
}
|
|
498
|
-
return changed ? next : prev;
|
|
499
|
-
});
|
|
500
|
-
}, [editorSlots, showComponentNavigatorDefault]);
|
|
449
|
+
const [showComponentNavigator, setShowComponentNavigator] = useState(userPreferences.showComponentNavigator ?? false);
|
|
501
450
|
const [showAgentsPanel, setShowAgentsPanel] = useState(userPreferences.showAgentsPanel ?? false);
|
|
502
451
|
const [showMinimap, setShowMinimap] = useState(userPreferences.showMinimap ?? true);
|
|
503
452
|
const [showHelpTerminal, setShowHelpTerminal] = useState(false);
|
|
504
453
|
const [helpTerminalInitialPrompt, setHelpTerminalInitialPrompt] = useState(undefined);
|
|
505
454
|
const [helpTerminalProfileName, setHelpTerminalProfileName] = useState(undefined);
|
|
506
455
|
const [helpTerminalActiveTab, setHelpTerminalActiveTab] = useState(undefined);
|
|
507
|
-
const [
|
|
508
|
-
const [showAgentsWorkspaceEditor, setShowAgentsWorkspaceEditor] = useState(false);
|
|
509
|
-
const [selectedAgentsWorkspaceAgentId, setSelectedAgentsWorkspaceAgentId] = useState(null);
|
|
456
|
+
const [showAgentsWorkspaceEditor, setShowAgentsWorkspaceEditor] = useState(true);
|
|
510
457
|
const [activeEditorTab, setActiveEditorTab] = useState(null);
|
|
511
458
|
const [showLayoutComponents, setShowLayoutComponents] = useState(userPreferences.showLayoutComponents ?? false);
|
|
512
459
|
const { quotaInfo, setQuotaInfo, isQuotaExceeded, getQuotaWarningMessage } = useQuota({
|
|
513
460
|
showError: ({ summary, details }) => showErrorToast({ summary, details }),
|
|
514
461
|
});
|
|
515
462
|
const [webSocketMessages, setWebSocketMessages] = useState([]);
|
|
516
|
-
const [socketDiagnostics, setSocketDiagnostics] = useState(() => createEditorSocketDiagnostics(sessionId));
|
|
517
463
|
const [favorites, setFavorites] = useState([]);
|
|
518
464
|
// Quick item switcher state
|
|
519
465
|
const [quickSwitcherVisible, setQuickSwitcherVisible] = useState(false);
|
|
@@ -531,12 +477,13 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
531
477
|
if (!startupChecks.hasBlockingIssues)
|
|
532
478
|
return;
|
|
533
479
|
// Don't redirect if already in settings workspace - let user navigate freely within settings
|
|
534
|
-
const currentWorkspace = searchParams.get("workspace");
|
|
480
|
+
const currentWorkspace = searchParams.get("workspace") ?? searchParams.get("view");
|
|
535
481
|
if (currentWorkspace === "settings")
|
|
536
482
|
return;
|
|
537
483
|
// Redirect to the status panel (where user can see all issues and navigate to fixes)
|
|
538
484
|
const url = new URL(window.location.href);
|
|
539
485
|
url.searchParams.set("workspace", "settings");
|
|
486
|
+
url.searchParams.delete("view"); // Remove legacy param
|
|
540
487
|
url.searchParams.set("ccpanel", "status");
|
|
541
488
|
router.push(url.toString(), { scroll: false });
|
|
542
489
|
}, [
|
|
@@ -554,16 +501,6 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
554
501
|
setMode(queryMode);
|
|
555
502
|
}
|
|
556
503
|
}, [searchParams, isInitialLoad]);
|
|
557
|
-
useEffect(() => {
|
|
558
|
-
if (!isInitialLoad)
|
|
559
|
-
return;
|
|
560
|
-
const helpParam = searchParams.get("help");
|
|
561
|
-
if (helpParam) {
|
|
562
|
-
setHelpTerminalActiveTab("manual");
|
|
563
|
-
setShowHelpTerminal(true);
|
|
564
|
-
setSelectedHelpSectionId(helpParam === "contents" || helpParam === "true" ? null : helpParam);
|
|
565
|
-
}
|
|
566
|
-
}, [searchParams, isInitialLoad]);
|
|
567
504
|
useEffect(() => {
|
|
568
505
|
if (mode === "suggestions") {
|
|
569
506
|
// Ensure we're in the editor workspace and open the feedback sidebar
|
|
@@ -610,19 +547,12 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
610
547
|
setSlotContexts((prev) => {
|
|
611
548
|
if (!prev.has(slotId))
|
|
612
549
|
return prev;
|
|
613
|
-
if (slotId === activeSlotIdRef.current) {
|
|
614
|
-
const activeCtx = prev.get(slotId);
|
|
615
|
-
if (activeCtx) {
|
|
616
|
-
lastActiveSlotContextRef.current = activeCtx;
|
|
617
|
-
}
|
|
618
|
-
}
|
|
619
550
|
const next = new Map(prev);
|
|
620
551
|
next.delete(slotId);
|
|
621
552
|
return next;
|
|
622
553
|
});
|
|
623
554
|
}, []);
|
|
624
555
|
const slotContextsRef = useRef(slotContexts);
|
|
625
|
-
const lastActiveSlotContextRef = useRef(null);
|
|
626
556
|
useEffect(() => {
|
|
627
557
|
slotContextsRef.current = slotContexts;
|
|
628
558
|
}, [slotContexts]);
|
|
@@ -648,12 +578,6 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
648
578
|
const activeSlotContext = activeSlotId
|
|
649
579
|
? slotContexts.get(activeSlotId)
|
|
650
580
|
: undefined;
|
|
651
|
-
const isComponentNavigatorOpenForSlot = useCallback((slotId) => {
|
|
652
|
-
if (!slotId)
|
|
653
|
-
return showComponentNavigatorDefault;
|
|
654
|
-
return (slotComponentNavigatorVisibility[slotId] ?? showComponentNavigatorDefault);
|
|
655
|
-
}, [slotComponentNavigatorVisibility, showComponentNavigatorDefault]);
|
|
656
|
-
const showComponentNavigator = isComponentNavigatorOpenForSlot(activeSlotId);
|
|
657
581
|
// Sync global compareMode from the active slot's compareMode for URL syncing
|
|
658
582
|
useEffect(() => {
|
|
659
583
|
if (activeSlotContext && activeSlotContext.compareMode !== compareMode) {
|
|
@@ -701,9 +625,6 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
701
625
|
const isItemUsedInCurrentPage = useCallback((item) => pageItemsSetRef.current.has(makeItemKey(item)), [makeItemKey]);
|
|
702
626
|
const socketMessageListeners = useRef(new Set());
|
|
703
627
|
const [socketConnectionVersion, setSocketConnectionVersion] = useState(0);
|
|
704
|
-
useEffect(() => {
|
|
705
|
-
setSocketDiagnostics(createEditorSocketDiagnostics(sessionId));
|
|
706
|
-
}, [sessionId]);
|
|
707
628
|
const addSocketMessageListener = useCallback((callback) => {
|
|
708
629
|
socketMessageListeners.current.add(callback);
|
|
709
630
|
return () => socketMessageListeners.current.delete(callback);
|
|
@@ -788,13 +709,8 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
788
709
|
console.error(`No workspace found for id: ${workspaceId}`);
|
|
789
710
|
return null;
|
|
790
711
|
}
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
return (configuration.commands.keyboardCommands ?? []).filter((command) => activeCommandIds.has(command.id));
|
|
794
|
-
}, [
|
|
795
|
-
currentWorkspace.keyboardCommandIds,
|
|
796
|
-
configuration.commands.keyboardCommands,
|
|
797
|
-
]);
|
|
712
|
+
// Legacy alias for backwards compatibility
|
|
713
|
+
const currentView = currentWorkspace;
|
|
798
714
|
useEffect(() => {
|
|
799
715
|
if (currentWorkspace?.component) {
|
|
800
716
|
setCenterPanelView(currentWorkspace.component);
|
|
@@ -822,12 +738,6 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
822
738
|
const sendClientInfo = useCallback(() => {
|
|
823
739
|
debouncedSendClientInfo();
|
|
824
740
|
}, [debouncedSendClientInfo]);
|
|
825
|
-
const getCurrentHistoryState = useCallback(() => {
|
|
826
|
-
if (typeof window === "undefined") {
|
|
827
|
-
return null;
|
|
828
|
-
}
|
|
829
|
-
return window.history.state;
|
|
830
|
-
}, []);
|
|
831
741
|
const startTour = useCallback(() => {
|
|
832
742
|
setIsTourActive(true);
|
|
833
743
|
// Persist tour state to URL so it survives navigation/remounts
|
|
@@ -835,61 +745,32 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
835
745
|
const params = new URLSearchParams(window.location.search);
|
|
836
746
|
params.set("tour", "active");
|
|
837
747
|
const newUrl = `${window.location.pathname}?${params.toString()}`;
|
|
838
|
-
window.history.replaceState(
|
|
748
|
+
window.history.replaceState(null, "", newUrl);
|
|
839
749
|
}, [setIsTourActive]);
|
|
840
|
-
const isMobile = useMediaQuery("(max-width:
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
if (isMobile) {
|
|
845
|
-
setLockedSidebars([]);
|
|
846
|
-
const current = openSidebarsRef.current;
|
|
847
|
-
const lastSidebar = current[current.length - 1];
|
|
848
|
-
if (current.length > 1 && lastSidebar) {
|
|
849
|
-
const trimmed = [lastSidebar];
|
|
850
|
-
openSidebarsRef.current = trimmed;
|
|
851
|
-
setOpenSidebars(trimmed);
|
|
852
|
-
}
|
|
853
|
-
}
|
|
854
|
-
}, [isMobile]);
|
|
855
|
-
const setComponentNavigatorOpenForSlot = useCallback((slotId, value) => {
|
|
856
|
-
const previousValue = isComponentNavigatorOpenForSlot(slotId);
|
|
857
|
-
const newValue = typeof value === "function" ? value(previousValue) : value;
|
|
858
|
-
if (slotId) {
|
|
859
|
-
setSlotComponentNavigatorVisibility((prev) => {
|
|
860
|
-
const currentValue = prev[slotId] ?? showComponentNavigatorDefault;
|
|
861
|
-
if (currentValue === newValue && prev[slotId] !== undefined) {
|
|
862
|
-
return prev;
|
|
863
|
-
}
|
|
864
|
-
return {
|
|
865
|
-
...prev,
|
|
866
|
-
[slotId]: newValue,
|
|
867
|
-
};
|
|
868
|
-
});
|
|
869
|
-
}
|
|
870
|
-
setShowComponentNavigatorDefault(newValue);
|
|
750
|
+
const isMobile = useMediaQuery("(max-width: 768px)");
|
|
751
|
+
const handleSetShowComponentNavigator = useCallback((value) => {
|
|
752
|
+
const newValue = typeof value === "function" ? value(showComponentNavigator) : value;
|
|
753
|
+
setShowComponentNavigator(newValue);
|
|
871
754
|
setUserPreferences({ showComponentNavigator: newValue });
|
|
755
|
+
// On mobile, close Agents Panel when opening Component Navigator
|
|
872
756
|
if (isMobile && newValue) {
|
|
873
757
|
setShowAgentsPanel(false);
|
|
874
758
|
setUserPreferences({ showAgentsPanel: false });
|
|
875
759
|
}
|
|
876
760
|
}, [
|
|
877
|
-
|
|
878
|
-
|
|
761
|
+
showComponentNavigator,
|
|
762
|
+
setShowComponentNavigator,
|
|
879
763
|
setUserPreferences,
|
|
880
764
|
isMobile,
|
|
881
765
|
setShowAgentsPanel,
|
|
882
766
|
]);
|
|
883
|
-
const handleSetShowComponentNavigator = useCallback((value) => {
|
|
884
|
-
setComponentNavigatorOpenForSlot(activeSlotIdRef.current, value);
|
|
885
|
-
}, [setComponentNavigatorOpenForSlot]);
|
|
886
767
|
const handleSetShowAgentsPanel = useCallback((value) => {
|
|
887
768
|
const newValue = typeof value === "function" ? value(showAgentsPanel) : value;
|
|
888
769
|
setShowAgentsPanel(newValue);
|
|
889
770
|
setUserPreferences({ showAgentsPanel: newValue });
|
|
890
771
|
// On mobile, close Component Navigator when opening Agents Panel
|
|
891
772
|
if (isMobile && newValue) {
|
|
892
|
-
|
|
773
|
+
setShowComponentNavigator(false);
|
|
893
774
|
setUserPreferences({ showComponentNavigator: false });
|
|
894
775
|
}
|
|
895
776
|
}, [
|
|
@@ -897,40 +778,8 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
897
778
|
setShowAgentsPanel,
|
|
898
779
|
setUserPreferences,
|
|
899
780
|
isMobile,
|
|
900
|
-
|
|
781
|
+
setShowComponentNavigator,
|
|
901
782
|
]);
|
|
902
|
-
// Mobile editor panel state (EditorForm shown in bottom panel on mobile)
|
|
903
|
-
const [mobileEditorPanelOpen, setMobileEditorPanelOpenRaw] = useState(false);
|
|
904
|
-
const [dismissedMobilePanelToken, setDismissedMobilePanelToken] = useState(null);
|
|
905
|
-
const previousActiveSlotIdRef = useRef(null);
|
|
906
|
-
const mobilePanelDismissToken = useMemo(() => {
|
|
907
|
-
const selectionKey = selection.join(",");
|
|
908
|
-
return [
|
|
909
|
-
activeSlotId || "no-slot",
|
|
910
|
-
selectionKey,
|
|
911
|
-
insertMode ? "insert" : "browse",
|
|
912
|
-
].join("|");
|
|
913
|
-
}, [activeSlotId, insertMode, selection]);
|
|
914
|
-
useEffect(() => {
|
|
915
|
-
const previousActiveSlotId = previousActiveSlotIdRef.current;
|
|
916
|
-
if (previousActiveSlotId !== activeSlotId) {
|
|
917
|
-
setDismissedMobilePanelToken(null);
|
|
918
|
-
}
|
|
919
|
-
previousActiveSlotIdRef.current = activeSlotId;
|
|
920
|
-
}, [activeSlotId]);
|
|
921
|
-
const handleSetMobileEditorPanelOpen = useCallback((open) => {
|
|
922
|
-
setMobileEditorPanelOpenRaw(open);
|
|
923
|
-
if (!open) {
|
|
924
|
-
setDismissedMobilePanelToken(mobilePanelDismissToken);
|
|
925
|
-
return;
|
|
926
|
-
}
|
|
927
|
-
setDismissedMobilePanelToken(null);
|
|
928
|
-
if (open && isMobile) {
|
|
929
|
-
// Close all sidebars when opening the editor panel on mobile
|
|
930
|
-
openSidebarsRef.current = [];
|
|
931
|
-
setOpenSidebars([]);
|
|
932
|
-
}
|
|
933
|
-
}, [isMobile, mobilePanelDismissToken]);
|
|
934
783
|
const handleSetShowMinimap = useCallback((value) => {
|
|
935
784
|
const newValue = typeof value === "function" ? value(showMinimap) : value;
|
|
936
785
|
setShowMinimap(newValue);
|
|
@@ -944,7 +793,6 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
944
793
|
setHelpTerminalInitialPrompt(undefined);
|
|
945
794
|
setHelpTerminalProfileName(undefined);
|
|
946
795
|
setHelpTerminalActiveTab(undefined);
|
|
947
|
-
setSelectedHelpSectionId(null);
|
|
948
796
|
}
|
|
949
797
|
}, [showHelpTerminal]);
|
|
950
798
|
const toggleHelpTerminal = useCallback((options) => {
|
|
@@ -987,27 +835,13 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
987
835
|
setOpenSidebars(newOrder);
|
|
988
836
|
setSidebarStacks((prev) => normalizeSidebarStacks(newOrder, prev));
|
|
989
837
|
}, []);
|
|
990
|
-
const ensureSidebarPinned = useCallback((sidebarId) => {
|
|
991
|
-
const currentPinnedSidebars = pinnedSidebarsRef.current;
|
|
992
|
-
if (currentPinnedSidebars.includes(sidebarId)) {
|
|
993
|
-
return;
|
|
994
|
-
}
|
|
995
|
-
const newPinnedSidebars = [...currentPinnedSidebars, sidebarId];
|
|
996
|
-
pinnedSidebarsRef.current = newPinnedSidebars;
|
|
997
|
-
setPinnedSidebars(newPinnedSidebars);
|
|
998
|
-
setUserPreferences({ pinnedSidebars: newPinnedSidebars });
|
|
999
|
-
}, [setUserPreferences]);
|
|
1000
838
|
// messageHandler is defined after loadItem/loadHistory declarations to avoid temporal dead zones
|
|
1001
839
|
const user = activeSessions.find((x) => x.sessionId === sessionId)?.user ||
|
|
1002
840
|
userInfo.user;
|
|
1003
|
-
// Self-heal if our session disappears (e.g., after HMR)
|
|
1004
|
-
// is showing so we don't spam recovery attempts when the connection was rejected.
|
|
841
|
+
// Self-heal if our session disappears (e.g., after HMR)
|
|
1005
842
|
const missingSessionRecoveryTimerRef = useRef(null);
|
|
1006
843
|
const missingSessionRecoveryAttemptsRef = useRef(0);
|
|
1007
|
-
const concurrentUserLimitErrorRef = useRef(null);
|
|
1008
844
|
useEffect(() => {
|
|
1009
|
-
if (concurrentUserLimitErrorRef.current !== null)
|
|
1010
|
-
return;
|
|
1011
845
|
const hasMySession = activeSessions.some((s) => s.sessionId === sessionId);
|
|
1012
846
|
if (hasMySession) {
|
|
1013
847
|
// Reset recovery state when we see ourselves again
|
|
@@ -1023,6 +857,7 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
1023
857
|
return;
|
|
1024
858
|
const attempt = missingSessionRecoveryAttemptsRef.current + 1;
|
|
1025
859
|
const delay = Math.min(250 * Math.pow(2, attempt - 1), 2000);
|
|
860
|
+
console.warn(`⚠️ Current session not present in active sessions. Recovery attempt ${attempt} in ${delay}ms...`);
|
|
1026
861
|
missingSessionRecoveryTimerRef.current = setTimeout(() => {
|
|
1027
862
|
missingSessionRecoveryTimerRef.current = null;
|
|
1028
863
|
missingSessionRecoveryAttemptsRef.current = attempt;
|
|
@@ -1031,7 +866,6 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
1031
866
|
}
|
|
1032
867
|
else {
|
|
1033
868
|
// Force a reconnect to refresh presence after several failed nudges
|
|
1034
|
-
console.warn("Session presence did not recover after retries. Forcing reconnect.");
|
|
1035
869
|
try {
|
|
1036
870
|
globalThis.editorSocket?.close(4000, "recover-presence");
|
|
1037
871
|
}
|
|
@@ -1051,15 +885,9 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
1051
885
|
// Initialize lastUrlRef to current URL on mount
|
|
1052
886
|
lastUrlRef.current = window.location.href;
|
|
1053
887
|
const keepAliveUrl = "/parhelia/keepalive";
|
|
1054
|
-
const
|
|
888
|
+
const interval = setInterval(() => {
|
|
1055
889
|
fetch(keepAliveUrl + "?ts=" + Date.now())
|
|
1056
890
|
.then((response) => {
|
|
1057
|
-
if (response.headers.get("X-Parhelia-Session-Revoked") === "true") {
|
|
1058
|
-
window.dispatchEvent(new CustomEvent("parhelia:session-revoked", {
|
|
1059
|
-
detail: { reason: "session-revoked" },
|
|
1060
|
-
}));
|
|
1061
|
-
return;
|
|
1062
|
-
}
|
|
1063
891
|
if (response.status === 401 || response.status === 403) {
|
|
1064
892
|
toast.error("Your session has expired", {
|
|
1065
893
|
description: "Please login again to continue editing.",
|
|
@@ -1072,24 +900,7 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
1072
900
|
}
|
|
1073
901
|
})
|
|
1074
902
|
.catch((error) => console.error("Keep Alive error:", error));
|
|
1075
|
-
};
|
|
1076
|
-
const keepaliveIntervalMs = (() => {
|
|
1077
|
-
const param = new URLSearchParams(window.location.search).get("keepaliveIntervalMs");
|
|
1078
|
-
if (!param)
|
|
1079
|
-
return 5 * 60 * 1000;
|
|
1080
|
-
const ms = parseInt(param, 10);
|
|
1081
|
-
return Number.isFinite(ms) && ms >= 2000 && ms <= 60000
|
|
1082
|
-
? ms
|
|
1083
|
-
: 5 * 60 * 1000;
|
|
1084
|
-
})();
|
|
1085
|
-
const interval = setInterval(() => {
|
|
1086
|
-
runSessionCheck();
|
|
1087
|
-
}, keepaliveIntervalMs);
|
|
1088
|
-
const handleVisibilityChange = () => {
|
|
1089
|
-
if (document.visibilityState === "visible") {
|
|
1090
|
-
runSessionCheck();
|
|
1091
|
-
}
|
|
1092
|
-
};
|
|
903
|
+
}, 5 * 60 * 1000);
|
|
1093
904
|
const handleMessage = (event) => {
|
|
1094
905
|
if (event.data.type === "componentsSelected") {
|
|
1095
906
|
setSelection(event.data.componentIds);
|
|
@@ -1104,8 +915,9 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
1104
915
|
isHandlingPopStateRef.current = true;
|
|
1105
916
|
// Sync URL parameters back to component state for browser navigation
|
|
1106
917
|
const urlParams = new URLSearchParams(window.location.search);
|
|
1107
|
-
|
|
1108
|
-
|
|
918
|
+
// Handle workspace changes (with legacy view fallback)
|
|
919
|
+
const urlWorkspace = urlParams.get("workspace") ?? urlParams.get("view");
|
|
920
|
+
if (urlWorkspace && urlWorkspace !== viewNameRef.current) {
|
|
1109
921
|
setWorkspaceId(urlWorkspace);
|
|
1110
922
|
}
|
|
1111
923
|
// Handle sidebar changes
|
|
@@ -1122,18 +934,6 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
1122
934
|
if (compareValue !== compareMode) {
|
|
1123
935
|
setCompareMode(compareValue);
|
|
1124
936
|
}
|
|
1125
|
-
// Handle help panel changes
|
|
1126
|
-
const helpParam = urlParams.get("help");
|
|
1127
|
-
if (helpParam) {
|
|
1128
|
-
setHelpTerminalActiveTab("manual");
|
|
1129
|
-
setShowHelpTerminal(true);
|
|
1130
|
-
setSelectedHelpSectionId(helpParam === "contents" || helpParam === "true"
|
|
1131
|
-
? null
|
|
1132
|
-
: helpParam);
|
|
1133
|
-
}
|
|
1134
|
-
else {
|
|
1135
|
-
handleSetShowHelpTerminal(false);
|
|
1136
|
-
}
|
|
1137
937
|
// Handle mode changes
|
|
1138
938
|
const urlMode = urlParams.get("mode");
|
|
1139
939
|
if (urlMode && urlMode !== mode) {
|
|
@@ -1189,11 +989,9 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
1189
989
|
};
|
|
1190
990
|
window.addEventListener("message", handleMessage);
|
|
1191
991
|
window.addEventListener("popstate", handlePopState);
|
|
1192
|
-
window.addEventListener("visibilitychange", handleVisibilityChange);
|
|
1193
992
|
return () => {
|
|
1194
993
|
window.removeEventListener("message", handleMessage);
|
|
1195
994
|
window.removeEventListener("popstate", handlePopState);
|
|
1196
|
-
window.removeEventListener("visibilitychange", handleVisibilityChange);
|
|
1197
995
|
clearInterval(interval);
|
|
1198
996
|
};
|
|
1199
997
|
}, []);
|
|
@@ -1203,34 +1001,14 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
1203
1001
|
if (searchParams.get("noTour") !== null) {
|
|
1204
1002
|
return;
|
|
1205
1003
|
}
|
|
1206
|
-
// Don't start tour when there are setup errors (user is or will be on system status page)
|
|
1207
|
-
if (startupChecks.state === "complete" && startupChecks.hasBlockingIssues) {
|
|
1208
|
-
return;
|
|
1209
|
-
}
|
|
1210
|
-
// Don't start tour when already on settings system status page
|
|
1211
|
-
if (viewName === "settings" && searchParams.get("ccpanel") === "status") {
|
|
1212
|
-
return;
|
|
1213
|
-
}
|
|
1214
|
-
// Wait for startup checks so we know whether we'll redirect to status
|
|
1215
|
-
if (startupChecks.state !== "complete") {
|
|
1216
|
-
return;
|
|
1217
|
-
}
|
|
1218
1004
|
const tour = configuration.activeTour;
|
|
1219
1005
|
const key = tour === "default" ? "editor.tourShown" : "editor.tourShown." + tour;
|
|
1220
|
-
const tourShown =
|
|
1006
|
+
const tourShown = localStorage.getItem(key);
|
|
1221
1007
|
if (!tourShown) {
|
|
1222
1008
|
startTour();
|
|
1223
|
-
|
|
1009
|
+
localStorage.setItem(key, "true");
|
|
1224
1010
|
}
|
|
1225
|
-
}, [
|
|
1226
|
-
user,
|
|
1227
|
-
startupChecks.state,
|
|
1228
|
-
startupChecks.hasBlockingIssues,
|
|
1229
|
-
viewName,
|
|
1230
|
-
searchParams,
|
|
1231
|
-
configuration.activeTour,
|
|
1232
|
-
startTour,
|
|
1233
|
-
]);
|
|
1011
|
+
}, [user]);
|
|
1234
1012
|
// WebSocket initialization is performed after messageHandler is defined
|
|
1235
1013
|
// Defer URL sync until loadItem is defined below
|
|
1236
1014
|
// Mark end of initial load phase
|
|
@@ -1362,8 +1140,7 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
1362
1140
|
const loadComments = useCallback(async () => {
|
|
1363
1141
|
if (!currentItemDescriptor)
|
|
1364
1142
|
return;
|
|
1365
|
-
const
|
|
1366
|
-
const result = await getComments(currentItemDescriptor.id, currentItemDescriptor.language, currentItemDescriptor.version, reviewId ?? undefined);
|
|
1143
|
+
const result = await getComments(currentItemDescriptor.id, currentItemDescriptor.language, currentItemDescriptor.version);
|
|
1367
1144
|
if (handleErrorResult(result, ui, state))
|
|
1368
1145
|
return;
|
|
1369
1146
|
setComments((x) => {
|
|
@@ -1376,7 +1153,7 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
1376
1153
|
allComments.sort((a, b) => a.position - b.position);
|
|
1377
1154
|
return allComments;
|
|
1378
1155
|
});
|
|
1379
|
-
}, [currentItemDescriptor
|
|
1156
|
+
}, [currentItemDescriptor]);
|
|
1380
1157
|
// Assuming currentItemDescriptor, ui, state, handleErrorResult, and setSuggestedEdits
|
|
1381
1158
|
// are available in your component context.
|
|
1382
1159
|
const loadSuggestedEdits = useCallback(async () => {
|
|
@@ -1385,8 +1162,7 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
1385
1162
|
const result = await getSuggestedEdits(item.descriptor.id, item.descriptor.language, item.descriptor.version);
|
|
1386
1163
|
if (handleErrorResult(result, ui, state))
|
|
1387
1164
|
return;
|
|
1388
|
-
|
|
1389
|
-
setSuggestedEdits(edits);
|
|
1165
|
+
setSuggestedEdits(result.data || []);
|
|
1390
1166
|
}, [item]);
|
|
1391
1167
|
const loadFavorites = useCallback(async () => {
|
|
1392
1168
|
try {
|
|
@@ -1460,25 +1236,6 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
1460
1236
|
return idB.localeCompare(idA);
|
|
1461
1237
|
});
|
|
1462
1238
|
}, []);
|
|
1463
|
-
const normalizeEditHistoryPayload = useCallback((value) => {
|
|
1464
|
-
if (Array.isArray(value)) {
|
|
1465
|
-
return value;
|
|
1466
|
-
}
|
|
1467
|
-
if (value && typeof value === "object") {
|
|
1468
|
-
const payload = value;
|
|
1469
|
-
const candidates = [
|
|
1470
|
-
payload.operations,
|
|
1471
|
-
payload.history,
|
|
1472
|
-
payload.items,
|
|
1473
|
-
payload.data,
|
|
1474
|
-
];
|
|
1475
|
-
const firstArray = candidates.find((candidate) => Array.isArray(candidate));
|
|
1476
|
-
if (Array.isArray(firstArray)) {
|
|
1477
|
-
return firstArray;
|
|
1478
|
-
}
|
|
1479
|
-
}
|
|
1480
|
-
return [];
|
|
1481
|
-
}, []);
|
|
1482
1239
|
useEffect(() => {
|
|
1483
1240
|
// Read fresh page from the mutable slot context ref chain.
|
|
1484
1241
|
// The slot context uses a stable ref that is mutated in-place (see editorSlotContext.ts),
|
|
@@ -1501,7 +1258,7 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
1501
1258
|
if (handleErrorResult(result, ui, state))
|
|
1502
1259
|
return;
|
|
1503
1260
|
setEditHistory((prev) => {
|
|
1504
|
-
const next =
|
|
1261
|
+
const next = result.data || [];
|
|
1505
1262
|
if (!prev.length)
|
|
1506
1263
|
return sortEditHistoryByDateDesc(next);
|
|
1507
1264
|
if (!next.length)
|
|
@@ -1560,8 +1317,6 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
1560
1317
|
const shouldFilterByLanguage = filterByLanguage !== undefined
|
|
1561
1318
|
? filterByLanguage
|
|
1562
1319
|
: filterByCurrentLanguage;
|
|
1563
|
-
const trimmedHistoryQuery = historySearchQuery.trim();
|
|
1564
|
-
const historyQuery = trimmedHistoryQuery.length > 0 ? trimmedHistoryQuery : undefined;
|
|
1565
1320
|
if (currentMode === "global") {
|
|
1566
1321
|
// Global mode: optionally filter by session and/or language
|
|
1567
1322
|
const currentLanguage = item?.descriptor?.language || currentItemDescriptor?.language;
|
|
@@ -1571,14 +1326,13 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
1571
1326
|
language: shouldFilterByLanguage && currentLanguage
|
|
1572
1327
|
? currentLanguage
|
|
1573
1328
|
: undefined,
|
|
1574
|
-
query: historyQuery,
|
|
1575
1329
|
});
|
|
1576
1330
|
if (handleErrorResult(result, ui, state)) {
|
|
1577
1331
|
console.error("[EditorShell] Failed to load history:", result);
|
|
1578
1332
|
return;
|
|
1579
1333
|
}
|
|
1580
1334
|
setEditHistory((prev) => {
|
|
1581
|
-
const next =
|
|
1335
|
+
const next = result.data || [];
|
|
1582
1336
|
const scope = {
|
|
1583
1337
|
mode: currentMode,
|
|
1584
1338
|
filterBySession: shouldFilterBySession,
|
|
@@ -1589,12 +1343,8 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
1589
1343
|
};
|
|
1590
1344
|
if (!prev.length)
|
|
1591
1345
|
return sortEditHistoryByDateDesc(next.filter((op) => matchesHistoryScope(op, scope)));
|
|
1592
|
-
if (!next.length)
|
|
1593
|
-
// When searching, respect the empty result — don't fall back to previous items
|
|
1594
|
-
if (historyQuery)
|
|
1595
|
-
return [];
|
|
1346
|
+
if (!next.length)
|
|
1596
1347
|
return sortEditHistoryByDateDesc(prev.filter((op) => matchesHistoryScope(op, scope)));
|
|
1597
|
-
}
|
|
1598
1348
|
const prevById = new Map(prev.map((x) => [x.id, x]));
|
|
1599
1349
|
const nextById = new Set(next.map((x) => x.id));
|
|
1600
1350
|
const merged = next
|
|
@@ -1630,12 +1380,9 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
1630
1380
|
return mergedOp;
|
|
1631
1381
|
});
|
|
1632
1382
|
// Preserve operations that arrived via WebSocket during the fetch window
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
if (!nextById.has(id) && matchesHistoryScope(priorOp, scope)) {
|
|
1637
|
-
merged.push(priorOp);
|
|
1638
|
-
}
|
|
1383
|
+
for (const [id, priorOp] of prevById) {
|
|
1384
|
+
if (!nextById.has(id) && matchesHistoryScope(priorOp, scope)) {
|
|
1385
|
+
merged.push(priorOp);
|
|
1639
1386
|
}
|
|
1640
1387
|
}
|
|
1641
1388
|
return sortEditHistoryByDateDesc(merged);
|
|
@@ -1658,13 +1405,12 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
1658
1405
|
const result = await getEditHistory({
|
|
1659
1406
|
item: itemFilter,
|
|
1660
1407
|
sessionId: shouldFilterBySession ? sessionId : undefined,
|
|
1661
|
-
query: historyQuery,
|
|
1662
1408
|
});
|
|
1663
1409
|
if (handleErrorResult(result, ui, state)) {
|
|
1664
1410
|
console.error("[EditorShell] Failed to load item history:", result);
|
|
1665
1411
|
return;
|
|
1666
1412
|
}
|
|
1667
|
-
let operations =
|
|
1413
|
+
let operations = result.data || [];
|
|
1668
1414
|
// Client-side version filtering for current-version mode
|
|
1669
1415
|
if (currentMode === "current-version") {
|
|
1670
1416
|
// Defensive filter: only include operations for the current version
|
|
@@ -1687,11 +1433,8 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
1687
1433
|
};
|
|
1688
1434
|
if (!prev.length)
|
|
1689
1435
|
return sortEditHistoryByDateDesc(operations.filter((op) => matchesHistoryScope(op, scope)));
|
|
1690
|
-
if (!operations.length)
|
|
1691
|
-
if (historyQuery)
|
|
1692
|
-
return [];
|
|
1436
|
+
if (!operations.length)
|
|
1693
1437
|
return sortEditHistoryByDateDesc(prev.filter((op) => matchesHistoryScope(op, scope)));
|
|
1694
|
-
}
|
|
1695
1438
|
const prevById = new Map(prev.map((x) => [x.id, x]));
|
|
1696
1439
|
const nextById = new Set(operations.map((x) => x.id));
|
|
1697
1440
|
const merged = operations
|
|
@@ -1727,12 +1470,9 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
1727
1470
|
return mergedOp;
|
|
1728
1471
|
});
|
|
1729
1472
|
// Preserve operations that arrived via WebSocket during the fetch window
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
if (!nextById.has(id) && matchesHistoryScope(priorOp, scope)) {
|
|
1734
|
-
merged.push(priorOp);
|
|
1735
|
-
}
|
|
1473
|
+
for (const [id, priorOp] of prevById) {
|
|
1474
|
+
if (!nextById.has(id) && matchesHistoryScope(priorOp, scope)) {
|
|
1475
|
+
merged.push(priorOp);
|
|
1736
1476
|
}
|
|
1737
1477
|
}
|
|
1738
1478
|
return sortEditHistoryByDateDesc(merged);
|
|
@@ -1743,11 +1483,9 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
1743
1483
|
historyMode,
|
|
1744
1484
|
showOnlyMyChanges,
|
|
1745
1485
|
filterByCurrentLanguage,
|
|
1746
|
-
historySearchQuery,
|
|
1747
1486
|
item,
|
|
1748
1487
|
currentItemDescriptor,
|
|
1749
1488
|
matchesHistoryScope,
|
|
1750
|
-
normalizeEditHistoryPayload,
|
|
1751
1489
|
sortEditHistoryByDateDesc,
|
|
1752
1490
|
]);
|
|
1753
1491
|
// Debounced history refresh to avoid hammering `/parhelia/editHistory` on rapid UI changes.
|
|
@@ -1813,14 +1551,13 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
1813
1551
|
}
|
|
1814
1552
|
}
|
|
1815
1553
|
else if (historyMode !== "global" && currentItemDescriptor) {
|
|
1816
|
-
// Always load immediately for page-centric/current-version/timeline so we don't show
|
|
1817
|
-
// an empty history list for the debounce window (e.g. 600ms). The effect only runs on
|
|
1818
|
-
// mode or item id/lang/version change, not on every keystroke, so this avoids flaky
|
|
1819
|
-
// undo/redo tests and improves UX when switching to page-centric.
|
|
1820
1554
|
if (!historyInitialLoadDoneRef.current) {
|
|
1821
1555
|
historyInitialLoadDoneRef.current = true;
|
|
1556
|
+
refreshHistoryRef.current(historyMode);
|
|
1557
|
+
}
|
|
1558
|
+
else {
|
|
1559
|
+
debouncedRefreshHistoryRef.current(historyMode);
|
|
1822
1560
|
}
|
|
1823
|
-
refreshHistoryRef.current(historyMode);
|
|
1824
1561
|
}
|
|
1825
1562
|
else if (historyMode !== "global" && !currentItemDescriptor) {
|
|
1826
1563
|
// Clear history if no item loaded in page-centric modes
|
|
@@ -1833,7 +1570,6 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
1833
1570
|
historyMode,
|
|
1834
1571
|
showOnlyMyChanges,
|
|
1835
1572
|
filterByCurrentLanguage,
|
|
1836
|
-
historySearchQuery,
|
|
1837
1573
|
currentItemDescriptor?.id,
|
|
1838
1574
|
currentItemDescriptor?.language,
|
|
1839
1575
|
currentItemDescriptor?.version,
|
|
@@ -1898,9 +1634,6 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
1898
1634
|
if (isInitialLoad)
|
|
1899
1635
|
return;
|
|
1900
1636
|
const current = new URLSearchParams(window.location.search);
|
|
1901
|
-
const urlWorkspace = current.get("workspace");
|
|
1902
|
-
const urlView = current.get("view");
|
|
1903
|
-
const isWorkspaceTransitioning = !!urlWorkspace && urlWorkspace !== viewName;
|
|
1904
1637
|
// Sync item-related parameters only when an item is selected
|
|
1905
1638
|
if (currentItemDescriptor) {
|
|
1906
1639
|
if (current.get("itemid") !== currentItemDescriptor.id) {
|
|
@@ -1931,9 +1664,10 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
1931
1664
|
// If reviewId or urlItemId exists, preserve itemid/lang/version from URL
|
|
1932
1665
|
}
|
|
1933
1666
|
// Always sync workspace-related parameters regardless of item selection
|
|
1934
|
-
if (
|
|
1667
|
+
if (current.get("workspace") !== viewName) {
|
|
1935
1668
|
current.set("workspace", viewName);
|
|
1936
1669
|
}
|
|
1670
|
+
current.delete("view"); // Remove legacy view param
|
|
1937
1671
|
// Sync sidebar state
|
|
1938
1672
|
const currentSidebars = current.get("sidebar") ?? "";
|
|
1939
1673
|
const newSidebars = openSidebars.join(",");
|
|
@@ -1945,12 +1679,6 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
1945
1679
|
current.delete("sidebar");
|
|
1946
1680
|
}
|
|
1947
1681
|
}
|
|
1948
|
-
if (showHelpTerminal) {
|
|
1949
|
-
current.set("help", selectedHelpSectionId ?? "contents");
|
|
1950
|
-
}
|
|
1951
|
-
else {
|
|
1952
|
-
current.delete("help");
|
|
1953
|
-
}
|
|
1954
1682
|
if (!compareMode) {
|
|
1955
1683
|
current.delete("compare");
|
|
1956
1684
|
current.delete("compareLanguage");
|
|
@@ -1975,15 +1703,15 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
1975
1703
|
else {
|
|
1976
1704
|
current.delete("wizardid");
|
|
1977
1705
|
}
|
|
1978
|
-
//
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1706
|
+
// Only preserve ccpanel parameter when on settings view, remove it otherwise
|
|
1707
|
+
if (viewName === "settings") {
|
|
1708
|
+
const ccpanel = current.get("ccpanel");
|
|
1709
|
+
if (ccpanel) {
|
|
1710
|
+
current.set("ccpanel", ccpanel);
|
|
1711
|
+
}
|
|
1712
|
+
}
|
|
1713
|
+
else {
|
|
1984
1714
|
current.delete("ccpanel");
|
|
1985
|
-
current.delete("providerId");
|
|
1986
|
-
current.delete("modelId");
|
|
1987
1715
|
}
|
|
1988
1716
|
// Preserve reviewId parameter if it exists (for review links)
|
|
1989
1717
|
// This ensures review links don't lose the reviewId when URL is synced
|
|
@@ -1996,28 +1724,17 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
1996
1724
|
const browserPathname = typeof window !== "undefined" ? window.location.pathname : pathname;
|
|
1997
1725
|
const newUrl = `${browserPathname}?${current.toString()}`;
|
|
1998
1726
|
const oldUrl = `${browserPathname}${window.location.search}`;
|
|
1999
|
-
const isRestoringLastSyncedUrl = newUrl === lastUrlRef.current;
|
|
2000
1727
|
// Skip pushing to history if we're handling a popstate event (browser back/forward)
|
|
2001
1728
|
// This prevents the URL sync from overwriting the history during back navigation
|
|
2002
1729
|
if (isHandlingPopStateRef.current) {
|
|
2003
1730
|
return;
|
|
2004
1731
|
}
|
|
2005
1732
|
if (newUrl !== oldUrl) {
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
}
|
|
2010
|
-
else {
|
|
2011
|
-
window.history.pushState(getCurrentHistoryState(), "", newUrl);
|
|
2012
|
-
}
|
|
1733
|
+
window.history.pushState(null, "", newUrl);
|
|
1734
|
+
// Update lastUrlRef so the popstate handler knows the current URL
|
|
1735
|
+
// This fixes the issue where goBack() wouldn't work because lastUrl was stale
|
|
2013
1736
|
lastUrlRef.current = newUrl;
|
|
2014
1737
|
}
|
|
2015
|
-
else if (switchWorkspacePushedRef.current) {
|
|
2016
|
-
// A workspace change may already have pushed the exact target URL. If we leave
|
|
2017
|
-
// this flag set, the next unrelated item navigation will incorrectly replace
|
|
2018
|
-
// history instead of pushing a new entry, which breaks browser back/forward.
|
|
2019
|
-
switchWorkspacePushedRef.current = false;
|
|
2020
|
-
}
|
|
2021
1738
|
}, [
|
|
2022
1739
|
currentItemDescriptor,
|
|
2023
1740
|
viewName,
|
|
@@ -2029,8 +1746,6 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
2029
1746
|
fullscreen,
|
|
2030
1747
|
currentWizardId,
|
|
2031
1748
|
openSidebars,
|
|
2032
|
-
showHelpTerminal,
|
|
2033
|
-
selectedHelpSectionId,
|
|
2034
1749
|
]);
|
|
2035
1750
|
useEffect(() => {
|
|
2036
1751
|
async function load() {
|
|
@@ -2127,9 +1842,12 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
2127
1842
|
"en",
|
|
2128
1843
|
version: 0,
|
|
2129
1844
|
};
|
|
1845
|
+
const loadedItem = await itemsRepository.getItem(itemToLoad);
|
|
1846
|
+
if (!loadedItem) {
|
|
1847
|
+
return undefined;
|
|
1848
|
+
}
|
|
2130
1849
|
// ensure this is object has no additional properties
|
|
2131
1850
|
itemToLoad = getItemDescriptor(itemToLoad);
|
|
2132
|
-
const requestedItemKey = makeItemKey(itemToLoad);
|
|
2133
1851
|
// Check if item is already open in any slot - if so, reuse that slot instead of creating a new one
|
|
2134
1852
|
const existingSlotForItem = editorSlots.find((s) => s.itemDescriptor.id === itemToLoad.id &&
|
|
2135
1853
|
s.itemDescriptor.language === itemToLoad.language &&
|
|
@@ -2140,17 +1858,6 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
2140
1858
|
!options?.openInNewSlot &&
|
|
2141
1859
|
!options?.targetSlotId) {
|
|
2142
1860
|
const isExistingSlotActive = existingSlotForItem.slotId === activeSlotIdRef.current;
|
|
2143
|
-
if (isExistingSlotActive) {
|
|
2144
|
-
latestGlobalLoadKeyRef.current = requestedItemKey;
|
|
2145
|
-
}
|
|
2146
|
-
const loadedItem = await itemsRepository.getItem(itemToLoad);
|
|
2147
|
-
if (!loadedItem) {
|
|
2148
|
-
return undefined;
|
|
2149
|
-
}
|
|
2150
|
-
if (isExistingSlotActive &&
|
|
2151
|
-
latestGlobalLoadKeyRef.current !== requestedItemKey) {
|
|
2152
|
-
return loadedItem;
|
|
2153
|
-
}
|
|
2154
1861
|
// If forceRefresh is true, update the slot with a new refreshToken to trigger a reload
|
|
2155
1862
|
if (options?.forceRefresh) {
|
|
2156
1863
|
setEditorSlots((prev) => {
|
|
@@ -2225,17 +1932,6 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
2225
1932
|
// - If the slot is active (or is becoming active as the first slot), do update.
|
|
2226
1933
|
const isFirstSlot = editorSlots.length === 0;
|
|
2227
1934
|
const shouldUpdateGlobalCurrentItem = isFirstSlot || targetSlotId === activeSlotIdRef.current;
|
|
2228
|
-
if (shouldUpdateGlobalCurrentItem) {
|
|
2229
|
-
latestGlobalLoadKeyRef.current = requestedItemKey;
|
|
2230
|
-
}
|
|
2231
|
-
const loadedItem = await itemsRepository.getItem(itemToLoad);
|
|
2232
|
-
if (!loadedItem) {
|
|
2233
|
-
return undefined;
|
|
2234
|
-
}
|
|
2235
|
-
if (shouldUpdateGlobalCurrentItem &&
|
|
2236
|
-
latestGlobalLoadKeyRef.current !== requestedItemKey) {
|
|
2237
|
-
return loadedItem;
|
|
2238
|
-
}
|
|
2239
1935
|
// Active slot is controlled ONLY by mouse hover - only activate the first slot on initial load
|
|
2240
1936
|
if (isFirstSlot) {
|
|
2241
1937
|
activeSlotIdRef.current = targetSlotId;
|
|
@@ -2343,10 +2039,9 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
2343
2039
|
useEffect(() => {
|
|
2344
2040
|
if (fullscreen &&
|
|
2345
2041
|
!searchParams.get("fullscreen") &&
|
|
2346
|
-
!configuration.forceFullscreen
|
|
2347
|
-
!isMobile)
|
|
2042
|
+
!configuration.forceFullscreen)
|
|
2348
2043
|
setShowFullscreenHint(true);
|
|
2349
|
-
}, [fullscreen, configuration.forceFullscreen, searchParams
|
|
2044
|
+
}, [fullscreen, configuration.forceFullscreen, searchParams]);
|
|
2350
2045
|
const state = {
|
|
2351
2046
|
page,
|
|
2352
2047
|
configuration,
|
|
@@ -2445,35 +2140,20 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
2445
2140
|
? existingOp.progress
|
|
2446
2141
|
: op.progress;
|
|
2447
2142
|
// IMPORTANT: Once canUndo becomes true, never downgrade it to false,
|
|
2448
|
-
// UNLESS this update indicates the operation was undone.
|
|
2449
|
-
//
|
|
2450
|
-
//
|
|
2451
|
-
|
|
2452
|
-
// without explicit undone/canRedo flags yet.
|
|
2453
|
-
const isExplicitUndoUpdate = op.undone === true || op.canRedo === true;
|
|
2454
|
-
const isInferredUndoCompletion = existingOp.executionStatus === "executing" &&
|
|
2455
|
-
op.executionStatus === "completed" &&
|
|
2456
|
-
existingOp.canUndo === true &&
|
|
2457
|
-
op.canUndo === false;
|
|
2458
|
-
const isUndoUpdate = isExplicitUndoUpdate || isInferredUndoCompletion;
|
|
2143
|
+
// UNLESS this update indicates the operation was undone. When an undo
|
|
2144
|
+
// completes, the server sends canUndo: false and canRedo: true (or undone: true).
|
|
2145
|
+
// We must respect that transition so the UI reflects the undo.
|
|
2146
|
+
const isUndoUpdate = op.undone === true || op.canRedo === true;
|
|
2459
2147
|
const mergedCanUndo = isUndoUpdate
|
|
2460
2148
|
? false
|
|
2461
2149
|
: existingOp.canUndo === true
|
|
2462
2150
|
? true
|
|
2463
2151
|
: op.canUndo;
|
|
2464
|
-
const mergedCanRedo = isUndoUpdate
|
|
2465
|
-
? true
|
|
2466
|
-
: op.canRedo ?? existingOp.canRedo;
|
|
2467
|
-
const mergedUndone = isUndoUpdate
|
|
2468
|
-
? true
|
|
2469
|
-
: op.undone ?? existingOp.undone;
|
|
2470
2152
|
const mergedOp = {
|
|
2471
2153
|
...existingOp,
|
|
2472
2154
|
...op,
|
|
2473
2155
|
progress: mergedProgress,
|
|
2474
2156
|
canUndo: mergedCanUndo,
|
|
2475
|
-
canRedo: mergedCanRedo,
|
|
2476
|
-
undone: mergedUndone,
|
|
2477
2157
|
};
|
|
2478
2158
|
// Ensure undone operations always have canRedo: true.
|
|
2479
2159
|
if (mergedOp.undone && !mergedOp.canRedo) {
|
|
@@ -2527,6 +2207,10 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
2527
2207
|
});
|
|
2528
2208
|
// Ref for markOperationComplete callback (needed because operationsContext is created later)
|
|
2529
2209
|
const markOperationCompleteRef = useRef(null);
|
|
2210
|
+
// When the websocket is reconnecting, we can briefly lose the ability to send messages.
|
|
2211
|
+
// Agent dialog responses (e.g. questionnaire cancel/submit) must not be dropped, otherwise
|
|
2212
|
+
// the backend tool call can remain pending and tests/users will hang.
|
|
2213
|
+
const pendingAgentDialogResponsesRef = useRef([]);
|
|
2530
2214
|
// WebSocket message handler and connection
|
|
2531
2215
|
const messageHandler = useSocketMessageHandler({
|
|
2532
2216
|
sessionId,
|
|
@@ -2552,31 +2236,28 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
2552
2236
|
markOperationCompleteRef.current?.(operationId);
|
|
2553
2237
|
},
|
|
2554
2238
|
});
|
|
2555
|
-
// Concurrent user limit error state
|
|
2556
|
-
const [concurrentUserLimitError, setConcurrentUserLimitError] = useState(null);
|
|
2557
|
-
concurrentUserLimitErrorRef.current = concurrentUserLimitError;
|
|
2558
|
-
const handleRetryConnection = useCallback(() => {
|
|
2559
|
-
setConcurrentUserLimitError(null);
|
|
2560
|
-
// Force reconnection by triggering a new connection attempt
|
|
2561
|
-
// The useEditorWebSocket hook will check availability again
|
|
2562
|
-
const socket = globalThis.editorSocket;
|
|
2563
|
-
if (socket) {
|
|
2564
|
-
socket.close();
|
|
2565
|
-
delete globalThis.editorSocket;
|
|
2566
|
-
}
|
|
2567
|
-
// The hook will automatically attempt to reconnect
|
|
2568
|
-
}, []);
|
|
2569
2239
|
const { socketRef: socketInstanceRef } = useEditorWebSocket({
|
|
2570
2240
|
sessionId,
|
|
2571
2241
|
onMessage: messageHandler,
|
|
2572
2242
|
onOpen: async () => {
|
|
2573
|
-
// Clear concurrent user limit error on successful connection
|
|
2574
|
-
setConcurrentUserLimitError(null);
|
|
2575
|
-
// Startup WebSocket probe may have failed with a blocking error while seats were full;
|
|
2576
|
-
// re-run status checks quietly so "1 error" does not stick after a successful connect.
|
|
2577
|
-
void startupChecks.recheckQuiet();
|
|
2578
2243
|
// Increment socket connection version to trigger re-subscriptions
|
|
2579
2244
|
setSocketConnectionVersion((v) => v + 1);
|
|
2245
|
+
// Flush any queued agent dialog responses now that the socket is open.
|
|
2246
|
+
// Keep this early so pending tool calls unblock ASAP.
|
|
2247
|
+
try {
|
|
2248
|
+
if (socketInstanceRef.current &&
|
|
2249
|
+
socketInstanceRef.current.readyState === WebSocket.OPEN &&
|
|
2250
|
+
pendingAgentDialogResponsesRef.current.length > 0) {
|
|
2251
|
+
// FIFO flush
|
|
2252
|
+
while (pendingAgentDialogResponsesRef.current.length > 0) {
|
|
2253
|
+
const queued = pendingAgentDialogResponsesRef.current.shift();
|
|
2254
|
+
socketInstanceRef.current.send(JSON.stringify(queued));
|
|
2255
|
+
}
|
|
2256
|
+
}
|
|
2257
|
+
}
|
|
2258
|
+
catch (e) {
|
|
2259
|
+
console.error("Failed to flush queued agent dialog responses:", e);
|
|
2260
|
+
}
|
|
2580
2261
|
// Fetch any running operations on (re)connect for auto-resume
|
|
2581
2262
|
// This ensures the UI shows operations that are still executing
|
|
2582
2263
|
try {
|
|
@@ -2592,37 +2273,24 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
2592
2273
|
}
|
|
2593
2274
|
},
|
|
2594
2275
|
onError: (error) => console.error("WebSocket error:", error),
|
|
2595
|
-
onConcurrentUserLimit: (error) => {
|
|
2596
|
-
setConcurrentUserLimitError(error);
|
|
2597
|
-
},
|
|
2598
|
-
onSessionRevoked: () => promptSessionReconnect("session-revoked"),
|
|
2599
2276
|
connectSocket,
|
|
2600
2277
|
requestQuota,
|
|
2601
2278
|
sendClientInfo,
|
|
2602
|
-
setSocketDiagnostics,
|
|
2603
2279
|
});
|
|
2604
|
-
useEffect(() => {
|
|
2605
|
-
const hasMySession = activeSessions.some((s) => s.sessionId === sessionId);
|
|
2606
|
-
if (hasMySession &&
|
|
2607
|
-
socketInstanceRef.current?.readyState === WebSocket.OPEN) {
|
|
2608
|
-
toast.dismiss("session-revoked");
|
|
2609
|
-
}
|
|
2610
|
-
}, [activeSessions, sessionId, socketConnectionVersion, socketInstanceRef]);
|
|
2611
|
-
useEffect(() => {
|
|
2612
|
-
const handleRevoked = (event) => {
|
|
2613
|
-
const customEvent = event;
|
|
2614
|
-
promptSessionReconnect(customEvent?.detail?.reason);
|
|
2615
|
-
};
|
|
2616
|
-
window.addEventListener("parhelia:session-revoked", handleRevoked);
|
|
2617
|
-
return () => {
|
|
2618
|
-
window.removeEventListener("parhelia:session-revoked", handleRevoked);
|
|
2619
|
-
};
|
|
2620
|
-
}, [promptSessionReconnect]);
|
|
2621
2280
|
const sendSocketMessage = useCallback((message) => {
|
|
2622
2281
|
if (socketInstanceRef.current &&
|
|
2623
2282
|
socketInstanceRef.current.readyState === WebSocket.OPEN) {
|
|
2624
2283
|
socketInstanceRef.current.send(JSON.stringify(message));
|
|
2625
2284
|
}
|
|
2285
|
+
else if (message.type === "agent-dialog-response") {
|
|
2286
|
+
// Queue dialog responses to avoid losing them during reconnects.
|
|
2287
|
+
pendingAgentDialogResponsesRef.current.push(message);
|
|
2288
|
+
// Prevent unbounded growth in pathological scenarios.
|
|
2289
|
+
if (pendingAgentDialogResponsesRef.current.length > 50) {
|
|
2290
|
+
pendingAgentDialogResponsesRef.current =
|
|
2291
|
+
pendingAgentDialogResponsesRef.current.slice(-50);
|
|
2292
|
+
}
|
|
2293
|
+
}
|
|
2626
2294
|
}, [socketInstanceRef]);
|
|
2627
2295
|
// URL update helper - defined early so it can be used by workspace/sidebar functions
|
|
2628
2296
|
const updateUrl = useCallback((params) => {
|
|
@@ -2641,7 +2309,7 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
2641
2309
|
? `${browserPathname}?${queryString}`
|
|
2642
2310
|
: browserPathname;
|
|
2643
2311
|
if (typeof window !== "undefined") {
|
|
2644
|
-
window.history.pushState(
|
|
2312
|
+
window.history.pushState(null, "", newUrl);
|
|
2645
2313
|
}
|
|
2646
2314
|
else {
|
|
2647
2315
|
router.push(newUrl, { scroll: false });
|
|
@@ -2666,13 +2334,8 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
2666
2334
|
if (!options?.skipNavigationHistory) {
|
|
2667
2335
|
addNavigationEntry(targetWorkspaceId, item);
|
|
2668
2336
|
}
|
|
2669
|
-
//
|
|
2670
|
-
|
|
2671
|
-
switchWorkspacePushedRef.current = true;
|
|
2672
|
-
updateUrl({
|
|
2673
|
-
workspace: targetWorkspaceId,
|
|
2674
|
-
...options?.urlParams,
|
|
2675
|
-
});
|
|
2337
|
+
// Update URL
|
|
2338
|
+
updateUrl({ workspace: targetWorkspaceId });
|
|
2676
2339
|
if (typeof document.startViewTransition === "function") {
|
|
2677
2340
|
document.startViewTransition(() => {
|
|
2678
2341
|
flushSync(() => {
|
|
@@ -2692,6 +2355,14 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
2692
2355
|
updateUrl,
|
|
2693
2356
|
handleSetShowAgentsPanel,
|
|
2694
2357
|
]);
|
|
2358
|
+
// Legacy alias for backwards compatibility
|
|
2359
|
+
const switchView = useCallback((viewName, options) => {
|
|
2360
|
+
// Handle ccpanel for settings workspace
|
|
2361
|
+
if (options?.ccpanel) {
|
|
2362
|
+
updateUrl({ ccpanel: options.ccpanel, workspace: viewName });
|
|
2363
|
+
}
|
|
2364
|
+
switchWorkspace(viewName, options);
|
|
2365
|
+
}, [switchWorkspace, updateUrl]);
|
|
2695
2366
|
// Helper: get all sidebar IDs that should be preserved (locked sidebars + their stack mates)
|
|
2696
2367
|
const getPreservedSidebarIds = useCallback(() => {
|
|
2697
2368
|
const lockedSet = new Set(lockedSidebarsRef.current);
|
|
@@ -2729,9 +2400,6 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
2729
2400
|
setOpenSidebars(newSidebars);
|
|
2730
2401
|
setLockedSidebars((locked) => locked.filter((id) => id !== sidebarId));
|
|
2731
2402
|
setSidebarStacks((prevStacks) => normalizeSidebarStacks(newSidebars, prevStacks));
|
|
2732
|
-
if (sidebarId === "agents-panel") {
|
|
2733
|
-
setUserPreferences({ showAgentsPanel: false });
|
|
2734
|
-
}
|
|
2735
2403
|
startTransition(() => {
|
|
2736
2404
|
updateUrl({ sidebar: newSidebars.join(",") || undefined });
|
|
2737
2405
|
});
|
|
@@ -2746,69 +2414,34 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
2746
2414
|
];
|
|
2747
2415
|
openSidebarsRef.current = newSidebars;
|
|
2748
2416
|
setOpenSidebars(newSidebars);
|
|
2749
|
-
ensureSidebarPinned(sidebarId);
|
|
2750
2417
|
setSidebarStacks((prevStacks) => normalizeSidebarStacks(newSidebars, prevStacks));
|
|
2751
|
-
if (sidebarId === "agents-panel") {
|
|
2752
|
-
setUserPreferences({ showAgentsPanel: true });
|
|
2753
|
-
}
|
|
2754
|
-
// On mobile, close the editor form panel when opening a sidebar
|
|
2755
|
-
if (isMobile) {
|
|
2756
|
-
setMobileEditorPanelOpenRaw(false);
|
|
2757
|
-
}
|
|
2758
2418
|
startTransition(() => {
|
|
2759
2419
|
updateUrl({ sidebar: newSidebars.join(",") || undefined });
|
|
2760
2420
|
});
|
|
2761
|
-
}, [
|
|
2762
|
-
updateUrl,
|
|
2763
|
-
getPreservedSidebarIds,
|
|
2764
|
-
normalizeSidebarStacks,
|
|
2765
|
-
ensureSidebarPinned,
|
|
2766
|
-
setUserPreferences,
|
|
2767
|
-
isMobile,
|
|
2768
|
-
]);
|
|
2421
|
+
}, [updateUrl, getPreservedSidebarIds, normalizeSidebarStacks]);
|
|
2769
2422
|
// Ensure a sidebar is open (without toggling it closed if already open)
|
|
2770
|
-
const openSidebar = useCallback((sidebarId
|
|
2423
|
+
const openSidebar = useCallback((sidebarId) => {
|
|
2771
2424
|
const currentOpenSidebars = openSidebarsRef.current;
|
|
2772
2425
|
if (currentOpenSidebars.includes(sidebarId)) {
|
|
2773
2426
|
// Already open, nothing to do
|
|
2774
2427
|
return;
|
|
2775
2428
|
}
|
|
2776
|
-
|
|
2777
|
-
|
|
2778
|
-
|
|
2779
|
-
|
|
2780
|
-
|
|
2781
|
-
|
|
2782
|
-
...currentOpenSidebars.filter((id) => preservedSet?.has(id)),
|
|
2783
|
-
sidebarId,
|
|
2784
|
-
];
|
|
2429
|
+
// Keep sidebars that are locked OR in a stack with a locked sidebar
|
|
2430
|
+
const preservedSet = getPreservedSidebarIds();
|
|
2431
|
+
const newSidebars = [
|
|
2432
|
+
...currentOpenSidebars.filter((id) => preservedSet.has(id)), // Keep locked stacks
|
|
2433
|
+
sidebarId, // Add the new one
|
|
2434
|
+
];
|
|
2785
2435
|
openSidebarsRef.current = newSidebars;
|
|
2786
2436
|
setOpenSidebars(newSidebars);
|
|
2787
|
-
ensureSidebarPinned(sidebarId);
|
|
2788
2437
|
setSidebarStacks((prevStacks) => normalizeSidebarStacks(newSidebars, prevStacks));
|
|
2789
|
-
if (sidebarId === "agents-panel") {
|
|
2790
|
-
setUserPreferences({ showAgentsPanel: true });
|
|
2791
|
-
}
|
|
2792
|
-
// On mobile, close the editor form panel when opening a sidebar
|
|
2793
|
-
if (isMobile) {
|
|
2794
|
-
setMobileEditorPanelOpenRaw(false);
|
|
2795
|
-
}
|
|
2796
2438
|
startTransition(() => {
|
|
2797
2439
|
updateUrl({ sidebar: newSidebars.join(",") || undefined });
|
|
2798
2440
|
});
|
|
2799
|
-
}, [
|
|
2800
|
-
updateUrl,
|
|
2801
|
-
getPreservedSidebarIds,
|
|
2802
|
-
normalizeSidebarStacks,
|
|
2803
|
-
ensureSidebarPinned,
|
|
2804
|
-
setUserPreferences,
|
|
2805
|
-
isMobile,
|
|
2806
|
-
]);
|
|
2441
|
+
}, [updateUrl, getPreservedSidebarIds, normalizeSidebarStacks]);
|
|
2807
2442
|
// Toggle lock state for a sidebar stack (keeps it visible when selecting another)
|
|
2808
2443
|
// When toggling any sidebar, we toggle the entire stack it belongs to
|
|
2809
2444
|
const toggleSidebarLock = useCallback((sidebarId) => {
|
|
2810
|
-
if (isMobile)
|
|
2811
|
-
return;
|
|
2812
2445
|
const currentStacks = sidebarStacksRef.current;
|
|
2813
2446
|
const stackContainingSidebar = currentStacks.find((stack) => stack.includes(sidebarId));
|
|
2814
2447
|
const sidebarIdsToToggle = stackContainingSidebar || [sidebarId];
|
|
@@ -2826,7 +2459,7 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
2826
2459
|
];
|
|
2827
2460
|
}
|
|
2828
2461
|
});
|
|
2829
|
-
}, [
|
|
2462
|
+
}, []);
|
|
2830
2463
|
const stackSidebar = useCallback((sidebarId, targetSidebarId, position = "after") => {
|
|
2831
2464
|
if (!sidebarId || !targetSidebarId || sidebarId === targetSidebarId)
|
|
2832
2465
|
return;
|
|
@@ -2858,38 +2491,6 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
2858
2491
|
return normalizeSidebarStacks(openIds, next);
|
|
2859
2492
|
});
|
|
2860
2493
|
}, [normalizeSidebarStacks]);
|
|
2861
|
-
const moveSidebarToColumn = useCallback((sidebarId, targetSidebarId, position = "after") => {
|
|
2862
|
-
if (!sidebarId || !targetSidebarId || sidebarId === targetSidebarId) {
|
|
2863
|
-
return;
|
|
2864
|
-
}
|
|
2865
|
-
const currentOpen = openSidebarsRef.current;
|
|
2866
|
-
const baseOpen = currentOpen.filter((id) => id !== sidebarId);
|
|
2867
|
-
const targetIndex = baseOpen.indexOf(targetSidebarId);
|
|
2868
|
-
if (targetIndex === -1) {
|
|
2869
|
-
return;
|
|
2870
|
-
}
|
|
2871
|
-
const insertIndex = position === "before" ? targetIndex : targetIndex + 1;
|
|
2872
|
-
const nextOpen = [...baseOpen];
|
|
2873
|
-
nextOpen.splice(insertIndex, 0, sidebarId);
|
|
2874
|
-
openSidebarsRef.current = nextOpen;
|
|
2875
|
-
setOpenSidebars(nextOpen);
|
|
2876
|
-
startTransition(() => {
|
|
2877
|
-
updateUrl({ sidebar: nextOpen.join(",") || undefined });
|
|
2878
|
-
});
|
|
2879
|
-
setSidebarStacks((prev) => {
|
|
2880
|
-
const normalized = normalizeSidebarStacks(nextOpen, prev);
|
|
2881
|
-
const next = normalized
|
|
2882
|
-
.map((stack) => stack.filter((id) => id !== sidebarId))
|
|
2883
|
-
.filter((stack) => stack.length > 0);
|
|
2884
|
-
const targetStackIndex = next.findIndex((stack) => stack.includes(targetSidebarId));
|
|
2885
|
-
if (targetStackIndex === -1) {
|
|
2886
|
-
next.push([sidebarId]);
|
|
2887
|
-
return normalizeSidebarStacks(nextOpen, next);
|
|
2888
|
-
}
|
|
2889
|
-
next.splice(position === "before" ? targetStackIndex : targetStackIndex + 1, 0, [sidebarId]);
|
|
2890
|
-
return normalizeSidebarStacks(nextOpen, next);
|
|
2891
|
-
});
|
|
2892
|
-
}, [normalizeSidebarStacks, updateUrl]);
|
|
2893
2494
|
const unstackSidebar = useCallback((sidebarId) => {
|
|
2894
2495
|
setSidebarStacks((prev) => {
|
|
2895
2496
|
const openIds = openSidebarsRef.current;
|
|
@@ -2935,34 +2536,8 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
2935
2536
|
// Get resolved sidebar (with panels materialized)
|
|
2936
2537
|
// Note: This is defined as a function that will be called later when editContext is available
|
|
2937
2538
|
const sidebars = configuration.editor.sidebars ?? [];
|
|
2938
|
-
const taskboardSidebarIds = new Set([
|
|
2939
|
-
"taskboard-project-list",
|
|
2940
|
-
"taskboard-my-tasks",
|
|
2941
|
-
]);
|
|
2942
|
-
const getSidebarsForWorkspace = useCallback((targetWorkspaceId) => {
|
|
2943
|
-
const isTaskboardWorkspace = targetWorkspaceId === "taskboard";
|
|
2944
|
-
const workspaceAllowedSidebarIds = userInfo.workspaces?.find((w) => w.id === targetWorkspaceId)
|
|
2945
|
-
?.sidebars ?? [];
|
|
2946
|
-
return sidebars.filter((s) => {
|
|
2947
|
-
const isTaskboardSidebar = taskboardSidebarIds.has(s.id);
|
|
2948
|
-
if (isTaskboardWorkspace && !isTaskboardSidebar)
|
|
2949
|
-
return false;
|
|
2950
|
-
if (!isTaskboardWorkspace && isTaskboardSidebar)
|
|
2951
|
-
return false;
|
|
2952
|
-
// Always show agents-panel regardless of workspace settings.
|
|
2953
|
-
if (s.id === "agents-panel") {
|
|
2954
|
-
return true;
|
|
2955
|
-
}
|
|
2956
|
-
// If no workspace settings or no sidebars defined for current workspace, show all.
|
|
2957
|
-
if (workspaceAllowedSidebarIds.length === 0) {
|
|
2958
|
-
return true;
|
|
2959
|
-
}
|
|
2960
|
-
// Only show sidebars that are in the allowed list for the current workspace.
|
|
2961
|
-
return workspaceAllowedSidebarIds.includes(s.id);
|
|
2962
|
-
});
|
|
2963
|
-
}, [sidebars, userInfo.workspaces]);
|
|
2964
2539
|
const getResolvedSidebar = useCallback((sidebarId) => {
|
|
2965
|
-
const sidebar =
|
|
2540
|
+
const sidebar = sidebars.find((s) => s.id === sidebarId);
|
|
2966
2541
|
if (!sidebar)
|
|
2967
2542
|
return undefined;
|
|
2968
2543
|
// Resolve panel factories using editContextRef to avoid circular dependency
|
|
@@ -2976,35 +2551,7 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
2976
2551
|
...sidebar,
|
|
2977
2552
|
panels: resolvedPanels,
|
|
2978
2553
|
};
|
|
2979
|
-
}, [
|
|
2980
|
-
useEffect(() => {
|
|
2981
|
-
if (!currentWorkspace.supportsSidebars) {
|
|
2982
|
-
return;
|
|
2983
|
-
}
|
|
2984
|
-
const allowedIds = new Set(getSidebarsForWorkspace(workspaceId).map((sidebar) => sidebar.id));
|
|
2985
|
-
const currentOpen = openSidebarsRef.current;
|
|
2986
|
-
let nextOpen = currentOpen.filter((id) => allowedIds.has(id));
|
|
2987
|
-
if (nextOpen.length === 0 && currentWorkspace.defaultSidebars?.length) {
|
|
2988
|
-
nextOpen = currentWorkspace.defaultSidebars.filter((id) => allowedIds.has(id));
|
|
2989
|
-
}
|
|
2990
|
-
const unchanged = nextOpen.length === currentOpen.length &&
|
|
2991
|
-
nextOpen.every((id, index) => id === currentOpen[index]);
|
|
2992
|
-
if (unchanged) {
|
|
2993
|
-
return;
|
|
2994
|
-
}
|
|
2995
|
-
openSidebarsRef.current = nextOpen;
|
|
2996
|
-
setOpenSidebars(nextOpen);
|
|
2997
|
-
setSidebarStacks((prev) => normalizeSidebarStacks(nextOpen, prev));
|
|
2998
|
-
startTransition(() => {
|
|
2999
|
-
updateUrl({ sidebar: nextOpen.join(",") || undefined });
|
|
3000
|
-
});
|
|
3001
|
-
}, [
|
|
3002
|
-
currentWorkspace,
|
|
3003
|
-
getSidebarsForWorkspace,
|
|
3004
|
-
normalizeSidebarStacks,
|
|
3005
|
-
updateUrl,
|
|
3006
|
-
workspaceId,
|
|
3007
|
-
]);
|
|
2554
|
+
}, [sidebars]);
|
|
3008
2555
|
// Listen for switch-workspace and open-sidebar commands from agents via websocket
|
|
3009
2556
|
useEffect(() => {
|
|
3010
2557
|
const handleAgentMessage = (message) => {
|
|
@@ -3218,45 +2765,9 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
3218
2765
|
}
|
|
3219
2766
|
return true;
|
|
3220
2767
|
}, [operations, ignoreBlur, sessionId]);
|
|
3221
|
-
const quickSwitcherEntries = useMemo(() => {
|
|
3222
|
-
const entries = [];
|
|
3223
|
-
const seen = new Set();
|
|
3224
|
-
const pushEntry = (entry) => {
|
|
3225
|
-
const key = entry.item
|
|
3226
|
-
? `${entry.workspaceId}:${entry.item.id}:${entry.item.language}:${entry.item.version}`
|
|
3227
|
-
: `${entry.workspaceId}:no-item`;
|
|
3228
|
-
if (seen.has(key))
|
|
3229
|
-
return;
|
|
3230
|
-
seen.add(key);
|
|
3231
|
-
entries.push(entry);
|
|
3232
|
-
};
|
|
3233
|
-
for (const entry of navigationHistory) {
|
|
3234
|
-
pushEntry(entry);
|
|
3235
|
-
}
|
|
3236
|
-
for (const entry of browseHistory) {
|
|
3237
|
-
if (!entry.id || !entry.language)
|
|
3238
|
-
continue;
|
|
3239
|
-
pushEntry({
|
|
3240
|
-
workspaceId,
|
|
3241
|
-
item: {
|
|
3242
|
-
id: entry.id,
|
|
3243
|
-
language: entry.language,
|
|
3244
|
-
version: entry.version ?? 0,
|
|
3245
|
-
},
|
|
3246
|
-
timestamp: entry.visitedAt
|
|
3247
|
-
? new Date(entry.visitedAt).getTime()
|
|
3248
|
-
: Date.now(),
|
|
3249
|
-
displayName: entry.name || workspaceId,
|
|
3250
|
-
itemName: entry.name,
|
|
3251
|
-
itemPath: entry.path,
|
|
3252
|
-
itemIcon: entry.icon,
|
|
3253
|
-
});
|
|
3254
|
-
}
|
|
3255
|
-
return entries.slice(0, 25);
|
|
3256
|
-
}, [navigationHistory, browseHistory, workspaceId]);
|
|
3257
2768
|
// Quick switcher handlers
|
|
3258
2769
|
const showQuickSwitcher = useCallback((show) => {
|
|
3259
|
-
if (show &&
|
|
2770
|
+
if (show && navigationHistory.length > 1) {
|
|
3260
2771
|
setQuickSwitcherVisible(true);
|
|
3261
2772
|
// Start with index 1 (second entry - previous entry) for quick switching
|
|
3262
2773
|
setQuickSwitcherSelectedIndex(1);
|
|
@@ -3264,11 +2775,11 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
3264
2775
|
else {
|
|
3265
2776
|
setQuickSwitcherVisible(false);
|
|
3266
2777
|
}
|
|
3267
|
-
}, [
|
|
2778
|
+
}, [navigationHistory]);
|
|
3268
2779
|
const cycleQuickSwitcher = useCallback((direction) => {
|
|
3269
2780
|
if (!quickSwitcherVisible)
|
|
3270
2781
|
return;
|
|
3271
|
-
const maxItems = Math.min(5,
|
|
2782
|
+
const maxItems = Math.min(5, navigationHistory.length);
|
|
3272
2783
|
setQuickSwitcherSelectedIndex((current) => {
|
|
3273
2784
|
let newIndex = current;
|
|
3274
2785
|
// Determine grid layout (responsive columns)
|
|
@@ -3313,9 +2824,9 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
3313
2824
|
}
|
|
3314
2825
|
return newIndex;
|
|
3315
2826
|
});
|
|
3316
|
-
}, [quickSwitcherVisible,
|
|
2827
|
+
}, [quickSwitcherVisible, navigationHistory]);
|
|
3317
2828
|
const handleQuickSwitcherSelect = useCallback((index) => {
|
|
3318
|
-
const selectedEntry =
|
|
2829
|
+
const selectedEntry = navigationHistory[index];
|
|
3319
2830
|
if (selectedEntry) {
|
|
3320
2831
|
// Determine target workspace: entries with items should go to "editor" workspace
|
|
3321
2832
|
// (fixes issue where browse history entries initialized with wrong workspaceId)
|
|
@@ -3367,46 +2878,23 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
3367
2878
|
}
|
|
3368
2879
|
setQuickSwitcherVisible(false);
|
|
3369
2880
|
}, [
|
|
3370
|
-
|
|
2881
|
+
navigationHistory,
|
|
3371
2882
|
loadItem,
|
|
3372
2883
|
switchWorkspace,
|
|
3373
2884
|
workspaceId,
|
|
3374
2885
|
item,
|
|
3375
2886
|
setNavigationHistory,
|
|
3376
2887
|
]);
|
|
3377
|
-
useEffect(() => {
|
|
3378
|
-
if (typeof window === "undefined" ||
|
|
3379
|
-
process.env.PARHELIA_DEV_MODE !== "true") {
|
|
3380
|
-
return;
|
|
3381
|
-
}
|
|
3382
|
-
window.__parheliaQuickSwitcherTestApi = {
|
|
3383
|
-
open: () => showQuickSwitcher(true),
|
|
3384
|
-
cycle: (direction = "next") => cycleQuickSwitcher(direction),
|
|
3385
|
-
closeWithoutSelection: () => setQuickSwitcherVisible(false),
|
|
3386
|
-
selectCurrent: () => handleQuickSwitcherSelect(quickSwitcherSelectedIndex),
|
|
3387
|
-
getState: () => ({
|
|
3388
|
-
visible: quickSwitcherVisible,
|
|
3389
|
-
selectedIndex: quickSwitcherSelectedIndex,
|
|
3390
|
-
entryCount: quickSwitcherEntries.length,
|
|
3391
|
-
entries: quickSwitcherEntries.map((entry) => ({
|
|
3392
|
-
workspaceId: entry.workspaceId,
|
|
3393
|
-
itemId: entry.item?.id,
|
|
3394
|
-
displayName: entry.displayName,
|
|
3395
|
-
})),
|
|
3396
|
-
}),
|
|
3397
|
-
};
|
|
3398
|
-
return () => {
|
|
3399
|
-
delete window.__parheliaQuickSwitcherTestApi;
|
|
3400
|
-
};
|
|
3401
|
-
}, [
|
|
3402
|
-
showQuickSwitcher,
|
|
3403
|
-
cycleQuickSwitcher,
|
|
3404
|
-
handleQuickSwitcherSelect,
|
|
3405
|
-
quickSwitcherSelectedIndex,
|
|
3406
|
-
]);
|
|
3407
2888
|
const { handleKeyDown } = useKeyboardNavigation({
|
|
3408
2889
|
editContextRef,
|
|
3409
|
-
|
|
2890
|
+
operations,
|
|
2891
|
+
pageViewContext: activePageViewContext,
|
|
2892
|
+
configuration,
|
|
2893
|
+
item,
|
|
2894
|
+
browseHistory,
|
|
2895
|
+
loadItem,
|
|
2896
|
+
showInfoToast,
|
|
2897
|
+
showErrorToast,
|
|
3410
2898
|
executeCommand,
|
|
3411
2899
|
showQuickSwitcher,
|
|
3412
2900
|
cycleQuickSwitcher,
|
|
@@ -3526,19 +3014,10 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
3526
3014
|
}
|
|
3527
3015
|
return null;
|
|
3528
3016
|
};
|
|
3529
|
-
let modifierWasPressedOnMouseDown = false;
|
|
3530
|
-
const handleMouseDown = (event) => {
|
|
3531
|
-
modifierWasPressedOnMouseDown = event.ctrlKey || event.metaKey;
|
|
3532
|
-
};
|
|
3533
3017
|
const handleCtrlClick = async (event) => {
|
|
3534
|
-
// Only proceed if Ctrl
|
|
3535
|
-
// This avoids accidental navigation when users press Ctrl after selecting text to copy.
|
|
3536
|
-
if (!modifierWasPressedOnMouseDown)
|
|
3537
|
-
return;
|
|
3538
|
-
// Also require the modifier to still be held for the final click event.
|
|
3018
|
+
// Only proceed if Ctrl (or Cmd on Mac) is pressed
|
|
3539
3019
|
if (!event.ctrlKey && !event.metaKey)
|
|
3540
3020
|
return;
|
|
3541
|
-
modifierWasPressedOnMouseDown = false;
|
|
3542
3021
|
const target = event.target;
|
|
3543
3022
|
const text = getTextFromElement(target);
|
|
3544
3023
|
if (text && isGuid(text)) {
|
|
@@ -3553,7 +3032,8 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
3553
3032
|
skipViewChange: true,
|
|
3554
3033
|
});
|
|
3555
3034
|
if (item) {
|
|
3556
|
-
|
|
3035
|
+
// Switch to the editor view
|
|
3036
|
+
switchView("editor", {
|
|
3557
3037
|
skipNavigationHistory: true,
|
|
3558
3038
|
});
|
|
3559
3039
|
showInfoToast({
|
|
@@ -3579,14 +3059,12 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
3579
3059
|
}
|
|
3580
3060
|
};
|
|
3581
3061
|
if (typeof document !== "undefined") {
|
|
3582
|
-
document.addEventListener("mousedown", handleMouseDown, true);
|
|
3583
3062
|
document.addEventListener("click", handleCtrlClick, true);
|
|
3584
3063
|
return () => {
|
|
3585
|
-
document.removeEventListener("mousedown", handleMouseDown, true);
|
|
3586
3064
|
document.removeEventListener("click", handleCtrlClick, true);
|
|
3587
3065
|
};
|
|
3588
3066
|
}
|
|
3589
|
-
}, [loadItem,
|
|
3067
|
+
}, [loadItem, switchView, showInfoToast, showErrorToast]);
|
|
3590
3068
|
useEffect(() => {
|
|
3591
3069
|
const handleGlobalBlur = () => {
|
|
3592
3070
|
operations.onFieldBlur?.();
|
|
@@ -3624,6 +3102,21 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
3624
3102
|
// Otherwise, only show workspaces that are in the settings
|
|
3625
3103
|
return workspaceIdsFromSettings.includes(w.id) && !w.visible;
|
|
3626
3104
|
});
|
|
3105
|
+
// Get sidebars allowed for the current workspace from settings
|
|
3106
|
+
const currentWorkspaceSettings = userInfo.workspaces?.find((w) => w.id === workspaceId);
|
|
3107
|
+
const allowedSidebarIds = currentWorkspaceSettings?.sidebars ?? [];
|
|
3108
|
+
// Legacy: Calculate visible views for backwards compatibility
|
|
3109
|
+
const allViews = (configuration.editor.views ?? [])
|
|
3110
|
+
.filter((x) => {
|
|
3111
|
+
return !x.visible && !x.hidden;
|
|
3112
|
+
})
|
|
3113
|
+
.filter((x) => !userInfo.views ||
|
|
3114
|
+
userInfo.views.map((view) => view.name).includes(x.name));
|
|
3115
|
+
const pinnedViews = userInfo.preferences?.pinnedViews ||
|
|
3116
|
+
configuration.editor.defaultPinnedViews ||
|
|
3117
|
+
[];
|
|
3118
|
+
// Legacy visibleViews for backwards compatibility
|
|
3119
|
+
const visibleViews = allViews.filter((view) => view.name === viewName || pinnedViews.includes(view.name));
|
|
3627
3120
|
// Handle initial mode setup from URL (only on initial load)
|
|
3628
3121
|
useEffect(() => {
|
|
3629
3122
|
if (!isInitialLoad)
|
|
@@ -3668,7 +3161,7 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
3668
3161
|
// This is especially important when called from the tour, where the current workspace
|
|
3669
3162
|
// might be the editor and URL-only navigation would get "corrected" back.
|
|
3670
3163
|
try {
|
|
3671
|
-
|
|
3164
|
+
switchView("home", {
|
|
3672
3165
|
skipConfirmation: true,
|
|
3673
3166
|
skipNavigationHistory: true,
|
|
3674
3167
|
});
|
|
@@ -3715,6 +3208,7 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
3715
3208
|
const current = new URLSearchParams(searchParams.toString());
|
|
3716
3209
|
current.delete("version");
|
|
3717
3210
|
current.delete("itemid");
|
|
3211
|
+
current.delete("view"); // Remove legacy param
|
|
3718
3212
|
current.delete("workspace"); // Clear workspace
|
|
3719
3213
|
current.set("create", "1");
|
|
3720
3214
|
const newUrl = `${pathname}?${current.toString()}`;
|
|
@@ -3994,8 +3488,6 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
3994
3488
|
setShowOnlyMyChanges,
|
|
3995
3489
|
filterByCurrentLanguage,
|
|
3996
3490
|
setFilterByCurrentLanguage,
|
|
3997
|
-
historySearchQuery,
|
|
3998
|
-
setHistorySearchQuery,
|
|
3999
3491
|
refreshHistory,
|
|
4000
3492
|
isRefreshing,
|
|
4001
3493
|
activeSessions,
|
|
@@ -4033,8 +3525,19 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
4033
3525
|
workspaceId,
|
|
4034
3526
|
previousWorkspaceId,
|
|
4035
3527
|
switchWorkspace,
|
|
4036
|
-
// Sidebar state
|
|
4037
|
-
availableSidebars:
|
|
3528
|
+
// Sidebar state - filter by workspace settings if available
|
|
3529
|
+
availableSidebars: (configuration.editor.sidebars ?? []).filter((s) => {
|
|
3530
|
+
// Always show agents-panel regardless of workspace settings
|
|
3531
|
+
if (s.id === "agents-panel") {
|
|
3532
|
+
return true;
|
|
3533
|
+
}
|
|
3534
|
+
// If no workspace settings or no sidebars defined for current workspace, show all
|
|
3535
|
+
if (!allowedSidebarIds || allowedSidebarIds.length === 0) {
|
|
3536
|
+
return true;
|
|
3537
|
+
}
|
|
3538
|
+
// Only show sidebars that are in the allowed list for the current workspace
|
|
3539
|
+
return allowedSidebarIds.includes(s.id);
|
|
3540
|
+
}),
|
|
4038
3541
|
openSidebars,
|
|
4039
3542
|
pinnedSidebars,
|
|
4040
3543
|
lockedSidebars,
|
|
@@ -4044,12 +3547,17 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
4044
3547
|
toggleSidebarPin,
|
|
4045
3548
|
toggleSidebarLock,
|
|
4046
3549
|
stackSidebar,
|
|
4047
|
-
moveSidebarToColumn,
|
|
4048
3550
|
unstackSidebar,
|
|
4049
3551
|
reorderSidebarInStack,
|
|
4050
3552
|
reorderPinnedSidebars,
|
|
4051
3553
|
reorderOpenSidebars,
|
|
4052
3554
|
getResolvedSidebar,
|
|
3555
|
+
// Legacy compatibility (deprecated)
|
|
3556
|
+
viewName,
|
|
3557
|
+
previousViewName,
|
|
3558
|
+
switchView,
|
|
3559
|
+
view: currentView,
|
|
3560
|
+
visibleViews,
|
|
4053
3561
|
compareMode,
|
|
4054
3562
|
setCompareMode,
|
|
4055
3563
|
fullscreen,
|
|
@@ -4089,7 +3597,6 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
4089
3597
|
addSocketMessageListener,
|
|
4090
3598
|
sendSocketMessage,
|
|
4091
3599
|
socketConnectionVersion,
|
|
4092
|
-
socketDiagnostics,
|
|
4093
3600
|
currentItemDescriptor,
|
|
4094
3601
|
editorSlots,
|
|
4095
3602
|
activeSlotId,
|
|
@@ -4102,7 +3609,6 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
4102
3609
|
setActiveSlot,
|
|
4103
3610
|
revision,
|
|
4104
3611
|
notifyPageModelReady,
|
|
4105
|
-
pageModelReadyToken,
|
|
4106
3612
|
selectedComment,
|
|
4107
3613
|
setSelectedComment,
|
|
4108
3614
|
comments,
|
|
@@ -4181,8 +3687,6 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
4181
3687
|
setEnableCompletions,
|
|
4182
3688
|
showComponentNavigator,
|
|
4183
3689
|
setShowComponentNavigator: handleSetShowComponentNavigator,
|
|
4184
|
-
isComponentNavigatorOpenForSlot,
|
|
4185
|
-
setComponentNavigatorOpenForSlot,
|
|
4186
3690
|
showAgentsPanel,
|
|
4187
3691
|
setShowAgentsPanel: handleSetShowAgentsPanel,
|
|
4188
3692
|
showMinimap,
|
|
@@ -4194,12 +3698,8 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
4194
3698
|
helpTerminalProfileName,
|
|
4195
3699
|
helpTerminalActiveTab,
|
|
4196
3700
|
setHelpTerminalActiveTab,
|
|
4197
|
-
selectedHelpSectionId,
|
|
4198
|
-
setSelectedHelpSectionId,
|
|
4199
3701
|
showAgentsWorkspaceEditor,
|
|
4200
3702
|
setShowAgentsWorkspaceEditor: handleSetShowAgentsWorkspaceEditor,
|
|
4201
|
-
selectedAgentsWorkspaceAgentId,
|
|
4202
|
-
setSelectedAgentsWorkspaceAgentId,
|
|
4203
3703
|
activeEditorTab,
|
|
4204
3704
|
setActiveEditorTab,
|
|
4205
3705
|
showLayoutComponents,
|
|
@@ -4208,8 +3708,6 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
4208
3708
|
isQuotaExceeded: isQuotaExceeded(),
|
|
4209
3709
|
getQuotaWarningMessage,
|
|
4210
3710
|
isMobile,
|
|
4211
|
-
mobileEditorPanelOpen,
|
|
4212
|
-
setMobileEditorPanelOpen: handleSetMobileEditorPanelOpen,
|
|
4213
3711
|
openDialog,
|
|
4214
3712
|
webSocketMessages,
|
|
4215
3713
|
clearWebSocketMessages: () => setWebSocketMessages([]),
|
|
@@ -4248,6 +3746,7 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
4248
3746
|
configuration,
|
|
4249
3747
|
updateUrl,
|
|
4250
3748
|
workspaceId,
|
|
3749
|
+
switchView,
|
|
4251
3750
|
pathname,
|
|
4252
3751
|
router,
|
|
4253
3752
|
item,
|
|
@@ -4277,6 +3776,7 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
4277
3776
|
currentWorkspace,
|
|
4278
3777
|
previousWorkspaceId,
|
|
4279
3778
|
switchWorkspace,
|
|
3779
|
+
allowedSidebarIds,
|
|
4280
3780
|
openSidebars,
|
|
4281
3781
|
pinnedSidebars,
|
|
4282
3782
|
lockedSidebars,
|
|
@@ -4288,6 +3788,9 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
4288
3788
|
reorderOpenSidebars,
|
|
4289
3789
|
getResolvedSidebar,
|
|
4290
3790
|
viewName,
|
|
3791
|
+
previousViewName,
|
|
3792
|
+
currentView,
|
|
3793
|
+
visibleViews,
|
|
4291
3794
|
compareMode,
|
|
4292
3795
|
// Important: in multi-slot mode the active PageViewContext can change
|
|
4293
3796
|
// without the base `pageViewContext` identity changing (e.g. switching slots).
|
|
@@ -4312,7 +3815,6 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
4312
3815
|
currentItemDescriptor,
|
|
4313
3816
|
revision,
|
|
4314
3817
|
notifyPageModelReady,
|
|
4315
|
-
pageModelReadyToken,
|
|
4316
3818
|
selectedComment,
|
|
4317
3819
|
comments,
|
|
4318
3820
|
availableCommentTags,
|
|
@@ -4331,7 +3833,6 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
4331
3833
|
quickSwitcherSelectedIndex,
|
|
4332
3834
|
handleQuickSwitcherSelect,
|
|
4333
3835
|
webSocketMessages,
|
|
4334
|
-
socketDiagnostics,
|
|
4335
3836
|
factoriesRef,
|
|
4336
3837
|
user,
|
|
4337
3838
|
statusMessage,
|
|
@@ -4340,11 +3841,7 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
4340
3841
|
isQuotaExceeded,
|
|
4341
3842
|
getQuotaWarningMessage,
|
|
4342
3843
|
isMobile,
|
|
4343
|
-
mobileEditorPanelOpen,
|
|
4344
|
-
handleSetMobileEditorPanelOpen,
|
|
4345
3844
|
showComponentNavigator,
|
|
4346
|
-
isComponentNavigatorOpenForSlot,
|
|
4347
|
-
setComponentNavigatorOpenForSlot,
|
|
4348
3845
|
handleSetShowComponentNavigator,
|
|
4349
3846
|
showAgentsPanel,
|
|
4350
3847
|
handleSetShowAgentsPanel,
|
|
@@ -4356,9 +3853,7 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
4356
3853
|
helpTerminalProfileName,
|
|
4357
3854
|
helpTerminalActiveTab,
|
|
4358
3855
|
setHelpTerminalActiveTab,
|
|
4359
|
-
selectedHelpSectionId,
|
|
4360
3856
|
showAgentsWorkspaceEditor,
|
|
4361
|
-
selectedAgentsWorkspaceAgentId,
|
|
4362
3857
|
activeEditorTab,
|
|
4363
3858
|
showLayoutComponents,
|
|
4364
3859
|
openDialog,
|
|
@@ -4603,40 +4098,18 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
4603
4098
|
// prevDependencies.current = currentDependencies;
|
|
4604
4099
|
// editContextRef.current = editContext;
|
|
4605
4100
|
// }, [editContext]);
|
|
4606
|
-
// Auto-open the mobile editor panel for new selection/intent changes, but
|
|
4607
|
-
// keep a manual close sticky for the exact same context.
|
|
4608
|
-
useEffect(() => {
|
|
4609
|
-
if (!isMobile || workspaceId !== "editor")
|
|
4610
|
-
return;
|
|
4611
|
-
if (activeEditorTab) {
|
|
4612
|
-
handleSetMobileEditorPanelOpen(true);
|
|
4613
|
-
return;
|
|
4614
|
-
}
|
|
4615
|
-
if (!(selection.length > 0 || insertMode))
|
|
4616
|
-
return;
|
|
4617
|
-
if (dismissedMobilePanelToken === mobilePanelDismissToken)
|
|
4618
|
-
return;
|
|
4619
|
-
handleSetMobileEditorPanelOpen(true);
|
|
4620
|
-
}, [
|
|
4621
|
-
activeEditorTab,
|
|
4622
|
-
dismissedMobilePanelToken,
|
|
4623
|
-
handleSetMobileEditorPanelOpen,
|
|
4624
|
-
insertMode,
|
|
4625
|
-
isMobile,
|
|
4626
|
-
mobilePanelDismissToken,
|
|
4627
|
-
selection,
|
|
4628
|
-
workspaceId,
|
|
4629
|
-
]);
|
|
4630
4101
|
useEffect(() => {
|
|
4631
4102
|
fieldsEditContext.clearModifiedFields();
|
|
4632
4103
|
}, [currentItemDescriptor]);
|
|
4633
|
-
if (!
|
|
4104
|
+
if (!currentView)
|
|
4634
4105
|
return null;
|
|
4635
|
-
const editorUi = fullscreen ? (_jsxs(_Fragment, { children: [_jsxs("div", { className: "fixed inset-0 flex", children: [_jsx(PageViewerFrame, { compareView: compareMode, pageViewContext: activePageViewContext }), _jsx(FullscreenControls, { device: activePageViewContext.device, setDevice: (d) => activePageViewContext.setDevice(d), canExit: !configuration.forceFullscreen, onExit: () => setFullscreen(false), firstMobileDeviceName: configuration.devices[0]?.name })] }), showFullscreenHint && !configuration.forceFullscreen &&
|
|
4106
|
+
const editorUi = fullscreen ? (_jsxs(_Fragment, { children: [_jsxs("div", { className: "fixed inset-0 flex", children: [_jsx(PageViewerFrame, { compareView: compareMode, pageViewContext: activePageViewContext }), _jsx(FullscreenControls, { device: activePageViewContext.device, setDevice: (d) => activePageViewContext.setDevice(d), canExit: !configuration.forceFullscreen, onExit: () => setFullscreen(false), firstMobileDeviceName: configuration.devices[0]?.name })] }), showFullscreenHint && !configuration.forceFullscreen && (_jsx("div", { className: "fixed inset-0", onMouseMoveCapture: () => {
|
|
4636
4107
|
setTimeout(() => {
|
|
4637
4108
|
setShowFullscreenHint(false);
|
|
4638
4109
|
}, 600);
|
|
4639
|
-
}, "data-testid": "fullscreen-hint-overlay", children: _jsxs("div", { className: "fixed top-6 left-1/2 -translate-x-1/2 transform rounded-full bg-black/60 px-6 py-2.5 text-sm font-medium text-white shadow-2xl backdrop-blur-md transition-all duration-500", children: ["Press", " ", _jsx("kbd", { className: "mx-1 rounded bg-white/20 px-1.5 py-0.5 text-xs font-semibold", children: "Ctrl + F11" }), " ", "to exit fullscreen"] }) }))] })) : (_jsxs(_Fragment, { children: [_jsx(EditorChrome, { className: className, currentWorkspace: currentWorkspace, centerPanelView: centerPanelView, editContext: editContext, showAgentsPanel: showAgentsPanel, handleSetShowAgentsPanel: handleSetShowAgentsPanel, workspaceId: workspaceId
|
|
4110
|
+
}, "data-testid": "fullscreen-hint-overlay", children: _jsxs("div", { className: "fixed top-6 left-1/2 -translate-x-1/2 transform rounded-full bg-black/60 px-6 py-2.5 text-sm font-medium text-white shadow-2xl backdrop-blur-md transition-all duration-500", children: ["Press", " ", _jsx("kbd", { className: "mx-1 rounded bg-white/20 px-1.5 py-0.5 text-xs font-semibold", children: "Ctrl + F11" }), " ", "to exit fullscreen"] }) }))] })) : (_jsxs(_Fragment, { children: [_jsx(EditorChrome, { className: className, currentWorkspace: currentWorkspace, centerPanelView: centerPanelView, editContext: editContext, showComponentNavigator: showComponentNavigator, handleSetShowComponentNavigator: handleSetShowComponentNavigator, showAgentsPanel: showAgentsPanel, handleSetShowAgentsPanel: handleSetShowAgentsPanel, workspaceId: workspaceId,
|
|
4111
|
+
// Legacy props for backwards compatibility
|
|
4112
|
+
currentView: currentView, viewName: viewName }), isTourActive && (_jsx(Tour, { tourStopCallback: () => {
|
|
4640
4113
|
setIsTourActive(false);
|
|
4641
4114
|
// Remove tour state from URL
|
|
4642
4115
|
// Use history.replaceState instead of router.replace to avoid triggering React navigation
|
|
@@ -4646,14 +4119,8 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
|
|
|
4646
4119
|
const newUrl = queryString
|
|
4647
4120
|
? `${window.location.pathname}?${queryString}`
|
|
4648
4121
|
: window.location.pathname;
|
|
4649
|
-
window.history.replaceState(
|
|
4650
|
-
}, configuration: configuration, restoredFromUrl: tourRestoredRef.current })), _jsx(
|
|
4651
|
-
return (_jsx(
|
|
4652
|
-
currentWorkspace.id === "taskboard") &&
|
|
4653
|
-
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) => {
|
|
4654
|
-
if (!open) {
|
|
4655
|
-
setConcurrentUserLimitError(null);
|
|
4656
|
-
}
|
|
4657
|
-
}, 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, {})] }) }) }) }) }));
|
|
4122
|
+
window.history.replaceState(null, "", newUrl);
|
|
4123
|
+
}, configuration: configuration, restoredFromUrl: tourRestoredRef.current })), _jsx(GuidanceOverlay, {}), _jsx(AgentDialogHandler, { sendWebSocketMessage: (type, payload) => sendSocketMessage({ type, payload }) })] }));
|
|
4124
|
+
return (_jsx("div", { className: `editor h-full w-full`, children: _jsx(OperationsContextProvider, { value: operationsContext.context, children: _jsx(FieldsEditContextProvider, { value: fieldsEditContext, children: _jsxs(EditContextProvider, { value: editContext, children: [_jsx(DevModeIndicator, {}), startupChecks.state === "loading" && (_jsx("div", { className: "fixed inset-0 z-50 flex items-center justify-center bg-white/70 backdrop-blur-[1px]", children: _jsx("div", { className: "flex items-center gap-3 rounded-md border border-gray-200 bg-white px-4 py-3 text-gray-700 shadow-sm", children: _jsx(Spinner, { size: "xl" }) }) })), editContext.isRefreshing && (_jsx("div", { className: "pointer-events-none fixed right-0 bottom-0 flex h-24 w-24 items-center justify-center text-gray-600 opacity-50 select-none", children: _jsx(Spinner, {}) })), children || editorUi, dialog, _jsx(Toaster, { position: "top-center" }), " ", _jsx(ConfirmationDialog, { ref: confirmationDialogRef }), _jsx(QuickItemSwitcher, { visible: quickSwitcherVisible, entries: navigationHistory.slice(0, 5), selectedIndex: quickSwitcherSelectedIndex, onSelect: handleQuickSwitcherSelect, onClose: () => setQuickSwitcherVisible(false) }), _jsx(EditContextMenu, { ref: contextMenuRef }), _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 })] }) }) }) }));
|
|
4658
4125
|
}
|
|
4659
4126
|
//# sourceMappingURL=EditorShell.js.map
|