@parhelia/core 0.1.12554 → 0.1.12555

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.
Files changed (575) hide show
  1. package/dist/agents-view/AgentCard.d.ts +4 -6
  2. package/dist/agents-view/AgentCard.js +24 -143
  3. package/dist/agents-view/AgentCard.js.map +1 -1
  4. package/dist/agents-view/AgentsInbox.d.ts +1 -1
  5. package/dist/agents-view/AgentsInbox.js +92 -7
  6. package/dist/agents-view/AgentsInbox.js.map +1 -1
  7. package/dist/agents-view/AgentsTitlebar.js +2 -3
  8. package/dist/agents-view/AgentsTitlebar.js.map +1 -1
  9. package/dist/agents-view/AgentsView.d.ts +7 -6
  10. package/dist/agents-view/AgentsView.js +98 -187
  11. package/dist/agents-view/AgentsView.js.map +1 -1
  12. package/dist/agents-view/AgentsWorkspaceView.d.ts +6 -2
  13. package/dist/agents-view/AgentsWorkspaceView.js +113 -266
  14. package/dist/agents-view/AgentsWorkspaceView.js.map +1 -1
  15. package/dist/agents-view/ProfileAgentsGroup.d.ts +1 -2
  16. package/dist/agents-view/ProfileAgentsGroup.js +3 -4
  17. package/dist/agents-view/ProfileAgentsGroup.js.map +1 -1
  18. package/dist/components/ActionButton.d.ts +1 -1
  19. package/dist/components/ActionButton.js.map +1 -1
  20. package/dist/components/FilterInput.d.ts +1 -1
  21. package/dist/components/FilterInput.js +1 -1
  22. package/dist/components/FilterInput.js.map +1 -1
  23. package/dist/components/ui/LanguageSelector.js +4 -2
  24. package/dist/components/ui/LanguageSelector.js.map +1 -1
  25. package/dist/components/ui/PlaceholderInput.js +3 -3
  26. package/dist/components/ui/PlaceholderInput.js.map +1 -1
  27. package/dist/components/ui/PlaceholderInputTypes.js +1 -1
  28. package/dist/components/ui/PlaceholderInputTypes.js.map +1 -1
  29. package/dist/components/ui/alert-dialog.d.ts +1 -1
  30. package/dist/components/ui/alert-dialog.js +10 -6
  31. package/dist/components/ui/alert-dialog.js.map +1 -1
  32. package/dist/components/ui/button.d.ts +4 -4
  33. package/dist/components/ui/button.js +1 -4
  34. package/dist/components/ui/button.js.map +1 -1
  35. package/dist/components/ui/context-menu.d.ts +1 -1
  36. package/dist/components/ui/context-menu.js +4 -12
  37. package/dist/components/ui/context-menu.js.map +1 -1
  38. package/dist/components/ui/copy-button.d.ts +1 -2
  39. package/dist/components/ui/copy-button.js +2 -2
  40. package/dist/components/ui/copy-button.js.map +1 -1
  41. package/dist/components/ui/dialog.d.ts +1 -1
  42. package/dist/components/ui/dialog.js +126 -21
  43. package/dist/components/ui/dialog.js.map +1 -1
  44. package/dist/components/ui/input.d.ts +1 -1
  45. package/dist/components/ui/input.js +3 -5
  46. package/dist/components/ui/input.js.map +1 -1
  47. package/dist/components/ui/paste-button.d.ts +1 -2
  48. package/dist/components/ui/paste-button.js +2 -2
  49. package/dist/components/ui/paste-button.js.map +1 -1
  50. package/dist/components/ui/popover.js +9 -1
  51. package/dist/components/ui/popover.js.map +1 -1
  52. package/dist/components/ui/select.js +1 -1
  53. package/dist/components/ui/select.js.map +1 -1
  54. package/dist/components/ui/styled-dialog-title.js +1 -1
  55. package/dist/components/ui/styled-dialog-title.js.map +1 -1
  56. package/dist/components/ui/tabs.d.ts +1 -1
  57. package/dist/components/ui/tabs.js +11 -4
  58. package/dist/components/ui/tabs.js.map +1 -1
  59. package/dist/config/config.d.ts +2 -4
  60. package/dist/config/config.js +70 -250
  61. package/dist/config/config.js.map +1 -1
  62. package/dist/config/types/workspace.d.ts +0 -6
  63. package/dist/config/types.d.ts +12 -63
  64. package/dist/config/types.js.map +1 -1
  65. package/dist/editor/ComponentInfo.d.ts +4 -0
  66. package/dist/editor/ComponentInfo.js +41 -0
  67. package/dist/editor/ComponentInfo.js.map +1 -0
  68. package/dist/editor/ConfirmationDialog.js +4 -20
  69. package/dist/editor/ConfirmationDialog.js.map +1 -1
  70. package/dist/editor/ContentTree.d.ts +1 -2
  71. package/dist/editor/ContentTree.js +32 -93
  72. package/dist/editor/ContentTree.js.map +1 -1
  73. package/dist/editor/Editor.js +22 -87
  74. package/dist/editor/Editor.js.map +1 -1
  75. package/dist/editor/FieldHistory.js +36 -84
  76. package/dist/editor/FieldHistory.js.map +1 -1
  77. package/dist/editor/FieldListField.js +9 -21
  78. package/dist/editor/FieldListField.js.map +1 -1
  79. package/dist/editor/FieldListFieldWithFallbacks.js +2 -23
  80. package/dist/editor/FieldListFieldWithFallbacks.js.map +1 -1
  81. package/dist/editor/GlobalMenuBar.js +2 -29
  82. package/dist/editor/GlobalMenuBar.js.map +1 -1
  83. package/dist/editor/ImageEditor.js +2 -5
  84. package/dist/editor/ImageEditor.js.map +1 -1
  85. package/dist/editor/ItemInfo.js +1 -36
  86. package/dist/editor/ItemInfo.js.map +1 -1
  87. package/dist/editor/LinkEditorDialog.js +0 -3
  88. package/dist/editor/LinkEditorDialog.js.map +1 -1
  89. package/dist/editor/MainLayout.d.ts +2 -0
  90. package/dist/editor/MainLayout.js +8 -65
  91. package/dist/editor/MainLayout.js.map +1 -1
  92. package/dist/editor/MigrationsView.js +5 -29
  93. package/dist/editor/MigrationsView.js.map +1 -1
  94. package/dist/editor/MobileLayout.js +12 -37
  95. package/dist/editor/MobileLayout.js.map +1 -1
  96. package/dist/editor/PictureCropper.js +45 -54
  97. package/dist/editor/PictureCropper.js.map +1 -1
  98. package/dist/editor/PictureEditor.js +15 -17
  99. package/dist/editor/PictureEditor.js.map +1 -1
  100. package/dist/editor/QuickItemSwitcher.js +21 -21
  101. package/dist/editor/QuickItemSwitcher.js.map +1 -1
  102. package/dist/editor/SetupWizard.js +12 -52
  103. package/dist/editor/SetupWizard.js.map +1 -1
  104. package/dist/editor/Titlebar.js +2 -7
  105. package/dist/editor/Titlebar.js.map +1 -1
  106. package/dist/editor/ai/AgentCostDisplay.d.ts +0 -1
  107. package/dist/editor/ai/AgentCostDisplay.js +1 -1
  108. package/dist/editor/ai/AgentCostDisplay.js.map +1 -1
  109. package/dist/editor/ai/AgentDocumentList.js +14 -32
  110. package/dist/editor/ai/AgentDocumentList.js.map +1 -1
  111. package/dist/editor/ai/AgentGreeting.js +2 -3
  112. package/dist/editor/ai/AgentGreeting.js.map +1 -1
  113. package/dist/editor/ai/AgentProfileSelector.js +1 -2
  114. package/dist/editor/ai/AgentProfileSelector.js.map +1 -1
  115. package/dist/editor/ai/AgentStatusBadge.d.ts +5 -0
  116. package/dist/editor/ai/AgentStatusBadge.js +65 -67
  117. package/dist/editor/ai/AgentStatusBadge.js.map +1 -1
  118. package/dist/editor/ai/AgentTerminal.d.ts +2 -14
  119. package/dist/editor/ai/AgentTerminal.js +483 -2377
  120. package/dist/editor/ai/AgentTerminal.js.map +1 -1
  121. package/dist/editor/ai/AgentTerminalStatusBar.d.ts +3 -8
  122. package/dist/editor/ai/AgentTerminalStatusBar.js +56 -460
  123. package/dist/editor/ai/AgentTerminalStatusBar.js.map +1 -1
  124. package/dist/editor/ai/Agents.js +113 -150
  125. package/dist/editor/ai/Agents.js.map +1 -1
  126. package/dist/editor/ai/AiResponseMessage.d.ts +1 -10
  127. package/dist/editor/ai/AiResponseMessage.js +23 -238
  128. package/dist/editor/ai/AiResponseMessage.js.map +1 -1
  129. package/dist/editor/ai/ContextInfoBar.d.ts +3 -2
  130. package/dist/editor/ai/ContextInfoBar.js +7 -64
  131. package/dist/editor/ai/ContextInfoBar.js.map +1 -1
  132. package/dist/editor/ai/GuidanceOverlay.js +11 -17
  133. package/dist/editor/ai/GuidanceOverlay.js.map +1 -1
  134. package/dist/editor/ai/HelpTerminal.d.ts +5 -0
  135. package/dist/editor/ai/HelpTerminal.js +166 -0
  136. package/dist/editor/ai/HelpTerminal.js.map +1 -0
  137. package/dist/editor/ai/InlineAiDialog.d.ts +1 -1
  138. package/dist/editor/ai/InlineAiDialog.js +192 -514
  139. package/dist/editor/ai/InlineAiDialog.js.map +1 -1
  140. package/dist/editor/ai/InlineAiTrigger.js +12 -115
  141. package/dist/editor/ai/InlineAiTrigger.js.map +1 -1
  142. package/dist/editor/ai/MediaImage.js +8 -40
  143. package/dist/editor/ai/MediaImage.js.map +1 -1
  144. package/dist/editor/ai/SpawnedAgentsPanel.js +12 -10
  145. package/dist/editor/ai/SpawnedAgentsPanel.js.map +1 -1
  146. package/dist/editor/ai/ToolCallDisplay.d.ts +2 -22
  147. package/dist/editor/ai/ToolCallDisplay.js +147 -518
  148. package/dist/editor/ai/ToolCallDisplay.js.map +1 -1
  149. package/dist/editor/ai/dialogs/AgentDialogHandler.d.ts +8 -1
  150. package/dist/editor/ai/dialogs/AgentDialogHandler.js +42 -379
  151. package/dist/editor/ai/dialogs/AgentDialogHandler.js.map +1 -1
  152. package/dist/editor/ai/dialogs/QuestionnaireInline.d.ts +1 -5
  153. package/dist/editor/ai/dialogs/QuestionnaireInline.js +60 -628
  154. package/dist/editor/ai/dialogs/QuestionnaireInline.js.map +1 -1
  155. package/dist/editor/ai/dialogs/agentDialogTypes.d.ts +0 -115
  156. package/dist/editor/ai/dialogs/agentDialogTypes.js +0 -2
  157. package/dist/editor/ai/dialogs/agentDialogTypes.js.map +1 -1
  158. package/dist/editor/ai/types.d.ts +1 -3
  159. package/dist/editor/ai/useAgentStatus.d.ts +1 -2
  160. package/dist/editor/ai/useAgentStatus.js +99 -86
  161. package/dist/editor/ai/useAgentStatus.js.map +1 -1
  162. package/dist/editor/ai/useInlineAiPosition.js +5 -45
  163. package/dist/editor/ai/useInlineAiPosition.js.map +1 -1
  164. package/dist/editor/client/AboutDialog.js +2 -4
  165. package/dist/editor/client/AboutDialog.js.map +1 -1
  166. package/dist/editor/client/EditorShell.d.ts +1 -4
  167. package/dist/editor/client/EditorShell.js +230 -730
  168. package/dist/editor/client/EditorShell.js.map +1 -1
  169. package/dist/editor/client/editContext.d.ts +19 -33
  170. package/dist/editor/client/editContext.js.map +1 -1
  171. package/dist/editor/client/helpers.js +0 -6
  172. package/dist/editor/client/helpers.js.map +1 -1
  173. package/dist/editor/client/hooks/useEditorUrlSync.js +2 -1
  174. package/dist/editor/client/hooks/useEditorUrlSync.js.map +1 -1
  175. package/dist/editor/client/hooks/useEditorWebSocket.d.ts +0 -10
  176. package/dist/editor/client/hooks/useEditorWebSocket.js +14 -209
  177. package/dist/editor/client/hooks/useEditorWebSocket.js.map +1 -1
  178. package/dist/editor/client/hooks/useQuota.d.ts +0 -8
  179. package/dist/editor/client/hooks/useQuota.js.map +1 -1
  180. package/dist/editor/client/hooks/useSocketMessageHandler.js +7 -68
  181. package/dist/editor/client/hooks/useSocketMessageHandler.js.map +1 -1
  182. package/dist/editor/client/itemsRepository.js +6 -10
  183. package/dist/editor/client/itemsRepository.js.map +1 -1
  184. package/dist/editor/client/operations.d.ts +3 -6
  185. package/dist/editor/client/operations.js +30 -208
  186. package/dist/editor/client/operations.js.map +1 -1
  187. package/dist/editor/client/pageModelBuilder.js +31 -4
  188. package/dist/editor/client/pageModelBuilder.js.map +1 -1
  189. package/dist/editor/client/ui/DevModeIndicator.js +2 -2
  190. package/dist/editor/client/ui/DevModeIndicator.js.map +1 -1
  191. package/dist/editor/client/ui/EditorChrome.d.ts +6 -0
  192. package/dist/editor/client/ui/EditorChrome.js +72 -55
  193. package/dist/editor/client/ui/EditorChrome.js.map +1 -1
  194. package/dist/editor/client/ui/FullscreenControls.js +3 -5
  195. package/dist/editor/client/ui/FullscreenControls.js.map +1 -1
  196. package/dist/editor/commands/commands.d.ts +1 -11
  197. package/dist/editor/commands/commands.js +1 -12
  198. package/dist/editor/commands/commands.js.map +1 -1
  199. package/dist/editor/commands/componentCommands.js +55 -109
  200. package/dist/editor/commands/componentCommands.js.map +1 -1
  201. package/dist/editor/commands/customCommandConverter.d.ts +1 -8
  202. package/dist/editor/commands/customCommandConverter.js +5 -35
  203. package/dist/editor/commands/customCommandConverter.js.map +1 -1
  204. package/dist/editor/commands/handlers/agentHandler.js +1 -2
  205. package/dist/editor/commands/handlers/agentHandler.js.map +1 -1
  206. package/dist/editor/commands/itemCommands.d.ts +0 -3
  207. package/dist/editor/commands/itemCommands.js +10 -93
  208. package/dist/editor/commands/itemCommands.js.map +1 -1
  209. package/dist/editor/commands/undo.d.ts +15 -9
  210. package/dist/editor/commands/undo.js +0 -24
  211. package/dist/editor/commands/undo.js.map +1 -1
  212. package/dist/editor/context-menu/InsertMenu.js +39 -83
  213. package/dist/editor/context-menu/InsertMenu.js.map +1 -1
  214. package/dist/editor/field-types/MultiLineText.js +1 -1
  215. package/dist/editor/field-types/MultiLineText.js.map +1 -1
  216. package/dist/editor/field-types/RawEditor.js +1 -1
  217. package/dist/editor/field-types/ReactQuill.d.ts +125 -0
  218. package/dist/editor/field-types/ReactQuill.js +385 -0
  219. package/dist/editor/field-types/ReactQuill.js.map +1 -0
  220. package/dist/editor/field-types/RichTextEditor.js +5 -13
  221. package/dist/editor/field-types/RichTextEditor.js.map +1 -1
  222. package/dist/editor/field-types/RichTextEditorComponent.js +3 -37
  223. package/dist/editor/field-types/RichTextEditorComponent.js.map +1 -1
  224. package/dist/editor/field-types/SingleLineText.js +1 -1
  225. package/dist/editor/field-types/TreeListEditor.js +2 -3
  226. package/dist/editor/field-types/TreeListEditor.js.map +1 -1
  227. package/dist/editor/field-types/richtext/components/ReactSlate.css +5 -23
  228. package/dist/editor/field-types/richtext/components/ReactSlate.d.ts +0 -2
  229. package/dist/editor/field-types/richtext/components/ReactSlate.js +4 -28
  230. package/dist/editor/field-types/richtext/components/ReactSlate.js.map +1 -1
  231. package/dist/editor/field-types/richtext/components/ToolbarButton.js +2 -4
  232. package/dist/editor/field-types/richtext/components/ToolbarButton.js.map +1 -1
  233. package/dist/editor/field-types/richtext/contextMenuFactory.d.ts +0 -13
  234. package/dist/editor/field-types/richtext/contextMenuFactory.js +24 -181
  235. package/dist/editor/field-types/richtext/contextMenuFactory.js.map +1 -1
  236. package/dist/editor/field-types/richtext/types.d.ts +0 -2
  237. package/dist/editor/field-types/richtext/types.js.map +1 -1
  238. package/dist/editor/field-types/richtext/utils/plugins.js +0 -4
  239. package/dist/editor/field-types/richtext/utils/plugins.js.map +1 -1
  240. package/dist/editor/field-types/textContextMenuFactory.js +2 -3
  241. package/dist/editor/field-types/textContextMenuFactory.js.map +1 -1
  242. package/dist/editor/media-selector/AiImageSearchPrompt.js +2 -4
  243. package/dist/editor/media-selector/AiImageSearchPrompt.js.map +1 -1
  244. package/dist/editor/media-selector/MediaFolderBrowser.js +1 -1
  245. package/dist/editor/media-selector/MediaFolderBrowser.js.map +1 -1
  246. package/dist/editor/media-selector/MediaSelector.js +1 -7
  247. package/dist/editor/media-selector/MediaSelector.js.map +1 -1
  248. package/dist/editor/media-selector/TreeSelector.js +35 -40
  249. package/dist/editor/media-selector/TreeSelector.js.map +1 -1
  250. package/dist/editor/menubar/ActiveUsers.js +1 -1
  251. package/dist/editor/menubar/ActiveUsers.js.map +1 -1
  252. package/dist/editor/menubar/GenericToolbar.js +2 -4
  253. package/dist/editor/menubar/GenericToolbar.js.map +1 -1
  254. package/dist/editor/menubar/ItemLanguageVersion.js +2 -2
  255. package/dist/editor/menubar/ItemLanguageVersion.js.map +1 -1
  256. package/dist/editor/menubar/PageSelector.js +147 -26
  257. package/dist/editor/menubar/PageSelector.js.map +1 -1
  258. package/dist/editor/menubar/Separator.js +1 -1
  259. package/dist/editor/menubar/VersionSelector.js +4 -2
  260. package/dist/editor/menubar/VersionSelector.js.map +1 -1
  261. package/dist/editor/menubar/WorkflowButton.js +12 -39
  262. package/dist/editor/menubar/WorkflowButton.js.map +1 -1
  263. package/dist/editor/menubar/toolbar-sections/CustomCommandsToolbar.js +38 -16
  264. package/dist/editor/menubar/toolbar-sections/CustomCommandsToolbar.js.map +1 -1
  265. package/dist/editor/menubar/toolbar-sections/EditControls.js +3 -3
  266. package/dist/editor/menubar/toolbar-sections/EditControls.js.map +1 -1
  267. package/dist/editor/menubar/toolbar-sections/HelpButton.js +0 -1
  268. package/dist/editor/menubar/toolbar-sections/HelpButton.js.map +1 -1
  269. package/dist/editor/menubar/toolbar-sections/ManualBrowser.d.ts +10 -6
  270. package/dist/editor/menubar/toolbar-sections/ManualBrowser.js +220 -597
  271. package/dist/editor/menubar/toolbar-sections/ManualBrowser.js.map +1 -1
  272. package/dist/editor/menubar/toolbar-sections/UtilityControls.js +2 -13
  273. package/dist/editor/menubar/toolbar-sections/UtilityControls.js.map +1 -1
  274. package/dist/editor/page-editor-chrome/CommentHighlighting.js +1 -42
  275. package/dist/editor/page-editor-chrome/CommentHighlighting.js.map +1 -1
  276. package/dist/editor/page-editor-chrome/FrameMenu.js +1 -1
  277. package/dist/editor/page-editor-chrome/FrameMenu.js.map +1 -1
  278. package/dist/editor/page-editor-chrome/InlineEditor.js +48 -97
  279. package/dist/editor/page-editor-chrome/InlineEditor.js.map +1 -1
  280. package/dist/editor/page-editor-chrome/PlaceholderDropZone.js +17 -38
  281. package/dist/editor/page-editor-chrome/PlaceholderDropZone.js.map +1 -1
  282. package/dist/editor/page-editor-chrome/PlaceholderDropZones.js +11 -17
  283. package/dist/editor/page-editor-chrome/PlaceholderDropZones.js.map +1 -1
  284. package/dist/editor/page-editor-chrome/useInlineAICompletion.js +301 -301
  285. package/dist/editor/page-editor-chrome/useInlineAICompletion.js.map +1 -1
  286. package/dist/editor/page-viewer/DeviceToolbar.js +1 -1
  287. package/dist/editor/page-viewer/DeviceToolbar.js.map +1 -1
  288. package/dist/editor/page-viewer/EditorForm.js +11 -69
  289. package/dist/editor/page-viewer/EditorForm.js.map +1 -1
  290. package/dist/editor/page-viewer/MiniMap.d.ts +4 -2
  291. package/dist/editor/page-viewer/MiniMap.js +28 -91
  292. package/dist/editor/page-viewer/MiniMap.js.map +1 -1
  293. package/dist/editor/page-viewer/PageViewer.d.ts +1 -3
  294. package/dist/editor/page-viewer/PageViewer.js +19 -92
  295. package/dist/editor/page-viewer/PageViewer.js.map +1 -1
  296. package/dist/editor/page-viewer/PageViewerFrame.d.ts +1 -2
  297. package/dist/editor/page-viewer/PageViewerFrame.js +115 -348
  298. package/dist/editor/page-viewer/PageViewerFrame.js.map +1 -1
  299. package/dist/editor/page-viewer/pageModelSkeletonBuilder.js +49 -114
  300. package/dist/editor/page-viewer/pageModelSkeletonBuilder.js.map +1 -1
  301. package/dist/editor/page-viewer/pageViewContext.d.ts +0 -1
  302. package/dist/editor/page-viewer/pageViewContext.js +14 -51
  303. package/dist/editor/page-viewer/pageViewContext.js.map +1 -1
  304. package/dist/editor/pageModel.d.ts +1 -14
  305. package/dist/editor/reviews/Comment.js +12 -26
  306. package/dist/editor/reviews/Comment.js.map +1 -1
  307. package/dist/editor/reviews/CommentDisplayPopover.js +5 -7
  308. package/dist/editor/reviews/CommentDisplayPopover.js.map +1 -1
  309. package/dist/editor/reviews/CommentView.js +4 -19
  310. package/dist/editor/reviews/CommentView.js.map +1 -1
  311. package/dist/editor/reviews/Comments.js +72 -89
  312. package/dist/editor/reviews/Comments.js.map +1 -1
  313. package/dist/editor/reviews/CreateReviewDialog.js +177 -281
  314. package/dist/editor/reviews/CreateReviewDialog.js.map +1 -1
  315. package/dist/editor/reviews/DecisionsMatrix.js +25 -96
  316. package/dist/editor/reviews/DecisionsMatrix.js.map +1 -1
  317. package/dist/editor/reviews/DiffView.js +14 -7
  318. package/dist/editor/reviews/DiffView.js.map +1 -1
  319. package/dist/editor/reviews/EditReviewSettingsDialog.js +4 -6
  320. package/dist/editor/reviews/EditReviewSettingsDialog.js.map +1 -1
  321. package/dist/editor/reviews/MultiReviewManager.js +3 -25
  322. package/dist/editor/reviews/MultiReviewManager.js.map +1 -1
  323. package/dist/editor/reviews/PagesPanel.js +15 -31
  324. package/dist/editor/reviews/PagesPanel.js.map +1 -1
  325. package/dist/editor/reviews/PreviewInfo.js +4 -1
  326. package/dist/editor/reviews/PreviewInfo.js.map +1 -1
  327. package/dist/editor/reviews/ReviewCard.js +7 -13
  328. package/dist/editor/reviews/ReviewCard.js.map +1 -1
  329. package/dist/editor/reviews/ReviewDetail.js +2 -3
  330. package/dist/editor/reviews/ReviewDetail.js.map +1 -1
  331. package/dist/editor/reviews/ReviewsList.js +3 -7
  332. package/dist/editor/reviews/ReviewsList.js.map +1 -1
  333. package/dist/editor/reviews/SuggestedEdit.js +3 -34
  334. package/dist/editor/reviews/SuggestedEdit.js.map +1 -1
  335. package/dist/editor/reviews/SuggestionDisplayPopover.js +5 -31
  336. package/dist/editor/reviews/SuggestionDisplayPopover.js.map +1 -1
  337. package/dist/editor/reviews/commentAi.js +6 -25
  338. package/dist/editor/reviews/commentAi.js.map +1 -1
  339. package/dist/editor/reviews/reviewCommands.js +1 -4
  340. package/dist/editor/reviews/reviewCommands.js.map +1 -1
  341. package/dist/editor/reviews/useMultiReview.js +2 -2
  342. package/dist/editor/reviews/useMultiReview.js.map +1 -1
  343. package/dist/editor/reviews/useReviews.d.ts +2 -2
  344. package/dist/editor/reviews/useReviews.js +30 -12
  345. package/dist/editor/reviews/useReviews.js.map +1 -1
  346. package/dist/editor/services/agentService.d.ts +5 -229
  347. package/dist/editor/services/agentService.js +39 -292
  348. package/dist/editor/services/agentService.js.map +1 -1
  349. package/dist/editor/services/aiService.d.ts +1 -57
  350. package/dist/editor/services/aiService.js +6 -79
  351. package/dist/editor/services/aiService.js.map +1 -1
  352. package/dist/editor/services/contentService.d.ts +3 -6
  353. package/dist/editor/services/contentService.js +12 -13
  354. package/dist/editor/services/contentService.js.map +1 -1
  355. package/dist/editor/services/editService.d.ts +1 -52
  356. package/dist/editor/services/editService.js +2 -94
  357. package/dist/editor/services/editService.js.map +1 -1
  358. package/dist/editor/services/indexService.js +1 -1
  359. package/dist/editor/services/indexService.js.map +1 -1
  360. package/dist/editor/services/reviewsService.d.ts +6 -3
  361. package/dist/editor/services/reviewsService.js +11 -2
  362. package/dist/editor/services/reviewsService.js.map +1 -1
  363. package/dist/editor/services/serviceHelper.d.ts +1 -2
  364. package/dist/editor/services/serviceHelper.js +20 -112
  365. package/dist/editor/services/serviceHelper.js.map +1 -1
  366. package/dist/editor/services/systemService.d.ts +1 -2
  367. package/dist/editor/services/systemService.js +0 -3
  368. package/dist/editor/services/systemService.js.map +1 -1
  369. package/dist/editor/services-server/api.d.ts +2 -1
  370. package/dist/editor/services-server/api.js +6 -11
  371. package/dist/editor/services-server/api.js.map +1 -1
  372. package/dist/editor/services-server/graphQL.d.ts +29 -0
  373. package/dist/editor/services-server/graphQL.js +53 -0
  374. package/dist/editor/services-server/graphQL.js.map +1 -0
  375. package/dist/editor/settings/About.js +3 -317
  376. package/dist/editor/settings/About.js.map +1 -1
  377. package/dist/editor/settings/AllAgentsPanel.d.ts +5 -0
  378. package/dist/editor/settings/AllAgentsPanel.js +139 -0
  379. package/dist/editor/settings/AllAgentsPanel.js.map +1 -0
  380. package/dist/editor/settings/LatestFeedback.d.ts +1 -0
  381. package/dist/editor/settings/LatestFeedback.js +136 -0
  382. package/dist/editor/settings/LatestFeedback.js.map +1 -0
  383. package/dist/editor/settings/QuotaInfo.js +4 -210
  384. package/dist/editor/settings/QuotaInfo.js.map +1 -1
  385. package/dist/editor/settings/SettingsView.js +23 -25
  386. package/dist/editor/settings/SettingsView.js.map +1 -1
  387. package/dist/editor/settings/Setup.d.ts +1 -0
  388. package/dist/editor/settings/Setup.js +211 -0
  389. package/dist/editor/settings/Setup.js.map +1 -0
  390. package/dist/editor/settings/Status.js +6 -7
  391. package/dist/editor/settings/Status.js.map +1 -1
  392. package/dist/editor/settings/index/useIndexStatus.js +22 -20
  393. package/dist/editor/settings/index/useIndexStatus.js.map +1 -1
  394. package/dist/editor/settings/panels/AgentsPanel.d.ts +4 -0
  395. package/dist/editor/settings/panels/AgentsPanel.js +121 -95
  396. package/dist/editor/settings/panels/AgentsPanel.js.map +1 -1
  397. package/dist/editor/settings/panels/DatabasePanel.d.ts +6 -0
  398. package/dist/editor/settings/panels/DatabasePanel.js +50 -0
  399. package/dist/editor/settings/panels/DatabasePanel.js.map +1 -0
  400. package/dist/editor/settings/panels/ModelsPanel.js +108 -329
  401. package/dist/editor/settings/panels/ModelsPanel.js.map +1 -1
  402. package/dist/editor/settings/panels/ProvidersPanel.d.ts +1 -1
  403. package/dist/editor/settings/panels/ProvidersPanel.js +59 -86
  404. package/dist/editor/settings/panels/ProvidersPanel.js.map +1 -1
  405. package/dist/editor/settings/panels/SearchConfigPanel.js +4 -4
  406. package/dist/editor/settings/panels/SearchConfigPanel.js.map +1 -1
  407. package/dist/editor/settings/panels/index.d.ts +2 -3
  408. package/dist/editor/settings/panels/index.js +2 -3
  409. package/dist/editor/settings/panels/index.js.map +1 -1
  410. package/dist/editor/settings/setup-steps/AiSetupStep/EmbeddingsModelSection.d.ts +2 -0
  411. package/dist/editor/settings/setup-steps/AiSetupStep/EmbeddingsModelSection.js +195 -0
  412. package/dist/editor/settings/setup-steps/AiSetupStep/EmbeddingsModelSection.js.map +1 -0
  413. package/dist/editor/settings/setup-steps/AiSetupStep/index.d.ts +2 -0
  414. package/dist/editor/settings/setup-steps/AiSetupStep/index.js +21 -0
  415. package/dist/editor/settings/setup-steps/AiSetupStep/index.js.map +1 -0
  416. package/dist/editor/settings/setup-steps/AiSetupStep/provider/ProviderSection.d.ts +1 -0
  417. package/dist/editor/settings/setup-steps/AiSetupStep/provider/ProviderSection.js +233 -0
  418. package/dist/editor/settings/setup-steps/AiSetupStep/provider/ProviderSection.js.map +1 -0
  419. package/dist/editor/settings/setup-steps/AiSetupStep/required-containers/RequiredContainersList.d.ts +15 -0
  420. package/dist/editor/settings/setup-steps/AiSetupStep/required-containers/RequiredContainersList.js +14 -0
  421. package/dist/editor/settings/setup-steps/AiSetupStep/required-containers/RequiredContainersList.js.map +1 -0
  422. package/dist/editor/settings/setup-steps/AiSetupStep/required-containers/RequiredContainersSection.d.ts +1 -0
  423. package/dist/editor/settings/setup-steps/AiSetupStep/required-containers/RequiredContainersSection.js +94 -0
  424. package/dist/editor/settings/setup-steps/AiSetupStep/required-containers/RequiredContainersSection.js.map +1 -0
  425. package/dist/editor/settings/setup-steps/AiSetupStep/types.d.ts +1 -0
  426. package/dist/editor/settings/setup-steps/AiSetupStep/types.js +2 -0
  427. package/dist/editor/settings/setup-steps/AiSetupStep/types.js.map +1 -0
  428. package/dist/editor/settings/setup-steps/AiSetupStep/utils.d.ts +5 -0
  429. package/dist/editor/settings/setup-steps/AiSetupStep/utils.js +44 -0
  430. package/dist/editor/settings/setup-steps/AiSetupStep/utils.js.map +1 -0
  431. package/dist/editor/settings/setup-steps/IndexSetupStep.d.ts +2 -0
  432. package/dist/editor/settings/setup-steps/IndexSetupStep.js +36 -0
  433. package/dist/editor/settings/setup-steps/IndexSetupStep.js.map +1 -0
  434. package/dist/editor/settings/setup-steps/SettingsSetupStep.d.ts +2 -0
  435. package/dist/editor/settings/setup-steps/SettingsSetupStep.js +111 -0
  436. package/dist/editor/settings/setup-steps/SettingsSetupStep.js.map +1 -0
  437. package/dist/editor/settings/setup-steps/SetupOverview.d.ts +14 -0
  438. package/dist/editor/settings/setup-steps/SetupOverview.js +38 -0
  439. package/dist/editor/settings/setup-steps/SetupOverview.js.map +1 -0
  440. package/dist/editor/settings/status/coreStatusChecks.js +19 -124
  441. package/dist/editor/settings/status/coreStatusChecks.js.map +1 -1
  442. package/dist/editor/settings/status/useStartupChecks.d.ts +1 -3
  443. package/dist/editor/settings/status/useStartupChecks.js +5 -9
  444. package/dist/editor/settings/status/useStartupChecks.js.map +1 -1
  445. package/dist/editor/setup-wizard/steps/CompleteStep.d.ts +1 -2
  446. package/dist/editor/setup-wizard/steps/CompleteStep.js +1 -2
  447. package/dist/editor/setup-wizard/steps/CompleteStep.js.map +1 -1
  448. package/dist/editor/sidebar/ComponentPalette.js +1 -2
  449. package/dist/editor/sidebar/ComponentPalette.js.map +1 -1
  450. package/dist/editor/sidebar/ComponentTree.d.ts +1 -8
  451. package/dist/editor/sidebar/ComponentTree.js +69 -216
  452. package/dist/editor/sidebar/ComponentTree.js.map +1 -1
  453. package/dist/editor/sidebar/Debug.d.ts +1 -0
  454. package/dist/editor/sidebar/Debug.js +70 -0
  455. package/dist/editor/sidebar/Debug.js.map +1 -0
  456. package/dist/editor/sidebar/EditHistory.js +46 -22
  457. package/dist/editor/sidebar/EditHistory.js.map +1 -1
  458. package/dist/editor/sidebar/Favorites.js +8 -4
  459. package/dist/editor/sidebar/Favorites.js.map +1 -1
  460. package/dist/editor/sidebar/GraphQL.d.ts +2 -0
  461. package/dist/editor/sidebar/GraphQL.js +234 -0
  462. package/dist/editor/sidebar/GraphQL.js.map +1 -0
  463. package/dist/editor/sidebar/LeftToolbar.d.ts +1 -0
  464. package/dist/editor/sidebar/LeftToolbar.js +12 -0
  465. package/dist/editor/sidebar/LeftToolbar.js.map +1 -0
  466. package/dist/editor/sidebar/MainContentTree.js +3 -4
  467. package/dist/editor/sidebar/MainContentTree.js.map +1 -1
  468. package/dist/editor/sidebar/NavigationSidebar.d.ts +4 -0
  469. package/dist/editor/sidebar/NavigationSidebar.js +254 -0
  470. package/dist/editor/sidebar/NavigationSidebar.js.map +1 -0
  471. package/dist/editor/sidebar/OperationItem.js +7 -21
  472. package/dist/editor/sidebar/OperationItem.js.map +1 -1
  473. package/dist/editor/sidebar/SidebarPanel.d.ts +1 -3
  474. package/dist/editor/sidebar/SidebarPanel.js +12 -44
  475. package/dist/editor/sidebar/SidebarPanel.js.map +1 -1
  476. package/dist/editor/sidebar/SidebarStack.d.ts +1 -2
  477. package/dist/editor/sidebar/SidebarStack.js +3 -4
  478. package/dist/editor/sidebar/SidebarStack.js.map +1 -1
  479. package/dist/editor/sidebar/Validation.js +12 -22
  480. package/dist/editor/sidebar/Validation.js.map +1 -1
  481. package/dist/editor/sidebar/Workbox.js +3 -53
  482. package/dist/editor/sidebar/Workbox.js.map +1 -1
  483. package/dist/editor/sidebar/WorkspaceRail.d.ts +1 -0
  484. package/dist/editor/sidebar/WorkspaceRail.js +167 -56
  485. package/dist/editor/sidebar/WorkspaceRail.js.map +1 -1
  486. package/dist/editor/tree-indicators/GutterColumns.d.ts +1 -3
  487. package/dist/editor/tree-indicators/GutterColumns.js +5 -26
  488. package/dist/editor/tree-indicators/GutterColumns.js.map +1 -1
  489. package/dist/editor/tree-indicators/GutterContext.d.ts +0 -4
  490. package/dist/editor/tree-indicators/GutterContext.js +0 -23
  491. package/dist/editor/tree-indicators/GutterContext.js.map +1 -1
  492. package/dist/editor/tree-indicators/GutterSelector.d.ts +5 -0
  493. package/dist/editor/tree-indicators/GutterSelector.js +91 -0
  494. package/dist/editor/tree-indicators/GutterSelector.js.map +1 -0
  495. package/dist/editor/tree-indicators/index.d.ts +1 -0
  496. package/dist/editor/tree-indicators/index.js +1 -0
  497. package/dist/editor/tree-indicators/index.js.map +1 -1
  498. package/dist/editor/tree-indicators/types.d.ts +1 -12
  499. package/dist/editor/ui/CopyMoveTargetSelectorDialog.js +1 -1
  500. package/dist/editor/ui/CopyMoveTargetSelectorDialog.js.map +1 -1
  501. package/dist/editor/ui/Icons.js +1 -1
  502. package/dist/editor/ui/Icons.js.map +1 -1
  503. package/dist/editor/ui/ItemNameDialogNew.d.ts +0 -2
  504. package/dist/editor/ui/ItemNameDialogNew.js +17 -33
  505. package/dist/editor/ui/ItemNameDialogNew.js.map +1 -1
  506. package/dist/editor/ui/ItemSearch.js +11 -7
  507. package/dist/editor/ui/ItemSearch.js.map +1 -1
  508. package/dist/editor/ui/SimpleIconButton.js +1 -1
  509. package/dist/editor/ui/SimpleIconButton.js.map +1 -1
  510. package/dist/editor/ui/SimpleTabs.d.ts +0 -1
  511. package/dist/editor/ui/SimpleTabs.js +25 -45
  512. package/dist/editor/ui/SimpleTabs.js.map +1 -1
  513. package/dist/editor/ui/Splitter.d.ts +0 -1
  514. package/dist/editor/ui/Splitter.js +86 -102
  515. package/dist/editor/ui/Splitter.js.map +1 -1
  516. package/dist/editor/ui/TemplateSelectorDialog.js +4 -4
  517. package/dist/editor/ui/TemplateSelectorDialog.js.map +1 -1
  518. package/dist/editor/ui/TreeListSelector.d.ts +1 -6
  519. package/dist/editor/ui/TreeListSelector.js +2 -2
  520. package/dist/editor/ui/TreeListSelector.js.map +1 -1
  521. package/dist/editor/utils/keyboardNavigation.d.ts +20 -6
  522. package/dist/editor/utils/keyboardNavigation.js +140 -48
  523. package/dist/editor/utils/keyboardNavigation.js.map +1 -1
  524. package/dist/editor/utils.js +9 -19
  525. package/dist/editor/utils.js.map +1 -1
  526. package/dist/editor/views/CompareView.d.ts +1 -3
  527. package/dist/editor/views/CompareView.js +5 -7
  528. package/dist/editor/views/CompareView.js.map +1 -1
  529. package/dist/editor/views/EditView.js +1 -1
  530. package/dist/editor/views/EditView.js.map +1 -1
  531. package/dist/editor/views/EditorSlot.js +34 -27
  532. package/dist/editor/views/EditorSlot.js.map +1 -1
  533. package/dist/editor/views/ItemEditor.js +3 -7
  534. package/dist/editor/views/ItemEditor.js.map +1 -1
  535. package/dist/editor/views/MediaFolderEditView.js +1 -1
  536. package/dist/editor/views/MediaFolderEditView.js.map +1 -1
  537. package/dist/editor/views/ParheliaView.js +6 -5
  538. package/dist/editor/views/ParheliaView.js.map +1 -1
  539. package/dist/editor/views/SingleEditView.d.ts +1 -2
  540. package/dist/editor/views/SingleEditView.js +8 -10
  541. package/dist/editor/views/SingleEditView.js.map +1 -1
  542. package/dist/editor/views/editorSlotContext.js +6 -35
  543. package/dist/editor/views/editorSlotContext.js.map +1 -1
  544. package/dist/index.d.ts +2 -16
  545. package/dist/index.js +0 -11
  546. package/dist/index.js.map +1 -1
  547. package/dist/revision.d.ts +2 -2
  548. package/dist/revision.js +2 -2
  549. package/dist/setup/services/setupWizardService.d.ts +13 -40
  550. package/dist/setup/services/setupWizardService.js +17 -32
  551. package/dist/setup/services/setupWizardService.js.map +1 -1
  552. package/dist/setup/wizard/steps/AddModelDialog.js +3 -12
  553. package/dist/setup/wizard/steps/AddModelDialog.js.map +1 -1
  554. package/dist/setup/wizard/steps/ImportModelDialog.js +22 -39
  555. package/dist/setup/wizard/steps/ImportModelDialog.js.map +1 -1
  556. package/dist/splash-screen/ModernSplashScreen.js +32 -112
  557. package/dist/splash-screen/ModernSplashScreen.js.map +1 -1
  558. package/dist/splash-screen/NewPage.js +50 -33
  559. package/dist/splash-screen/NewPage.js.map +1 -1
  560. package/dist/splash-screen/OpenPage.js +6 -2
  561. package/dist/splash-screen/OpenPage.js.map +1 -1
  562. package/dist/splash-screen/ParheliaAssistantChat.js +29 -12
  563. package/dist/splash-screen/ParheliaAssistantChat.js.map +1 -1
  564. package/dist/splash-screen/ParheliaLogo.js +37 -87
  565. package/dist/splash-screen/ParheliaLogo.js.map +1 -1
  566. package/dist/splash-screen/RecentPages.js +3 -3
  567. package/dist/splash-screen/RecentPages.js.map +1 -1
  568. package/dist/tour/Tour.d.ts +1 -2
  569. package/dist/tour/Tour.js +75 -256
  570. package/dist/tour/Tour.js.map +1 -1
  571. package/dist/tour/default-tour.js +96 -222
  572. package/dist/tour/default-tour.js.map +1 -1
  573. package/dist/types.d.ts +29 -63
  574. package/package.json +15 -19
  575. package/styles.css +10 -14
@@ -1,17 +1,15 @@
1
1
  "use client";
2
- import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
3
  import React, { useState, useEffect, useRef, useCallback, useSyncExternalStore, useMemo, startTransition, } from "react";
4
4
  import { toast } from "sonner";
5
- import { EditContextProvider, FieldsEditContextProvider, OperationsContextProvider, useEditContext, } from "./editContext";
5
+ import { EditContextProvider, FieldsEditContextProvider, OperationsContextProvider, } from "./editContext";
6
6
  import { fieldModificationStore } from "./fieldModificationStore";
7
- import { useRouter, useSearchParams, usePathname } from "./navigation";
7
+ import { useRouter, useSearchParams, usePathname } from "next/navigation";
8
8
  import { findComponent, getComponentById } from "../componentTreeHelper";
9
9
  import { getOperationsContext } from "./operations";
10
10
  import { handleErrorResult } from "./helpers";
11
- import { executeFieldAction as executeFieldServerAction, connectSocket, getEditHistory, getRunningOperations, reconnectSession, releaseFieldLocks, validateItems, } from "../services/editService";
11
+ import { executeFieldAction as executeFieldServerAction, connectSocket, getEditHistory, getRunningOperations, releaseFieldLocks, validateItems, } from "../services/editService";
12
12
  import { useEditorWebSocket } from "./hooks/useEditorWebSocket";
13
- import { createEditorSocketDiagnostics, } from "./socketDiagnostics";
14
- import { localStorageService } from "../services/localStorageService";
15
13
  import { useSocketMessageHandler } from "./hooks/useSocketMessageHandler";
16
14
  import "react-json-view-lite/dist/index.css";
17
15
  import { MediaSelector, } from "../media-selector/MediaSelector";
@@ -22,7 +20,6 @@ import { getItemDescriptor } from "../utils";
22
20
  import { EditContextMenu } from "../ContextMenu";
23
21
  import { InlineAiTrigger } from "../ai/InlineAiTrigger";
24
22
  import { FieldEditorPopup } from "../FieldEditorPopup";
25
- import { ConcurrentUserLimitDialog } from "../ConcurrentUserLimitDialog";
26
23
  import { post } from "../services/serviceHelper";
27
24
  import { PageViewerFrame } from "../page-viewer/PageViewerFrame";
28
25
  import { useItemsRepository } from "./itemsRepository";
@@ -36,7 +33,6 @@ import { GuidanceOverlay } from "../ai/GuidanceOverlay";
36
33
  import { AgentDialogHandler } from "../ai/dialogs";
37
34
  import { usePageViewContext, } from "../page-viewer/pageViewContext";
38
35
  import { QuickItemSwitcher } from "../QuickItemSwitcher";
39
- import { useEditorSlotContext, } from "../views/editorSlotContext";
40
36
  import { getComments, getAvailableCommentTags, } from "../services/reviewsService";
41
37
  import { useReviews } from "../reviews/useReviews";
42
38
  import uuid from "react-uuid";
@@ -53,33 +49,7 @@ import { useWorkbox } from "./hooks/useWorkbox";
53
49
  import { useMediaSelector } from "./hooks/useMediaSelector";
54
50
  import { useGlobalEditorKeyDown } from "./hooks/useGlobalEditorKeyDown";
55
51
  import { useStartupChecks } from "../settings/status/index";
56
- import { FeatureGate, LicenseFeatures, LicenseProvider, LicenseOverlay, } from "../../licensing";
57
- function AgentsSlotContextBridge({ slot }) {
58
- const editContext = useEditContext();
59
- const slotContext = useEditorSlotContext({
60
- slotId: slot.slotId,
61
- itemDescriptor: slot.itemDescriptor,
62
- refreshToken: slot.refreshToken,
63
- });
64
- if (!editContext || !slotContext)
65
- return null;
66
- useEffect(() => {
67
- editContext.registerSlotContext(slot.slotId, slotContext);
68
- return () => {
69
- editContext.unregisterSlotContext(slot.slotId);
70
- };
71
- }, [
72
- slot.slotId,
73
- slotContext,
74
- editContext.registerSlotContext,
75
- editContext.unregisterSlotContext,
76
- ]);
77
- return null;
78
- }
79
- function AgentsSlotContextBridgeHost({ slots }) {
80
- return (_jsx(_Fragment, { children: slots.map((slot) => (_jsx(AgentsSlotContextBridge, { slot: slot }, `agents-slot-bridge-${slot.slotId}`))) }));
81
- }
82
- export function EditorShell({ configuration, className, item: loadItemDescriptor, sessionId, userInfo, userPreferences, initialLicenseStatus, initialLicenseStatusLoaded, parheliaSettings, setUserPreferences, children, }) {
52
+ export function EditorShell({ configuration, className, item: loadItemDescriptor, sessionId, userInfo, userPreferences, parheliaSettings, setUserPreferences, children, }) {
83
53
  const router = useRouter();
84
54
  const pathname = usePathname();
85
55
  const searchParams = useSearchParams();
@@ -127,7 +97,6 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
127
97
  const [historyMode, setHistoryMode] = useState("global");
128
98
  const [showOnlyMyChanges, setShowOnlyMyChanges] = useState(true);
129
99
  const [filterByCurrentLanguage, setFilterByCurrentLanguage] = useState(true);
130
- const [historySearchQuery, setHistorySearchQuery] = useState("");
131
100
  const [recentEdits, setRecentEdits] = useState([]);
132
101
  const addRecentEdit = useCallback((edit) => {
133
102
  setRecentEdits((prevEditedFields) => {
@@ -155,14 +124,14 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
155
124
  if (typeof window !== "undefined")
156
125
  sessionStorage?.setItem("sessionId", sessionId);
157
126
  // Workspace state
158
- // Note: "reviews" is a sidebar, not a workspace. If workspace=reviews, we should
127
+ // Note: "reviews" is a sidebar, not a workspace. If view/workspace=reviews, we should
159
128
  // set workspace to "editor" and open the reviews sidebar instead.
160
129
  // Memoize searchParams reads to avoid triggering Router state updates during render
161
130
  // (Next.js App Router uses startTransition internally for URL changes)
162
- const rawWorkspace = useMemo(() => searchParams.get("workspace"), [searchParams]);
131
+ const rawWorkspace = useMemo(() => searchParams.get("workspace") ?? searchParams.get("view"), [searchParams]);
163
132
  const isReviewsSidebarRequest = rawWorkspace === "reviews";
164
133
  const [workspaceId, setWorkspaceId] = useState(
165
- // If workspace=reviews, use "editor" workspace (reviews is a sidebar, not a workspace)
134
+ // If view=reviews, use "editor" workspace (reviews is a sidebar, not a workspace)
166
135
  isReviewsSidebarRequest
167
136
  ? "editor"
168
137
  : (rawWorkspace ??
@@ -184,7 +153,7 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
184
153
  else {
185
154
  sidebars = [...(configuration.editor.defaultOpenSidebars ?? [])];
186
155
  }
187
- // If workspace=reviews was requested, ensure reviews sidebar is open
156
+ // If view/workspace=reviews was requested, ensure reviews sidebar is open
188
157
  if (isReviewsSidebarRequest && !sidebars.includes("reviews")) {
189
158
  sidebars.push("reviews");
190
159
  }
@@ -192,11 +161,17 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
192
161
  });
193
162
  // Toolbar pinned sidebars - icons always visible in toolbar (defined early so callbacks can access)
194
163
  const [pinnedSidebars, setPinnedSidebars] = useState(userInfo.preferences?.pinnedSidebars || []);
195
- const pinnedSidebarsRef = useRef(pinnedSidebars);
196
164
  // Locked sidebars - open panels that stay visible when selecting another sidebar
197
165
  const [lockedSidebars, setLockedSidebars] = useState(() => {
166
+ if (typeof window === "undefined") {
167
+ return [];
168
+ }
198
169
  try {
199
- const parsed = localStorageService.getOrSetItem("editor.lockedSidebars", []);
170
+ const stored = window.localStorage.getItem("editor.lockedSidebars");
171
+ if (!stored) {
172
+ return [];
173
+ }
174
+ const parsed = JSON.parse(stored);
200
175
  if (!Array.isArray(parsed) ||
201
176
  !parsed.every((id) => typeof id === "string")) {
202
177
  return [];
@@ -212,9 +187,6 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
212
187
  useEffect(() => {
213
188
  lockedSidebarsRef.current = lockedSidebars;
214
189
  }, [lockedSidebars]);
215
- useEffect(() => {
216
- pinnedSidebarsRef.current = pinnedSidebars;
217
- }, [pinnedSidebars]);
218
190
  // Filter locked sidebars to only include currently open sidebars
219
191
  useEffect(() => {
220
192
  const openSet = new Set(openSidebars);
@@ -276,11 +248,15 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
276
248
  // Group open sidebars into vertical stacks (each stack shares one left column).
277
249
  const [sidebarStacks, setSidebarStacks] = useState(() => {
278
250
  const defaultStacks = openSidebars.map((id) => [id]);
251
+ if (typeof window === "undefined") {
252
+ return normalizeSidebarStacks(openSidebars, defaultStacks);
253
+ }
279
254
  try {
280
- const parsed = localStorageService.getItem("editor.sidebarStacks");
281
- if (!parsed) {
255
+ const stored = window.localStorage.getItem("editor.sidebarStacks");
256
+ if (!stored) {
282
257
  return normalizeSidebarStacks(openSidebars, defaultStacks);
283
258
  }
259
+ const parsed = JSON.parse(stored);
284
260
  if (!Array.isArray(parsed) ||
285
261
  !parsed.every((x) => Array.isArray(x) && x.every((id) => typeof id === "string"))) {
286
262
  return normalizeSidebarStacks(openSidebars, defaultStacks);
@@ -302,19 +278,28 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
302
278
  }, [openSidebars, normalizeSidebarStacks]);
303
279
  // Persist stacks independently of the URL (user layout preference).
304
280
  useEffect(() => {
281
+ if (typeof window === "undefined")
282
+ return;
305
283
  try {
306
- localStorageService.setItem("editor.sidebarStacks", sidebarStacks);
284
+ window.localStorage.setItem("editor.sidebarStacks", JSON.stringify(sidebarStacks));
307
285
  }
308
286
  catch { }
309
287
  }, [sidebarStacks]);
310
288
  // Persist locked sidebars to localStorage.
311
289
  useEffect(() => {
290
+ if (typeof window === "undefined")
291
+ return;
312
292
  try {
313
- localStorageService.setItem("editor.lockedSidebars", lockedSidebars);
293
+ window.localStorage.setItem("editor.lockedSidebars", JSON.stringify(lockedSidebars));
314
294
  }
315
295
  catch { }
316
296
  }, [lockedSidebars]);
297
+ // Legacy aliases for backwards compatibility
317
298
  const viewName = workspaceId;
299
+ const setViewName = setWorkspaceId;
300
+ const viewNameRef = workspaceIdRef;
301
+ const previousViewName = previousWorkspaceId;
302
+ const setPreviousViewName = setPreviousWorkspaceId;
318
303
  const [compareMode, setCompareModeState] = useState(false);
319
304
  const [componentDesignerComponent, setComponentDesignerComponent] = useState();
320
305
  const [componentDesignerRendering, setComponentDesignerRendering] = useState();
@@ -341,29 +326,6 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
341
326
  activeSlotIdRef.current = activeSlotId;
342
327
  }, [activeSlotId]);
343
328
  const [slotContexts, setSlotContexts] = useState(() => new Map());
344
- const promptSessionReconnect = useCallback((reason) => {
345
- const description = reason && reason !== "session-revoked"
346
- ? `${reason}. Click reconnect to continue in this browser.`
347
- : "You were disconnected because this account is active in another browser.";
348
- toast.error("Session disconnected", {
349
- id: "session-revoked",
350
- description,
351
- action: {
352
- label: "Reconnect",
353
- onClick: async () => {
354
- const result = await reconnectSession(sessionId);
355
- if (result.type === "success") {
356
- window.location.reload();
357
- return;
358
- }
359
- toast.error("Reconnect failed", {
360
- description: "Could not claim this browser session. Try again.",
361
- });
362
- },
363
- },
364
- duration: Infinity,
365
- });
366
- }, [sessionId]);
367
329
  // Track previous item ID to detect actual navigation between pages
368
330
  const previousItemIdRef = useRef(undefined);
369
331
  useEffect(() => {
@@ -392,9 +354,6 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
392
354
  // Ref to track when we're handling a popstate event (browser back/forward)
393
355
  // This prevents the URL sync effect from pushing new history entries during back navigation
394
356
  const isHandlingPopStateRef = useRef(false);
395
- // When switchWorkspace already pushed a URL entry, the follow-up URL sync
396
- // effect should only *replace* that entry (not push a second one).
397
- const switchWorkspacePushedRef = useRef(false);
398
357
  // Ref to track the last known URL for the popstate handler
399
358
  // This is updated both when the popstate handler runs AND when the URL sync effect pushes a new URL
400
359
  // Without this, the popstate handler would have a stale lastUrl value after pushState calls
@@ -411,16 +370,26 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
411
370
  const [showSuggestedEditsDiff, setShowSuggestedEditsDiff] = useState(false);
412
371
  const [availableCommentTags, setAvailableCommentTags] = useState([]);
413
372
  const [showComments, setShowComments] = useState(() => {
414
- return localStorageService.getOrSetItem("editor.showComments", true);
373
+ const savedShowComments = typeof window !== "undefined"
374
+ ? localStorage.getItem("editor.showComments")
375
+ : null;
376
+ return savedShowComments ? JSON.parse(savedShowComments) : true;
415
377
  });
416
378
  useEffect(() => {
417
- localStorageService.setItem("editor.showComments", showComments);
379
+ if (typeof window !== "undefined") {
380
+ localStorage.setItem("editor.showComments", JSON.stringify(showComments));
381
+ }
418
382
  }, [showComments]);
419
383
  const [showResolvedComments, setShowResolvedComments] = useState(() => {
420
- return localStorageService.getOrSetItem("editor.showResolvedComments", false);
384
+ const saved = typeof window !== "undefined"
385
+ ? localStorage.getItem("editor.showResolvedComments")
386
+ : null;
387
+ return saved ? JSON.parse(saved) : false;
421
388
  });
422
389
  useEffect(() => {
423
- localStorageService.setItem("editor.showResolvedComments", showResolvedComments);
390
+ if (typeof window !== "undefined") {
391
+ localStorage.setItem("editor.showResolvedComments", JSON.stringify(showResolvedComments));
392
+ }
424
393
  }, [showResolvedComments]);
425
394
  const [selectedComment, setSelectedComment] = useState();
426
395
  const [browseHistory, setBrowseHistory] = useState(() => {
@@ -439,12 +408,13 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
439
408
  visitedAt: entry.visitedAt,
440
409
  }));
441
410
  });
442
- // Navigation history for browser history (workspace + item combinations)
411
+ // Navigation history for browser history (view + item combinations)
443
412
  const [navigationHistory, setNavigationHistory] = useState(() => {
444
- // Initialize from browse history with the current workspace
413
+ // Initialize from browse history with current view
445
414
  if (!userInfo.browseHistory)
446
415
  return [];
447
416
  const defaultWorkspaceId = searchParams.get("workspace") ??
417
+ searchParams.get("view") ??
448
418
  configuration.editor.defaultWorkspace ??
449
419
  configuration.editor.workspaces?.[0]?.id ??
450
420
  "editor";
@@ -476,43 +446,20 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
476
446
  const [statusMessage, setStatusMessage] = useState("");
477
447
  const [focusFieldComponentId, setFocusFieldComponentId] = useState();
478
448
  const [enableCompletions, setEnableCompletions] = useState(false);
479
- const [showComponentNavigatorDefault, setShowComponentNavigatorDefault] = useState(userPreferences.showComponentNavigator ?? false);
480
- const [slotComponentNavigatorVisibility, setSlotComponentNavigatorVisibility] = useState({});
481
- useEffect(() => {
482
- setSlotComponentNavigatorVisibility((prev) => {
483
- const next = {};
484
- let changed = false;
485
- for (const slot of editorSlots) {
486
- if (Object.prototype.hasOwnProperty.call(prev, slot.slotId)) {
487
- next[slot.slotId] = prev[slot.slotId];
488
- }
489
- else {
490
- next[slot.slotId] = showComponentNavigatorDefault;
491
- changed = true;
492
- }
493
- }
494
- if (Object.keys(prev).length !== editorSlots.length) {
495
- changed = true;
496
- }
497
- return changed ? next : prev;
498
- });
499
- }, [editorSlots, showComponentNavigatorDefault]);
449
+ const [showComponentNavigator, setShowComponentNavigator] = useState(userPreferences.showComponentNavigator ?? false);
500
450
  const [showAgentsPanel, setShowAgentsPanel] = useState(userPreferences.showAgentsPanel ?? false);
501
451
  const [showMinimap, setShowMinimap] = useState(userPreferences.showMinimap ?? true);
502
452
  const [showHelpTerminal, setShowHelpTerminal] = useState(false);
503
453
  const [helpTerminalInitialPrompt, setHelpTerminalInitialPrompt] = useState(undefined);
504
454
  const [helpTerminalProfileName, setHelpTerminalProfileName] = useState(undefined);
505
455
  const [helpTerminalActiveTab, setHelpTerminalActiveTab] = useState(undefined);
506
- const [selectedHelpSectionId, setSelectedHelpSectionId] = useState(null);
507
- const [showAgentsWorkspaceEditor, setShowAgentsWorkspaceEditor] = useState(false);
508
- const [selectedAgentsWorkspaceAgentId, setSelectedAgentsWorkspaceAgentId] = useState(null);
456
+ const [showAgentsWorkspaceEditor, setShowAgentsWorkspaceEditor] = useState(true);
509
457
  const [activeEditorTab, setActiveEditorTab] = useState(null);
510
458
  const [showLayoutComponents, setShowLayoutComponents] = useState(userPreferences.showLayoutComponents ?? false);
511
459
  const { quotaInfo, setQuotaInfo, isQuotaExceeded, getQuotaWarningMessage } = useQuota({
512
460
  showError: ({ summary, details }) => showErrorToast({ summary, details }),
513
461
  });
514
462
  const [webSocketMessages, setWebSocketMessages] = useState([]);
515
- const [socketDiagnostics, setSocketDiagnostics] = useState(() => createEditorSocketDiagnostics(sessionId));
516
463
  const [favorites, setFavorites] = useState([]);
517
464
  // Quick item switcher state
518
465
  const [quickSwitcherVisible, setQuickSwitcherVisible] = useState(false);
@@ -530,12 +477,13 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
530
477
  if (!startupChecks.hasBlockingIssues)
531
478
  return;
532
479
  // Don't redirect if already in settings workspace - let user navigate freely within settings
533
- const currentWorkspace = searchParams.get("workspace");
480
+ const currentWorkspace = searchParams.get("workspace") ?? searchParams.get("view");
534
481
  if (currentWorkspace === "settings")
535
482
  return;
536
483
  // Redirect to the status panel (where user can see all issues and navigate to fixes)
537
484
  const url = new URL(window.location.href);
538
485
  url.searchParams.set("workspace", "settings");
486
+ url.searchParams.delete("view"); // Remove legacy param
539
487
  url.searchParams.set("ccpanel", "status");
540
488
  router.push(url.toString(), { scroll: false });
541
489
  }, [
@@ -553,16 +501,6 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
553
501
  setMode(queryMode);
554
502
  }
555
503
  }, [searchParams, isInitialLoad]);
556
- useEffect(() => {
557
- if (!isInitialLoad)
558
- return;
559
- const helpParam = searchParams.get("help");
560
- if (helpParam) {
561
- setHelpTerminalActiveTab("manual");
562
- setShowHelpTerminal(true);
563
- setSelectedHelpSectionId(helpParam === "contents" || helpParam === "true" ? null : helpParam);
564
- }
565
- }, [searchParams, isInitialLoad]);
566
504
  useEffect(() => {
567
505
  if (mode === "suggestions") {
568
506
  // Ensure we're in the editor workspace and open the feedback sidebar
@@ -609,19 +547,12 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
609
547
  setSlotContexts((prev) => {
610
548
  if (!prev.has(slotId))
611
549
  return prev;
612
- if (slotId === activeSlotIdRef.current) {
613
- const activeCtx = prev.get(slotId);
614
- if (activeCtx) {
615
- lastActiveSlotContextRef.current = activeCtx;
616
- }
617
- }
618
550
  const next = new Map(prev);
619
551
  next.delete(slotId);
620
552
  return next;
621
553
  });
622
554
  }, []);
623
555
  const slotContextsRef = useRef(slotContexts);
624
- const lastActiveSlotContextRef = useRef(null);
625
556
  useEffect(() => {
626
557
  slotContextsRef.current = slotContexts;
627
558
  }, [slotContexts]);
@@ -647,12 +578,6 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
647
578
  const activeSlotContext = activeSlotId
648
579
  ? slotContexts.get(activeSlotId)
649
580
  : undefined;
650
- const isComponentNavigatorOpenForSlot = useCallback((slotId) => {
651
- if (!slotId)
652
- return showComponentNavigatorDefault;
653
- return (slotComponentNavigatorVisibility[slotId] ?? showComponentNavigatorDefault);
654
- }, [slotComponentNavigatorVisibility, showComponentNavigatorDefault]);
655
- const showComponentNavigator = isComponentNavigatorOpenForSlot(activeSlotId);
656
581
  // Sync global compareMode from the active slot's compareMode for URL syncing
657
582
  useEffect(() => {
658
583
  if (activeSlotContext && activeSlotContext.compareMode !== compareMode) {
@@ -700,9 +625,6 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
700
625
  const isItemUsedInCurrentPage = useCallback((item) => pageItemsSetRef.current.has(makeItemKey(item)), [makeItemKey]);
701
626
  const socketMessageListeners = useRef(new Set());
702
627
  const [socketConnectionVersion, setSocketConnectionVersion] = useState(0);
703
- useEffect(() => {
704
- setSocketDiagnostics(createEditorSocketDiagnostics(sessionId));
705
- }, [sessionId]);
706
628
  const addSocketMessageListener = useCallback((callback) => {
707
629
  socketMessageListeners.current.add(callback);
708
630
  return () => socketMessageListeners.current.delete(callback);
@@ -787,13 +709,8 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
787
709
  console.error(`No workspace found for id: ${workspaceId}`);
788
710
  return null;
789
711
  }
790
- const activeKeyboardCommands = useMemo(() => {
791
- const activeCommandIds = new Set(currentWorkspace.keyboardCommandIds ?? []);
792
- return (configuration.commands.keyboardCommands ?? []).filter((command) => activeCommandIds.has(command.id));
793
- }, [
794
- currentWorkspace.keyboardCommandIds,
795
- configuration.commands.keyboardCommands,
796
- ]);
712
+ // Legacy alias for backwards compatibility
713
+ const currentView = currentWorkspace;
797
714
  useEffect(() => {
798
715
  if (currentWorkspace?.component) {
799
716
  setCenterPanelView(currentWorkspace.component);
@@ -830,59 +747,30 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
830
747
  const newUrl = `${window.location.pathname}?${params.toString()}`;
831
748
  window.history.replaceState(null, "", newUrl);
832
749
  }, [setIsTourActive]);
833
- const isMobile = useMediaQuery("(max-width: 767px)");
834
- // On mobile, clear all locked sidebars and keep only the last-opened panel.
835
- // Handles viewport resize: desktop -> mobile unlocks everything and trims to one panel.
836
- useEffect(() => {
837
- if (isMobile) {
838
- setLockedSidebars([]);
839
- const current = openSidebarsRef.current;
840
- const lastSidebar = current[current.length - 1];
841
- if (current.length > 1 && lastSidebar) {
842
- const trimmed = [lastSidebar];
843
- openSidebarsRef.current = trimmed;
844
- setOpenSidebars(trimmed);
845
- }
846
- }
847
- }, [isMobile]);
848
- const setComponentNavigatorOpenForSlot = useCallback((slotId, value) => {
849
- const previousValue = isComponentNavigatorOpenForSlot(slotId);
850
- const newValue = typeof value === "function" ? value(previousValue) : value;
851
- if (slotId) {
852
- setSlotComponentNavigatorVisibility((prev) => {
853
- const currentValue = prev[slotId] ?? showComponentNavigatorDefault;
854
- if (currentValue === newValue && prev[slotId] !== undefined) {
855
- return prev;
856
- }
857
- return {
858
- ...prev,
859
- [slotId]: newValue,
860
- };
861
- });
862
- }
863
- setShowComponentNavigatorDefault(newValue);
750
+ const isMobile = useMediaQuery("(max-width: 768px)");
751
+ const handleSetShowComponentNavigator = useCallback((value) => {
752
+ const newValue = typeof value === "function" ? value(showComponentNavigator) : value;
753
+ setShowComponentNavigator(newValue);
864
754
  setUserPreferences({ showComponentNavigator: newValue });
755
+ // On mobile, close Agents Panel when opening Component Navigator
865
756
  if (isMobile && newValue) {
866
757
  setShowAgentsPanel(false);
867
758
  setUserPreferences({ showAgentsPanel: false });
868
759
  }
869
760
  }, [
870
- isComponentNavigatorOpenForSlot,
871
- showComponentNavigatorDefault,
761
+ showComponentNavigator,
762
+ setShowComponentNavigator,
872
763
  setUserPreferences,
873
764
  isMobile,
874
765
  setShowAgentsPanel,
875
766
  ]);
876
- const handleSetShowComponentNavigator = useCallback((value) => {
877
- setComponentNavigatorOpenForSlot(activeSlotIdRef.current, value);
878
- }, [setComponentNavigatorOpenForSlot]);
879
767
  const handleSetShowAgentsPanel = useCallback((value) => {
880
768
  const newValue = typeof value === "function" ? value(showAgentsPanel) : value;
881
769
  setShowAgentsPanel(newValue);
882
770
  setUserPreferences({ showAgentsPanel: newValue });
883
771
  // On mobile, close Component Navigator when opening Agents Panel
884
772
  if (isMobile && newValue) {
885
- setComponentNavigatorOpenForSlot(activeSlotIdRef.current, false);
773
+ setShowComponentNavigator(false);
886
774
  setUserPreferences({ showComponentNavigator: false });
887
775
  }
888
776
  }, [
@@ -890,40 +778,8 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
890
778
  setShowAgentsPanel,
891
779
  setUserPreferences,
892
780
  isMobile,
893
- setComponentNavigatorOpenForSlot,
781
+ setShowComponentNavigator,
894
782
  ]);
895
- // Mobile editor panel state (EditorForm shown in bottom panel on mobile)
896
- const [mobileEditorPanelOpen, setMobileEditorPanelOpenRaw] = useState(false);
897
- const [dismissedMobilePanelToken, setDismissedMobilePanelToken] = useState(null);
898
- const previousActiveSlotIdRef = useRef(null);
899
- const mobilePanelDismissToken = useMemo(() => {
900
- const selectionKey = selection.join(",");
901
- return [
902
- activeSlotId || "no-slot",
903
- selectionKey,
904
- insertMode ? "insert" : "browse",
905
- ].join("|");
906
- }, [activeSlotId, insertMode, selection]);
907
- useEffect(() => {
908
- const previousActiveSlotId = previousActiveSlotIdRef.current;
909
- if (previousActiveSlotId !== activeSlotId) {
910
- setDismissedMobilePanelToken(null);
911
- }
912
- previousActiveSlotIdRef.current = activeSlotId;
913
- }, [activeSlotId]);
914
- const handleSetMobileEditorPanelOpen = useCallback((open) => {
915
- setMobileEditorPanelOpenRaw(open);
916
- if (!open) {
917
- setDismissedMobilePanelToken(mobilePanelDismissToken);
918
- return;
919
- }
920
- setDismissedMobilePanelToken(null);
921
- if (open && isMobile) {
922
- // Close all sidebars when opening the editor panel on mobile
923
- openSidebarsRef.current = [];
924
- setOpenSidebars([]);
925
- }
926
- }, [isMobile, mobilePanelDismissToken]);
927
783
  const handleSetShowMinimap = useCallback((value) => {
928
784
  const newValue = typeof value === "function" ? value(showMinimap) : value;
929
785
  setShowMinimap(newValue);
@@ -937,7 +793,6 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
937
793
  setHelpTerminalInitialPrompt(undefined);
938
794
  setHelpTerminalProfileName(undefined);
939
795
  setHelpTerminalActiveTab(undefined);
940
- setSelectedHelpSectionId(null);
941
796
  }
942
797
  }, [showHelpTerminal]);
943
798
  const toggleHelpTerminal = useCallback((options) => {
@@ -980,27 +835,13 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
980
835
  setOpenSidebars(newOrder);
981
836
  setSidebarStacks((prev) => normalizeSidebarStacks(newOrder, prev));
982
837
  }, []);
983
- const ensureSidebarPinned = useCallback((sidebarId) => {
984
- const currentPinnedSidebars = pinnedSidebarsRef.current;
985
- if (currentPinnedSidebars.includes(sidebarId)) {
986
- return;
987
- }
988
- const newPinnedSidebars = [...currentPinnedSidebars, sidebarId];
989
- pinnedSidebarsRef.current = newPinnedSidebars;
990
- setPinnedSidebars(newPinnedSidebars);
991
- setUserPreferences({ pinnedSidebars: newPinnedSidebars });
992
- }, [setUserPreferences]);
993
838
  // messageHandler is defined after loadItem/loadHistory declarations to avoid temporal dead zones
994
839
  const user = activeSessions.find((x) => x.sessionId === sessionId)?.user ||
995
840
  userInfo.user;
996
- // Self-heal if our session disappears (e.g., after HMR). Skip when concurrent user limit
997
- // is showing so we don't spam recovery attempts when the connection was rejected.
841
+ // Self-heal if our session disappears (e.g., after HMR)
998
842
  const missingSessionRecoveryTimerRef = useRef(null);
999
843
  const missingSessionRecoveryAttemptsRef = useRef(0);
1000
- const concurrentUserLimitErrorRef = useRef(null);
1001
844
  useEffect(() => {
1002
- if (concurrentUserLimitErrorRef.current !== null)
1003
- return;
1004
845
  const hasMySession = activeSessions.some((s) => s.sessionId === sessionId);
1005
846
  if (hasMySession) {
1006
847
  // Reset recovery state when we see ourselves again
@@ -1016,6 +857,7 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
1016
857
  return;
1017
858
  const attempt = missingSessionRecoveryAttemptsRef.current + 1;
1018
859
  const delay = Math.min(250 * Math.pow(2, attempt - 1), 2000);
860
+ console.warn(`⚠️ Current session not present in active sessions. Recovery attempt ${attempt} in ${delay}ms...`);
1019
861
  missingSessionRecoveryTimerRef.current = setTimeout(() => {
1020
862
  missingSessionRecoveryTimerRef.current = null;
1021
863
  missingSessionRecoveryAttemptsRef.current = attempt;
@@ -1024,7 +866,6 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
1024
866
  }
1025
867
  else {
1026
868
  // Force a reconnect to refresh presence after several failed nudges
1027
- console.warn("Session presence did not recover after retries. Forcing reconnect.");
1028
869
  try {
1029
870
  globalThis.editorSocket?.close(4000, "recover-presence");
1030
871
  }
@@ -1044,15 +885,9 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
1044
885
  // Initialize lastUrlRef to current URL on mount
1045
886
  lastUrlRef.current = window.location.href;
1046
887
  const keepAliveUrl = "/parhelia/keepalive";
1047
- const runSessionCheck = () => {
888
+ const interval = setInterval(() => {
1048
889
  fetch(keepAliveUrl + "?ts=" + Date.now())
1049
890
  .then((response) => {
1050
- if (response.headers.get("X-Parhelia-Session-Revoked") === "true") {
1051
- window.dispatchEvent(new CustomEvent("parhelia:session-revoked", {
1052
- detail: { reason: "session-revoked" },
1053
- }));
1054
- return;
1055
- }
1056
891
  if (response.status === 401 || response.status === 403) {
1057
892
  toast.error("Your session has expired", {
1058
893
  description: "Please login again to continue editing.",
@@ -1065,24 +900,7 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
1065
900
  }
1066
901
  })
1067
902
  .catch((error) => console.error("Keep Alive error:", error));
1068
- };
1069
- const keepaliveIntervalMs = (() => {
1070
- const param = new URLSearchParams(window.location.search).get("keepaliveIntervalMs");
1071
- if (!param)
1072
- return 5 * 60 * 1000;
1073
- const ms = parseInt(param, 10);
1074
- return Number.isFinite(ms) && ms >= 2000 && ms <= 60000
1075
- ? ms
1076
- : 5 * 60 * 1000;
1077
- })();
1078
- const interval = setInterval(() => {
1079
- runSessionCheck();
1080
- }, keepaliveIntervalMs);
1081
- const handleVisibilityChange = () => {
1082
- if (document.visibilityState === "visible") {
1083
- runSessionCheck();
1084
- }
1085
- };
903
+ }, 5 * 60 * 1000);
1086
904
  const handleMessage = (event) => {
1087
905
  if (event.data.type === "componentsSelected") {
1088
906
  setSelection(event.data.componentIds);
@@ -1097,8 +915,9 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
1097
915
  isHandlingPopStateRef.current = true;
1098
916
  // Sync URL parameters back to component state for browser navigation
1099
917
  const urlParams = new URLSearchParams(window.location.search);
1100
- const urlWorkspace = urlParams.get("workspace");
1101
- if (urlWorkspace && urlWorkspace !== workspaceIdRef.current) {
918
+ // Handle workspace changes (with legacy view fallback)
919
+ const urlWorkspace = urlParams.get("workspace") ?? urlParams.get("view");
920
+ if (urlWorkspace && urlWorkspace !== viewNameRef.current) {
1102
921
  setWorkspaceId(urlWorkspace);
1103
922
  }
1104
923
  // Handle sidebar changes
@@ -1115,18 +934,6 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
1115
934
  if (compareValue !== compareMode) {
1116
935
  setCompareMode(compareValue);
1117
936
  }
1118
- // Handle help panel changes
1119
- const helpParam = urlParams.get("help");
1120
- if (helpParam) {
1121
- setHelpTerminalActiveTab("manual");
1122
- setShowHelpTerminal(true);
1123
- setSelectedHelpSectionId(helpParam === "contents" || helpParam === "true"
1124
- ? null
1125
- : helpParam);
1126
- }
1127
- else {
1128
- handleSetShowHelpTerminal(false);
1129
- }
1130
937
  // Handle mode changes
1131
938
  const urlMode = urlParams.get("mode");
1132
939
  if (urlMode && urlMode !== mode) {
@@ -1182,11 +989,9 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
1182
989
  };
1183
990
  window.addEventListener("message", handleMessage);
1184
991
  window.addEventListener("popstate", handlePopState);
1185
- window.addEventListener("visibilitychange", handleVisibilityChange);
1186
992
  return () => {
1187
993
  window.removeEventListener("message", handleMessage);
1188
994
  window.removeEventListener("popstate", handlePopState);
1189
- window.removeEventListener("visibilitychange", handleVisibilityChange);
1190
995
  clearInterval(interval);
1191
996
  };
1192
997
  }, []);
@@ -1196,34 +1001,14 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
1196
1001
  if (searchParams.get("noTour") !== null) {
1197
1002
  return;
1198
1003
  }
1199
- // Don't start tour when there are setup errors (user is or will be on system status page)
1200
- if (startupChecks.state === "complete" && startupChecks.hasBlockingIssues) {
1201
- return;
1202
- }
1203
- // Don't start tour when already on settings system status page
1204
- if (viewName === "settings" && searchParams.get("ccpanel") === "status") {
1205
- return;
1206
- }
1207
- // Wait for startup checks so we know whether we'll redirect to status
1208
- if (startupChecks.state !== "complete") {
1209
- return;
1210
- }
1211
1004
  const tour = configuration.activeTour;
1212
1005
  const key = tour === "default" ? "editor.tourShown" : "editor.tourShown." + tour;
1213
- const tourShown = localStorageService.getString(key);
1006
+ const tourShown = localStorage.getItem(key);
1214
1007
  if (!tourShown) {
1215
1008
  startTour();
1216
- localStorageService.setString(key, "true");
1009
+ localStorage.setItem(key, "true");
1217
1010
  }
1218
- }, [
1219
- user,
1220
- startupChecks.state,
1221
- startupChecks.hasBlockingIssues,
1222
- viewName,
1223
- searchParams,
1224
- configuration.activeTour,
1225
- startTour,
1226
- ]);
1011
+ }, [user]);
1227
1012
  // WebSocket initialization is performed after messageHandler is defined
1228
1013
  // Defer URL sync until loadItem is defined below
1229
1014
  // Mark end of initial load phase
@@ -1355,8 +1140,7 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
1355
1140
  const loadComments = useCallback(async () => {
1356
1141
  if (!currentItemDescriptor)
1357
1142
  return;
1358
- const reviewId = searchParams.get("reviewId");
1359
- const result = await getComments(currentItemDescriptor.id, currentItemDescriptor.language, currentItemDescriptor.version, reviewId ?? undefined);
1143
+ const result = await getComments(currentItemDescriptor.id, currentItemDescriptor.language, currentItemDescriptor.version);
1360
1144
  if (handleErrorResult(result, ui, state))
1361
1145
  return;
1362
1146
  setComments((x) => {
@@ -1369,7 +1153,7 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
1369
1153
  allComments.sort((a, b) => a.position - b.position);
1370
1154
  return allComments;
1371
1155
  });
1372
- }, [currentItemDescriptor, searchParams]);
1156
+ }, [currentItemDescriptor]);
1373
1157
  // Assuming currentItemDescriptor, ui, state, handleErrorResult, and setSuggestedEdits
1374
1158
  // are available in your component context.
1375
1159
  const loadSuggestedEdits = useCallback(async () => {
@@ -1378,8 +1162,7 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
1378
1162
  const result = await getSuggestedEdits(item.descriptor.id, item.descriptor.language, item.descriptor.version);
1379
1163
  if (handleErrorResult(result, ui, state))
1380
1164
  return;
1381
- const edits = result.data || [];
1382
- setSuggestedEdits(edits);
1165
+ setSuggestedEdits(result.data || []);
1383
1166
  }, [item]);
1384
1167
  const loadFavorites = useCallback(async () => {
1385
1168
  try {
@@ -1453,25 +1236,6 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
1453
1236
  return idB.localeCompare(idA);
1454
1237
  });
1455
1238
  }, []);
1456
- const normalizeEditHistoryPayload = useCallback((value) => {
1457
- if (Array.isArray(value)) {
1458
- return value;
1459
- }
1460
- if (value && typeof value === "object") {
1461
- const payload = value;
1462
- const candidates = [
1463
- payload.operations,
1464
- payload.history,
1465
- payload.items,
1466
- payload.data,
1467
- ];
1468
- const firstArray = candidates.find((candidate) => Array.isArray(candidate));
1469
- if (Array.isArray(firstArray)) {
1470
- return firstArray;
1471
- }
1472
- }
1473
- return [];
1474
- }, []);
1475
1239
  useEffect(() => {
1476
1240
  // Read fresh page from the mutable slot context ref chain.
1477
1241
  // The slot context uses a stable ref that is mutated in-place (see editorSlotContext.ts),
@@ -1494,7 +1258,7 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
1494
1258
  if (handleErrorResult(result, ui, state))
1495
1259
  return;
1496
1260
  setEditHistory((prev) => {
1497
- const next = normalizeEditHistoryPayload(result.data);
1261
+ const next = result.data || [];
1498
1262
  if (!prev.length)
1499
1263
  return sortEditHistoryByDateDesc(next);
1500
1264
  if (!next.length)
@@ -1553,8 +1317,6 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
1553
1317
  const shouldFilterByLanguage = filterByLanguage !== undefined
1554
1318
  ? filterByLanguage
1555
1319
  : filterByCurrentLanguage;
1556
- const trimmedHistoryQuery = historySearchQuery.trim();
1557
- const historyQuery = trimmedHistoryQuery.length > 0 ? trimmedHistoryQuery : undefined;
1558
1320
  if (currentMode === "global") {
1559
1321
  // Global mode: optionally filter by session and/or language
1560
1322
  const currentLanguage = item?.descriptor?.language || currentItemDescriptor?.language;
@@ -1564,14 +1326,13 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
1564
1326
  language: shouldFilterByLanguage && currentLanguage
1565
1327
  ? currentLanguage
1566
1328
  : undefined,
1567
- query: historyQuery,
1568
1329
  });
1569
1330
  if (handleErrorResult(result, ui, state)) {
1570
1331
  console.error("[EditorShell] Failed to load history:", result);
1571
1332
  return;
1572
1333
  }
1573
1334
  setEditHistory((prev) => {
1574
- const next = normalizeEditHistoryPayload(result.data);
1335
+ const next = result.data || [];
1575
1336
  const scope = {
1576
1337
  mode: currentMode,
1577
1338
  filterBySession: shouldFilterBySession,
@@ -1582,12 +1343,8 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
1582
1343
  };
1583
1344
  if (!prev.length)
1584
1345
  return sortEditHistoryByDateDesc(next.filter((op) => matchesHistoryScope(op, scope)));
1585
- if (!next.length) {
1586
- // When searching, respect the empty result — don't fall back to previous items
1587
- if (historyQuery)
1588
- return [];
1346
+ if (!next.length)
1589
1347
  return sortEditHistoryByDateDesc(prev.filter((op) => matchesHistoryScope(op, scope)));
1590
- }
1591
1348
  const prevById = new Map(prev.map((x) => [x.id, x]));
1592
1349
  const nextById = new Set(next.map((x) => x.id));
1593
1350
  const merged = next
@@ -1623,12 +1380,9 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
1623
1380
  return mergedOp;
1624
1381
  });
1625
1382
  // Preserve operations that arrived via WebSocket during the fetch window
1626
- // but not when filtering by search query — search results are authoritative
1627
- if (!historyQuery) {
1628
- for (const [id, priorOp] of prevById) {
1629
- if (!nextById.has(id) && matchesHistoryScope(priorOp, scope)) {
1630
- merged.push(priorOp);
1631
- }
1383
+ for (const [id, priorOp] of prevById) {
1384
+ if (!nextById.has(id) && matchesHistoryScope(priorOp, scope)) {
1385
+ merged.push(priorOp);
1632
1386
  }
1633
1387
  }
1634
1388
  return sortEditHistoryByDateDesc(merged);
@@ -1651,13 +1405,12 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
1651
1405
  const result = await getEditHistory({
1652
1406
  item: itemFilter,
1653
1407
  sessionId: shouldFilterBySession ? sessionId : undefined,
1654
- query: historyQuery,
1655
1408
  });
1656
1409
  if (handleErrorResult(result, ui, state)) {
1657
1410
  console.error("[EditorShell] Failed to load item history:", result);
1658
1411
  return;
1659
1412
  }
1660
- let operations = normalizeEditHistoryPayload(result.data);
1413
+ let operations = result.data || [];
1661
1414
  // Client-side version filtering for current-version mode
1662
1415
  if (currentMode === "current-version") {
1663
1416
  // Defensive filter: only include operations for the current version
@@ -1680,11 +1433,8 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
1680
1433
  };
1681
1434
  if (!prev.length)
1682
1435
  return sortEditHistoryByDateDesc(operations.filter((op) => matchesHistoryScope(op, scope)));
1683
- if (!operations.length) {
1684
- if (historyQuery)
1685
- return [];
1436
+ if (!operations.length)
1686
1437
  return sortEditHistoryByDateDesc(prev.filter((op) => matchesHistoryScope(op, scope)));
1687
- }
1688
1438
  const prevById = new Map(prev.map((x) => [x.id, x]));
1689
1439
  const nextById = new Set(operations.map((x) => x.id));
1690
1440
  const merged = operations
@@ -1720,12 +1470,9 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
1720
1470
  return mergedOp;
1721
1471
  });
1722
1472
  // Preserve operations that arrived via WebSocket during the fetch window
1723
- // but not when filtering by search query — search results are authoritative
1724
- if (!historyQuery) {
1725
- for (const [id, priorOp] of prevById) {
1726
- if (!nextById.has(id) && matchesHistoryScope(priorOp, scope)) {
1727
- merged.push(priorOp);
1728
- }
1473
+ for (const [id, priorOp] of prevById) {
1474
+ if (!nextById.has(id) && matchesHistoryScope(priorOp, scope)) {
1475
+ merged.push(priorOp);
1729
1476
  }
1730
1477
  }
1731
1478
  return sortEditHistoryByDateDesc(merged);
@@ -1736,11 +1483,9 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
1736
1483
  historyMode,
1737
1484
  showOnlyMyChanges,
1738
1485
  filterByCurrentLanguage,
1739
- historySearchQuery,
1740
1486
  item,
1741
1487
  currentItemDescriptor,
1742
1488
  matchesHistoryScope,
1743
- normalizeEditHistoryPayload,
1744
1489
  sortEditHistoryByDateDesc,
1745
1490
  ]);
1746
1491
  // Debounced history refresh to avoid hammering `/parhelia/editHistory` on rapid UI changes.
@@ -1806,14 +1551,13 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
1806
1551
  }
1807
1552
  }
1808
1553
  else if (historyMode !== "global" && currentItemDescriptor) {
1809
- // Always load immediately for page-centric/current-version/timeline so we don't show
1810
- // an empty history list for the debounce window (e.g. 600ms). The effect only runs on
1811
- // mode or item id/lang/version change, not on every keystroke, so this avoids flaky
1812
- // undo/redo tests and improves UX when switching to page-centric.
1813
1554
  if (!historyInitialLoadDoneRef.current) {
1814
1555
  historyInitialLoadDoneRef.current = true;
1556
+ refreshHistoryRef.current(historyMode);
1557
+ }
1558
+ else {
1559
+ debouncedRefreshHistoryRef.current(historyMode);
1815
1560
  }
1816
- refreshHistoryRef.current(historyMode);
1817
1561
  }
1818
1562
  else if (historyMode !== "global" && !currentItemDescriptor) {
1819
1563
  // Clear history if no item loaded in page-centric modes
@@ -1826,7 +1570,6 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
1826
1570
  historyMode,
1827
1571
  showOnlyMyChanges,
1828
1572
  filterByCurrentLanguage,
1829
- historySearchQuery,
1830
1573
  currentItemDescriptor?.id,
1831
1574
  currentItemDescriptor?.language,
1832
1575
  currentItemDescriptor?.version,
@@ -1891,9 +1634,6 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
1891
1634
  if (isInitialLoad)
1892
1635
  return;
1893
1636
  const current = new URLSearchParams(window.location.search);
1894
- const urlWorkspace = current.get("workspace");
1895
- const urlView = current.get("view");
1896
- const isWorkspaceTransitioning = !!urlWorkspace && urlWorkspace !== viewName;
1897
1637
  // Sync item-related parameters only when an item is selected
1898
1638
  if (currentItemDescriptor) {
1899
1639
  if (current.get("itemid") !== currentItemDescriptor.id) {
@@ -1924,9 +1664,10 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
1924
1664
  // If reviewId or urlItemId exists, preserve itemid/lang/version from URL
1925
1665
  }
1926
1666
  // Always sync workspace-related parameters regardless of item selection
1927
- if (!isWorkspaceTransitioning && current.get("workspace") !== viewName) {
1667
+ if (current.get("workspace") !== viewName) {
1928
1668
  current.set("workspace", viewName);
1929
1669
  }
1670
+ current.delete("view"); // Remove legacy view param
1930
1671
  // Sync sidebar state
1931
1672
  const currentSidebars = current.get("sidebar") ?? "";
1932
1673
  const newSidebars = openSidebars.join(",");
@@ -1938,12 +1679,6 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
1938
1679
  current.delete("sidebar");
1939
1680
  }
1940
1681
  }
1941
- if (showHelpTerminal) {
1942
- current.set("help", selectedHelpSectionId ?? "contents");
1943
- }
1944
- else {
1945
- current.delete("help");
1946
- }
1947
1682
  if (!compareMode) {
1948
1683
  current.delete("compare");
1949
1684
  current.delete("compareLanguage");
@@ -1968,15 +1703,15 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
1968
1703
  else {
1969
1704
  current.delete("wizardid");
1970
1705
  }
1971
- // Preserve settings-specific parameters while transitioning into Settings too.
1972
- // Some callers update the URL first and switch the workspace state a moment later.
1973
- const isSettingsNavigation = viewName === "settings" ||
1974
- urlWorkspace === "settings" ||
1975
- urlView === "settings";
1976
- if (!isSettingsNavigation) {
1706
+ // Only preserve ccpanel parameter when on settings view, remove it otherwise
1707
+ if (viewName === "settings") {
1708
+ const ccpanel = current.get("ccpanel");
1709
+ if (ccpanel) {
1710
+ current.set("ccpanel", ccpanel);
1711
+ }
1712
+ }
1713
+ else {
1977
1714
  current.delete("ccpanel");
1978
- current.delete("providerId");
1979
- current.delete("modelId");
1980
1715
  }
1981
1716
  // Preserve reviewId parameter if it exists (for review links)
1982
1717
  // This ensures review links don't lose the reviewId when URL is synced
@@ -1995,13 +1730,9 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
1995
1730
  return;
1996
1731
  }
1997
1732
  if (newUrl !== oldUrl) {
1998
- if (switchWorkspacePushedRef.current) {
1999
- window.history.replaceState(null, "", newUrl);
2000
- switchWorkspacePushedRef.current = false;
2001
- }
2002
- else {
2003
- window.history.pushState(null, "", newUrl);
2004
- }
1733
+ window.history.pushState(null, "", newUrl);
1734
+ // Update lastUrlRef so the popstate handler knows the current URL
1735
+ // This fixes the issue where goBack() wouldn't work because lastUrl was stale
2005
1736
  lastUrlRef.current = newUrl;
2006
1737
  }
2007
1738
  }, [
@@ -2015,8 +1746,6 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
2015
1746
  fullscreen,
2016
1747
  currentWizardId,
2017
1748
  openSidebars,
2018
- showHelpTerminal,
2019
- selectedHelpSectionId,
2020
1749
  ]);
2021
1750
  useEffect(() => {
2022
1751
  async function load() {
@@ -2310,10 +2039,9 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
2310
2039
  useEffect(() => {
2311
2040
  if (fullscreen &&
2312
2041
  !searchParams.get("fullscreen") &&
2313
- !configuration.forceFullscreen &&
2314
- !isMobile)
2042
+ !configuration.forceFullscreen)
2315
2043
  setShowFullscreenHint(true);
2316
- }, [fullscreen, configuration.forceFullscreen, searchParams, isMobile]);
2044
+ }, [fullscreen, configuration.forceFullscreen, searchParams]);
2317
2045
  const state = {
2318
2046
  page,
2319
2047
  configuration,
@@ -2412,35 +2140,20 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
2412
2140
  ? existingOp.progress
2413
2141
  : op.progress;
2414
2142
  // IMPORTANT: Once canUndo becomes true, never downgrade it to false,
2415
- // UNLESS this update indicates the operation was undone.
2416
- // Runtime logs show long-running undo completion can arrive as:
2417
- // - existing: canUndo=true, executionStatus=executing
2418
- // - incoming: canUndo=false, executionStatus=completed
2419
- // without explicit undone/canRedo flags yet.
2420
- const isExplicitUndoUpdate = op.undone === true || op.canRedo === true;
2421
- const isInferredUndoCompletion = existingOp.executionStatus === "executing" &&
2422
- op.executionStatus === "completed" &&
2423
- existingOp.canUndo === true &&
2424
- op.canUndo === false;
2425
- const isUndoUpdate = isExplicitUndoUpdate || isInferredUndoCompletion;
2143
+ // UNLESS this update indicates the operation was undone. When an undo
2144
+ // completes, the server sends canUndo: false and canRedo: true (or undone: true).
2145
+ // We must respect that transition so the UI reflects the undo.
2146
+ const isUndoUpdate = op.undone === true || op.canRedo === true;
2426
2147
  const mergedCanUndo = isUndoUpdate
2427
2148
  ? false
2428
2149
  : existingOp.canUndo === true
2429
2150
  ? true
2430
2151
  : op.canUndo;
2431
- const mergedCanRedo = isUndoUpdate
2432
- ? true
2433
- : op.canRedo ?? existingOp.canRedo;
2434
- const mergedUndone = isUndoUpdate
2435
- ? true
2436
- : op.undone ?? existingOp.undone;
2437
2152
  const mergedOp = {
2438
2153
  ...existingOp,
2439
2154
  ...op,
2440
2155
  progress: mergedProgress,
2441
2156
  canUndo: mergedCanUndo,
2442
- canRedo: mergedCanRedo,
2443
- undone: mergedUndone,
2444
2157
  };
2445
2158
  // Ensure undone operations always have canRedo: true.
2446
2159
  if (mergedOp.undone && !mergedOp.canRedo) {
@@ -2494,6 +2207,10 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
2494
2207
  });
2495
2208
  // Ref for markOperationComplete callback (needed because operationsContext is created later)
2496
2209
  const markOperationCompleteRef = useRef(null);
2210
+ // When the websocket is reconnecting, we can briefly lose the ability to send messages.
2211
+ // Agent dialog responses (e.g. questionnaire cancel/submit) must not be dropped, otherwise
2212
+ // the backend tool call can remain pending and tests/users will hang.
2213
+ const pendingAgentDialogResponsesRef = useRef([]);
2497
2214
  // WebSocket message handler and connection
2498
2215
  const messageHandler = useSocketMessageHandler({
2499
2216
  sessionId,
@@ -2519,31 +2236,28 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
2519
2236
  markOperationCompleteRef.current?.(operationId);
2520
2237
  },
2521
2238
  });
2522
- // Concurrent user limit error state
2523
- const [concurrentUserLimitError, setConcurrentUserLimitError] = useState(null);
2524
- concurrentUserLimitErrorRef.current = concurrentUserLimitError;
2525
- const handleRetryConnection = useCallback(() => {
2526
- setConcurrentUserLimitError(null);
2527
- // Force reconnection by triggering a new connection attempt
2528
- // The useEditorWebSocket hook will check availability again
2529
- const socket = globalThis.editorSocket;
2530
- if (socket) {
2531
- socket.close();
2532
- delete globalThis.editorSocket;
2533
- }
2534
- // The hook will automatically attempt to reconnect
2535
- }, []);
2536
2239
  const { socketRef: socketInstanceRef } = useEditorWebSocket({
2537
2240
  sessionId,
2538
2241
  onMessage: messageHandler,
2539
2242
  onOpen: async () => {
2540
- // Clear concurrent user limit error on successful connection
2541
- setConcurrentUserLimitError(null);
2542
- // Startup WebSocket probe may have failed with a blocking error while seats were full;
2543
- // re-run status checks quietly so "1 error" does not stick after a successful connect.
2544
- void startupChecks.recheckQuiet();
2545
2243
  // Increment socket connection version to trigger re-subscriptions
2546
2244
  setSocketConnectionVersion((v) => v + 1);
2245
+ // Flush any queued agent dialog responses now that the socket is open.
2246
+ // Keep this early so pending tool calls unblock ASAP.
2247
+ try {
2248
+ if (socketInstanceRef.current &&
2249
+ socketInstanceRef.current.readyState === WebSocket.OPEN &&
2250
+ pendingAgentDialogResponsesRef.current.length > 0) {
2251
+ // FIFO flush
2252
+ while (pendingAgentDialogResponsesRef.current.length > 0) {
2253
+ const queued = pendingAgentDialogResponsesRef.current.shift();
2254
+ socketInstanceRef.current.send(JSON.stringify(queued));
2255
+ }
2256
+ }
2257
+ }
2258
+ catch (e) {
2259
+ console.error("Failed to flush queued agent dialog responses:", e);
2260
+ }
2547
2261
  // Fetch any running operations on (re)connect for auto-resume
2548
2262
  // This ensures the UI shows operations that are still executing
2549
2263
  try {
@@ -2559,37 +2273,24 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
2559
2273
  }
2560
2274
  },
2561
2275
  onError: (error) => console.error("WebSocket error:", error),
2562
- onConcurrentUserLimit: (error) => {
2563
- setConcurrentUserLimitError(error);
2564
- },
2565
- onSessionRevoked: () => promptSessionReconnect("session-revoked"),
2566
2276
  connectSocket,
2567
2277
  requestQuota,
2568
2278
  sendClientInfo,
2569
- setSocketDiagnostics,
2570
2279
  });
2571
- useEffect(() => {
2572
- const hasMySession = activeSessions.some((s) => s.sessionId === sessionId);
2573
- if (hasMySession &&
2574
- socketInstanceRef.current?.readyState === WebSocket.OPEN) {
2575
- toast.dismiss("session-revoked");
2576
- }
2577
- }, [activeSessions, sessionId, socketConnectionVersion, socketInstanceRef]);
2578
- useEffect(() => {
2579
- const handleRevoked = (event) => {
2580
- const customEvent = event;
2581
- promptSessionReconnect(customEvent?.detail?.reason);
2582
- };
2583
- window.addEventListener("parhelia:session-revoked", handleRevoked);
2584
- return () => {
2585
- window.removeEventListener("parhelia:session-revoked", handleRevoked);
2586
- };
2587
- }, [promptSessionReconnect]);
2588
2280
  const sendSocketMessage = useCallback((message) => {
2589
2281
  if (socketInstanceRef.current &&
2590
2282
  socketInstanceRef.current.readyState === WebSocket.OPEN) {
2591
2283
  socketInstanceRef.current.send(JSON.stringify(message));
2592
2284
  }
2285
+ else if (message.type === "agent-dialog-response") {
2286
+ // Queue dialog responses to avoid losing them during reconnects.
2287
+ pendingAgentDialogResponsesRef.current.push(message);
2288
+ // Prevent unbounded growth in pathological scenarios.
2289
+ if (pendingAgentDialogResponsesRef.current.length > 50) {
2290
+ pendingAgentDialogResponsesRef.current =
2291
+ pendingAgentDialogResponsesRef.current.slice(-50);
2292
+ }
2293
+ }
2593
2294
  }, [socketInstanceRef]);
2594
2295
  // URL update helper - defined early so it can be used by workspace/sidebar functions
2595
2296
  const updateUrl = useCallback((params) => {
@@ -2633,13 +2334,8 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
2633
2334
  if (!options?.skipNavigationHistory) {
2634
2335
  addNavigationEntry(targetWorkspaceId, item);
2635
2336
  }
2636
- // Mark that we're pushing from switchWorkspace so the URL sync effect
2637
- // will replaceState instead of pushing a second history entry.
2638
- switchWorkspacePushedRef.current = true;
2639
- updateUrl({
2640
- workspace: targetWorkspaceId,
2641
- ...options?.urlParams,
2642
- });
2337
+ // Update URL
2338
+ updateUrl({ workspace: targetWorkspaceId });
2643
2339
  if (typeof document.startViewTransition === "function") {
2644
2340
  document.startViewTransition(() => {
2645
2341
  flushSync(() => {
@@ -2659,6 +2355,14 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
2659
2355
  updateUrl,
2660
2356
  handleSetShowAgentsPanel,
2661
2357
  ]);
2358
+ // Legacy alias for backwards compatibility
2359
+ const switchView = useCallback((viewName, options) => {
2360
+ // Handle ccpanel for settings workspace
2361
+ if (options?.ccpanel) {
2362
+ updateUrl({ ccpanel: options.ccpanel, workspace: viewName });
2363
+ }
2364
+ switchWorkspace(viewName, options);
2365
+ }, [switchWorkspace, updateUrl]);
2662
2366
  // Helper: get all sidebar IDs that should be preserved (locked sidebars + their stack mates)
2663
2367
  const getPreservedSidebarIds = useCallback(() => {
2664
2368
  const lockedSet = new Set(lockedSidebarsRef.current);
@@ -2696,9 +2400,6 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
2696
2400
  setOpenSidebars(newSidebars);
2697
2401
  setLockedSidebars((locked) => locked.filter((id) => id !== sidebarId));
2698
2402
  setSidebarStacks((prevStacks) => normalizeSidebarStacks(newSidebars, prevStacks));
2699
- if (sidebarId === "agents-panel") {
2700
- setUserPreferences({ showAgentsPanel: false });
2701
- }
2702
2403
  startTransition(() => {
2703
2404
  updateUrl({ sidebar: newSidebars.join(",") || undefined });
2704
2405
  });
@@ -2713,69 +2414,34 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
2713
2414
  ];
2714
2415
  openSidebarsRef.current = newSidebars;
2715
2416
  setOpenSidebars(newSidebars);
2716
- ensureSidebarPinned(sidebarId);
2717
2417
  setSidebarStacks((prevStacks) => normalizeSidebarStacks(newSidebars, prevStacks));
2718
- if (sidebarId === "agents-panel") {
2719
- setUserPreferences({ showAgentsPanel: true });
2720
- }
2721
- // On mobile, close the editor form panel when opening a sidebar
2722
- if (isMobile) {
2723
- setMobileEditorPanelOpenRaw(false);
2724
- }
2725
2418
  startTransition(() => {
2726
2419
  updateUrl({ sidebar: newSidebars.join(",") || undefined });
2727
2420
  });
2728
- }, [
2729
- updateUrl,
2730
- getPreservedSidebarIds,
2731
- normalizeSidebarStacks,
2732
- ensureSidebarPinned,
2733
- setUserPreferences,
2734
- isMobile,
2735
- ]);
2421
+ }, [updateUrl, getPreservedSidebarIds, normalizeSidebarStacks]);
2736
2422
  // Ensure a sidebar is open (without toggling it closed if already open)
2737
- const openSidebar = useCallback((sidebarId, options) => {
2423
+ const openSidebar = useCallback((sidebarId) => {
2738
2424
  const currentOpenSidebars = openSidebarsRef.current;
2739
2425
  if (currentOpenSidebars.includes(sidebarId)) {
2740
2426
  // Already open, nothing to do
2741
2427
  return;
2742
2428
  }
2743
- const preservedSet = options?.preserveOpenSidebars
2744
- ? undefined
2745
- : getPreservedSidebarIds();
2746
- const newSidebars = options?.preserveOpenSidebars
2747
- ? [...currentOpenSidebars, sidebarId]
2748
- : [
2749
- ...currentOpenSidebars.filter((id) => preservedSet?.has(id)),
2750
- sidebarId,
2751
- ];
2429
+ // Keep sidebars that are locked OR in a stack with a locked sidebar
2430
+ const preservedSet = getPreservedSidebarIds();
2431
+ const newSidebars = [
2432
+ ...currentOpenSidebars.filter((id) => preservedSet.has(id)), // Keep locked stacks
2433
+ sidebarId, // Add the new one
2434
+ ];
2752
2435
  openSidebarsRef.current = newSidebars;
2753
2436
  setOpenSidebars(newSidebars);
2754
- ensureSidebarPinned(sidebarId);
2755
2437
  setSidebarStacks((prevStacks) => normalizeSidebarStacks(newSidebars, prevStacks));
2756
- if (sidebarId === "agents-panel") {
2757
- setUserPreferences({ showAgentsPanel: true });
2758
- }
2759
- // On mobile, close the editor form panel when opening a sidebar
2760
- if (isMobile) {
2761
- setMobileEditorPanelOpenRaw(false);
2762
- }
2763
2438
  startTransition(() => {
2764
2439
  updateUrl({ sidebar: newSidebars.join(",") || undefined });
2765
2440
  });
2766
- }, [
2767
- updateUrl,
2768
- getPreservedSidebarIds,
2769
- normalizeSidebarStacks,
2770
- ensureSidebarPinned,
2771
- setUserPreferences,
2772
- isMobile,
2773
- ]);
2441
+ }, [updateUrl, getPreservedSidebarIds, normalizeSidebarStacks]);
2774
2442
  // Toggle lock state for a sidebar stack (keeps it visible when selecting another)
2775
2443
  // When toggling any sidebar, we toggle the entire stack it belongs to
2776
2444
  const toggleSidebarLock = useCallback((sidebarId) => {
2777
- if (isMobile)
2778
- return;
2779
2445
  const currentStacks = sidebarStacksRef.current;
2780
2446
  const stackContainingSidebar = currentStacks.find((stack) => stack.includes(sidebarId));
2781
2447
  const sidebarIdsToToggle = stackContainingSidebar || [sidebarId];
@@ -2793,7 +2459,7 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
2793
2459
  ];
2794
2460
  }
2795
2461
  });
2796
- }, [isMobile]);
2462
+ }, []);
2797
2463
  const stackSidebar = useCallback((sidebarId, targetSidebarId, position = "after") => {
2798
2464
  if (!sidebarId || !targetSidebarId || sidebarId === targetSidebarId)
2799
2465
  return;
@@ -2825,38 +2491,6 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
2825
2491
  return normalizeSidebarStacks(openIds, next);
2826
2492
  });
2827
2493
  }, [normalizeSidebarStacks]);
2828
- const moveSidebarToColumn = useCallback((sidebarId, targetSidebarId, position = "after") => {
2829
- if (!sidebarId || !targetSidebarId || sidebarId === targetSidebarId) {
2830
- return;
2831
- }
2832
- const currentOpen = openSidebarsRef.current;
2833
- const baseOpen = currentOpen.filter((id) => id !== sidebarId);
2834
- const targetIndex = baseOpen.indexOf(targetSidebarId);
2835
- if (targetIndex === -1) {
2836
- return;
2837
- }
2838
- const insertIndex = position === "before" ? targetIndex : targetIndex + 1;
2839
- const nextOpen = [...baseOpen];
2840
- nextOpen.splice(insertIndex, 0, sidebarId);
2841
- openSidebarsRef.current = nextOpen;
2842
- setOpenSidebars(nextOpen);
2843
- startTransition(() => {
2844
- updateUrl({ sidebar: nextOpen.join(",") || undefined });
2845
- });
2846
- setSidebarStacks((prev) => {
2847
- const normalized = normalizeSidebarStacks(nextOpen, prev);
2848
- const next = normalized
2849
- .map((stack) => stack.filter((id) => id !== sidebarId))
2850
- .filter((stack) => stack.length > 0);
2851
- const targetStackIndex = next.findIndex((stack) => stack.includes(targetSidebarId));
2852
- if (targetStackIndex === -1) {
2853
- next.push([sidebarId]);
2854
- return normalizeSidebarStacks(nextOpen, next);
2855
- }
2856
- next.splice(position === "before" ? targetStackIndex : targetStackIndex + 1, 0, [sidebarId]);
2857
- return normalizeSidebarStacks(nextOpen, next);
2858
- });
2859
- }, [normalizeSidebarStacks, updateUrl]);
2860
2494
  const unstackSidebar = useCallback((sidebarId) => {
2861
2495
  setSidebarStacks((prev) => {
2862
2496
  const openIds = openSidebarsRef.current;
@@ -2902,34 +2536,8 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
2902
2536
  // Get resolved sidebar (with panels materialized)
2903
2537
  // Note: This is defined as a function that will be called later when editContext is available
2904
2538
  const sidebars = configuration.editor.sidebars ?? [];
2905
- const taskboardSidebarIds = new Set([
2906
- "taskboard-project-list",
2907
- "taskboard-my-tasks",
2908
- ]);
2909
- const getSidebarsForWorkspace = useCallback((targetWorkspaceId) => {
2910
- const isTaskboardWorkspace = targetWorkspaceId === "taskboard";
2911
- const workspaceAllowedSidebarIds = userInfo.workspaces?.find((w) => w.id === targetWorkspaceId)
2912
- ?.sidebars ?? [];
2913
- return sidebars.filter((s) => {
2914
- const isTaskboardSidebar = taskboardSidebarIds.has(s.id);
2915
- if (isTaskboardWorkspace && !isTaskboardSidebar)
2916
- return false;
2917
- if (!isTaskboardWorkspace && isTaskboardSidebar)
2918
- return false;
2919
- // Always show agents-panel regardless of workspace settings.
2920
- if (s.id === "agents-panel") {
2921
- return true;
2922
- }
2923
- // If no workspace settings or no sidebars defined for current workspace, show all.
2924
- if (workspaceAllowedSidebarIds.length === 0) {
2925
- return true;
2926
- }
2927
- // Only show sidebars that are in the allowed list for the current workspace.
2928
- return workspaceAllowedSidebarIds.includes(s.id);
2929
- });
2930
- }, [sidebars, userInfo.workspaces]);
2931
2539
  const getResolvedSidebar = useCallback((sidebarId) => {
2932
- const sidebar = getSidebarsForWorkspace(workspaceId).find((s) => s.id === sidebarId);
2540
+ const sidebar = sidebars.find((s) => s.id === sidebarId);
2933
2541
  if (!sidebar)
2934
2542
  return undefined;
2935
2543
  // Resolve panel factories using editContextRef to avoid circular dependency
@@ -2943,35 +2551,7 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
2943
2551
  ...sidebar,
2944
2552
  panels: resolvedPanels,
2945
2553
  };
2946
- }, [getSidebarsForWorkspace, workspaceId]);
2947
- useEffect(() => {
2948
- if (!currentWorkspace.supportsSidebars) {
2949
- return;
2950
- }
2951
- const allowedIds = new Set(getSidebarsForWorkspace(workspaceId).map((sidebar) => sidebar.id));
2952
- const currentOpen = openSidebarsRef.current;
2953
- let nextOpen = currentOpen.filter((id) => allowedIds.has(id));
2954
- if (nextOpen.length === 0 && currentWorkspace.defaultSidebars?.length) {
2955
- nextOpen = currentWorkspace.defaultSidebars.filter((id) => allowedIds.has(id));
2956
- }
2957
- const unchanged = nextOpen.length === currentOpen.length &&
2958
- nextOpen.every((id, index) => id === currentOpen[index]);
2959
- if (unchanged) {
2960
- return;
2961
- }
2962
- openSidebarsRef.current = nextOpen;
2963
- setOpenSidebars(nextOpen);
2964
- setSidebarStacks((prev) => normalizeSidebarStacks(nextOpen, prev));
2965
- startTransition(() => {
2966
- updateUrl({ sidebar: nextOpen.join(",") || undefined });
2967
- });
2968
- }, [
2969
- currentWorkspace,
2970
- getSidebarsForWorkspace,
2971
- normalizeSidebarStacks,
2972
- updateUrl,
2973
- workspaceId,
2974
- ]);
2554
+ }, [sidebars]);
2975
2555
  // Listen for switch-workspace and open-sidebar commands from agents via websocket
2976
2556
  useEffect(() => {
2977
2557
  const handleAgentMessage = (message) => {
@@ -3185,45 +2765,9 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
3185
2765
  }
3186
2766
  return true;
3187
2767
  }, [operations, ignoreBlur, sessionId]);
3188
- const quickSwitcherEntries = useMemo(() => {
3189
- const entries = [];
3190
- const seen = new Set();
3191
- const pushEntry = (entry) => {
3192
- const key = entry.item
3193
- ? `${entry.workspaceId}:${entry.item.id}:${entry.item.language}:${entry.item.version}`
3194
- : `${entry.workspaceId}:no-item`;
3195
- if (seen.has(key))
3196
- return;
3197
- seen.add(key);
3198
- entries.push(entry);
3199
- };
3200
- for (const entry of navigationHistory) {
3201
- pushEntry(entry);
3202
- }
3203
- for (const entry of browseHistory) {
3204
- if (!entry.id || !entry.language)
3205
- continue;
3206
- pushEntry({
3207
- workspaceId,
3208
- item: {
3209
- id: entry.id,
3210
- language: entry.language,
3211
- version: entry.version ?? 0,
3212
- },
3213
- timestamp: entry.visitedAt
3214
- ? new Date(entry.visitedAt).getTime()
3215
- : Date.now(),
3216
- displayName: entry.name || workspaceId,
3217
- itemName: entry.name,
3218
- itemPath: entry.path,
3219
- itemIcon: entry.icon,
3220
- });
3221
- }
3222
- return entries.slice(0, 25);
3223
- }, [navigationHistory, browseHistory, workspaceId]);
3224
2768
  // Quick switcher handlers
3225
2769
  const showQuickSwitcher = useCallback((show) => {
3226
- if (show && quickSwitcherEntries.length > 1) {
2770
+ if (show && navigationHistory.length > 1) {
3227
2771
  setQuickSwitcherVisible(true);
3228
2772
  // Start with index 1 (second entry - previous entry) for quick switching
3229
2773
  setQuickSwitcherSelectedIndex(1);
@@ -3231,11 +2775,11 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
3231
2775
  else {
3232
2776
  setQuickSwitcherVisible(false);
3233
2777
  }
3234
- }, [quickSwitcherEntries]);
2778
+ }, [navigationHistory]);
3235
2779
  const cycleQuickSwitcher = useCallback((direction) => {
3236
2780
  if (!quickSwitcherVisible)
3237
2781
  return;
3238
- const maxItems = Math.min(5, quickSwitcherEntries.length);
2782
+ const maxItems = Math.min(5, navigationHistory.length);
3239
2783
  setQuickSwitcherSelectedIndex((current) => {
3240
2784
  let newIndex = current;
3241
2785
  // Determine grid layout (responsive columns)
@@ -3280,9 +2824,9 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
3280
2824
  }
3281
2825
  return newIndex;
3282
2826
  });
3283
- }, [quickSwitcherVisible, quickSwitcherEntries]);
2827
+ }, [quickSwitcherVisible, navigationHistory]);
3284
2828
  const handleQuickSwitcherSelect = useCallback((index) => {
3285
- const selectedEntry = quickSwitcherEntries[index];
2829
+ const selectedEntry = navigationHistory[index];
3286
2830
  if (selectedEntry) {
3287
2831
  // Determine target workspace: entries with items should go to "editor" workspace
3288
2832
  // (fixes issue where browse history entries initialized with wrong workspaceId)
@@ -3334,46 +2878,23 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
3334
2878
  }
3335
2879
  setQuickSwitcherVisible(false);
3336
2880
  }, [
3337
- quickSwitcherEntries,
2881
+ navigationHistory,
3338
2882
  loadItem,
3339
2883
  switchWorkspace,
3340
2884
  workspaceId,
3341
2885
  item,
3342
2886
  setNavigationHistory,
3343
2887
  ]);
3344
- useEffect(() => {
3345
- if (typeof window === "undefined" ||
3346
- process.env.PARHELIA_DEV_MODE !== "true") {
3347
- return;
3348
- }
3349
- window.__parheliaQuickSwitcherTestApi = {
3350
- open: () => showQuickSwitcher(true),
3351
- cycle: (direction = "next") => cycleQuickSwitcher(direction),
3352
- closeWithoutSelection: () => setQuickSwitcherVisible(false),
3353
- selectCurrent: () => handleQuickSwitcherSelect(quickSwitcherSelectedIndex),
3354
- getState: () => ({
3355
- visible: quickSwitcherVisible,
3356
- selectedIndex: quickSwitcherSelectedIndex,
3357
- entryCount: quickSwitcherEntries.length,
3358
- entries: quickSwitcherEntries.map((entry) => ({
3359
- workspaceId: entry.workspaceId,
3360
- itemId: entry.item?.id,
3361
- displayName: entry.displayName,
3362
- })),
3363
- }),
3364
- };
3365
- return () => {
3366
- delete window.__parheliaQuickSwitcherTestApi;
3367
- };
3368
- }, [
3369
- showQuickSwitcher,
3370
- cycleQuickSwitcher,
3371
- handleQuickSwitcherSelect,
3372
- quickSwitcherSelectedIndex,
3373
- ]);
3374
2888
  const { handleKeyDown } = useKeyboardNavigation({
3375
2889
  editContextRef,
3376
- keyboardCommands: activeKeyboardCommands,
2890
+ operations,
2891
+ pageViewContext: activePageViewContext,
2892
+ configuration,
2893
+ item,
2894
+ browseHistory,
2895
+ loadItem,
2896
+ showInfoToast,
2897
+ showErrorToast,
3377
2898
  executeCommand,
3378
2899
  showQuickSwitcher,
3379
2900
  cycleQuickSwitcher,
@@ -3493,19 +3014,10 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
3493
3014
  }
3494
3015
  return null;
3495
3016
  };
3496
- let modifierWasPressedOnMouseDown = false;
3497
- const handleMouseDown = (event) => {
3498
- modifierWasPressedOnMouseDown = event.ctrlKey || event.metaKey;
3499
- };
3500
3017
  const handleCtrlClick = async (event) => {
3501
- // Only proceed if Ctrl/Cmd was already pressed when the mouse interaction started.
3502
- // This avoids accidental navigation when users press Ctrl after selecting text to copy.
3503
- if (!modifierWasPressedOnMouseDown)
3504
- return;
3505
- // Also require the modifier to still be held for the final click event.
3018
+ // Only proceed if Ctrl (or Cmd on Mac) is pressed
3506
3019
  if (!event.ctrlKey && !event.metaKey)
3507
3020
  return;
3508
- modifierWasPressedOnMouseDown = false;
3509
3021
  const target = event.target;
3510
3022
  const text = getTextFromElement(target);
3511
3023
  if (text && isGuid(text)) {
@@ -3520,7 +3032,8 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
3520
3032
  skipViewChange: true,
3521
3033
  });
3522
3034
  if (item) {
3523
- switchWorkspace("editor", {
3035
+ // Switch to the editor view
3036
+ switchView("editor", {
3524
3037
  skipNavigationHistory: true,
3525
3038
  });
3526
3039
  showInfoToast({
@@ -3546,14 +3059,12 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
3546
3059
  }
3547
3060
  };
3548
3061
  if (typeof document !== "undefined") {
3549
- document.addEventListener("mousedown", handleMouseDown, true);
3550
3062
  document.addEventListener("click", handleCtrlClick, true);
3551
3063
  return () => {
3552
- document.removeEventListener("mousedown", handleMouseDown, true);
3553
3064
  document.removeEventListener("click", handleCtrlClick, true);
3554
3065
  };
3555
3066
  }
3556
- }, [loadItem, switchWorkspace, showInfoToast, showErrorToast]);
3067
+ }, [loadItem, switchView, showInfoToast, showErrorToast]);
3557
3068
  useEffect(() => {
3558
3069
  const handleGlobalBlur = () => {
3559
3070
  operations.onFieldBlur?.();
@@ -3591,6 +3102,21 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
3591
3102
  // Otherwise, only show workspaces that are in the settings
3592
3103
  return workspaceIdsFromSettings.includes(w.id) && !w.visible;
3593
3104
  });
3105
+ // Get sidebars allowed for the current workspace from settings
3106
+ const currentWorkspaceSettings = userInfo.workspaces?.find((w) => w.id === workspaceId);
3107
+ const allowedSidebarIds = currentWorkspaceSettings?.sidebars ?? [];
3108
+ // Legacy: Calculate visible views for backwards compatibility
3109
+ const allViews = (configuration.editor.views ?? [])
3110
+ .filter((x) => {
3111
+ return !x.visible && !x.hidden;
3112
+ })
3113
+ .filter((x) => !userInfo.views ||
3114
+ userInfo.views.map((view) => view.name).includes(x.name));
3115
+ const pinnedViews = userInfo.preferences?.pinnedViews ||
3116
+ configuration.editor.defaultPinnedViews ||
3117
+ [];
3118
+ // Legacy visibleViews for backwards compatibility
3119
+ const visibleViews = allViews.filter((view) => view.name === viewName || pinnedViews.includes(view.name));
3594
3120
  // Handle initial mode setup from URL (only on initial load)
3595
3121
  useEffect(() => {
3596
3122
  if (!isInitialLoad)
@@ -3635,7 +3161,7 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
3635
3161
  // This is especially important when called from the tour, where the current workspace
3636
3162
  // might be the editor and URL-only navigation would get "corrected" back.
3637
3163
  try {
3638
- switchWorkspace("home", {
3164
+ switchView("home", {
3639
3165
  skipConfirmation: true,
3640
3166
  skipNavigationHistory: true,
3641
3167
  });
@@ -3682,6 +3208,7 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
3682
3208
  const current = new URLSearchParams(searchParams.toString());
3683
3209
  current.delete("version");
3684
3210
  current.delete("itemid");
3211
+ current.delete("view"); // Remove legacy param
3685
3212
  current.delete("workspace"); // Clear workspace
3686
3213
  current.set("create", "1");
3687
3214
  const newUrl = `${pathname}?${current.toString()}`;
@@ -3961,8 +3488,6 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
3961
3488
  setShowOnlyMyChanges,
3962
3489
  filterByCurrentLanguage,
3963
3490
  setFilterByCurrentLanguage,
3964
- historySearchQuery,
3965
- setHistorySearchQuery,
3966
3491
  refreshHistory,
3967
3492
  isRefreshing,
3968
3493
  activeSessions,
@@ -4000,8 +3525,19 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
4000
3525
  workspaceId,
4001
3526
  previousWorkspaceId,
4002
3527
  switchWorkspace,
4003
- // Sidebar state
4004
- availableSidebars: getSidebarsForWorkspace(workspaceId),
3528
+ // Sidebar state - filter by workspace settings if available
3529
+ availableSidebars: (configuration.editor.sidebars ?? []).filter((s) => {
3530
+ // Always show agents-panel regardless of workspace settings
3531
+ if (s.id === "agents-panel") {
3532
+ return true;
3533
+ }
3534
+ // If no workspace settings or no sidebars defined for current workspace, show all
3535
+ if (!allowedSidebarIds || allowedSidebarIds.length === 0) {
3536
+ return true;
3537
+ }
3538
+ // Only show sidebars that are in the allowed list for the current workspace
3539
+ return allowedSidebarIds.includes(s.id);
3540
+ }),
4005
3541
  openSidebars,
4006
3542
  pinnedSidebars,
4007
3543
  lockedSidebars,
@@ -4011,12 +3547,17 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
4011
3547
  toggleSidebarPin,
4012
3548
  toggleSidebarLock,
4013
3549
  stackSidebar,
4014
- moveSidebarToColumn,
4015
3550
  unstackSidebar,
4016
3551
  reorderSidebarInStack,
4017
3552
  reorderPinnedSidebars,
4018
3553
  reorderOpenSidebars,
4019
3554
  getResolvedSidebar,
3555
+ // Legacy compatibility (deprecated)
3556
+ viewName,
3557
+ previousViewName,
3558
+ switchView,
3559
+ view: currentView,
3560
+ visibleViews,
4020
3561
  compareMode,
4021
3562
  setCompareMode,
4022
3563
  fullscreen,
@@ -4056,7 +3597,6 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
4056
3597
  addSocketMessageListener,
4057
3598
  sendSocketMessage,
4058
3599
  socketConnectionVersion,
4059
- socketDiagnostics,
4060
3600
  currentItemDescriptor,
4061
3601
  editorSlots,
4062
3602
  activeSlotId,
@@ -4069,7 +3609,6 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
4069
3609
  setActiveSlot,
4070
3610
  revision,
4071
3611
  notifyPageModelReady,
4072
- pageModelReadyToken,
4073
3612
  selectedComment,
4074
3613
  setSelectedComment,
4075
3614
  comments,
@@ -4148,8 +3687,6 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
4148
3687
  setEnableCompletions,
4149
3688
  showComponentNavigator,
4150
3689
  setShowComponentNavigator: handleSetShowComponentNavigator,
4151
- isComponentNavigatorOpenForSlot,
4152
- setComponentNavigatorOpenForSlot,
4153
3690
  showAgentsPanel,
4154
3691
  setShowAgentsPanel: handleSetShowAgentsPanel,
4155
3692
  showMinimap,
@@ -4161,12 +3698,8 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
4161
3698
  helpTerminalProfileName,
4162
3699
  helpTerminalActiveTab,
4163
3700
  setHelpTerminalActiveTab,
4164
- selectedHelpSectionId,
4165
- setSelectedHelpSectionId,
4166
3701
  showAgentsWorkspaceEditor,
4167
3702
  setShowAgentsWorkspaceEditor: handleSetShowAgentsWorkspaceEditor,
4168
- selectedAgentsWorkspaceAgentId,
4169
- setSelectedAgentsWorkspaceAgentId,
4170
3703
  activeEditorTab,
4171
3704
  setActiveEditorTab,
4172
3705
  showLayoutComponents,
@@ -4175,8 +3708,6 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
4175
3708
  isQuotaExceeded: isQuotaExceeded(),
4176
3709
  getQuotaWarningMessage,
4177
3710
  isMobile,
4178
- mobileEditorPanelOpen,
4179
- setMobileEditorPanelOpen: handleSetMobileEditorPanelOpen,
4180
3711
  openDialog,
4181
3712
  webSocketMessages,
4182
3713
  clearWebSocketMessages: () => setWebSocketMessages([]),
@@ -4215,6 +3746,7 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
4215
3746
  configuration,
4216
3747
  updateUrl,
4217
3748
  workspaceId,
3749
+ switchView,
4218
3750
  pathname,
4219
3751
  router,
4220
3752
  item,
@@ -4244,6 +3776,7 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
4244
3776
  currentWorkspace,
4245
3777
  previousWorkspaceId,
4246
3778
  switchWorkspace,
3779
+ allowedSidebarIds,
4247
3780
  openSidebars,
4248
3781
  pinnedSidebars,
4249
3782
  lockedSidebars,
@@ -4255,6 +3788,9 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
4255
3788
  reorderOpenSidebars,
4256
3789
  getResolvedSidebar,
4257
3790
  viewName,
3791
+ previousViewName,
3792
+ currentView,
3793
+ visibleViews,
4258
3794
  compareMode,
4259
3795
  // Important: in multi-slot mode the active PageViewContext can change
4260
3796
  // without the base `pageViewContext` identity changing (e.g. switching slots).
@@ -4279,7 +3815,6 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
4279
3815
  currentItemDescriptor,
4280
3816
  revision,
4281
3817
  notifyPageModelReady,
4282
- pageModelReadyToken,
4283
3818
  selectedComment,
4284
3819
  comments,
4285
3820
  availableCommentTags,
@@ -4298,7 +3833,6 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
4298
3833
  quickSwitcherSelectedIndex,
4299
3834
  handleQuickSwitcherSelect,
4300
3835
  webSocketMessages,
4301
- socketDiagnostics,
4302
3836
  factoriesRef,
4303
3837
  user,
4304
3838
  statusMessage,
@@ -4307,11 +3841,7 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
4307
3841
  isQuotaExceeded,
4308
3842
  getQuotaWarningMessage,
4309
3843
  isMobile,
4310
- mobileEditorPanelOpen,
4311
- handleSetMobileEditorPanelOpen,
4312
3844
  showComponentNavigator,
4313
- isComponentNavigatorOpenForSlot,
4314
- setComponentNavigatorOpenForSlot,
4315
3845
  handleSetShowComponentNavigator,
4316
3846
  showAgentsPanel,
4317
3847
  handleSetShowAgentsPanel,
@@ -4323,9 +3853,7 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
4323
3853
  helpTerminalProfileName,
4324
3854
  helpTerminalActiveTab,
4325
3855
  setHelpTerminalActiveTab,
4326
- selectedHelpSectionId,
4327
3856
  showAgentsWorkspaceEditor,
4328
- selectedAgentsWorkspaceAgentId,
4329
3857
  activeEditorTab,
4330
3858
  showLayoutComponents,
4331
3859
  openDialog,
@@ -4570,40 +4098,18 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
4570
4098
  // prevDependencies.current = currentDependencies;
4571
4099
  // editContextRef.current = editContext;
4572
4100
  // }, [editContext]);
4573
- // Auto-open the mobile editor panel for new selection/intent changes, but
4574
- // keep a manual close sticky for the exact same context.
4575
- useEffect(() => {
4576
- if (!isMobile || workspaceId !== "editor")
4577
- return;
4578
- if (activeEditorTab) {
4579
- handleSetMobileEditorPanelOpen(true);
4580
- return;
4581
- }
4582
- if (!(selection.length > 0 || insertMode))
4583
- return;
4584
- if (dismissedMobilePanelToken === mobilePanelDismissToken)
4585
- return;
4586
- handleSetMobileEditorPanelOpen(true);
4587
- }, [
4588
- activeEditorTab,
4589
- dismissedMobilePanelToken,
4590
- handleSetMobileEditorPanelOpen,
4591
- insertMode,
4592
- isMobile,
4593
- mobilePanelDismissToken,
4594
- selection,
4595
- workspaceId,
4596
- ]);
4597
4101
  useEffect(() => {
4598
4102
  fieldsEditContext.clearModifiedFields();
4599
4103
  }, [currentItemDescriptor]);
4600
- if (!currentWorkspace)
4104
+ if (!currentView)
4601
4105
  return null;
4602
- const editorUi = fullscreen ? (_jsxs(_Fragment, { children: [_jsxs("div", { className: "fixed inset-0 flex", children: [_jsx(PageViewerFrame, { compareView: compareMode, pageViewContext: activePageViewContext }), _jsx(FullscreenControls, { device: activePageViewContext.device, setDevice: (d) => activePageViewContext.setDevice(d), canExit: !configuration.forceFullscreen, onExit: () => setFullscreen(false), firstMobileDeviceName: configuration.devices[0]?.name })] }), showFullscreenHint && !configuration.forceFullscreen && !isMobile && (_jsx("div", { className: "fixed inset-0 z-10000", onMouseMoveCapture: () => {
4106
+ const editorUi = fullscreen ? (_jsxs(_Fragment, { children: [_jsxs("div", { className: "fixed inset-0 flex", children: [_jsx(PageViewerFrame, { compareView: compareMode, pageViewContext: activePageViewContext }), _jsx(FullscreenControls, { device: activePageViewContext.device, setDevice: (d) => activePageViewContext.setDevice(d), canExit: !configuration.forceFullscreen, onExit: () => setFullscreen(false), firstMobileDeviceName: configuration.devices[0]?.name })] }), showFullscreenHint && !configuration.forceFullscreen && (_jsx("div", { className: "fixed inset-0", onMouseMoveCapture: () => {
4603
4107
  setTimeout(() => {
4604
4108
  setShowFullscreenHint(false);
4605
4109
  }, 600);
4606
- }, "data-testid": "fullscreen-hint-overlay", children: _jsxs("div", { className: "fixed top-6 left-1/2 -translate-x-1/2 transform rounded-full bg-black/60 px-6 py-2.5 text-sm font-medium text-white shadow-2xl backdrop-blur-md transition-all duration-500", children: ["Press", " ", _jsx("kbd", { className: "mx-1 rounded bg-white/20 px-1.5 py-0.5 text-xs font-semibold", children: "Ctrl + F11" }), " ", "to exit fullscreen"] }) }))] })) : (_jsxs(_Fragment, { children: [_jsx(EditorChrome, { className: className, currentWorkspace: currentWorkspace, centerPanelView: centerPanelView, editContext: editContext, showAgentsPanel: showAgentsPanel, handleSetShowAgentsPanel: handleSetShowAgentsPanel, workspaceId: workspaceId }), isTourActive && (_jsx(Tour, { tourStopCallback: () => {
4110
+ }, "data-testid": "fullscreen-hint-overlay", children: _jsxs("div", { className: "fixed top-6 left-1/2 -translate-x-1/2 transform rounded-full bg-black/60 px-6 py-2.5 text-sm font-medium text-white shadow-2xl backdrop-blur-md transition-all duration-500", children: ["Press", " ", _jsx("kbd", { className: "mx-1 rounded bg-white/20 px-1.5 py-0.5 text-xs font-semibold", children: "Ctrl + F11" }), " ", "to exit fullscreen"] }) }))] })) : (_jsxs(_Fragment, { children: [_jsx(EditorChrome, { className: className, currentWorkspace: currentWorkspace, centerPanelView: centerPanelView, editContext: editContext, showComponentNavigator: showComponentNavigator, handleSetShowComponentNavigator: handleSetShowComponentNavigator, showAgentsPanel: showAgentsPanel, handleSetShowAgentsPanel: handleSetShowAgentsPanel, workspaceId: workspaceId,
4111
+ // Legacy props for backwards compatibility
4112
+ currentView: currentView, viewName: viewName }), isTourActive && (_jsx(Tour, { tourStopCallback: () => {
4607
4113
  setIsTourActive(false);
4608
4114
  // Remove tour state from URL
4609
4115
  // Use history.replaceState instead of router.replace to avoid triggering React navigation
@@ -4614,13 +4120,7 @@ export function EditorShell({ configuration, className, item: loadItemDescriptor
4614
4120
  ? `${window.location.pathname}?${queryString}`
4615
4121
  : window.location.pathname;
4616
4122
  window.history.replaceState(null, "", newUrl);
4617
- }, configuration: configuration, restoredFromUrl: tourRestoredRef.current })), _jsx(FeatureGate, { feature: LicenseFeatures.AI, children: _jsx(GuidanceOverlay, {}) }), _jsx(FeatureGate, { feature: LicenseFeatures.AI, children: _jsx(AgentDialogHandler, {}) })] }));
4618
- return (_jsx(LicenseProvider, { initialLicenseStatus: initialLicenseStatus, initialStatusLoaded: initialLicenseStatusLoaded, children: _jsx("div", { className: `editor h-full w-full`, children: _jsx(OperationsContextProvider, { value: operationsContext.context, children: _jsx(FieldsEditContextProvider, { value: fieldsEditContext, children: _jsxs(EditContextProvider, { value: editContext, children: [_jsx(DevModeIndicator, {}), startupChecks.state === "loading" && (_jsx("div", { className: "fixed inset-0 z-50 flex items-center justify-center bg-white/70 backdrop-blur-[1px]", children: _jsx("div", { className: "flex items-center gap-3 rounded-md border border-gray-200 bg-white px-4 py-3 text-gray-700 shadow-sm", children: _jsx(Spinner, { size: "xl" }) }) })), editContext.isRefreshing && (_jsx("div", { className: "pointer-events-none fixed right-0 bottom-0 flex h-24 w-24 items-center justify-center text-gray-600 opacity-50 select-none", children: _jsx(Spinner, {}) })), (currentWorkspace.id === "agents" ||
4619
- currentWorkspace.id === "taskboard") &&
4620
- showAgentsWorkspaceEditor && (_jsx(AgentsSlotContextBridgeHost, { slots: editorSlots })), startupChecks.state !== "loading" && (children || editorUi), startupChecks.state !== "loading" && dialog, _jsx(Toaster, { position: "top-center" }), " ", _jsx(ConfirmationDialog, { ref: confirmationDialogRef }), _jsx(ConcurrentUserLimitDialog, { open: concurrentUserLimitError !== null, onOpenChange: (open) => {
4621
- if (!open) {
4622
- setConcurrentUserLimitError(null);
4623
- }
4624
- }, sessionId: sessionId, currentUsers: concurrentUserLimitError?.currentUsers ?? 0, maxUsers: concurrentUserLimitError?.maxUsers ?? 0, message: concurrentUserLimitError?.message ?? "", onRetry: handleRetryConnection, isAdministrator: userInfo.user.isAdministrator === true }), _jsx(QuickItemSwitcher, { visible: quickSwitcherVisible, entries: quickSwitcherEntries.slice(0, 5), selectedIndex: quickSwitcherSelectedIndex, onSelect: handleQuickSwitcherSelect, onClose: () => setQuickSwitcherVisible(false) }), _jsx(EditContextMenu, { ref: contextMenuRef }), _jsx(FeatureGate, { feature: LicenseFeatures.AI, children: _jsx(InlineAiTrigger, {}) }), media.mediaSelectorVisible && (_jsx(MediaSelector, { language: editContext.currentItemDescriptor.language, visible: media.mediaSelectorVisible, onHide: media.handleHide, onMediaSelected: media.onMediaSelect, selectedIdPath: media.selectedMediaIdPath, mode: media.mediaSelectorMode, initialSearchTerm: media.initialSearchTerm })), _jsx(FieldEditorPopup, { ref: fieldEditorPopupRef }), _jsx(LicenseOverlay, {})] }) }) }) }) }));
4123
+ }, configuration: configuration, restoredFromUrl: tourRestoredRef.current })), _jsx(GuidanceOverlay, {}), _jsx(AgentDialogHandler, { sendWebSocketMessage: (type, payload) => sendSocketMessage({ type, payload }) })] }));
4124
+ return (_jsx("div", { className: `editor h-full w-full`, children: _jsx(OperationsContextProvider, { value: operationsContext.context, children: _jsx(FieldsEditContextProvider, { value: fieldsEditContext, children: _jsxs(EditContextProvider, { value: editContext, children: [_jsx(DevModeIndicator, {}), startupChecks.state === "loading" && (_jsx("div", { className: "fixed inset-0 z-50 flex items-center justify-center bg-white/70 backdrop-blur-[1px]", children: _jsx("div", { className: "flex items-center gap-3 rounded-md border border-gray-200 bg-white px-4 py-3 text-gray-700 shadow-sm", children: _jsx(Spinner, { size: "xl" }) }) })), editContext.isRefreshing && (_jsx("div", { className: "pointer-events-none fixed right-0 bottom-0 flex h-24 w-24 items-center justify-center text-gray-600 opacity-50 select-none", children: _jsx(Spinner, {}) })), children || editorUi, dialog, _jsx(Toaster, { position: "top-center" }), " ", _jsx(ConfirmationDialog, { ref: confirmationDialogRef }), _jsx(QuickItemSwitcher, { visible: quickSwitcherVisible, entries: navigationHistory.slice(0, 5), selectedIndex: quickSwitcherSelectedIndex, onSelect: handleQuickSwitcherSelect, onClose: () => setQuickSwitcherVisible(false) }), _jsx(EditContextMenu, { ref: contextMenuRef }), _jsx(InlineAiTrigger, {}), media.mediaSelectorVisible && (_jsx(MediaSelector, { language: editContext.currentItemDescriptor.language, visible: media.mediaSelectorVisible, onHide: media.handleHide, onMediaSelected: media.onMediaSelect, selectedIdPath: media.selectedMediaIdPath, mode: media.mediaSelectorMode, initialSearchTerm: media.initialSearchTerm })), _jsx(FieldEditorPopup, { ref: fieldEditorPopupRef })] }) }) }) }));
4625
4125
  }
4626
4126
  //# sourceMappingURL=EditorShell.js.map