@parhelia/core 0.1.12556 → 0.1.12565
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 +6 -4
- package/dist/agents-view/AgentCard.js +143 -24
- package/dist/agents-view/AgentCard.js.map +1 -1
- package/dist/agents-view/AgentsInbox.d.ts +1 -1
- package/dist/agents-view/AgentsInbox.js +7 -92
- package/dist/agents-view/AgentsInbox.js.map +1 -1
- package/dist/agents-view/AgentsTitlebar.js +3 -2
- package/dist/agents-view/AgentsTitlebar.js.map +1 -1
- package/dist/agents-view/AgentsView.d.ts +6 -7
- package/dist/agents-view/AgentsView.js +191 -99
- package/dist/agents-view/AgentsView.js.map +1 -1
- package/dist/agents-view/AgentsWorkspaceView.d.ts +2 -6
- package/dist/agents-view/AgentsWorkspaceView.js +266 -113
- package/dist/agents-view/AgentsWorkspaceView.js.map +1 -1
- package/dist/agents-view/ProfileAgentsGroup.d.ts +2 -1
- package/dist/agents-view/ProfileAgentsGroup.js +4 -3
- 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 +2 -4
- 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 +6 -10
- 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 +4 -1
- 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 +12 -4
- package/dist/components/ui/context-menu.js.map +1 -1
- package/dist/components/ui/copy-button.d.ts +2 -1
- 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 +21 -126
- package/dist/components/ui/dialog.js.map +1 -1
- package/dist/components/ui/input.d.ts +1 -1
- package/dist/components/ui/input.js +5 -3
- package/dist/components/ui/input.js.map +1 -1
- package/dist/components/ui/paste-button.d.ts +2 -1
- 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 +1 -9
- 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 +4 -11
- package/dist/components/ui/tabs.js.map +1 -1
- package/dist/config/config.d.ts +4 -2
- package/dist/config/config.js +250 -70
- package/dist/config/config.js.map +1 -1
- package/dist/config/notificationRoutes.js +14 -0
- package/dist/config/notificationRoutes.js.map +1 -1
- package/dist/config/types/workspace.d.ts +6 -0
- package/dist/config/types.d.ts +63 -12
- package/dist/config/types.js.map +1 -1
- package/dist/editor/ConfirmationDialog.js +20 -4
- package/dist/editor/ConfirmationDialog.js.map +1 -1
- package/dist/editor/ContentTree.d.ts +2 -1
- package/dist/editor/ContentTree.js +93 -32
- package/dist/editor/ContentTree.js.map +1 -1
- package/dist/editor/Editor.js +87 -22
- package/dist/editor/Editor.js.map +1 -1
- package/dist/editor/FieldHistory.js +84 -36
- package/dist/editor/FieldHistory.js.map +1 -1
- package/dist/editor/FieldListField.js +21 -9
- package/dist/editor/FieldListField.js.map +1 -1
- package/dist/editor/FieldListFieldWithFallbacks.js +23 -2
- package/dist/editor/FieldListFieldWithFallbacks.js.map +1 -1
- package/dist/editor/GlobalMenuBar.js +29 -2
- package/dist/editor/GlobalMenuBar.js.map +1 -1
- package/dist/editor/ImageEditor.js +5 -2
- package/dist/editor/ImageEditor.js.map +1 -1
- package/dist/editor/ItemInfo.js +36 -1
- package/dist/editor/ItemInfo.js.map +1 -1
- package/dist/editor/LinkEditorDialog.js +3 -0
- package/dist/editor/LinkEditorDialog.js.map +1 -1
- package/dist/editor/MainLayout.d.ts +0 -2
- package/dist/editor/MainLayout.js +65 -8
- package/dist/editor/MainLayout.js.map +1 -1
- package/dist/editor/MigrationsView.js +29 -5
- package/dist/editor/MigrationsView.js.map +1 -1
- package/dist/editor/MobileLayout.js +37 -12
- package/dist/editor/MobileLayout.js.map +1 -1
- package/dist/editor/PictureCropper.js +54 -45
- package/dist/editor/PictureCropper.js.map +1 -1
- package/dist/editor/PictureEditor.js +17 -15
- 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 +52 -12
- package/dist/editor/SetupWizard.js.map +1 -1
- package/dist/editor/Titlebar.js +7 -2
- package/dist/editor/Titlebar.js.map +1 -1
- package/dist/editor/ai/AgentCostDisplay.d.ts +1 -0
- package/dist/editor/ai/AgentCostDisplay.js +1 -1
- package/dist/editor/ai/AgentCostDisplay.js.map +1 -1
- package/dist/editor/ai/AgentDocumentList.js +32 -14
- package/dist/editor/ai/AgentDocumentList.js.map +1 -1
- package/dist/editor/ai/AgentGreeting.js +3 -2
- package/dist/editor/ai/AgentGreeting.js.map +1 -1
- package/dist/editor/ai/AgentProfileSelector.js +2 -1
- package/dist/editor/ai/AgentProfileSelector.js.map +1 -1
- package/dist/editor/ai/AgentStatusBadge.d.ts +0 -5
- package/dist/editor/ai/AgentStatusBadge.js +67 -65
- package/dist/editor/ai/AgentStatusBadge.js.map +1 -1
- package/dist/editor/ai/AgentTerminal.d.ts +14 -2
- package/dist/editor/ai/AgentTerminal.js +2406 -496
- package/dist/editor/ai/AgentTerminal.js.map +1 -1
- package/dist/editor/ai/AgentTerminalStatusBar.d.ts +8 -3
- package/dist/editor/ai/AgentTerminalStatusBar.js +481 -56
- package/dist/editor/ai/AgentTerminalStatusBar.js.map +1 -1
- package/dist/editor/ai/Agents.js +161 -113
- package/dist/editor/ai/Agents.js.map +1 -1
- package/dist/editor/ai/AiResponseMessage.d.ts +10 -1
- package/dist/editor/ai/AiResponseMessage.js +267 -26
- package/dist/editor/ai/AiResponseMessage.js.map +1 -1
- package/dist/editor/ai/ContextInfoBar.d.ts +2 -3
- package/dist/editor/ai/ContextInfoBar.js +64 -7
- package/dist/editor/ai/ContextInfoBar.js.map +1 -1
- package/dist/editor/ai/GuidanceOverlay.js +17 -11
- package/dist/editor/ai/GuidanceOverlay.js.map +1 -1
- package/dist/editor/ai/InlineAiDialog.d.ts +1 -1
- package/dist/editor/ai/InlineAiDialog.js +514 -192
- package/dist/editor/ai/InlineAiDialog.js.map +1 -1
- package/dist/editor/ai/InlineAiTrigger.js +115 -12
- package/dist/editor/ai/InlineAiTrigger.js.map +1 -1
- package/dist/editor/ai/MediaImage.js +40 -8
- package/dist/editor/ai/MediaImage.js.map +1 -1
- package/dist/editor/ai/SpawnedAgentsPanel.js +10 -12
- package/dist/editor/ai/SpawnedAgentsPanel.js.map +1 -1
- package/dist/editor/ai/ToolCallDisplay.d.ts +22 -2
- package/dist/editor/ai/ToolCallDisplay.js +542 -150
- package/dist/editor/ai/ToolCallDisplay.js.map +1 -1
- package/dist/editor/ai/agentDiagnostics.d.ts +7 -0
- package/dist/editor/ai/agentDiagnostics.js.map +1 -1
- package/dist/editor/ai/dialogs/AgentDialogHandler.d.ts +1 -8
- package/dist/editor/ai/dialogs/AgentDialogHandler.js +379 -42
- package/dist/editor/ai/dialogs/AgentDialogHandler.js.map +1 -1
- package/dist/editor/ai/dialogs/QuestionnaireInline.d.ts +5 -1
- package/dist/editor/ai/dialogs/QuestionnaireInline.js +628 -60
- package/dist/editor/ai/dialogs/QuestionnaireInline.js.map +1 -1
- package/dist/editor/ai/dialogs/agentDialogTypes.d.ts +115 -0
- package/dist/editor/ai/dialogs/agentDialogTypes.js +2 -0
- package/dist/editor/ai/dialogs/agentDialogTypes.js.map +1 -1
- package/dist/editor/ai/types.d.ts +3 -1
- package/dist/editor/ai/useAgentStatus.d.ts +2 -1
- package/dist/editor/ai/useAgentStatus.js +90 -100
- package/dist/editor/ai/useAgentStatus.js.map +1 -1
- package/dist/editor/ai/useInlineAiPosition.js +45 -5
- package/dist/editor/ai/useInlineAiPosition.js.map +1 -1
- package/dist/editor/client/AboutDialog.js +4 -2
- package/dist/editor/client/AboutDialog.js.map +1 -1
- package/dist/editor/client/EditorShell.d.ts +4 -1
- package/dist/editor/client/EditorShell.js +770 -237
- package/dist/editor/client/EditorShell.js.map +1 -1
- package/dist/editor/client/editContext.d.ts +33 -19
- package/dist/editor/client/editContext.js.map +1 -1
- package/dist/editor/client/helpers.js +6 -0
- package/dist/editor/client/helpers.js.map +1 -1
- package/dist/editor/client/hooks/useEditorUrlSync.js +1 -2
- package/dist/editor/client/hooks/useEditorUrlSync.js.map +1 -1
- package/dist/editor/client/hooks/useEditorWebSocket.d.ts +10 -0
- package/dist/editor/client/hooks/useEditorWebSocket.js +209 -14
- package/dist/editor/client/hooks/useEditorWebSocket.js.map +1 -1
- package/dist/editor/client/hooks/useQuota.d.ts +8 -0
- package/dist/editor/client/hooks/useQuota.js.map +1 -1
- package/dist/editor/client/hooks/useSocketMessageHandler.js +73 -15
- package/dist/editor/client/hooks/useSocketMessageHandler.js.map +1 -1
- package/dist/editor/client/itemsRepository.js +10 -6
- package/dist/editor/client/itemsRepository.js.map +1 -1
- package/dist/editor/client/navigation.js +35 -3
- package/dist/editor/client/navigation.js.map +1 -1
- package/dist/editor/client/operations.d.ts +6 -3
- package/dist/editor/client/operations.js +208 -30
- package/dist/editor/client/operations.js.map +1 -1
- package/dist/editor/client/pageModelBuilder.js +4 -31
- 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 +0 -6
- package/dist/editor/client/ui/EditorChrome.js +55 -72
- package/dist/editor/client/ui/EditorChrome.js.map +1 -1
- package/dist/editor/client/ui/FullscreenControls.js +5 -3
- package/dist/editor/client/ui/FullscreenControls.js.map +1 -1
- package/dist/editor/commands/commands.d.ts +11 -1
- package/dist/editor/commands/commands.js +12 -1
- package/dist/editor/commands/commands.js.map +1 -1
- package/dist/editor/commands/componentCommands.js +109 -55
- package/dist/editor/commands/componentCommands.js.map +1 -1
- package/dist/editor/commands/customCommandConverter.d.ts +8 -1
- package/dist/editor/commands/customCommandConverter.js +35 -5
- package/dist/editor/commands/customCommandConverter.js.map +1 -1
- package/dist/editor/commands/handlers/agentHandler.js +2 -1
- package/dist/editor/commands/handlers/agentHandler.js.map +1 -1
- package/dist/editor/commands/itemCommands.d.ts +3 -0
- package/dist/editor/commands/itemCommands.js +93 -10
- package/dist/editor/commands/itemCommands.js.map +1 -1
- package/dist/editor/commands/undo.d.ts +9 -15
- package/dist/editor/commands/undo.js +24 -0
- package/dist/editor/commands/undo.js.map +1 -1
- package/dist/editor/context-menu/InsertMenu.js +83 -39
- 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/RichTextEditor.js +13 -5
- package/dist/editor/field-types/RichTextEditor.js.map +1 -1
- package/dist/editor/field-types/RichTextEditorComponent.js +37 -3
- 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 +3 -2
- package/dist/editor/field-types/TreeListEditor.js.map +1 -1
- package/dist/editor/field-types/richtext/components/ReactSlate.css +23 -5
- package/dist/editor/field-types/richtext/components/ReactSlate.d.ts +2 -0
- package/dist/editor/field-types/richtext/components/ReactSlate.js +28 -4
- package/dist/editor/field-types/richtext/components/ReactSlate.js.map +1 -1
- package/dist/editor/field-types/richtext/components/ToolbarButton.js +4 -2
- package/dist/editor/field-types/richtext/components/ToolbarButton.js.map +1 -1
- package/dist/editor/field-types/richtext/contextMenuFactory.d.ts +13 -0
- package/dist/editor/field-types/richtext/contextMenuFactory.js +181 -24
- package/dist/editor/field-types/richtext/contextMenuFactory.js.map +1 -1
- package/dist/editor/field-types/richtext/types.d.ts +2 -0
- package/dist/editor/field-types/richtext/types.js.map +1 -1
- package/dist/editor/field-types/richtext/utils/plugins.js +4 -0
- package/dist/editor/field-types/richtext/utils/plugins.js.map +1 -1
- package/dist/editor/field-types/textContextMenuFactory.js +3 -2
- package/dist/editor/field-types/textContextMenuFactory.js.map +1 -1
- package/dist/editor/media-selector/AiImageSearchPrompt.js +4 -2
- 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 +7 -1
- package/dist/editor/media-selector/MediaSelector.js.map +1 -1
- package/dist/editor/media-selector/TreeSelector.js +40 -35
- 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 +4 -2
- 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 +26 -147
- package/dist/editor/menubar/PageSelector.js.map +1 -1
- package/dist/editor/menubar/Separator.js +1 -1
- package/dist/editor/menubar/VersionSelector.js +2 -4
- package/dist/editor/menubar/VersionSelector.js.map +1 -1
- package/dist/editor/menubar/WorkflowButton.js +39 -12
- package/dist/editor/menubar/WorkflowButton.js.map +1 -1
- package/dist/editor/menubar/toolbar-sections/CustomCommandsToolbar.js +16 -38
- 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 +1 -0
- package/dist/editor/menubar/toolbar-sections/HelpButton.js.map +1 -1
- package/dist/editor/menubar/toolbar-sections/ManualBrowser.d.ts +6 -10
- package/dist/editor/menubar/toolbar-sections/ManualBrowser.js +597 -220
- package/dist/editor/menubar/toolbar-sections/ManualBrowser.js.map +1 -1
- package/dist/editor/menubar/toolbar-sections/UtilityControls.js +13 -2
- package/dist/editor/menubar/toolbar-sections/UtilityControls.js.map +1 -1
- package/dist/editor/page-editor-chrome/CommentHighlighting.js +42 -1
- 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 +97 -48
- package/dist/editor/page-editor-chrome/InlineEditor.js.map +1 -1
- package/dist/editor/page-editor-chrome/PlaceholderDropZone.js +38 -17
- package/dist/editor/page-editor-chrome/PlaceholderDropZone.js.map +1 -1
- package/dist/editor/page-editor-chrome/PlaceholderDropZones.js +17 -11
- 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 +69 -11
- package/dist/editor/page-viewer/EditorForm.js.map +1 -1
- package/dist/editor/page-viewer/MiniMap.d.ts +2 -4
- package/dist/editor/page-viewer/MiniMap.js +91 -28
- package/dist/editor/page-viewer/MiniMap.js.map +1 -1
- package/dist/editor/page-viewer/PageViewer.d.ts +3 -1
- package/dist/editor/page-viewer/PageViewer.js +92 -19
- package/dist/editor/page-viewer/PageViewer.js.map +1 -1
- package/dist/editor/page-viewer/PageViewerFrame.d.ts +2 -1
- package/dist/editor/page-viewer/PageViewerFrame.js +348 -115
- package/dist/editor/page-viewer/PageViewerFrame.js.map +1 -1
- package/dist/editor/page-viewer/pageModelSkeletonBuilder.js +114 -49
- package/dist/editor/page-viewer/pageModelSkeletonBuilder.js.map +1 -1
- package/dist/editor/page-viewer/pageViewContext.d.ts +1 -0
- package/dist/editor/page-viewer/pageViewContext.js +51 -14
- package/dist/editor/page-viewer/pageViewContext.js.map +1 -1
- package/dist/editor/pageModel.d.ts +14 -1
- package/dist/editor/reviews/Comment.js +26 -12
- package/dist/editor/reviews/Comment.js.map +1 -1
- package/dist/editor/reviews/CommentDisplayPopover.js +7 -5
- package/dist/editor/reviews/CommentDisplayPopover.js.map +1 -1
- package/dist/editor/reviews/CommentView.js +19 -4
- package/dist/editor/reviews/CommentView.js.map +1 -1
- package/dist/editor/reviews/Comments.js +89 -72
- package/dist/editor/reviews/Comments.js.map +1 -1
- package/dist/editor/reviews/CreateReviewDialog.js +281 -177
- package/dist/editor/reviews/CreateReviewDialog.js.map +1 -1
- package/dist/editor/reviews/DecisionsMatrix.js +96 -25
- package/dist/editor/reviews/DecisionsMatrix.js.map +1 -1
- package/dist/editor/reviews/DiffView.js +7 -14
- package/dist/editor/reviews/DiffView.js.map +1 -1
- package/dist/editor/reviews/EditReviewSettingsDialog.js +6 -4
- package/dist/editor/reviews/EditReviewSettingsDialog.js.map +1 -1
- package/dist/editor/reviews/MultiReviewManager.js +25 -3
- package/dist/editor/reviews/MultiReviewManager.js.map +1 -1
- package/dist/editor/reviews/PagesPanel.js +31 -15
- package/dist/editor/reviews/PagesPanel.js.map +1 -1
- package/dist/editor/reviews/PreviewInfo.js +1 -4
- package/dist/editor/reviews/PreviewInfo.js.map +1 -1
- package/dist/editor/reviews/ReviewCard.js +13 -7
- package/dist/editor/reviews/ReviewCard.js.map +1 -1
- package/dist/editor/reviews/ReviewDetail.js +3 -2
- package/dist/editor/reviews/ReviewDetail.js.map +1 -1
- package/dist/editor/reviews/ReviewsList.js +7 -3
- package/dist/editor/reviews/ReviewsList.js.map +1 -1
- package/dist/editor/reviews/SuggestedEdit.js +34 -3
- package/dist/editor/reviews/SuggestedEdit.js.map +1 -1
- package/dist/editor/reviews/SuggestionDisplayPopover.js +31 -5
- package/dist/editor/reviews/SuggestionDisplayPopover.js.map +1 -1
- package/dist/editor/reviews/commentAi.js +25 -6
- package/dist/editor/reviews/commentAi.js.map +1 -1
- package/dist/editor/reviews/reviewCommands.js +4 -1
- 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 +12 -30
- package/dist/editor/reviews/useReviews.js.map +1 -1
- package/dist/editor/services/agentErrorMessage.d.ts +1 -0
- package/dist/editor/services/agentErrorMessage.js +91 -0
- package/dist/editor/services/agentErrorMessage.js.map +1 -0
- package/dist/editor/services/agentService.d.ts +229 -5
- package/dist/editor/services/agentService.js +292 -39
- package/dist/editor/services/agentService.js.map +1 -1
- package/dist/editor/services/agentStatus.d.ts +1 -0
- package/dist/editor/services/agentStatus.js +19 -0
- package/dist/editor/services/agentStatus.js.map +1 -1
- package/dist/editor/services/aiService.d.ts +57 -1
- package/dist/editor/services/aiService.js +79 -6
- package/dist/editor/services/aiService.js.map +1 -1
- package/dist/editor/services/contentService.d.ts +6 -3
- package/dist/editor/services/contentService.js +13 -12
- package/dist/editor/services/contentService.js.map +1 -1
- package/dist/editor/services/editService.d.ts +52 -1
- package/dist/editor/services/editService.js +94 -2
- 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 +3 -6
- package/dist/editor/services/reviewsService.js +2 -11
- package/dist/editor/services/reviewsService.js.map +1 -1
- package/dist/editor/services/serviceHelper.d.ts +2 -1
- package/dist/editor/services/serviceHelper.js +112 -20
- package/dist/editor/services/serviceHelper.js.map +1 -1
- package/dist/editor/services/systemService.d.ts +2 -1
- package/dist/editor/services/systemService.js +3 -0
- package/dist/editor/services/systemService.js.map +1 -1
- package/dist/editor/services-server/api.d.ts +1 -2
- package/dist/editor/services-server/api.js +11 -6
- package/dist/editor/services-server/api.js.map +1 -1
- package/dist/editor/settings/About.js +317 -3
- package/dist/editor/settings/About.js.map +1 -1
- package/dist/editor/settings/QuotaInfo.js +210 -4
- package/dist/editor/settings/QuotaInfo.js.map +1 -1
- package/dist/editor/settings/SettingsView.js +25 -23
- package/dist/editor/settings/SettingsView.js.map +1 -1
- package/dist/editor/settings/Status.js +7 -6
- package/dist/editor/settings/Status.js.map +1 -1
- package/dist/editor/settings/index/useIndexStatus.js +20 -22
- package/dist/editor/settings/index/useIndexStatus.js.map +1 -1
- package/dist/editor/settings/panels/AgentsPanel.d.ts +0 -4
- package/dist/editor/settings/panels/AgentsPanel.js +95 -121
- package/dist/editor/settings/panels/AgentsPanel.js.map +1 -1
- package/dist/editor/settings/panels/ModelsPanel.js +329 -108
- 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 +86 -59
- 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 +3 -2
- package/dist/editor/settings/panels/index.js +3 -2
- package/dist/editor/settings/panels/index.js.map +1 -1
- package/dist/editor/settings/status/coreStatusChecks.js +124 -19
- package/dist/editor/settings/status/coreStatusChecks.js.map +1 -1
- package/dist/editor/settings/status/useStartupChecks.d.ts +3 -1
- package/dist/editor/settings/status/useStartupChecks.js +9 -5
- package/dist/editor/settings/status/useStartupChecks.js.map +1 -1
- package/dist/editor/setup-wizard/steps/CompleteStep.d.ts +2 -1
- package/dist/editor/setup-wizard/steps/CompleteStep.js +2 -1
- package/dist/editor/setup-wizard/steps/CompleteStep.js.map +1 -1
- package/dist/editor/sidebar/ComponentPalette.js +2 -1
- package/dist/editor/sidebar/ComponentPalette.js.map +1 -1
- package/dist/editor/sidebar/ComponentTree.d.ts +8 -1
- package/dist/editor/sidebar/ComponentTree.js +216 -69
- package/dist/editor/sidebar/ComponentTree.js.map +1 -1
- package/dist/editor/sidebar/EditHistory.js +22 -46
- package/dist/editor/sidebar/EditHistory.js.map +1 -1
- package/dist/editor/sidebar/Favorites.js +4 -8
- package/dist/editor/sidebar/Favorites.js.map +1 -1
- package/dist/editor/sidebar/MainContentTree.js +4 -3
- package/dist/editor/sidebar/MainContentTree.js.map +1 -1
- package/dist/editor/sidebar/OperationItem.js +21 -7
- package/dist/editor/sidebar/OperationItem.js.map +1 -1
- package/dist/editor/sidebar/SidebarPanel.d.ts +3 -1
- package/dist/editor/sidebar/SidebarPanel.js +44 -12
- package/dist/editor/sidebar/SidebarPanel.js.map +1 -1
- package/dist/editor/sidebar/SidebarStack.d.ts +2 -1
- package/dist/editor/sidebar/SidebarStack.js +4 -3
- package/dist/editor/sidebar/SidebarStack.js.map +1 -1
- package/dist/editor/sidebar/Validation.js +24 -12
- package/dist/editor/sidebar/Validation.js.map +1 -1
- package/dist/editor/sidebar/Workbox.js +53 -3
- package/dist/editor/sidebar/Workbox.js.map +1 -1
- package/dist/editor/sidebar/WorkspaceRail.d.ts +0 -1
- package/dist/editor/sidebar/WorkspaceRail.js +56 -167
- package/dist/editor/sidebar/WorkspaceRail.js.map +1 -1
- package/dist/editor/tree-indicators/GutterColumns.d.ts +3 -1
- package/dist/editor/tree-indicators/GutterColumns.js +26 -5
- package/dist/editor/tree-indicators/GutterColumns.js.map +1 -1
- package/dist/editor/tree-indicators/GutterContext.d.ts +4 -0
- package/dist/editor/tree-indicators/GutterContext.js +23 -0
- package/dist/editor/tree-indicators/GutterContext.js.map +1 -1
- package/dist/editor/tree-indicators/index.d.ts +0 -1
- package/dist/editor/tree-indicators/index.js +0 -1
- package/dist/editor/tree-indicators/index.js.map +1 -1
- package/dist/editor/tree-indicators/types.d.ts +12 -1
- 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 +2 -0
- package/dist/editor/ui/ItemNameDialogNew.js +33 -17
- package/dist/editor/ui/ItemNameDialogNew.js.map +1 -1
- package/dist/editor/ui/ItemSearch.js +7 -11
- 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 +1 -0
- package/dist/editor/ui/SimpleTabs.js +45 -25
- package/dist/editor/ui/SimpleTabs.js.map +1 -1
- package/dist/editor/ui/Splitter.d.ts +1 -0
- package/dist/editor/ui/Splitter.js +102 -86
- 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 +6 -1
- package/dist/editor/ui/TreeListSelector.js +2 -2
- package/dist/editor/ui/TreeListSelector.js.map +1 -1
- package/dist/editor/utils/keyboardNavigation.d.ts +6 -20
- package/dist/editor/utils/keyboardNavigation.js +48 -140
- package/dist/editor/utils/keyboardNavigation.js.map +1 -1
- package/dist/editor/utils.js +19 -9
- package/dist/editor/utils.js.map +1 -1
- package/dist/editor/views/CompareView.d.ts +3 -1
- package/dist/editor/views/CompareView.js +7 -5
- 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 +27 -34
- package/dist/editor/views/EditorSlot.js.map +1 -1
- package/dist/editor/views/ItemEditor.js +7 -3
- 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 +5 -6
- package/dist/editor/views/ParheliaView.js.map +1 -1
- package/dist/editor/views/SingleEditView.d.ts +2 -1
- package/dist/editor/views/SingleEditView.js +10 -8
- package/dist/editor/views/SingleEditView.js.map +1 -1
- package/dist/editor/views/editorSlotContext.js +35 -6
- package/dist/editor/views/editorSlotContext.js.map +1 -1
- package/dist/index.d.ts +16 -2
- package/dist/index.js +11 -0
- 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 +40 -13
- package/dist/setup/services/setupWizardService.js +32 -17
- package/dist/setup/services/setupWizardService.js.map +1 -1
- package/dist/setup/wizard/steps/AddModelDialog.js +12 -3
- package/dist/setup/wizard/steps/AddModelDialog.js.map +1 -1
- package/dist/setup/wizard/steps/ImportModelDialog.js +39 -22
- package/dist/setup/wizard/steps/ImportModelDialog.js.map +1 -1
- package/dist/splash-screen/ModernSplashScreen.js +112 -32
- package/dist/splash-screen/ModernSplashScreen.js.map +1 -1
- package/dist/splash-screen/NewPage.js +33 -50
- package/dist/splash-screen/NewPage.js.map +1 -1
- package/dist/splash-screen/OpenPage.js +2 -6
- package/dist/splash-screen/OpenPage.js.map +1 -1
- package/dist/splash-screen/ParheliaAssistantChat.js +12 -29
- package/dist/splash-screen/ParheliaAssistantChat.js.map +1 -1
- package/dist/splash-screen/ParheliaLogo.js +87 -37
- 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 +2 -1
- package/dist/tour/Tour.js +256 -75
- package/dist/tour/Tour.js.map +1 -1
- package/dist/tour/default-tour.js +222 -96
- package/dist/tour/default-tour.js.map +1 -1
- package/dist/types.d.ts +63 -29
- package/package.json +19 -15
- package/styles.css +39 -10
- package/dist/editor/ComponentInfo.d.ts +0 -4
- package/dist/editor/ComponentInfo.js +0 -41
- package/dist/editor/ComponentInfo.js.map +0 -1
- package/dist/editor/ai/HelpTerminal.d.ts +0 -5
- package/dist/editor/ai/HelpTerminal.js +0 -166
- package/dist/editor/ai/HelpTerminal.js.map +0 -1
- package/dist/editor/field-types/ReactQuill.d.ts +0 -125
- package/dist/editor/field-types/ReactQuill.js +0 -385
- package/dist/editor/field-types/ReactQuill.js.map +0 -1
- package/dist/editor/services-server/graphQL.d.ts +0 -29
- package/dist/editor/services-server/graphQL.js +0 -53
- package/dist/editor/services-server/graphQL.js.map +0 -1
- package/dist/editor/settings/AllAgentsPanel.d.ts +0 -5
- package/dist/editor/settings/AllAgentsPanel.js +0 -139
- package/dist/editor/settings/AllAgentsPanel.js.map +0 -1
- package/dist/editor/settings/LatestFeedback.d.ts +0 -1
- package/dist/editor/settings/LatestFeedback.js +0 -136
- package/dist/editor/settings/LatestFeedback.js.map +0 -1
- package/dist/editor/settings/Setup.d.ts +0 -1
- package/dist/editor/settings/Setup.js +0 -211
- package/dist/editor/settings/Setup.js.map +0 -1
- package/dist/editor/settings/panels/DatabasePanel.d.ts +0 -6
- package/dist/editor/settings/panels/DatabasePanel.js +0 -50
- package/dist/editor/settings/panels/DatabasePanel.js.map +0 -1
- package/dist/editor/settings/setup-steps/AiSetupStep/EmbeddingsModelSection.d.ts +0 -2
- package/dist/editor/settings/setup-steps/AiSetupStep/EmbeddingsModelSection.js +0 -195
- package/dist/editor/settings/setup-steps/AiSetupStep/EmbeddingsModelSection.js.map +0 -1
- package/dist/editor/settings/setup-steps/AiSetupStep/index.d.ts +0 -2
- package/dist/editor/settings/setup-steps/AiSetupStep/index.js +0 -21
- package/dist/editor/settings/setup-steps/AiSetupStep/index.js.map +0 -1
- package/dist/editor/settings/setup-steps/AiSetupStep/provider/ProviderSection.d.ts +0 -1
- package/dist/editor/settings/setup-steps/AiSetupStep/provider/ProviderSection.js +0 -233
- package/dist/editor/settings/setup-steps/AiSetupStep/provider/ProviderSection.js.map +0 -1
- package/dist/editor/settings/setup-steps/AiSetupStep/required-containers/RequiredContainersList.d.ts +0 -15
- package/dist/editor/settings/setup-steps/AiSetupStep/required-containers/RequiredContainersList.js +0 -14
- package/dist/editor/settings/setup-steps/AiSetupStep/required-containers/RequiredContainersList.js.map +0 -1
- package/dist/editor/settings/setup-steps/AiSetupStep/required-containers/RequiredContainersSection.d.ts +0 -1
- package/dist/editor/settings/setup-steps/AiSetupStep/required-containers/RequiredContainersSection.js +0 -94
- package/dist/editor/settings/setup-steps/AiSetupStep/required-containers/RequiredContainersSection.js.map +0 -1
- package/dist/editor/settings/setup-steps/AiSetupStep/types.d.ts +0 -1
- package/dist/editor/settings/setup-steps/AiSetupStep/types.js +0 -2
- package/dist/editor/settings/setup-steps/AiSetupStep/types.js.map +0 -1
- package/dist/editor/settings/setup-steps/AiSetupStep/utils.d.ts +0 -5
- package/dist/editor/settings/setup-steps/AiSetupStep/utils.js +0 -44
- package/dist/editor/settings/setup-steps/AiSetupStep/utils.js.map +0 -1
- package/dist/editor/settings/setup-steps/IndexSetupStep.d.ts +0 -2
- package/dist/editor/settings/setup-steps/IndexSetupStep.js +0 -36
- package/dist/editor/settings/setup-steps/IndexSetupStep.js.map +0 -1
- package/dist/editor/settings/setup-steps/SettingsSetupStep.d.ts +0 -2
- package/dist/editor/settings/setup-steps/SettingsSetupStep.js +0 -111
- package/dist/editor/settings/setup-steps/SettingsSetupStep.js.map +0 -1
- package/dist/editor/settings/setup-steps/SetupOverview.d.ts +0 -14
- package/dist/editor/settings/setup-steps/SetupOverview.js +0 -38
- package/dist/editor/settings/setup-steps/SetupOverview.js.map +0 -1
- package/dist/editor/sidebar/Debug.d.ts +0 -1
- package/dist/editor/sidebar/Debug.js +0 -70
- package/dist/editor/sidebar/Debug.js.map +0 -1
- package/dist/editor/sidebar/GraphQL.d.ts +0 -2
- package/dist/editor/sidebar/GraphQL.js +0 -234
- package/dist/editor/sidebar/GraphQL.js.map +0 -1
- package/dist/editor/sidebar/LeftToolbar.d.ts +0 -1
- package/dist/editor/sidebar/LeftToolbar.js +0 -12
- package/dist/editor/sidebar/LeftToolbar.js.map +0 -1
- package/dist/editor/sidebar/NavigationSidebar.d.ts +0 -4
- package/dist/editor/sidebar/NavigationSidebar.js +0 -254
- package/dist/editor/sidebar/NavigationSidebar.js.map +0 -1
- package/dist/editor/tree-indicators/GutterSelector.d.ts +0 -5
- package/dist/editor/tree-indicators/GutterSelector.js +0 -91
- package/dist/editor/tree-indicators/GutterSelector.js.map +0 -1
|
@@ -1,11 +1,27 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
-
import { useState, useEffect, useCallback, useMemo, useRef, } from "react";
|
|
3
|
-
import { Book, Loader2, Edit, ArrowLeft } from "lucide-react";
|
|
2
|
+
import React, { useState, useEffect, useCallback, useMemo, useRef, } from "react";
|
|
3
|
+
import { Book, BookOpen, Loader2, Edit, ArrowLeft, ArrowRight, ChevronDown, ChevronRight, LocateFixed, Rocket, FileEdit, X, } from "lucide-react";
|
|
4
4
|
import { loadManualToc, loadManualSection, invalidateManualSectionCache, } from "../../services/aiService";
|
|
5
|
-
import {
|
|
5
|
+
import { executeSearch } from "../../services/searchService";
|
|
6
|
+
import { FilterInput } from "../../../components/FilterInput";
|
|
7
|
+
import { MarkdownDisplay, } from "../../../components/MarkdownDisplay";
|
|
6
8
|
import { Tooltip, TooltipTrigger, TooltipContent, } from "../../../components/ui/tooltip";
|
|
7
9
|
import { useEditContext } from "../../client/editContext";
|
|
8
10
|
import { cn } from "../../../lib/utils";
|
|
11
|
+
import { sanitizeSvg } from "../../../lib/sanitize";
|
|
12
|
+
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, } from "../../../components/ui/dropdown-menu";
|
|
13
|
+
/** Render a sanitized SVG string at a specific pixel size. */
|
|
14
|
+
function SvgIcon({ svg, size, className, }) {
|
|
15
|
+
const sanitizedSvg = sanitizeSvg(svg).trim();
|
|
16
|
+
return (_jsx("span", { className: cn("inline-flex items-center justify-center [&>svg]:block [&>svg]:h-full [&>svg]:w-full", className), style: { width: size, height: size }, dangerouslySetInnerHTML: { __html: sanitizedSvg } }));
|
|
17
|
+
}
|
|
18
|
+
const HIGHLIGHT_DURATION_MS = 2000;
|
|
19
|
+
const manualMarkdownComponents = {
|
|
20
|
+
h1: ({ children }) => (_jsx("h1", { className: "mt-4 mb-0 text-xl font-bold text-gray-900", children: children })),
|
|
21
|
+
h2: ({ children }) => (_jsx("h2", { className: "mt-3 mb-0 text-lg font-semibold text-gray-800", children: children })),
|
|
22
|
+
h3: ({ children }) => (_jsx("h3", { className: "mt-2 mb-0 text-base font-semibold text-gray-700", children: children })),
|
|
23
|
+
h4: ({ children }) => (_jsx("h4", { className: "mt-2 mb-0 text-sm font-semibold text-gray-700", children: children })),
|
|
24
|
+
};
|
|
9
25
|
// Parse the uiSelectors field
|
|
10
26
|
// Formats:
|
|
11
27
|
// - @selector-name: Description | Not found message
|
|
@@ -14,7 +30,10 @@ export function parseUiSelectors(uiSelectors) {
|
|
|
14
30
|
const map = new Map();
|
|
15
31
|
if (!uiSelectors)
|
|
16
32
|
return map;
|
|
17
|
-
const lines = uiSelectors
|
|
33
|
+
const lines = uiSelectors
|
|
34
|
+
.split(/\r?\n/)
|
|
35
|
+
.map((line) => line.trim())
|
|
36
|
+
.filter(Boolean);
|
|
18
37
|
for (const line of lines) {
|
|
19
38
|
// Format: @selector-name: ...
|
|
20
39
|
const match = line.match(/^@([\w\-]+):\s*(.+)$/);
|
|
@@ -23,10 +42,34 @@ export function parseUiSelectors(uiSelectors) {
|
|
|
23
42
|
const rest = match[2];
|
|
24
43
|
if (!name || !rest)
|
|
25
44
|
continue;
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
45
|
+
const segments = rest
|
|
46
|
+
.split("|")
|
|
47
|
+
.map((segment) => segment.trim())
|
|
48
|
+
.filter(Boolean);
|
|
49
|
+
const description = segments.shift() ?? "";
|
|
50
|
+
let notFoundMessage;
|
|
51
|
+
let beforeAction;
|
|
52
|
+
let afterAction;
|
|
53
|
+
let availabilitySelector;
|
|
54
|
+
for (const segment of segments) {
|
|
55
|
+
if (segment.startsWith("beforeAction=")) {
|
|
56
|
+
beforeAction = segment.substring("beforeAction=".length).trim();
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
if (segment.startsWith("afterAction=")) {
|
|
60
|
+
afterAction = segment.substring("afterAction=".length).trim();
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
if (segment.startsWith("availabilitySelector=")) {
|
|
64
|
+
availabilitySelector = segment
|
|
65
|
+
.substring("availabilitySelector=".length)
|
|
66
|
+
.trim();
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
if (!notFoundMessage) {
|
|
70
|
+
notFoundMessage = segment;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
30
73
|
// Check if this is a sidebar-only selector (e.g., @reviews-sidebar)
|
|
31
74
|
// These end with -sidebar
|
|
32
75
|
const isSidebarOnly = name.endsWith("-sidebar");
|
|
@@ -37,10 +80,13 @@ export function parseUiSelectors(uiSelectors) {
|
|
|
37
80
|
const parsed = {
|
|
38
81
|
name,
|
|
39
82
|
selector: isSidebarOnly ? "" : `@${name}`, // Empty selector for sidebar-only
|
|
83
|
+
availabilitySelector,
|
|
40
84
|
description,
|
|
41
85
|
notFoundMessage: notFoundMessage || undefined,
|
|
42
86
|
location: isSidebarOnly ? sidebarId : undefined, // Use actual sidebar ID (without -sidebar suffix) for sidebar-only
|
|
43
87
|
isSidebarOnly,
|
|
88
|
+
beforeAction,
|
|
89
|
+
afterAction,
|
|
44
90
|
};
|
|
45
91
|
// Primary key remains the selector name
|
|
46
92
|
map.set(name, parsed);
|
|
@@ -94,59 +140,122 @@ export function expandSelector(selectorShorthand) {
|
|
|
94
140
|
// Default: data-testid selector: @name → [data-testid="name"]
|
|
95
141
|
return `[data-testid="${selector}"]`;
|
|
96
142
|
}
|
|
97
|
-
|
|
98
|
-
export function highlightElement(selector, duration = 2000) {
|
|
143
|
+
function getElementsForSelector(selector) {
|
|
99
144
|
const cssSelector = expandSelector(selector);
|
|
100
|
-
// Handle iframe selectors
|
|
101
145
|
if (cssSelector.startsWith("iframe:")) {
|
|
102
146
|
const iframeSelector = cssSelector.substring(7);
|
|
103
147
|
const iframe = document.querySelector("iframe.page-iframe");
|
|
104
|
-
if (iframe?.contentDocument) {
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
148
|
+
if (!iframe?.contentDocument) {
|
|
149
|
+
return [];
|
|
150
|
+
}
|
|
151
|
+
return Array.from(iframe.contentDocument.querySelectorAll(iframeSelector));
|
|
152
|
+
}
|
|
153
|
+
return Array.from(document.querySelectorAll(cssSelector));
|
|
154
|
+
}
|
|
155
|
+
function shouldSkipHighlightScroll(element) {
|
|
156
|
+
const rect = element.getBoundingClientRect();
|
|
157
|
+
const computedStyle = window.getComputedStyle(element);
|
|
158
|
+
const viewportPadding = 24;
|
|
159
|
+
const isFixedLike = computedStyle.position === "fixed" || computedStyle.position === "sticky";
|
|
160
|
+
const isFullyVisible = rect.top >= viewportPadding &&
|
|
161
|
+
rect.bottom <= window.innerHeight - viewportPadding &&
|
|
162
|
+
rect.left >= 0 &&
|
|
163
|
+
rect.right <= window.innerWidth;
|
|
164
|
+
const isLargeTarget = rect.height >= window.innerHeight * 0.6;
|
|
165
|
+
return isFixedLike || isFullyVisible || isLargeTarget;
|
|
166
|
+
}
|
|
167
|
+
function waitForNextFrame() {
|
|
168
|
+
return new Promise((resolve) => {
|
|
169
|
+
window.requestAnimationFrame(() => resolve());
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
async function waitForScrollToFinish(element) {
|
|
173
|
+
let stableFrames = 0;
|
|
174
|
+
let previousRect = element.getBoundingClientRect();
|
|
175
|
+
for (let frame = 0; frame < 30; frame++) {
|
|
176
|
+
await waitForNextFrame();
|
|
177
|
+
const currentRect = element.getBoundingClientRect();
|
|
178
|
+
const moved = Math.abs(currentRect.top - previousRect.top) > 0.5 ||
|
|
179
|
+
Math.abs(currentRect.left - previousRect.left) > 0.5;
|
|
180
|
+
if (moved) {
|
|
181
|
+
stableFrames = 0;
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
stableFrames += 1;
|
|
185
|
+
if (stableFrames >= 2) {
|
|
186
|
+
return;
|
|
114
187
|
}
|
|
115
188
|
}
|
|
189
|
+
previousRect = currentRect;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
async function scrollElementForHighlight(element) {
|
|
193
|
+
if (shouldSkipHighlightScroll(element)) {
|
|
116
194
|
return;
|
|
117
195
|
}
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
196
|
+
element.scrollIntoView({
|
|
197
|
+
behavior: "smooth",
|
|
198
|
+
block: "nearest",
|
|
199
|
+
inline: "nearest",
|
|
200
|
+
});
|
|
201
|
+
await waitForScrollToFinish(element);
|
|
202
|
+
}
|
|
203
|
+
// Highlight an element temporarily
|
|
204
|
+
export async function highlightElement(selector, duration = HIGHLIGHT_DURATION_MS) {
|
|
205
|
+
const cssSelector = expandSelector(selector);
|
|
206
|
+
const elements = getElementsForSelector(selector);
|
|
207
|
+
if (elements.length === 0)
|
|
208
|
+
return;
|
|
209
|
+
if (cssSelector.startsWith("iframe:")) {
|
|
210
|
+
const iframe = document.querySelector("iframe.page-iframe");
|
|
211
|
+
const iframeRect = iframe?.getBoundingClientRect();
|
|
212
|
+
if (elements[0]) {
|
|
213
|
+
await scrollElementForHighlight(elements[0]);
|
|
214
|
+
}
|
|
121
215
|
elements.forEach((element) => {
|
|
122
|
-
const
|
|
123
|
-
showHighlightOverlay(
|
|
216
|
+
const elementRect = element.getBoundingClientRect();
|
|
217
|
+
showHighlightOverlay(elementRect.left + (iframeRect?.left ?? 0), elementRect.top + (iframeRect?.top ?? 0), elementRect.width, elementRect.height, duration);
|
|
124
218
|
});
|
|
125
|
-
|
|
126
|
-
elements[0]?.scrollIntoView({ behavior: "smooth", block: "center" });
|
|
219
|
+
return;
|
|
127
220
|
}
|
|
221
|
+
if (elements[0]) {
|
|
222
|
+
await scrollElementForHighlight(elements[0]);
|
|
223
|
+
}
|
|
224
|
+
elements.forEach((element) => {
|
|
225
|
+
const rect = element.getBoundingClientRect();
|
|
226
|
+
showHighlightOverlay(rect.left, rect.top, rect.width, rect.height, duration);
|
|
227
|
+
});
|
|
128
228
|
}
|
|
129
229
|
// Check if an element is currently available in the DOM
|
|
130
230
|
function isElementAvailable(selector) {
|
|
131
|
-
|
|
132
|
-
if (cssSelector.startsWith("iframe:")) {
|
|
133
|
-
const iframeSelector = cssSelector.substring(7);
|
|
134
|
-
const iframe = document.querySelector("iframe.page-iframe");
|
|
135
|
-
return !!iframe?.contentDocument?.querySelector(iframeSelector);
|
|
136
|
-
}
|
|
137
|
-
return !!document.querySelector(cssSelector);
|
|
231
|
+
return getElementsForSelector(selector).length > 0;
|
|
138
232
|
}
|
|
139
233
|
// Create a temporary highlight overlay
|
|
140
234
|
function showHighlightOverlay(x, y, width, height, duration) {
|
|
141
235
|
const padding = 4;
|
|
236
|
+
const viewportWidth = window.innerWidth;
|
|
237
|
+
const viewportHeight = window.innerHeight;
|
|
238
|
+
const rawLeft = x - padding;
|
|
239
|
+
const rawTop = y - padding;
|
|
240
|
+
const rawRight = x + width + padding;
|
|
241
|
+
const rawBottom = y + height + padding;
|
|
242
|
+
const left = Math.max(0, Math.min(rawLeft, viewportWidth));
|
|
243
|
+
const top = Math.max(0, Math.min(rawTop, viewportHeight));
|
|
244
|
+
const right = Math.max(0, Math.min(rawRight, viewportWidth));
|
|
245
|
+
const bottom = Math.max(0, Math.min(rawBottom, viewportHeight));
|
|
246
|
+
const clampedWidth = right - left;
|
|
247
|
+
const clampedHeight = bottom - top;
|
|
248
|
+
// Skip if target is fully outside the viewport after clamping.
|
|
249
|
+
if (clampedWidth <= 0 || clampedHeight <= 0)
|
|
250
|
+
return;
|
|
142
251
|
const overlay = document.createElement("div");
|
|
143
252
|
overlay.className = "selector-highlight-overlay";
|
|
144
253
|
overlay.style.cssText = `
|
|
145
254
|
position: fixed;
|
|
146
|
-
left: ${
|
|
147
|
-
top: ${
|
|
148
|
-
width: ${
|
|
149
|
-
height: ${
|
|
255
|
+
left: ${left}px;
|
|
256
|
+
top: ${top}px;
|
|
257
|
+
width: ${clampedWidth}px;
|
|
258
|
+
height: ${clampedHeight}px;
|
|
150
259
|
border: 2px solid #3b82f6;
|
|
151
260
|
border-radius: 4px;
|
|
152
261
|
background: rgba(59, 130, 246, 0.1);
|
|
@@ -175,6 +284,8 @@ function showHighlightOverlay(x, y, width, height, duration) {
|
|
|
175
284
|
// Button component for "Show me" functionality with availability detection
|
|
176
285
|
function SelectorButton({ selectorDef, keyProp, }) {
|
|
177
286
|
const editContext = useEditContext();
|
|
287
|
+
const manualActions = editContext?.configuration.editor.manualActions;
|
|
288
|
+
const availabilitySelector = selectorDef.availabilitySelector || selectorDef.selector;
|
|
178
289
|
// For sidebar-only selectors, we don't need to check for an element
|
|
179
290
|
const isSidebarOnly = selectorDef.isSidebarOnly;
|
|
180
291
|
// Initialize to true for sidebar-only, false otherwise to avoid hydration mismatch
|
|
@@ -182,9 +293,12 @@ function SelectorButton({ selectorDef, keyProp, }) {
|
|
|
182
293
|
const [isAvailable, setIsAvailable] = useState(isSidebarOnly ? true : false);
|
|
183
294
|
// Can open sidebar if: sidebar-only selector
|
|
184
295
|
const canAutoOpenSidebar = Boolean(isSidebarOnly && editContext?.openSidebar && selectorDef.location);
|
|
296
|
+
const hasBeforeAction = Boolean(selectorDef.beforeAction &&
|
|
297
|
+
manualActions?.[selectorDef.beforeAction] &&
|
|
298
|
+
editContext);
|
|
185
299
|
const isActionable = isSidebarOnly
|
|
186
|
-
? canAutoOpenSidebar
|
|
187
|
-
: isAvailable || canAutoOpenSidebar;
|
|
300
|
+
? canAutoOpenSidebar || hasBeforeAction
|
|
301
|
+
: isAvailable || canAutoOpenSidebar || hasBeforeAction;
|
|
188
302
|
// Monitor for element availability changes (skip for sidebar-only selectors)
|
|
189
303
|
useEffect(() => {
|
|
190
304
|
// Sidebar-only selectors are always "available" if openSidebar exists
|
|
@@ -193,10 +307,11 @@ function SelectorButton({ selectorDef, keyProp, }) {
|
|
|
193
307
|
return;
|
|
194
308
|
}
|
|
195
309
|
// Initial check
|
|
196
|
-
|
|
310
|
+
const initialAvailable = isElementAvailable(availabilitySelector);
|
|
311
|
+
setIsAvailable(initialAvailable);
|
|
197
312
|
// Set up MutationObserver to watch for DOM changes
|
|
198
313
|
const checkAvailability = () => {
|
|
199
|
-
const available = isElementAvailable(
|
|
314
|
+
const available = isElementAvailable(availabilitySelector);
|
|
200
315
|
setIsAvailable(available);
|
|
201
316
|
};
|
|
202
317
|
// Watch the main document for changes
|
|
@@ -226,13 +341,31 @@ function SelectorButton({ selectorDef, keyProp, }) {
|
|
|
226
341
|
iframeObserver?.disconnect();
|
|
227
342
|
clearInterval(intervalId);
|
|
228
343
|
};
|
|
229
|
-
}, [
|
|
230
|
-
const tooltipText =
|
|
344
|
+
}, [availabilitySelector, isSidebarOnly]);
|
|
345
|
+
const tooltipText = isActionable
|
|
231
346
|
? selectorDef.description
|
|
232
347
|
: selectorDef.notFoundMessage || selectorDef.description;
|
|
233
|
-
return (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children:
|
|
348
|
+
return (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsxs("button", { "aria-label": "Show me", onClick: async () => {
|
|
234
349
|
if (!isActionable)
|
|
235
350
|
return;
|
|
351
|
+
const runId = globalThis.crypto?.randomUUID?.() ??
|
|
352
|
+
`manual-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
353
|
+
const resolveElements = (selector = selectorDef.selector) => selector ? getElementsForSelector(selector) : [];
|
|
354
|
+
const runManualAction = async (actionName, elements) => {
|
|
355
|
+
if (!actionName || !editContext || !manualActions?.[actionName]) {
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
358
|
+
const action = manualActions[actionName];
|
|
359
|
+
const actionProps = {
|
|
360
|
+
editContext,
|
|
361
|
+
selectorDef,
|
|
362
|
+
duration: HIGHLIGHT_DURATION_MS,
|
|
363
|
+
runId,
|
|
364
|
+
elements,
|
|
365
|
+
resolveElements,
|
|
366
|
+
};
|
|
367
|
+
await action(actionProps);
|
|
368
|
+
};
|
|
236
369
|
// If this selector is sidebar-only, open the sidebar before highlighting.
|
|
237
370
|
// For sidebar-only selectors, location is the sidebar ID (without -sidebar suffix)
|
|
238
371
|
if (selectorDef.isSidebarOnly &&
|
|
@@ -246,164 +379,68 @@ function SelectorButton({ selectorDef, keyProp, }) {
|
|
|
246
379
|
await new Promise((resolve) => setTimeout(resolve, 150));
|
|
247
380
|
}
|
|
248
381
|
}
|
|
382
|
+
const resolvedElements = !isSidebarOnly ? resolveElements() : [];
|
|
383
|
+
await runManualAction(selectorDef.beforeAction, resolvedElements);
|
|
249
384
|
// For sidebar-only selectors, we just open the sidebar (done above)
|
|
250
385
|
// For regular selectors, also highlight the element
|
|
251
386
|
if (!isSidebarOnly && selectorDef.selector) {
|
|
252
|
-
highlightElement(selectorDef.selector);
|
|
387
|
+
await highlightElement(selectorDef.selector, HIGHLIGHT_DURATION_MS);
|
|
388
|
+
}
|
|
389
|
+
if (selectorDef.afterAction) {
|
|
390
|
+
window.setTimeout(() => {
|
|
391
|
+
void runManualAction(selectorDef.afterAction, !isSidebarOnly ? resolveElements() : []);
|
|
392
|
+
}, HIGHLIGHT_DURATION_MS);
|
|
253
393
|
}
|
|
254
|
-
}, disabled: !isActionable, className: cn("inline-flex
|
|
394
|
+
}, disabled: !isActionable, className: cn("inline-flex h-5 w-5 items-center justify-center rounded border transition-colors", isActionable
|
|
255
395
|
? "cursor-pointer border-blue-200 bg-blue-50 text-blue-700 hover:bg-blue-100"
|
|
256
|
-
: "cursor-not-allowed border-gray-200 bg-gray-100 text-gray-400"), children: "Show me" }, keyProp) }), _jsx(TooltipContent, { children: tooltipText })] }));
|
|
257
|
-
}
|
|
258
|
-
// Check if a line is a markdown table row (starts and ends with |)
|
|
259
|
-
function isTableRow(line) {
|
|
260
|
-
const trimmed = line.trim();
|
|
261
|
-
return trimmed.startsWith("|") && trimmed.endsWith("|");
|
|
262
|
-
}
|
|
263
|
-
// Check if a line is a table separator row (contains only |, -, :, and spaces)
|
|
264
|
-
function isTableSeparator(line) {
|
|
265
|
-
const trimmed = line.trim();
|
|
266
|
-
return isTableRow(line) && /^\|[\s\-:|]+\|$/.test(trimmed);
|
|
267
|
-
}
|
|
268
|
-
// Parse table cells from a row, handling the | delimiters
|
|
269
|
-
function parseTableCells(line) {
|
|
270
|
-
const trimmed = line.trim();
|
|
271
|
-
// Remove leading and trailing |, then split by |
|
|
272
|
-
const inner = trimmed.slice(1, -1);
|
|
273
|
-
return inner.split("|").map((cell) => cell.trim());
|
|
274
|
-
}
|
|
275
|
-
// Parse column alignments from separator row
|
|
276
|
-
function parseTableAlignments(separatorLine) {
|
|
277
|
-
const cells = parseTableCells(separatorLine);
|
|
278
|
-
return cells.map((cell) => {
|
|
279
|
-
const trimmed = cell.trim();
|
|
280
|
-
const startsWithColon = trimmed.startsWith(":");
|
|
281
|
-
const endsWithColon = trimmed.endsWith(":");
|
|
282
|
-
if (startsWithColon && endsWithColon)
|
|
283
|
-
return "center";
|
|
284
|
-
if (endsWithColon)
|
|
285
|
-
return "right";
|
|
286
|
-
return "left";
|
|
287
|
-
});
|
|
288
|
-
}
|
|
289
|
-
// Render a markdown table
|
|
290
|
-
function renderTable(headerCells, alignments, bodyRows, uiSelectors, keyPrefix) {
|
|
291
|
-
const alignClasses = {
|
|
292
|
-
left: "text-left",
|
|
293
|
-
center: "text-center",
|
|
294
|
-
right: "text-right",
|
|
295
|
-
};
|
|
296
|
-
return (_jsx("div", { className: "my-3 overflow-x-auto", children: _jsxs("table", { className: "min-w-full border-collapse rounded-md border border-gray-200 text-sm", children: [_jsx("thead", { className: "bg-gray-50", children: _jsx("tr", { children: headerCells.map((cell, cellIndex) => (_jsx("th", { className: cn("border border-gray-200 px-3 py-2 font-semibold text-gray-700", alignClasses[alignments[cellIndex] || "left"]), children: renderLineWithSelectors(cell, uiSelectors) }, cellIndex))) }) }), _jsx("tbody", { children: bodyRows.map((row, rowIndex) => (_jsx("tr", { className: rowIndex % 2 === 0 ? "bg-white" : "bg-gray-50", children: row.map((cell, cellIndex) => (_jsx("td", { className: cn("border border-gray-200 px-3 py-2 text-gray-600", alignClasses[alignments[cellIndex] || "left"]), children: renderLineWithSelectors(cell, uiSelectors) }, cellIndex))) }, rowIndex))) })] }) }, keyPrefix));
|
|
396
|
+
: "cursor-not-allowed border-gray-200 bg-gray-100 text-gray-400"), children: [_jsx(LocateFixed, { className: "h-3.5 w-3.5", strokeWidth: 1.5 }), _jsx("span", { className: "sr-only", children: "Show me" })] }, keyProp) }), _jsx(TooltipContent, { children: tooltipText })] }));
|
|
297
397
|
}
|
|
298
398
|
// Render markdown content with clickable selectors
|
|
299
399
|
// Supports both {{selectorName}} syntax (looks up in uiSelectors) and legacy @selector syntax
|
|
300
|
-
function renderMarkdownWithSelectors(content, uiSelectors) {
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
// Collect body rows
|
|
321
|
-
while (tableLineIndex < lines.length &&
|
|
322
|
-
isTableRow(lines[tableLineIndex] || "") &&
|
|
323
|
-
!isTableSeparator(lines[tableLineIndex] || "")) {
|
|
324
|
-
bodyRows.push(parseTableCells(lines[tableLineIndex] || ""));
|
|
325
|
-
tableLineIndex++;
|
|
326
|
-
}
|
|
327
|
-
elements.push(renderTable(headerCells, alignments, bodyRows, uiSelectors, lineIndex));
|
|
328
|
-
lineIndex = tableLineIndex;
|
|
329
|
-
continue;
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
// Handle headings
|
|
333
|
-
if (line.startsWith("# ")) {
|
|
334
|
-
elements.push(_jsx("h1", { className: "mt-4 mb-2 text-xl font-bold text-gray-900", children: renderLineWithSelectors(line.substring(2), uiSelectors) }, lineIndex));
|
|
335
|
-
lineIndex++;
|
|
336
|
-
continue;
|
|
337
|
-
}
|
|
338
|
-
if (line.startsWith("## ")) {
|
|
339
|
-
elements.push(_jsx("h2", { className: "mt-3 mb-2 text-lg font-semibold text-gray-800", children: renderLineWithSelectors(line.substring(3), uiSelectors) }, lineIndex));
|
|
340
|
-
lineIndex++;
|
|
341
|
-
continue;
|
|
342
|
-
}
|
|
343
|
-
if (line.startsWith("### ")) {
|
|
344
|
-
elements.push(_jsx("h3", { className: "mt-2 mb-1 text-base font-semibold text-gray-700", children: renderLineWithSelectors(line.substring(4), uiSelectors) }, lineIndex));
|
|
345
|
-
lineIndex++;
|
|
346
|
-
continue;
|
|
347
|
-
}
|
|
348
|
-
// Handle unordered list items - collect consecutive items and wrap in <ul>
|
|
349
|
-
if (line.match(/^[-*] /)) {
|
|
350
|
-
const listItems = [];
|
|
351
|
-
const startIndex = lineIndex;
|
|
352
|
-
while (lineIndex < lines.length &&
|
|
353
|
-
(lines[lineIndex] || "").match(/^[-*] /)) {
|
|
354
|
-
const itemLine = lines[lineIndex] || "";
|
|
355
|
-
listItems.push(_jsx("li", { className: "text-sm text-gray-600", children: renderLineWithSelectors(itemLine.substring(2), uiSelectors) }, lineIndex));
|
|
356
|
-
lineIndex++;
|
|
357
|
-
}
|
|
358
|
-
elements.push(_jsx("ul", { className: "my-2 ml-6 space-y-1", style: { listStyleType: "disc", paddingLeft: "1rem" }, children: listItems }, `ul-${startIndex}`));
|
|
359
|
-
continue;
|
|
360
|
-
}
|
|
361
|
-
// Handle ordered list items - collect consecutive items and wrap in <ol>
|
|
362
|
-
if (line.match(/^\d+\.\s/)) {
|
|
363
|
-
const listItems = [];
|
|
364
|
-
const startIndex = lineIndex;
|
|
365
|
-
while (lineIndex < lines.length &&
|
|
366
|
-
(lines[lineIndex] || "").match(/^\d+\.\s/)) {
|
|
367
|
-
const itemLine = lines[lineIndex] || "";
|
|
368
|
-
// Extract content after "N. " - use substring to get everything after the number and dot
|
|
369
|
-
const dotIndex = itemLine.indexOf(".");
|
|
370
|
-
const itemContent = dotIndex >= 0
|
|
371
|
-
? itemLine.substring(dotIndex + 1).trimStart()
|
|
372
|
-
: itemLine;
|
|
373
|
-
listItems.push(_jsx("li", { className: "text-sm text-gray-600", children: renderLineWithSelectors(itemContent, uiSelectors) }, lineIndex));
|
|
374
|
-
lineIndex++;
|
|
375
|
-
}
|
|
376
|
-
elements.push(_jsx("ol", { className: "my-2 ml-6 space-y-1", style: { listStyleType: "decimal", paddingLeft: "1rem" }, children: listItems }, `ol-${startIndex}`));
|
|
377
|
-
continue;
|
|
378
|
-
}
|
|
379
|
-
// Handle horizontal rules (---, ***, ___)
|
|
380
|
-
if (line.match(/^[-*_]{3,}\s*$/)) {
|
|
381
|
-
elements.push(_jsx("hr", { className: "my-4 border-t border-gray-200" }, lineIndex));
|
|
382
|
-
lineIndex++;
|
|
383
|
-
continue;
|
|
400
|
+
function renderMarkdownWithSelectors(content, uiSelectors, manualLinkTargets, onManualLinkClick) {
|
|
401
|
+
return (_jsx(MarkdownDisplay, { source: content, className: "space-y-0", components: manualMarkdownComponents, renderInline: (line) => renderLineWithSelectors(line, uiSelectors, manualLinkTargets, onManualLinkClick) }));
|
|
402
|
+
}
|
|
403
|
+
// Render a line with clickable selectors and basic formatting
|
|
404
|
+
// Supports: {{selectorName}} for named selectors, @selector for legacy direct selectors, **bold** text
|
|
405
|
+
// Parentheses around selectors (e.g., ({{name}})) are automatically hidden
|
|
406
|
+
function renderLineWithSelectors(text, uiSelectors, manualLinkTargets, onManualLinkClick) {
|
|
407
|
+
if (!manualLinkTargets || !onManualLinkClick) {
|
|
408
|
+
return renderInlineSelectorsAndFormatting(text, uiSelectors);
|
|
409
|
+
}
|
|
410
|
+
const parts = [];
|
|
411
|
+
const linkRegex = /\[\[([^\]]+)\]\]/g;
|
|
412
|
+
let lastIndex = 0;
|
|
413
|
+
let match;
|
|
414
|
+
while ((match = linkRegex.exec(text)) !== null) {
|
|
415
|
+
const fullMatch = match[0] || "";
|
|
416
|
+
const linkTitle = (match[1] || "").trim();
|
|
417
|
+
if (match.index > lastIndex) {
|
|
418
|
+
const prefix = text.substring(lastIndex, match.index);
|
|
419
|
+
parts.push(_jsx(React.Fragment, { children: renderInlineSelectorsAndFormatting(prefix, uiSelectors) }, `text-${match.index}`));
|
|
384
420
|
}
|
|
385
|
-
|
|
386
|
-
if (
|
|
387
|
-
|
|
421
|
+
const targetId = manualLinkTargets.get(linkTitle.toLowerCase());
|
|
422
|
+
if (targetId) {
|
|
423
|
+
parts.push(_jsx("button", { type: "button", onClick: () => onManualLinkClick(targetId), className: "cursor-pointer text-blue-600 underline decoration-blue-300 underline-offset-2 hover:text-blue-700", title: `Open "${linkTitle}"`, children: linkTitle }, `manual-link-${match.index}`));
|
|
388
424
|
}
|
|
389
425
|
else {
|
|
390
|
-
|
|
426
|
+
parts.push(_jsx("span", { className: "text-orange-600", title: `Manual section not found: ${linkTitle}`, children: fullMatch }, `manual-link-missing-${match.index}`));
|
|
391
427
|
}
|
|
392
|
-
|
|
428
|
+
lastIndex = match.index + fullMatch.length;
|
|
429
|
+
}
|
|
430
|
+
if (lastIndex < text.length) {
|
|
431
|
+
const suffix = text.substring(lastIndex);
|
|
432
|
+
parts.push(_jsx(React.Fragment, { children: renderInlineSelectorsAndFormatting(suffix, uiSelectors) }, `suffix-${lastIndex}`));
|
|
393
433
|
}
|
|
394
|
-
return _jsx(
|
|
434
|
+
return _jsx(_Fragment, { children: parts });
|
|
395
435
|
}
|
|
396
|
-
|
|
397
|
-
// Supports: {{selectorName}} for named selectors, @selector for legacy direct selectors, **bold** text
|
|
398
|
-
// Parentheses around selectors (e.g., ({{name}})) are automatically hidden
|
|
399
|
-
function renderLineWithSelectors(text, uiSelectors) {
|
|
436
|
+
function renderInlineSelectorsAndFormatting(text, uiSelectors) {
|
|
400
437
|
const parts = [];
|
|
401
438
|
let lastIndex = 0;
|
|
402
439
|
// Combined regex for {{namedSelector}}, @selector, and **bold**
|
|
403
440
|
// Note: @selector can include -sidebar suffix for sidebar-only selectors
|
|
404
441
|
// Also supports @iframe:selector syntax (iframe: is special and allowed)
|
|
405
442
|
// Now also matches optional parentheses around selectors: ({{name}}) or (@selector)
|
|
406
|
-
const regex = /(\()?(\{\{([\w\-]+)\}\})|(\()?(@(?:iframe:[\w\-\.#\[\]=]
|
|
443
|
+
const regex = /(\()?(\{\{([\w\-]+)\}\})|(\()?(@(?:iframe:[\w\-\.#\[\]=]*[\w\-#\[\]=]|[\w\-\.#\[\]=]*[\w\-#\[\]=]))|(\*\*(.+?)\*\*)/g;
|
|
407
444
|
let match;
|
|
408
445
|
while ((match = regex.exec(text)) !== null) {
|
|
409
446
|
// Check if there's an opening parenthesis before the selector
|
|
@@ -440,7 +477,9 @@ function renderLineWithSelectors(text, uiSelectors) {
|
|
|
440
477
|
// @selector match (legacy direct selector syntax) - create ad-hoc selector def
|
|
441
478
|
const selectorToken = match[5];
|
|
442
479
|
const parsed = parseSelectorToken(selectorToken);
|
|
443
|
-
const
|
|
480
|
+
const selectorName = selectorToken.replace(/^@/, "");
|
|
481
|
+
const registeredSelectorDef = uiSelectors.get(selectorName);
|
|
482
|
+
const effectiveSelectorDef = registeredSelectorDef ?? {
|
|
444
483
|
name: selectorToken,
|
|
445
484
|
selector: parsed.selector,
|
|
446
485
|
description: parsed.isSidebarOnly
|
|
@@ -452,7 +491,7 @@ function renderLineWithSelectors(text, uiSelectors) {
|
|
|
452
491
|
// Check if there's a closing paren after this selector
|
|
453
492
|
const afterMatch = match.index + match[0].length;
|
|
454
493
|
const hasCloseParen = text[afterMatch] === ")";
|
|
455
|
-
parts.push(_jsx(SelectorButton, { selectorDef:
|
|
494
|
+
parts.push(_jsx(SelectorButton, { selectorDef: effectiveSelectorDef, keyProp: match.index }, match.index));
|
|
456
495
|
// Skip the closing paren if present
|
|
457
496
|
if (hasCloseParen && hasOpenParen) {
|
|
458
497
|
lastIndex = afterMatch + 1;
|
|
@@ -472,21 +511,6 @@ function renderLineWithSelectors(text, uiSelectors) {
|
|
|
472
511
|
}
|
|
473
512
|
return _jsx(_Fragment, { children: parts });
|
|
474
513
|
}
|
|
475
|
-
// Flatten TOC tree into options with indentation for hierarchy
|
|
476
|
-
function flattenTocToOptions(sections, depth = 0) {
|
|
477
|
-
const options = [];
|
|
478
|
-
for (const section of sections) {
|
|
479
|
-
const indent = "\u00A0\u00A0".repeat(depth); // Non-breaking spaces for indentation
|
|
480
|
-
options.push({
|
|
481
|
-
value: section.id,
|
|
482
|
-
label: `${indent}${section.title || "Untitled"}`,
|
|
483
|
-
});
|
|
484
|
-
if (section.children && section.children.length > 0) {
|
|
485
|
-
options.push(...flattenTocToOptions(section.children, depth + 1));
|
|
486
|
-
}
|
|
487
|
-
}
|
|
488
|
-
return options;
|
|
489
|
-
}
|
|
490
514
|
function findTocPath(sections, targetId, ancestors = []) {
|
|
491
515
|
for (const section of sections) {
|
|
492
516
|
const nextAncestors = [...ancestors, section];
|
|
@@ -500,36 +524,278 @@ function findTocPath(sections, targetId, ancestors = []) {
|
|
|
500
524
|
}
|
|
501
525
|
return null;
|
|
502
526
|
}
|
|
503
|
-
|
|
527
|
+
function isDirectlyNavigableSection(section) {
|
|
528
|
+
return !!section.hasContent || section.children.length === 0;
|
|
529
|
+
}
|
|
530
|
+
function resolveFirstNavigableSection(section) {
|
|
531
|
+
if (isDirectlyNavigableSection(section) || section.children.length === 0) {
|
|
532
|
+
return section;
|
|
533
|
+
}
|
|
534
|
+
return resolveFirstNavigableSection(section.children[0]);
|
|
535
|
+
}
|
|
536
|
+
function resolveSelectedSectionId(sections, targetId) {
|
|
537
|
+
const path = findTocPath(sections, targetId);
|
|
538
|
+
const targetSection = path?.[path.length - 1];
|
|
539
|
+
if (!targetSection)
|
|
540
|
+
return targetId;
|
|
541
|
+
return resolveFirstNavigableSection(targetSection).id;
|
|
542
|
+
}
|
|
543
|
+
function findNearestNavigableAncestor(path) {
|
|
544
|
+
if (!path || path.length < 2)
|
|
545
|
+
return null;
|
|
546
|
+
for (let i = path.length - 2; i >= 0; i -= 1) {
|
|
547
|
+
const section = path[i];
|
|
548
|
+
if (section && isDirectlyNavigableSection(section)) {
|
|
549
|
+
return section;
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
return null;
|
|
553
|
+
}
|
|
554
|
+
const SECTION_THEMES = {
|
|
555
|
+
"getting started": {
|
|
556
|
+
icon: Rocket,
|
|
557
|
+
color: "text-emerald-600",
|
|
558
|
+
bg: "bg-emerald-50",
|
|
559
|
+
border: "border-emerald-100",
|
|
560
|
+
accent: "bg-emerald-500",
|
|
561
|
+
},
|
|
562
|
+
"page editing": {
|
|
563
|
+
icon: FileEdit,
|
|
564
|
+
color: "text-blue-600",
|
|
565
|
+
bg: "bg-blue-50",
|
|
566
|
+
border: "border-blue-100",
|
|
567
|
+
accent: "bg-blue-500",
|
|
568
|
+
},
|
|
569
|
+
"managing content": {
|
|
570
|
+
icon: BookOpen,
|
|
571
|
+
color: "text-amber-600",
|
|
572
|
+
bg: "bg-amber-50",
|
|
573
|
+
border: "border-amber-100",
|
|
574
|
+
accent: "bg-amber-500",
|
|
575
|
+
},
|
|
576
|
+
"ai assistant": {
|
|
577
|
+
icon: BookOpen,
|
|
578
|
+
color: "text-violet-600",
|
|
579
|
+
bg: "bg-violet-50",
|
|
580
|
+
border: "border-violet-100",
|
|
581
|
+
accent: "bg-violet-500",
|
|
582
|
+
},
|
|
583
|
+
};
|
|
584
|
+
const DEFAULT_THEME = {
|
|
585
|
+
icon: BookOpen,
|
|
586
|
+
color: "text-violet-600",
|
|
587
|
+
bg: "bg-violet-50",
|
|
588
|
+
border: "border-violet-100",
|
|
589
|
+
accent: "bg-violet-500",
|
|
590
|
+
};
|
|
591
|
+
function getSectionTheme(title) {
|
|
592
|
+
if (!title)
|
|
593
|
+
return DEFAULT_THEME;
|
|
594
|
+
return SECTION_THEMES[title.toLowerCase()] ?? DEFAULT_THEME;
|
|
595
|
+
}
|
|
596
|
+
function TocSectionCard({ section, onSelect, onToggleCollapse, isCollapsed, }) {
|
|
597
|
+
const theme = getSectionTheme(section.title);
|
|
598
|
+
const Icon = theme.icon;
|
|
599
|
+
const hasChildren = !!(section.children && section.children.length > 0);
|
|
600
|
+
return (_jsxs("div", { className: "group", children: [_jsx("button", { type: "button", onClick: () => onSelect(section.id), className: cn("w-full rounded-lg p-3 text-left transition-all", "bg-white hover:bg-gray-50/50"), children: _jsxs("div", { className: "flex items-start gap-3", children: [_jsx("div", { className: cn("flex h-9 w-9 shrink-0 items-center justify-center rounded-lg", theme.bg), children: section.svgIcon ? (_jsx(SvgIcon, { svg: section.svgIcon, size: 24, className: theme.color })) : (_jsx(Icon, { className: cn("h-[18px] w-[18px]", theme.color), strokeWidth: 1.75 })) }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("div", { className: "flex items-center gap-2", children: _jsx("span", { className: "text-sm font-semibold text-gray-900", children: section.title || "Untitled" }) }), section.summary && (_jsx("p", { className: "mt-0.5 line-clamp-2 text-xs leading-relaxed text-gray-500", children: section.summary }))] })] }) }), hasChildren && (_jsxs("div", { className: "mt-1", children: [_jsxs("button", { type: "button", onClick: () => onToggleCollapse(section.id), className: "ml-[60px] flex w-fit items-center gap-1.5 rounded-md py-1 text-xs text-gray-400 transition-colors hover:text-gray-600", children: [_jsx(ChevronRight, { className: cn("h-3 w-3 shrink-0 transition-transform", !isCollapsed && "rotate-90") }), _jsx("span", { children: isCollapsed ? "Show articles" : "Hide articles" })] }), !isCollapsed && (_jsx("div", { className: "mt-0.5 ml-[60px] space-y-px border-l-2 border-gray-100 pl-3", children: section.children.map((child) => (_jsxs("button", { type: "button", onClick: () => onSelect(child.id), className: "flex w-full items-center gap-2 rounded-md px-2 py-1.5 text-left text-sm text-gray-600 transition-colors hover:bg-gray-50 hover:text-gray-900", children: [_jsx("span", { className: cn("h-1.5 w-1.5 shrink-0 rounded-full", theme.accent, "opacity-40 transition-opacity group-hover:opacity-70") }), _jsx("span", { className: "truncate", children: child.title || "Untitled" })] }, child.id))) }))] }))] }));
|
|
601
|
+
}
|
|
602
|
+
function renderTocTree(sections, onSelect, onToggleCollapse, collapsedSectionIds, depth = 0) {
|
|
603
|
+
if (depth === 0) {
|
|
604
|
+
return (_jsx("div", { className: "space-y-3", children: sections.map((section) => {
|
|
605
|
+
const isCollapsed = collapsedSectionIds.has(section.id);
|
|
606
|
+
return (_jsx(TocSectionCard, { section: section, onSelect: onSelect, onToggleCollapse: onToggleCollapse, isCollapsed: isCollapsed }, section.id));
|
|
607
|
+
}) }));
|
|
608
|
+
}
|
|
609
|
+
return (_jsx("div", { className: cn(depth > 0 && "ml-3 border-l border-gray-100 pl-2"), children: sections.map((section) => {
|
|
610
|
+
const hasChildren = !!(section.children && section.children.length > 0);
|
|
611
|
+
const isCollapsed = hasChildren && collapsedSectionIds.has(section.id);
|
|
612
|
+
return (_jsxs("div", { className: "my-0.5", children: [_jsxs("div", { className: cn("group flex w-full items-center gap-1.5 rounded-md px-2 py-1.5 transition-colors hover:bg-gray-50", "text-sm text-gray-500 hover:text-gray-700"), children: [hasChildren ? (_jsx("button", { type: "button", onClick: () => onToggleCollapse(section.id), className: "rounded p-0.5 text-gray-300 transition-colors hover:bg-gray-100 hover:text-gray-500", "aria-label": isCollapsed
|
|
613
|
+
? `Expand ${section.title || "section"}`
|
|
614
|
+
: `Collapse ${section.title || "section"}`, title: isCollapsed ? "Expand section" : "Collapse section", children: _jsx(ChevronRight, { className: cn("h-3.5 w-3.5 shrink-0 transition-transform", !isCollapsed && "rotate-90") }) })) : (_jsx("span", { className: "h-3.5 w-3.5 shrink-0" })), _jsx("button", { type: "button", onClick: () => onSelect(section.id), className: "flex-1 text-left", children: section.title || "Untitled" })] }), hasChildren &&
|
|
615
|
+
!isCollapsed &&
|
|
616
|
+
renderTocTree(section.children, onSelect, onToggleCollapse, collapsedSectionIds, depth + 1)] }, section.id));
|
|
617
|
+
}) }));
|
|
618
|
+
}
|
|
619
|
+
function buildChapterOptions(chapter) {
|
|
620
|
+
const result = [];
|
|
621
|
+
const walk = (sections, depth) => {
|
|
622
|
+
for (const section of sections) {
|
|
623
|
+
result.push({ section, depth });
|
|
624
|
+
if (section.children.length > 0) {
|
|
625
|
+
walk(section.children, depth + 1);
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
};
|
|
629
|
+
// Include the chapter itself if it has content, then its children
|
|
630
|
+
if (isDirectlyNavigableSection(chapter)) {
|
|
631
|
+
result.push({ section: chapter, depth: 0 });
|
|
632
|
+
}
|
|
633
|
+
walk(chapter.children, isDirectlyNavigableSection(chapter) ? 1 : 0);
|
|
634
|
+
return result;
|
|
635
|
+
}
|
|
636
|
+
function InChapterDropdown({ toc, currentTocPath, selectedSectionId, onSelect, }) {
|
|
637
|
+
const chapter = currentTocPath?.[0] ?? null;
|
|
638
|
+
const chapterOptions = useMemo(() => (chapter ? buildChapterOptions(chapter) : []), [chapter]);
|
|
639
|
+
const allChapters = useMemo(() => toc, [toc]);
|
|
640
|
+
// Don't render if there's no chapter or only one page in it
|
|
641
|
+
if (!chapter || chapterOptions.length <= 1)
|
|
642
|
+
return null;
|
|
643
|
+
const selectedTitle = chapterOptions.find((o) => o.section.id === selectedSectionId)?.section.title;
|
|
644
|
+
return (_jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsxs("button", { type: "button", className: "inline-flex w-full items-center justify-between gap-2 rounded-md border border-gray-200 bg-white px-2.5 py-1.5 text-xs transition-colors hover:bg-gray-50", children: [_jsxs("span", { className: "truncate text-gray-500", children: [_jsx("span", { className: "font-medium text-gray-700", children: selectedTitle ?? chapter.title }), " ", _jsxs("span", { className: "text-gray-400", children: ["\u2014 in ", chapter.title] })] }), _jsx(ChevronDown, { className: "h-3.5 w-3.5 shrink-0 text-gray-400" })] }) }), _jsxs(DropdownMenuContent, { align: "start", className: "max-h-80 w-[--radix-dropdown-menu-trigger-width] overflow-y-auto", children: [allChapters.length > 0 && (_jsxs(_Fragment, { children: [_jsx(DropdownMenuLabel, { className: "text-[11px] font-semibold tracking-wide text-gray-400 uppercase", children: "Chapters" }), allChapters.map((c) => {
|
|
645
|
+
const isCurrent = c.id === chapter?.id;
|
|
646
|
+
const theme = getSectionTheme(c.title);
|
|
647
|
+
const Icon = theme.icon;
|
|
648
|
+
return (_jsxs(DropdownMenuItem, { onClick: () => !isCurrent && onSelect(c.id), className: cn(isCurrent && "bg-blue-50 font-medium"), children: [c.svgIcon ? (_jsx(SvgIcon, { svg: c.svgIcon, size: 14, className: cn("mr-1.5 shrink-0", theme.color) })) : (_jsx(Icon, { className: cn("mr-1.5 h-3.5 w-3.5 shrink-0", theme.color), strokeWidth: 1.75 })), _jsx("span", { className: "truncate", children: c.title })] }, c.id));
|
|
649
|
+
}), _jsx(DropdownMenuSeparator, {}), _jsxs(DropdownMenuLabel, { className: "text-[11px] font-semibold tracking-wide text-gray-400 uppercase", children: ["In ", chapter.title] })] })), chapterOptions.map(({ section, depth }) => {
|
|
650
|
+
const isActive = section.id === selectedSectionId;
|
|
651
|
+
const navigable = isDirectlyNavigableSection(section);
|
|
652
|
+
return (_jsx(DropdownMenuItem, { disabled: !navigable, onClick: () => navigable && onSelect(section.id), className: cn(isActive && "bg-blue-50 font-medium", !navigable && "pointer-events-none opacity-60"), style: { paddingLeft: `${8 + depth * 16}px` }, children: _jsx("span", { className: "truncate", children: section.title || "Untitled" }) }, section.id));
|
|
653
|
+
})] })] }));
|
|
654
|
+
}
|
|
655
|
+
function flattenSections(sections) {
|
|
656
|
+
const flattened = [];
|
|
657
|
+
for (const section of sections) {
|
|
658
|
+
flattened.push(section);
|
|
659
|
+
if (section.children && section.children.length > 0) {
|
|
660
|
+
flattened.push(...flattenSections(section.children));
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
return flattened;
|
|
664
|
+
}
|
|
665
|
+
function flattenNavigableSections(sections) {
|
|
666
|
+
const flattened = [];
|
|
667
|
+
for (const section of sections) {
|
|
668
|
+
if (isDirectlyNavigableSection(section)) {
|
|
669
|
+
flattened.push(section);
|
|
670
|
+
}
|
|
671
|
+
if (section.children.length > 0) {
|
|
672
|
+
flattened.push(...flattenNavigableSections(section.children));
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
return flattened;
|
|
676
|
+
}
|
|
677
|
+
const MANUAL_SECTION_TEMPLATE_ID = "c5f1e8a2-9b50-4fe2-9b6d-3db00c3b3b8a";
|
|
678
|
+
export function ManualBrowser({ onClose }) {
|
|
504
679
|
const editContext = useEditContext();
|
|
505
680
|
const [toc, setToc] = useState([]);
|
|
506
|
-
const
|
|
681
|
+
const selectedSectionId = editContext?.selectedHelpSectionId ?? null;
|
|
507
682
|
const [currentSection, setCurrentSection] = useState(null);
|
|
683
|
+
const currentSectionRef = useRef(null);
|
|
508
684
|
const [loadingToc, setLoadingToc] = useState(false);
|
|
509
685
|
const [loadingSection, setLoadingSection] = useState(false);
|
|
510
686
|
const [error, setError] = useState(null);
|
|
687
|
+
const [searchQuery, setSearchQuery] = useState("");
|
|
688
|
+
const [searchResults, setSearchResults] = useState([]);
|
|
689
|
+
const [searching, setSearching] = useState(false);
|
|
690
|
+
const [collapsedTocSectionIds, setCollapsedTocSectionIds] = useState(() => new Set());
|
|
691
|
+
const [manualBackHistory, setManualBackHistory] = useState([]);
|
|
511
692
|
// Track revision to force re-fetch (incremented when websocket notifies of changes)
|
|
512
693
|
const [sectionRevision, setSectionRevision] = useState(0);
|
|
513
694
|
// Keep a ref to all TOC item IDs for checking if changed item is in the manual
|
|
514
695
|
const tocItemIdsRef = useRef(new Set());
|
|
696
|
+
const manualBackHistoryRef = useRef([]);
|
|
697
|
+
const historyNavigationModeRef = useRef(null);
|
|
698
|
+
const lastObservedSelectedSectionIdRef = useRef(undefined);
|
|
515
699
|
// Keep a ref to selectedSectionId to avoid stale closures in websocket callback
|
|
516
700
|
const selectedSectionIdRef = useRef(null);
|
|
517
|
-
// Flatten TOC into select options
|
|
518
|
-
const sectionOptions = useMemo(() => flattenTocToOptions(toc), [toc]);
|
|
519
701
|
const currentTocPath = useMemo(() => {
|
|
520
702
|
if (!selectedSectionId)
|
|
521
703
|
return null;
|
|
522
704
|
return findTocPath(toc, selectedSectionId);
|
|
523
705
|
}, [toc, selectedSectionId]);
|
|
524
706
|
const parentTocSection = useMemo(() => {
|
|
525
|
-
|
|
526
|
-
return null;
|
|
527
|
-
return currentTocPath[currentTocPath.length - 2] || null;
|
|
707
|
+
return findNearestNavigableAncestor(currentTocPath);
|
|
528
708
|
}, [currentTocPath]);
|
|
709
|
+
const chapterNavigation = useMemo(() => {
|
|
710
|
+
if (!selectedSectionId)
|
|
711
|
+
return { previous: null, next: null };
|
|
712
|
+
const flatSections = flattenNavigableSections(toc);
|
|
713
|
+
const currentIndex = flatSections.findIndex((section) => section.id === selectedSectionId);
|
|
714
|
+
if (currentIndex < 0)
|
|
715
|
+
return { previous: null, next: null };
|
|
716
|
+
return {
|
|
717
|
+
previous: currentIndex > 0 ? flatSections[currentIndex - 1] : null,
|
|
718
|
+
next: currentIndex < flatSections.length - 1
|
|
719
|
+
? flatSections[currentIndex + 1]
|
|
720
|
+
: null,
|
|
721
|
+
};
|
|
722
|
+
}, [toc, selectedSectionId]);
|
|
723
|
+
const manualLinkTargets = useMemo(() => {
|
|
724
|
+
const lookup = new Map();
|
|
725
|
+
const sections = flattenSections(toc);
|
|
726
|
+
for (const section of sections) {
|
|
727
|
+
const key = section.title?.trim().toLowerCase();
|
|
728
|
+
if (key && !lookup.has(key)) {
|
|
729
|
+
lookup.set(key, resolveFirstNavigableSection(section).id);
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
return lookup;
|
|
733
|
+
}, [toc]);
|
|
734
|
+
const manualSectionsById = useMemo(() => {
|
|
735
|
+
const map = new Map();
|
|
736
|
+
const sections = flattenSections(toc);
|
|
737
|
+
for (const section of sections) {
|
|
738
|
+
map.set(section.id.toLowerCase(), section);
|
|
739
|
+
}
|
|
740
|
+
return map;
|
|
741
|
+
}, [toc]);
|
|
742
|
+
const backTargetSectionId = manualBackHistory.length > 0
|
|
743
|
+
? manualBackHistory[manualBackHistory.length - 1]
|
|
744
|
+
: null;
|
|
745
|
+
const backTargetSection = useMemo(() => {
|
|
746
|
+
if (!backTargetSectionId)
|
|
747
|
+
return null;
|
|
748
|
+
return manualSectionsById.get(backTargetSectionId.toLowerCase()) ?? null;
|
|
749
|
+
}, [backTargetSectionId, manualSectionsById]);
|
|
750
|
+
const backButtonLabel = backTargetSection?.title
|
|
751
|
+
? `Back to ${backTargetSection.title}`
|
|
752
|
+
: "Back to contents";
|
|
753
|
+
const backButtonText = backTargetSectionId === null ? "Contents" : "Back";
|
|
529
754
|
// Keep selectedSectionId ref in sync
|
|
530
755
|
useEffect(() => {
|
|
531
756
|
selectedSectionIdRef.current = selectedSectionId;
|
|
532
757
|
}, [selectedSectionId]);
|
|
758
|
+
useEffect(() => {
|
|
759
|
+
currentSectionRef.current = currentSection;
|
|
760
|
+
}, [currentSection]);
|
|
761
|
+
useEffect(() => {
|
|
762
|
+
manualBackHistoryRef.current = manualBackHistory;
|
|
763
|
+
}, [manualBackHistory]);
|
|
764
|
+
useEffect(() => {
|
|
765
|
+
const previousSelectedSectionId = lastObservedSelectedSectionIdRef.current;
|
|
766
|
+
if (previousSelectedSectionId === undefined) {
|
|
767
|
+
lastObservedSelectedSectionIdRef.current = selectedSectionId;
|
|
768
|
+
return;
|
|
769
|
+
}
|
|
770
|
+
const normalizedPreviousSelectedSectionId = previousSelectedSectionId && toc.length > 0
|
|
771
|
+
? resolveSelectedSectionId(toc, previousSelectedSectionId)
|
|
772
|
+
: previousSelectedSectionId;
|
|
773
|
+
const normalizedSelectedSectionId = selectedSectionId && toc.length > 0
|
|
774
|
+
? resolveSelectedSectionId(toc, selectedSectionId)
|
|
775
|
+
: selectedSectionId;
|
|
776
|
+
if (normalizedPreviousSelectedSectionId === normalizedSelectedSectionId) {
|
|
777
|
+
lastObservedSelectedSectionIdRef.current = selectedSectionId;
|
|
778
|
+
return;
|
|
779
|
+
}
|
|
780
|
+
if (historyNavigationModeRef.current === "back") {
|
|
781
|
+
historyNavigationModeRef.current = null;
|
|
782
|
+
}
|
|
783
|
+
else {
|
|
784
|
+
setManualBackHistory((prev) => [
|
|
785
|
+
...prev,
|
|
786
|
+
normalizedPreviousSelectedSectionId,
|
|
787
|
+
]);
|
|
788
|
+
}
|
|
789
|
+
lastObservedSelectedSectionIdRef.current = selectedSectionId;
|
|
790
|
+
}, [selectedSectionId, toc]);
|
|
791
|
+
useEffect(() => {
|
|
792
|
+
if (!selectedSectionId || !editContext || toc.length === 0)
|
|
793
|
+
return;
|
|
794
|
+
const resolvedSectionId = resolveSelectedSectionId(toc, selectedSectionId);
|
|
795
|
+
if (resolvedSectionId !== selectedSectionId) {
|
|
796
|
+
editContext.setSelectedHelpSectionId(resolvedSectionId);
|
|
797
|
+
}
|
|
798
|
+
}, [editContext, selectedSectionId, toc]);
|
|
533
799
|
// Build set of all TOC item IDs (for websocket matching)
|
|
534
800
|
useEffect(() => {
|
|
535
801
|
const collectIds = (sections) => {
|
|
@@ -551,10 +817,6 @@ export function ManualBrowser() {
|
|
|
551
817
|
loadManualToc()
|
|
552
818
|
.then((data) => {
|
|
553
819
|
setToc(data);
|
|
554
|
-
// Auto-select first section if available
|
|
555
|
-
if (data.length > 0 && data[0]) {
|
|
556
|
-
setSelectedSectionId(data[0].id);
|
|
557
|
-
}
|
|
558
820
|
})
|
|
559
821
|
.catch((err) => {
|
|
560
822
|
console.error("Failed to load manual TOC:", err);
|
|
@@ -566,28 +828,96 @@ export function ManualBrowser() {
|
|
|
566
828
|
}, []);
|
|
567
829
|
// Load section content when selection changes or revision changes
|
|
568
830
|
useEffect(() => {
|
|
831
|
+
let cancelled = false;
|
|
569
832
|
if (!selectedSectionId) {
|
|
570
833
|
setCurrentSection(null);
|
|
571
834
|
setLoadingSection(false);
|
|
572
835
|
return;
|
|
573
836
|
}
|
|
837
|
+
const resolvedSectionId = toc.length > 0
|
|
838
|
+
? resolveSelectedSectionId(toc, selectedSectionId)
|
|
839
|
+
: selectedSectionId;
|
|
840
|
+
if (resolvedSectionId !== selectedSectionId) {
|
|
841
|
+
return () => {
|
|
842
|
+
cancelled = true;
|
|
843
|
+
};
|
|
844
|
+
}
|
|
574
845
|
// Only show loading spinner if we don't have current section (initial load)
|
|
575
846
|
// For refreshes, keep showing the old content to avoid flicker
|
|
576
|
-
const isInitialLoad = !
|
|
847
|
+
const isInitialLoad = !currentSectionRef.current ||
|
|
848
|
+
currentSectionRef.current.id !== selectedSectionId;
|
|
577
849
|
if (isInitialLoad) {
|
|
578
850
|
setLoadingSection(true);
|
|
579
851
|
}
|
|
580
|
-
loadManualSection(
|
|
852
|
+
loadManualSection(resolvedSectionId)
|
|
581
853
|
.then((data) => {
|
|
854
|
+
if (cancelled)
|
|
855
|
+
return;
|
|
582
856
|
setCurrentSection(data);
|
|
583
857
|
setLoadingSection(false);
|
|
584
858
|
})
|
|
585
859
|
.catch((err) => {
|
|
860
|
+
if (cancelled)
|
|
861
|
+
return;
|
|
586
862
|
console.error("Failed to load section:", err);
|
|
587
863
|
setCurrentSection(null);
|
|
588
864
|
setLoadingSection(false);
|
|
589
865
|
});
|
|
590
|
-
|
|
866
|
+
return () => {
|
|
867
|
+
cancelled = true;
|
|
868
|
+
};
|
|
869
|
+
}, [sectionRevision, selectedSectionId, toc]);
|
|
870
|
+
// Search manual sections using internal search (SQL + AI providers).
|
|
871
|
+
useEffect(() => {
|
|
872
|
+
let cancelled = false;
|
|
873
|
+
const trimmedQuery = searchQuery.trim();
|
|
874
|
+
if (!trimmedQuery || !editContext) {
|
|
875
|
+
setSearching(false);
|
|
876
|
+
setSearchResults([]);
|
|
877
|
+
return;
|
|
878
|
+
}
|
|
879
|
+
const timeoutId = window.setTimeout(async () => {
|
|
880
|
+
setSearching(true);
|
|
881
|
+
try {
|
|
882
|
+
const result = await executeSearch({
|
|
883
|
+
query: `${trimmedQuery}|template:${MANUAL_SECTION_TEMPLATE_ID}`,
|
|
884
|
+
editContext,
|
|
885
|
+
maxResults: 20,
|
|
886
|
+
index: "master",
|
|
887
|
+
skipValidation: true,
|
|
888
|
+
});
|
|
889
|
+
if (cancelled)
|
|
890
|
+
return;
|
|
891
|
+
if (result.type === "success") {
|
|
892
|
+
const items = result.data || [];
|
|
893
|
+
const mapped = items
|
|
894
|
+
.map((item) => manualSectionsById.get(String(item.id || "").toLowerCase()))
|
|
895
|
+
.filter((section) => !!section);
|
|
896
|
+
const unique = Array.from(new Map(mapped.map((section) => [section.id, section])).values());
|
|
897
|
+
setSearchResults(unique);
|
|
898
|
+
}
|
|
899
|
+
else {
|
|
900
|
+
console.error("Failed to search manual", result.response.statusText);
|
|
901
|
+
setSearchResults([]);
|
|
902
|
+
}
|
|
903
|
+
}
|
|
904
|
+
catch (err) {
|
|
905
|
+
if (!cancelled) {
|
|
906
|
+
console.error("Manual search failed", err);
|
|
907
|
+
setSearchResults([]);
|
|
908
|
+
}
|
|
909
|
+
}
|
|
910
|
+
finally {
|
|
911
|
+
if (!cancelled) {
|
|
912
|
+
setSearching(false);
|
|
913
|
+
}
|
|
914
|
+
}
|
|
915
|
+
}, 300);
|
|
916
|
+
return () => {
|
|
917
|
+
cancelled = true;
|
|
918
|
+
window.clearTimeout(timeoutId);
|
|
919
|
+
};
|
|
920
|
+
}, [searchQuery, editContext, manualSectionsById]);
|
|
591
921
|
// Listen for websocket messages to auto-refresh when manual items change
|
|
592
922
|
// Use ref for selectedSectionId to avoid stale closures and only re-register when selection actually changes
|
|
593
923
|
useEffect(() => {
|
|
@@ -621,8 +951,43 @@ export function ManualBrowser() {
|
|
|
621
951
|
return removeListener;
|
|
622
952
|
}, [selectedSectionId]); // Only re-register when selectedSectionId changes, not when editContext object changes
|
|
623
953
|
const handleSelectSection = useCallback((id) => {
|
|
624
|
-
|
|
954
|
+
if (!editContext)
|
|
955
|
+
return;
|
|
956
|
+
editContext.setSelectedHelpSectionId(resolveSelectedSectionId(toc, id));
|
|
957
|
+
}, [editContext, toc]);
|
|
958
|
+
const handleSelectSearchResult = useCallback((id) => {
|
|
959
|
+
if (!editContext)
|
|
960
|
+
return;
|
|
961
|
+
editContext.setSelectedHelpSectionId(resolveSelectedSectionId(toc, id));
|
|
962
|
+
setSearchQuery("");
|
|
963
|
+
setSearchResults([]);
|
|
964
|
+
}, [editContext, toc]);
|
|
965
|
+
const handleToggleTocSection = useCallback((id) => {
|
|
966
|
+
setCollapsedTocSectionIds((prev) => {
|
|
967
|
+
const next = new Set(prev);
|
|
968
|
+
if (next.has(id)) {
|
|
969
|
+
next.delete(id);
|
|
970
|
+
}
|
|
971
|
+
else {
|
|
972
|
+
next.add(id);
|
|
973
|
+
}
|
|
974
|
+
return next;
|
|
975
|
+
});
|
|
625
976
|
}, []);
|
|
977
|
+
const normalizeHistorySectionId = useCallback((id) => {
|
|
978
|
+
if (!id || toc.length === 0)
|
|
979
|
+
return id;
|
|
980
|
+
return resolveSelectedSectionId(toc, id);
|
|
981
|
+
}, [toc]);
|
|
982
|
+
const handleGoBack = useCallback(() => {
|
|
983
|
+
if (!editContext || !selectedSectionId)
|
|
984
|
+
return;
|
|
985
|
+
const history = manualBackHistoryRef.current;
|
|
986
|
+
const previousSectionId = history.length > 0 ? history[history.length - 1] : null;
|
|
987
|
+
historyNavigationModeRef.current = "back";
|
|
988
|
+
setManualBackHistory((prev) => prev.length > 0 ? prev.slice(0, -1) : prev);
|
|
989
|
+
editContext.setSelectedHelpSectionId(normalizeHistorySectionId(previousSectionId));
|
|
990
|
+
}, [editContext, normalizeHistorySectionId, selectedSectionId]);
|
|
626
991
|
if (loadingToc) {
|
|
627
992
|
return (_jsx("div", { className: "flex items-center justify-center py-8", children: _jsx(Loader2, { className: "h-5 w-5 animate-spin text-gray-400" }) }));
|
|
628
993
|
}
|
|
@@ -632,7 +997,7 @@ export function ManualBrowser() {
|
|
|
632
997
|
if (toc.length === 0) {
|
|
633
998
|
return (_jsxs("div", { className: "px-4 py-8 text-center text-sm text-gray-500", children: [_jsx(Book, { className: "mx-auto mb-2 h-8 w-8 text-gray-300" }), _jsx("p", { children: "No manual content available yet." })] }));
|
|
634
999
|
}
|
|
635
|
-
return (_jsxs("div", { className: "flex h-full flex-col", children: [
|
|
1000
|
+
return (_jsxs("div", { className: "flex h-full flex-col", children: [_jsxs("div", { className: "shrink-0 border-b border-gray-200/60 bg-linear-to-b from-gray-50 to-white px-4 py-3", children: [_jsxs("div", { className: "flex items-center justify-between gap-2", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("div", { className: "flex h-7 w-7 items-center justify-center rounded-lg bg-blue-50", children: _jsx(Book, { className: "h-4 w-4 text-blue-600", strokeWidth: 1.75 }) }), _jsx("h2", { className: "text-base font-semibold text-gray-900", children: "User Manual" })] }), onClose && (_jsx("button", { onClick: onClose, className: "shrink-0 rounded p-1 text-gray-400 transition-colors hover:bg-gray-200 hover:text-gray-600", "aria-label": "Close", children: _jsx(X, { size: 16, strokeWidth: 1.5 }) }))] }), _jsx("div", { className: "mt-2", children: _jsx(FilterInput, { value: searchQuery, onChange: setSearchQuery, placeholder: "Search manual pages...", size: "xs", loading: searching }) }), selectedSectionId && (_jsx("div", { className: "mt-2", children: _jsx(InChapterDropdown, { toc: toc, currentTocPath: currentTocPath, selectedSectionId: selectedSectionId, onSelect: handleSelectSection }) })), searchQuery.trim().length > 0 && (_jsx("div", { className: "mt-2 max-h-52 overflow-y-auto rounded-lg border border-gray-200 bg-white shadow-sm", children: searching ? (_jsxs("div", { className: "flex items-center gap-2 px-3 py-3 text-xs text-gray-500", children: [_jsx(Loader2, { className: "h-3 w-3 animate-spin" }), "Searching manual..."] })) : searchResults.length > 0 ? (searchResults.map((section) => (_jsxs("button", { type: "button", onClick: () => handleSelectSearchResult(section.id), className: "group block w-full border-b border-gray-50 px-3 py-2.5 text-left transition-colors last:border-b-0 hover:bg-blue-50/50", children: [_jsx("span", { className: "block text-sm font-medium text-gray-900 transition-colors group-hover:text-blue-700", children: section.title || "Untitled" }), section.summary && (_jsx("span", { className: "mt-0.5 line-clamp-2 block text-xs leading-relaxed text-gray-500", children: section.summary }))] }, section.id)))) : (_jsx("div", { className: "px-3 py-3 text-center text-xs text-gray-500", children: "No manual pages matched your search." })) }))] }), _jsx("div", { className: "flex-1 overflow-y-auto p-4 select-text", children: loadingSection ? (_jsx("div", { className: "flex items-center justify-center py-8", children: _jsx(Loader2, { className: "h-5 w-5 animate-spin text-gray-400" }) })) : !selectedSectionId ? (_jsx("div", { children: renderTocTree(toc, handleSelectSection, handleToggleTocSection, collapsedTocSectionIds) })) : currentSection ? (_jsxs("div", { children: [_jsxs("div", { className: "mb-1 flex items-center justify-between", children: [_jsxs("button", { type: "button", onClick: handleGoBack, className: "inline-flex shrink-0 items-center gap-1 rounded px-2 py-1 text-sm text-gray-600 transition-colors hover:bg-gray-100 hover:text-gray-900", "aria-label": backButtonLabel, title: backButtonLabel, children: [_jsx(ArrowLeft, { className: "h-4 w-4" }), _jsx("span", { className: "hidden sm:inline", children: backButtonText })] }), editContext?.user?.isAdministrator && editContext?.loadItem && (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { type: "button", onClick: async (e) => {
|
|
636
1001
|
e.preventDefault();
|
|
637
1002
|
e.stopPropagation();
|
|
638
1003
|
if (!editContext?.loadItem) {
|
|
@@ -640,7 +1005,6 @@ export function ManualBrowser() {
|
|
|
640
1005
|
return;
|
|
641
1006
|
}
|
|
642
1007
|
try {
|
|
643
|
-
// Load the manual section item in the editor
|
|
644
1008
|
const language = editContext?.currentItemDescriptor?.language ||
|
|
645
1009
|
editContext?.item?.language ||
|
|
646
1010
|
"en";
|
|
@@ -655,7 +1019,20 @@ export function ManualBrowser() {
|
|
|
655
1019
|
catch (error) {
|
|
656
1020
|
console.error("Failed to load manual section:", error);
|
|
657
1021
|
}
|
|
658
|
-
}, className: "shrink-0 rounded p-1.5 text-gray-500 transition-colors hover:bg-gray-100 hover:text-gray-700", "aria-label": "Edit item", title: "Edit item", children: _jsx(Edit, { className: "h-4 w-4" }) }) }), _jsx(TooltipContent, { children: "Edit item" })] }))] }),
|
|
659
|
-
|
|
1022
|
+
}, className: "shrink-0 rounded p-1.5 text-gray-500 transition-colors hover:bg-gray-100 hover:text-gray-700", "aria-label": "Edit item", title: "Edit item", children: _jsx(Edit, { className: "h-4 w-4" }) }) }), _jsx(TooltipContent, { children: "Edit item" })] }))] }), _jsxs("h2", { className: "my-2 flex items-center gap-2 text-xl font-bold text-gray-900", children: [currentSection.svgIcon && (_jsx(SvgIcon, { svg: currentSection.svgIcon, size: 24, className: "shrink-0 text-gray-500" })), currentSection.title] }), currentSection.summary &&
|
|
1023
|
+
(() => {
|
|
1024
|
+
const theme = parentTocSection
|
|
1025
|
+
? getSectionTheme(parentTocSection.title)
|
|
1026
|
+
: getSectionTheme(currentSection.title);
|
|
1027
|
+
return (_jsx("p", { className: cn("my-4 mb-8 border-l-2 pl-3 text-sm text-gray-500 italic", theme.border), children: currentSection.summary }));
|
|
1028
|
+
})(), _jsx("div", { className: "prose prose-sm max-w-none select-text", children: renderMarkdownWithSelectors(currentSection.content || "", parseUiSelectors(currentSection.uiSelectors), manualLinkTargets, handleSelectSection) }), currentSection.subsections &&
|
|
1029
|
+
currentSection.subsections.length > 0 && (_jsxs("div", { className: "mt-8 border-t border-gray-100 pt-4", children: [_jsx("h3", { className: "mb-3 text-[11px] font-bold tracking-widest text-gray-400 uppercase", children: "In this section" }), _jsx("div", { className: "space-y-0.5", children: currentSection.subsections.map((subsection) => {
|
|
1030
|
+
const theme = getSectionTheme(currentSection.title);
|
|
1031
|
+
return (_jsxs("button", { onClick: () => handleSelectSection(subsection.id), className: "group flex w-full items-center gap-2.5 rounded-lg px-3 py-2 text-left text-sm text-gray-600 transition-all hover:bg-gray-50 hover:text-gray-900", children: [_jsx("span", { className: cn("h-1.5 w-1.5 shrink-0 rounded-full transition-transform group-hover:scale-125", theme.accent, "opacity-50 group-hover:opacity-80") }), _jsx("span", { className: "flex-1 truncate font-medium", children: subsection.title }), _jsx(ChevronRight, { className: "h-3.5 w-3.5 shrink-0 text-gray-300 transition-colors group-hover:text-gray-500" })] }, subsection.id));
|
|
1032
|
+
}) })] }))] })) : (_jsx("div", { className: "py-8 text-center text-sm text-gray-500", children: "Select a section to view its content" })) }), selectedSectionId &&
|
|
1033
|
+
currentSection &&
|
|
1034
|
+
(chapterNavigation.previous || chapterNavigation.next) && (_jsx("div", { className: "shrink-0 border-t border-gray-200/60 bg-white px-4 py-3", children: _jsxs("div", { className: "grid grid-cols-2 gap-2", children: [chapterNavigation.previous ? (_jsxs("button", { type: "button", onClick: () => chapterNavigation.previous &&
|
|
1035
|
+
handleSelectSection(chapterNavigation.previous.id), className: "group rounded-lg border border-gray-200 px-3 py-2 text-left transition-all hover:border-blue-200 hover:bg-blue-50/30", children: [_jsxs("span", { className: "mb-0.5 inline-flex items-center gap-1 text-xs font-medium text-gray-400 transition-colors group-hover:text-blue-500", children: [_jsx(ArrowLeft, { className: "h-3 w-3" }), "Previous"] }), _jsx("span", { className: "block truncate text-sm font-medium text-gray-700 transition-colors group-hover:text-gray-900", children: chapterNavigation.previous.title })] })) : (_jsx("div", {})), chapterNavigation.next ? (_jsxs("button", { type: "button", onClick: () => chapterNavigation.next &&
|
|
1036
|
+
handleSelectSection(chapterNavigation.next.id), className: "group rounded-lg border border-gray-200 px-3 py-2 text-right transition-all hover:border-blue-200 hover:bg-blue-50/30", children: [_jsxs("span", { className: "mb-0.5 inline-flex items-center justify-end gap-1 text-xs font-medium text-gray-400 transition-colors group-hover:text-blue-500", children: ["Next", _jsx(ArrowRight, { className: "h-3 w-3" })] }), _jsx("span", { className: "block truncate text-sm font-medium text-gray-700 transition-colors group-hover:text-gray-900", children: chapterNavigation.next.title })] })) : (_jsx("div", {}))] }) }))] }));
|
|
660
1037
|
}
|
|
661
1038
|
//# sourceMappingURL=ManualBrowser.js.map
|