@flowdrop/flowdrop 1.0.1 → 1.1.0

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 (386) hide show
  1. package/README.md +50 -50
  2. package/dist/adapters/WorkflowAdapter.d.ts +1 -1
  3. package/dist/adapters/WorkflowAdapter.js +25 -25
  4. package/dist/adapters/agentspec/AgentSpecAdapter.d.ts +2 -2
  5. package/dist/adapters/agentspec/AgentSpecAdapter.js +133 -122
  6. package/dist/adapters/agentspec/agentAdapter.d.ts +2 -2
  7. package/dist/adapters/agentspec/agentAdapter.js +10 -10
  8. package/dist/adapters/agentspec/autoLayout.d.ts +1 -1
  9. package/dist/adapters/agentspec/autoLayout.js +2 -2
  10. package/dist/adapters/agentspec/componentTypeDefaults.d.ts +1 -1
  11. package/dist/adapters/agentspec/componentTypeDefaults.js +120 -120
  12. package/dist/adapters/agentspec/defaultNodeTypes.d.ts +2 -2
  13. package/dist/adapters/agentspec/defaultNodeTypes.js +307 -307
  14. package/dist/adapters/agentspec/index.d.ts +10 -10
  15. package/dist/adapters/agentspec/index.js +6 -6
  16. package/dist/adapters/agentspec/validator.d.ts +2 -2
  17. package/dist/adapters/agentspec/validator.js +22 -20
  18. package/dist/api/enhanced-client.d.ts +3 -3
  19. package/dist/api/enhanced-client.js +73 -72
  20. package/dist/components/App.svelte +1081 -961
  21. package/dist/components/App.svelte.d.ts +9 -6
  22. package/dist/components/CanvasBanner.stories.svelte +23 -20
  23. package/dist/components/CanvasBanner.stories.svelte.d.ts +1 -1
  24. package/dist/components/CanvasBanner.svelte +46 -46
  25. package/dist/components/ConfigForm.svelte +1164 -1065
  26. package/dist/components/ConfigForm.svelte.d.ts +2 -2
  27. package/dist/components/ConfigModal.svelte +180 -180
  28. package/dist/components/ConfigModal.svelte.d.ts +1 -1
  29. package/dist/components/ConfigPanel.stories.svelte +35 -35
  30. package/dist/components/ConfigPanel.stories.svelte.d.ts +1 -1
  31. package/dist/components/ConfigPanel.svelte +178 -167
  32. package/dist/components/ConfigPanel.svelte.d.ts +1 -1
  33. package/dist/components/ConnectionLine.svelte +25 -25
  34. package/dist/components/EdgeRefresher.svelte +26 -26
  35. package/dist/components/FlowDropEdge.stories.svelte +179 -143
  36. package/dist/components/FlowDropEdge.svelte +147 -147
  37. package/dist/components/FlowDropEdge.svelte.d.ts +1 -1
  38. package/dist/components/FlowDropZone.svelte +63 -60
  39. package/dist/components/FlowDropZone.svelte.d.ts +1 -1
  40. package/dist/components/LoadingSpinner.stories.svelte +19 -19
  41. package/dist/components/LoadingSpinner.stories.svelte.d.ts +1 -1
  42. package/dist/components/LoadingSpinner.svelte +21 -21
  43. package/dist/components/LoadingSpinner.svelte.d.ts +1 -1
  44. package/dist/components/Logo.stories.svelte +13 -13
  45. package/dist/components/Logo.stories.svelte.d.ts +1 -1
  46. package/dist/components/Logo.svelte +101 -95
  47. package/dist/components/LogsSidebar.svelte +553 -546
  48. package/dist/components/LogsSidebar.svelte.d.ts +1 -1
  49. package/dist/components/MarkdownDisplay.stories.svelte +29 -23
  50. package/dist/components/MarkdownDisplay.stories.svelte.d.ts +1 -1
  51. package/dist/components/MarkdownDisplay.svelte +16 -14
  52. package/dist/components/Navbar.stories.svelte +43 -38
  53. package/dist/components/Navbar.stories.svelte.d.ts +1 -1
  54. package/dist/components/Navbar.svelte +760 -706
  55. package/dist/components/Navbar.svelte.d.ts +1 -1
  56. package/dist/components/NodeSidebar.svelte +900 -746
  57. package/dist/components/NodeSidebar.svelte.d.ts +3 -1
  58. package/dist/components/NodeStatusOverlay.stories.svelte +82 -70
  59. package/dist/components/NodeStatusOverlay.stories.svelte.d.ts +1 -1
  60. package/dist/components/NodeStatusOverlay.svelte +295 -280
  61. package/dist/components/NodeStatusOverlay.svelte.d.ts +3 -3
  62. package/dist/components/PipelineStatus.svelte +326 -300
  63. package/dist/components/PipelineStatus.svelte.d.ts +4 -4
  64. package/dist/components/PortCoordinateTracker.svelte +49 -47
  65. package/dist/components/PortCoordinateTracker.svelte.d.ts +1 -1
  66. package/dist/components/ReadOnlyDetails.svelte +156 -156
  67. package/dist/components/SchemaForm.stories.svelte +106 -98
  68. package/dist/components/SchemaForm.stories.svelte.d.ts +1 -1
  69. package/dist/components/SchemaForm.svelte +490 -463
  70. package/dist/components/SchemaForm.svelte.d.ts +2 -2
  71. package/dist/components/SettingsModal.svelte +226 -223
  72. package/dist/components/SettingsModal.svelte.d.ts +1 -1
  73. package/dist/components/SettingsPanel.svelte +637 -601
  74. package/dist/components/SettingsPanel.svelte.d.ts +1 -1
  75. package/dist/components/StatusIcon.stories.svelte +62 -49
  76. package/dist/components/StatusIcon.stories.svelte.d.ts +1 -1
  77. package/dist/components/StatusIcon.svelte +87 -87
  78. package/dist/components/StatusIcon.svelte.d.ts +2 -2
  79. package/dist/components/StatusLabel.stories.svelte +12 -12
  80. package/dist/components/StatusLabel.stories.svelte.d.ts +1 -1
  81. package/dist/components/StatusLabel.svelte +19 -19
  82. package/dist/components/ThemeToggle.stories.svelte +16 -16
  83. package/dist/components/ThemeToggle.stories.svelte.d.ts +1 -1
  84. package/dist/components/ThemeToggle.svelte +180 -169
  85. package/dist/components/ThemeToggle.svelte.d.ts +1 -1
  86. package/dist/components/UniversalNode.svelte +150 -138
  87. package/dist/components/UniversalNode.svelte.d.ts +3 -3
  88. package/dist/components/WorkflowEditor.svelte +1069 -1014
  89. package/dist/components/WorkflowEditor.svelte.d.ts +4 -4
  90. package/dist/components/form/FormArray.svelte +1034 -973
  91. package/dist/components/form/FormArray.svelte.d.ts +1 -1
  92. package/dist/components/form/FormAutocomplete.svelte +1021 -978
  93. package/dist/components/form/FormAutocomplete.svelte.d.ts +1 -1
  94. package/dist/components/form/FormCheckboxGroup.stories.svelte +23 -20
  95. package/dist/components/form/FormCheckboxGroup.stories.svelte.d.ts +1 -1
  96. package/dist/components/form/FormCheckboxGroup.svelte +136 -136
  97. package/dist/components/form/FormCodeEditor.svelte +452 -434
  98. package/dist/components/form/FormField.svelte +366 -355
  99. package/dist/components/form/FormField.svelte.d.ts +2 -2
  100. package/dist/components/form/FormFieldLight.svelte +400 -384
  101. package/dist/components/form/FormFieldLight.svelte.d.ts +1 -1
  102. package/dist/components/form/FormFieldWrapper.stories.svelte +42 -42
  103. package/dist/components/form/FormFieldWrapper.stories.svelte.d.ts +1 -1
  104. package/dist/components/form/FormFieldWrapper.svelte +100 -93
  105. package/dist/components/form/FormFieldWrapper.svelte.d.ts +1 -1
  106. package/dist/components/form/FormFieldset.svelte +108 -108
  107. package/dist/components/form/FormFieldset.svelte.d.ts +2 -2
  108. package/dist/components/form/FormMarkdownEditor.svelte +758 -725
  109. package/dist/components/form/FormNumberField.stories.svelte +25 -25
  110. package/dist/components/form/FormNumberField.stories.svelte.d.ts +1 -1
  111. package/dist/components/form/FormNumberField.svelte +88 -88
  112. package/dist/components/form/FormRangeField.stories.svelte +20 -20
  113. package/dist/components/form/FormRangeField.stories.svelte.d.ts +1 -1
  114. package/dist/components/form/FormRangeField.svelte +234 -226
  115. package/dist/components/form/FormSelect.stories.svelte +38 -38
  116. package/dist/components/form/FormSelect.stories.svelte.d.ts +1 -1
  117. package/dist/components/form/FormSelect.svelte +101 -101
  118. package/dist/components/form/FormSelect.svelte.d.ts +1 -1
  119. package/dist/components/form/FormTemplateEditor.svelte +847 -798
  120. package/dist/components/form/FormTemplateEditor.svelte.d.ts +1 -1
  121. package/dist/components/form/FormTextField.stories.svelte +29 -23
  122. package/dist/components/form/FormTextField.stories.svelte.d.ts +1 -1
  123. package/dist/components/form/FormTextField.svelte +68 -68
  124. package/dist/components/form/FormTextarea.stories.svelte +28 -25
  125. package/dist/components/form/FormTextarea.stories.svelte.d.ts +1 -1
  126. package/dist/components/form/FormTextarea.svelte +74 -74
  127. package/dist/components/form/FormToggle.stories.svelte +23 -20
  128. package/dist/components/form/FormToggle.stories.svelte.d.ts +1 -1
  129. package/dist/components/form/FormToggle.svelte +98 -98
  130. package/dist/components/form/FormUISchemaRenderer.svelte +120 -113
  131. package/dist/components/form/FormUISchemaRenderer.svelte.d.ts +3 -3
  132. package/dist/components/form/index.d.ts +19 -19
  133. package/dist/components/form/index.js +18 -18
  134. package/dist/components/form/templateAutocomplete.d.ts +2 -2
  135. package/dist/components/form/templateAutocomplete.js +64 -55
  136. package/dist/components/form/types.d.ts +6 -6
  137. package/dist/components/form/types.js +9 -4
  138. package/dist/components/icons/AlertCircleIcon.svelte +11 -0
  139. package/dist/components/icons/AlertCircleIcon.svelte.d.ts +26 -0
  140. package/dist/components/icons/CogIcon.svelte +11 -0
  141. package/dist/components/icons/CogIcon.svelte.d.ts +26 -0
  142. package/dist/components/interrupt/ChoicePrompt.stories.svelte +54 -38
  143. package/dist/components/interrupt/ChoicePrompt.stories.svelte.d.ts +1 -1
  144. package/dist/components/interrupt/ChoicePrompt.svelte +407 -383
  145. package/dist/components/interrupt/ChoicePrompt.svelte.d.ts +1 -1
  146. package/dist/components/interrupt/ConfirmationPrompt.stories.svelte +48 -48
  147. package/dist/components/interrupt/ConfirmationPrompt.stories.svelte.d.ts +1 -1
  148. package/dist/components/interrupt/ConfirmationPrompt.svelte +280 -274
  149. package/dist/components/interrupt/ConfirmationPrompt.svelte.d.ts +1 -1
  150. package/dist/components/interrupt/FormPrompt.svelte +223 -218
  151. package/dist/components/interrupt/FormPrompt.svelte.d.ts +1 -1
  152. package/dist/components/interrupt/InterruptBubble.svelte +617 -583
  153. package/dist/components/interrupt/InterruptBubble.svelte.d.ts +2 -2
  154. package/dist/components/interrupt/ReviewPrompt.stories.svelte +66 -56
  155. package/dist/components/interrupt/ReviewPrompt.stories.svelte.d.ts +1 -1
  156. package/dist/components/interrupt/ReviewPrompt.svelte +861 -841
  157. package/dist/components/interrupt/ReviewPrompt.svelte.d.ts +1 -1
  158. package/dist/components/interrupt/TextInputPrompt.stories.svelte +38 -33
  159. package/dist/components/interrupt/TextInputPrompt.stories.svelte.d.ts +1 -1
  160. package/dist/components/interrupt/TextInputPrompt.svelte +333 -328
  161. package/dist/components/interrupt/TextInputPrompt.svelte.d.ts +1 -1
  162. package/dist/components/interrupt/index.d.ts +5 -5
  163. package/dist/components/interrupt/index.js +5 -5
  164. package/dist/components/layouts/MainLayout.svelte +724 -691
  165. package/dist/components/layouts/MainLayout.svelte.d.ts +6 -6
  166. package/dist/components/nodes/GatewayNode.stories.svelte +100 -99
  167. package/dist/components/nodes/GatewayNode.svelte +605 -571
  168. package/dist/components/nodes/GatewayNode.svelte.d.ts +3 -3
  169. package/dist/components/nodes/IdeaNode.stories.svelte +44 -43
  170. package/dist/components/nodes/IdeaNode.svelte +451 -437
  171. package/dist/components/nodes/IdeaNode.svelte.d.ts +1 -1
  172. package/dist/components/nodes/NotesNode.stories.svelte +65 -64
  173. package/dist/components/nodes/NotesNode.svelte +380 -369
  174. package/dist/components/nodes/NotesNode.svelte.d.ts +1 -1
  175. package/dist/components/nodes/SimpleNode.stories.svelte +145 -144
  176. package/dist/components/nodes/SimpleNode.svelte +486 -424
  177. package/dist/components/nodes/SimpleNode.svelte.d.ts +1 -1
  178. package/dist/components/nodes/SquareNode.stories.svelte +73 -73
  179. package/dist/components/nodes/SquareNode.svelte +439 -380
  180. package/dist/components/nodes/SquareNode.svelte.d.ts +1 -1
  181. package/dist/components/nodes/TerminalNode.stories.svelte +13 -13
  182. package/dist/components/nodes/TerminalNode.svelte +709 -670
  183. package/dist/components/nodes/TerminalNode.svelte.d.ts +1 -1
  184. package/dist/components/nodes/ToolNode.stories.svelte +181 -180
  185. package/dist/components/nodes/ToolNode.svelte +505 -447
  186. package/dist/components/nodes/ToolNode.svelte.d.ts +1 -1
  187. package/dist/components/nodes/WorkflowNode.stories.svelte +70 -46
  188. package/dist/components/nodes/WorkflowNode.svelte +621 -551
  189. package/dist/components/nodes/WorkflowNode.svelte.d.ts +3 -3
  190. package/dist/components/playground/ChatPanel.svelte +945 -889
  191. package/dist/components/playground/ExecutionLogs.svelte +495 -472
  192. package/dist/components/playground/InputCollector.svelte +449 -428
  193. package/dist/components/playground/MessageBubble.stories.svelte +47 -47
  194. package/dist/components/playground/MessageBubble.stories.svelte.d.ts +1 -1
  195. package/dist/components/playground/MessageBubble.svelte +626 -610
  196. package/dist/components/playground/MessageBubble.svelte.d.ts +1 -1
  197. package/dist/components/playground/Playground.svelte +1088 -1057
  198. package/dist/components/playground/Playground.svelte.d.ts +3 -3
  199. package/dist/components/playground/PlaygroundModal.svelte +208 -204
  200. package/dist/components/playground/PlaygroundModal.svelte.d.ts +3 -3
  201. package/dist/components/playground/SessionManager.svelte +527 -521
  202. package/dist/components/playground/SessionManager.svelte.d.ts +1 -1
  203. package/dist/config/agentSpecEndpoints.d.ts +1 -1
  204. package/dist/config/agentSpecEndpoints.js +20 -20
  205. package/dist/config/constants.js +2 -2
  206. package/dist/config/defaultCategories.d.ts +1 -1
  207. package/dist/config/defaultCategories.js +86 -86
  208. package/dist/config/defaultPortConfig.d.ts +1 -1
  209. package/dist/config/defaultPortConfig.js +144 -144
  210. package/dist/config/endpoints.d.ts +4 -4
  211. package/dist/config/endpoints.js +65 -65
  212. package/dist/config/runtimeConfig.d.ts +2 -2
  213. package/dist/config/runtimeConfig.js +8 -8
  214. package/dist/core/index.d.ts +63 -59
  215. package/dist/core/index.js +35 -33
  216. package/dist/display/index.d.ts +2 -2
  217. package/dist/display/index.js +2 -2
  218. package/dist/editor/index.d.ts +62 -62
  219. package/dist/editor/index.js +53 -53
  220. package/dist/form/code.d.ts +5 -5
  221. package/dist/form/code.js +14 -14
  222. package/dist/form/fieldRegistry.d.ts +3 -3
  223. package/dist/form/fieldRegistry.js +11 -9
  224. package/dist/form/full.d.ts +8 -8
  225. package/dist/form/full.js +9 -9
  226. package/dist/form/index.d.ts +18 -18
  227. package/dist/form/index.js +16 -16
  228. package/dist/form/markdown.d.ts +4 -4
  229. package/dist/form/markdown.js +8 -8
  230. package/dist/helpers/proximityConnect.d.ts +3 -3
  231. package/dist/helpers/proximityConnect.js +34 -32
  232. package/dist/helpers/workflowEditorHelper.d.ts +5 -5
  233. package/dist/helpers/workflowEditorHelper.js +108 -96
  234. package/dist/index.d.ts +6 -6
  235. package/dist/index.js +6 -6
  236. package/dist/mocks/app-environment.js +2 -2
  237. package/dist/mocks/app-forms.js +9 -9
  238. package/dist/mocks/app-navigation.js +11 -11
  239. package/dist/mocks/app-stores.js +8 -8
  240. package/dist/playground/index.d.ts +19 -19
  241. package/dist/playground/index.js +16 -16
  242. package/dist/playground/mount.d.ts +3 -3
  243. package/dist/playground/mount.js +24 -24
  244. package/dist/registry/builtinFormats.js +13 -13
  245. package/dist/registry/builtinNodes.d.ts +2 -2
  246. package/dist/registry/builtinNodes.js +77 -77
  247. package/dist/registry/index.d.ts +4 -4
  248. package/dist/registry/index.js +4 -4
  249. package/dist/registry/nodeComponentRegistry.d.ts +8 -8
  250. package/dist/registry/nodeComponentRegistry.js +11 -9
  251. package/dist/registry/plugin.d.ts +2 -2
  252. package/dist/registry/plugin.js +11 -11
  253. package/dist/registry/workflowFormatRegistry.d.ts +3 -3
  254. package/dist/registry/workflowFormatRegistry.js +2 -2
  255. package/dist/schema/index.d.ts +1 -1
  256. package/dist/schema/index.js +2 -2
  257. package/dist/schemas/v1/workflow.schema.json +22 -107
  258. package/dist/services/agentSpecExecutionService.d.ts +3 -3
  259. package/dist/services/agentSpecExecutionService.js +59 -55
  260. package/dist/services/api.d.ts +2 -2
  261. package/dist/services/api.js +37 -37
  262. package/dist/services/apiVariableService.d.ts +1 -1
  263. package/dist/services/apiVariableService.js +41 -34
  264. package/dist/services/autoSaveService.js +8 -8
  265. package/dist/services/categoriesApi.d.ts +2 -2
  266. package/dist/services/categoriesApi.js +8 -8
  267. package/dist/services/draftStorage.d.ts +1 -1
  268. package/dist/services/draftStorage.js +11 -11
  269. package/dist/services/dynamicSchemaService.d.ts +1 -1
  270. package/dist/services/dynamicSchemaService.js +41 -39
  271. package/dist/services/globalSave.d.ts +2 -2
  272. package/dist/services/globalSave.js +41 -38
  273. package/dist/services/historyService.d.ts +1 -1
  274. package/dist/services/historyService.js +8 -8
  275. package/dist/services/interruptService.d.ts +1 -1
  276. package/dist/services/interruptService.js +35 -29
  277. package/dist/services/nodeExecutionService.d.ts +1 -1
  278. package/dist/services/nodeExecutionService.js +45 -44
  279. package/dist/services/playgroundService.d.ts +1 -1
  280. package/dist/services/playgroundService.js +29 -29
  281. package/dist/services/portConfigApi.d.ts +2 -2
  282. package/dist/services/portConfigApi.js +8 -8
  283. package/dist/services/settingsService.d.ts +2 -2
  284. package/dist/services/settingsService.js +25 -19
  285. package/dist/services/toastService.d.ts +4 -4
  286. package/dist/services/toastService.js +33 -33
  287. package/dist/services/variableService.d.ts +1 -1
  288. package/dist/services/variableService.js +36 -36
  289. package/dist/services/workflowStorage.d.ts +2 -2
  290. package/dist/services/workflowStorage.js +13 -13
  291. package/dist/settings/index.d.ts +7 -7
  292. package/dist/settings/index.js +6 -6
  293. package/dist/skins/default.d.ts +2 -0
  294. package/dist/skins/default.js +1 -0
  295. package/dist/skins/index.d.ts +13 -0
  296. package/dist/skins/index.js +30 -0
  297. package/dist/skins/slate.d.ts +2 -0
  298. package/dist/skins/slate.js +78 -0
  299. package/dist/stores/categoriesStore.svelte.d.ts +1 -1
  300. package/dist/stores/categoriesStore.svelte.js +5 -5
  301. package/dist/stores/editorStateMachine.svelte.d.ts +2 -2
  302. package/dist/stores/editorStateMachine.svelte.js +65 -33
  303. package/dist/stores/historyStore.svelte.d.ts +4 -4
  304. package/dist/stores/historyStore.svelte.js +4 -4
  305. package/dist/stores/interruptStore.svelte.d.ts +3 -3
  306. package/dist/stores/interruptStore.svelte.js +21 -21
  307. package/dist/stores/playgroundStore.svelte.d.ts +2 -2
  308. package/dist/stores/playgroundStore.svelte.js +25 -18
  309. package/dist/stores/portCoordinateStore.svelte.d.ts +2 -2
  310. package/dist/stores/portCoordinateStore.svelte.js +15 -8
  311. package/dist/stores/settingsStore.svelte.d.ts +2 -2
  312. package/dist/stores/settingsStore.svelte.js +62 -57
  313. package/dist/stores/workflowStore.svelte.d.ts +3 -3
  314. package/dist/stores/workflowStore.svelte.js +50 -47
  315. package/dist/stories/CanvasDecorator.svelte +35 -32
  316. package/dist/stories/CanvasDecorator.svelte.d.ts +2 -2
  317. package/dist/stories/EdgeDecorator.svelte +102 -99
  318. package/dist/stories/EdgeDecorator.svelte.d.ts +1 -1
  319. package/dist/stories/NodeDecorator.svelte +59 -53
  320. package/dist/stories/NodeDecorator.svelte.d.ts +1 -1
  321. package/dist/stories/utils.d.ts +2 -2
  322. package/dist/stories/utils.js +105 -67
  323. package/dist/styles/base.css +599 -595
  324. package/dist/styles/toast.css +14 -14
  325. package/dist/styles/tokens.css +409 -378
  326. package/dist/svelte-app.d.ts +9 -9
  327. package/dist/svelte-app.js +39 -39
  328. package/dist/themes/default.d.ts +2 -0
  329. package/dist/themes/default.js +9 -0
  330. package/dist/themes/index.d.ts +13 -0
  331. package/dist/themes/index.js +44 -0
  332. package/dist/themes/minimal.d.ts +2 -0
  333. package/dist/themes/minimal.js +11 -0
  334. package/dist/types/agentspec.d.ts +18 -18
  335. package/dist/types/agentspec.js +2 -2
  336. package/dist/types/auth.d.ts +1 -1
  337. package/dist/types/auth.js +6 -6
  338. package/dist/types/config.d.ts +6 -6
  339. package/dist/types/events.d.ts +2 -2
  340. package/dist/types/events.js +2 -2
  341. package/dist/types/index.d.ts +32 -32
  342. package/dist/types/index.js +6 -6
  343. package/dist/types/interrupt.d.ts +6 -6
  344. package/dist/types/interrupt.js +21 -21
  345. package/dist/types/interruptState.d.ts +12 -12
  346. package/dist/types/interruptState.js +66 -66
  347. package/dist/types/playground.d.ts +7 -7
  348. package/dist/types/playground.js +14 -14
  349. package/dist/types/settings.d.ts +5 -3
  350. package/dist/types/settings.js +25 -18
  351. package/dist/types/skin.d.ts +31 -0
  352. package/dist/types/skin.js +1 -0
  353. package/dist/types/theme.d.ts +35 -0
  354. package/dist/types/theme.js +1 -0
  355. package/dist/types/uischema.d.ts +4 -4
  356. package/dist/types/uischema.js +3 -3
  357. package/dist/utils/colors.d.ts +1 -1
  358. package/dist/utils/colors.js +97 -95
  359. package/dist/utils/config.d.ts +2 -2
  360. package/dist/utils/config.js +48 -48
  361. package/dist/utils/connections.d.ts +2 -2
  362. package/dist/utils/connections.js +15 -15
  363. package/dist/utils/errors.js +3 -3
  364. package/dist/utils/fetchWithAuth.d.ts +1 -1
  365. package/dist/utils/fetchWithAuth.js +2 -2
  366. package/dist/utils/handleIds.d.ts +2 -2
  367. package/dist/utils/handleIds.js +8 -8
  368. package/dist/utils/handlePositioning.d.ts +1 -1
  369. package/dist/utils/handlePositioning.js +2 -2
  370. package/dist/utils/icons.d.ts +1 -1
  371. package/dist/utils/icons.js +74 -74
  372. package/dist/utils/logger.d.ts +1 -1
  373. package/dist/utils/logger.js +7 -7
  374. package/dist/utils/nodeStatus.d.ts +1 -1
  375. package/dist/utils/nodeStatus.js +48 -48
  376. package/dist/utils/nodeTypes.d.ts +1 -1
  377. package/dist/utils/nodeTypes.js +21 -20
  378. package/dist/utils/nodeWrapper.d.ts +7 -7
  379. package/dist/utils/nodeWrapper.js +21 -19
  380. package/dist/utils/performanceUtils.d.ts +1 -1
  381. package/dist/utils/performanceUtils.js +2 -1
  382. package/dist/utils/sanitize.js +1 -1
  383. package/dist/utils/uischema.d.ts +2 -2
  384. package/dist/utils/uischema.js +8 -8
  385. package/dist/utils/validation.js +20 -8
  386. package/package.json +1 -1
@@ -9,853 +9,873 @@
9
9
  -->
10
10
 
11
11
  <script lang="ts">
12
- import Icon from '@iconify/svelte';
13
- import { diffWords, diffArrays, diffJson } from 'diff';
14
- import type { Change } from 'diff';
15
- import { sanitizeHtml } from '../../utils/sanitize.js';
16
- import type {
17
- ReviewConfig,
18
- ReviewResolution,
19
- ReviewFieldDecision
20
- } from '../../types/interrupt.js';
21
-
22
- /**
23
- * Component props
24
- */
25
- interface Props {
26
- /** Review configuration from the interrupt */
27
- config: ReviewConfig;
28
- /** Whether this interrupt has been resolved */
29
- isResolved: boolean;
30
- /** The resolved value if resolved */
31
- resolvedValue?: ReviewResolution;
32
- /** Whether the form is currently submitting */
33
- isSubmitting: boolean;
34
- /** Error message if submission failed */
35
- error?: string;
36
- /** Username of the person who resolved the interrupt */
37
- resolvedByUserName?: string;
38
- /** Callback when user submits review */
39
- onSubmit: (value: ReviewResolution) => void;
40
- }
41
-
42
- let {
43
- config,
44
- isResolved,
45
- resolvedValue,
46
- isSubmitting,
47
- error,
48
- resolvedByUserName,
49
- onSubmit
50
- }: Props = $props();
51
-
52
- /** Local state: map of field -> accepted boolean. Default all to true (accept). */
53
- // svelte-ignore state_referenced_locally — initial default, user toggles during review
54
- let decisions = $state<Record<string, boolean>>(
55
- Object.fromEntries(config.changes.map((c) => [c.field, true]))
56
- );
57
-
58
- /** Local state: map of field -> HTML view mode ('rendered' or 'raw'). Default to 'rendered'. */
59
- // svelte-ignore state_referenced_locally
60
- let htmlViewMode = $state<Record<string, 'rendered' | 'raw'>>(
61
- Object.fromEntries(config.changes.map((c) => [c.field, 'rendered']))
62
- );
63
-
64
- /** Count of accepted fields */
65
- const acceptedCount = $derived(Object.values(decisions).filter((v) => v).length);
66
-
67
- /** Count of rejected fields */
68
- const rejectedCount = $derived(Object.values(decisions).filter((v) => !v).length);
69
-
70
- /** Total number of changes */
71
- const totalCount = $derived(config.changes.length);
72
-
73
- /** Button labels with defaults */
74
- const acceptAllLabel = $derived(config.acceptAllLabel ?? 'Accept All');
75
- const rejectAllLabel = $derived(config.rejectAllLabel ?? 'Reject All');
76
- const submitLabel = $derived(config.submitLabel ?? 'Submit Review');
77
-
78
- /**
79
- * Set a specific field's decision
80
- */
81
- function setFieldDecision(field: string, accepted: boolean): void {
82
- if (isResolved || isSubmitting) return;
83
- decisions = { ...decisions, [field]: accepted };
84
- }
85
-
86
- /**
87
- * Accept all changes
88
- */
89
- function handleAcceptAll(): void {
90
- if (isResolved || isSubmitting) return;
91
- decisions = Object.fromEntries(config.changes.map((c) => [c.field, true]));
92
- }
93
-
94
- /**
95
- * Reject all changes
96
- */
97
- function handleRejectAll(): void {
98
- if (isResolved || isSubmitting) return;
99
- decisions = Object.fromEntries(config.changes.map((c) => [c.field, false]));
100
- }
101
-
102
- /**
103
- * Submit the review
104
- */
105
- function handleSubmit(): void {
106
- if (isResolved || isSubmitting) return;
107
-
108
- const fieldDecisions: Record<string, ReviewFieldDecision> = {};
109
- for (const change of config.changes) {
110
- const accepted = decisions[change.field] ?? true;
111
- fieldDecisions[change.field] = {
112
- accepted,
113
- value: accepted ? change.proposed : change.original
114
- };
115
- }
116
-
117
- const resolution: ReviewResolution = {
118
- decisions: fieldDecisions,
119
- summary: {
120
- accepted: acceptedCount,
121
- rejected: rejectedCount,
122
- total: totalCount
123
- }
124
- };
125
-
126
- onSubmit(resolution);
127
- }
128
-
129
- /**
130
- * Toggle HTML view mode between rendered and raw for a field.
131
- */
132
- function toggleHtmlView(field: string): void {
133
- htmlViewMode = {
134
- ...htmlViewMode,
135
- [field]: htmlViewMode[field] === 'rendered' ? 'raw' : 'rendered'
136
- };
137
- }
138
-
139
- /**
140
- * Check if a string contains HTML tags.
141
- */
142
- function containsHtml(value: unknown): boolean {
143
- return typeof value === 'string' && /<[a-z][\s\S]*?>/i.test(value);
144
- }
145
-
146
- /**
147
- * Strip HTML tags from a string, preserving text content.
148
- * Collapses whitespace and trims the result.
149
- */
150
- function stripHtmlTags(html: string): string {
151
- return html
152
- .replace(/<br\s*\/?>/gi, '\n')
153
- .replace(/<\/(?:p|div|li|h[1-6])>/gi, '\n')
154
- .replace(/<[^>]+>/g, '')
155
- .replace(/&amp;/g, '&')
156
- .replace(/&lt;/g, '<')
157
- .replace(/&gt;/g, '>')
158
- .replace(/&quot;/g, '"')
159
- .replace(/&#39;/g, "'")
160
- .replace(/&nbsp;/g, ' ')
161
- .replace(/\n{3,}/g, '\n\n')
162
- .trim();
163
- }
164
-
165
- /**
166
- * Format a value for display
167
- */
168
- function formatValue(value: unknown): string {
169
- if (value === null || value === undefined) return '(empty)';
170
- if (typeof value === 'string') return value;
171
- if (typeof value === 'boolean') return value ? 'Yes' : 'No';
172
- if (typeof value === 'object') return JSON.stringify(value, null, 2);
173
- return String(value);
174
- }
175
-
176
- /**
177
- * Compute a diff between two values.
178
- * Supports strings (word-level), arrays (element-level), and objects (JSON line-level).
179
- * For HTML strings, strips tags and diffs the plain text content.
180
- */
181
- function computeDiff(
182
- original: unknown,
183
- proposed: unknown,
184
- rawMode: boolean = false
185
- ): Change[] | null {
186
- if (typeof original === 'string' && typeof proposed === 'string') {
187
- const origText = !rawMode && containsHtml(original) ? stripHtmlTags(original) : original;
188
- const propText = !rawMode && containsHtml(proposed) ? stripHtmlTags(proposed) : proposed;
189
- return diffWords(origText, propText);
190
- }
191
- if (Array.isArray(original) && Array.isArray(proposed)) {
192
- const arrayChanges = diffArrays(original, proposed);
193
- return arrayChanges.map((part) => ({
194
- value: part.value.map((v: unknown) => JSON.stringify(v)).join(', '),
195
- added: part.added,
196
- removed: part.removed,
197
- count: part.count
198
- }));
199
- }
200
- if (
201
- typeof original === 'object' &&
202
- original !== null &&
203
- !Array.isArray(original) &&
204
- typeof proposed === 'object' &&
205
- proposed !== null &&
206
- !Array.isArray(proposed)
207
- ) {
208
- return diffJson(original, proposed);
209
- }
210
- return null;
211
- }
212
-
213
- /**
214
- * Check if a diff result contains multi-line content (e.g. JSON diffs).
215
- */
216
- function isMultiLineDiff(changes: Change[]): boolean {
217
- return changes.some((part) => part.value.includes('\n'));
218
- }
12
+ import Icon from "@iconify/svelte";
13
+ import { diffWords, diffArrays, diffJson } from "diff";
14
+ import type { Change } from "diff";
15
+ import { sanitizeHtml } from "../../utils/sanitize.js";
16
+ import type {
17
+ ReviewConfig,
18
+ ReviewResolution,
19
+ ReviewFieldDecision,
20
+ } from "../../types/interrupt.js";
21
+
22
+ /**
23
+ * Component props
24
+ */
25
+ interface Props {
26
+ /** Review configuration from the interrupt */
27
+ config: ReviewConfig;
28
+ /** Whether this interrupt has been resolved */
29
+ isResolved: boolean;
30
+ /** The resolved value if resolved */
31
+ resolvedValue?: ReviewResolution;
32
+ /** Whether the form is currently submitting */
33
+ isSubmitting: boolean;
34
+ /** Error message if submission failed */
35
+ error?: string;
36
+ /** Username of the person who resolved the interrupt */
37
+ resolvedByUserName?: string;
38
+ /** Callback when user submits review */
39
+ onSubmit: (value: ReviewResolution) => void;
40
+ }
41
+
42
+ let {
43
+ config,
44
+ isResolved,
45
+ resolvedValue,
46
+ isSubmitting,
47
+ error,
48
+ resolvedByUserName,
49
+ onSubmit,
50
+ }: Props = $props();
51
+
52
+ /** Local state: map of field -> accepted boolean. Default all to true (accept). */
53
+ // svelte-ignore state_referenced_locally — initial default, user toggles during review
54
+ let decisions = $state<Record<string, boolean>>(
55
+ Object.fromEntries(config.changes.map((c) => [c.field, true])),
56
+ );
57
+
58
+ /** Local state: map of field -> HTML view mode ('rendered' or 'raw'). Default to 'rendered'. */
59
+ // svelte-ignore state_referenced_locally
60
+ let htmlViewMode = $state<Record<string, "rendered" | "raw">>(
61
+ Object.fromEntries(config.changes.map((c) => [c.field, "rendered"])),
62
+ );
63
+
64
+ /** Count of accepted fields */
65
+ const acceptedCount = $derived(
66
+ Object.values(decisions).filter((v) => v).length,
67
+ );
68
+
69
+ /** Count of rejected fields */
70
+ const rejectedCount = $derived(
71
+ Object.values(decisions).filter((v) => !v).length,
72
+ );
73
+
74
+ /** Total number of changes */
75
+ const totalCount = $derived(config.changes.length);
76
+
77
+ /** Button labels with defaults */
78
+ const acceptAllLabel = $derived(config.acceptAllLabel ?? "Accept All");
79
+ const rejectAllLabel = $derived(config.rejectAllLabel ?? "Reject All");
80
+ const submitLabel = $derived(config.submitLabel ?? "Submit Review");
81
+
82
+ /**
83
+ * Set a specific field's decision
84
+ */
85
+ function setFieldDecision(field: string, accepted: boolean): void {
86
+ if (isResolved || isSubmitting) return;
87
+ decisions = { ...decisions, [field]: accepted };
88
+ }
89
+
90
+ /**
91
+ * Accept all changes
92
+ */
93
+ function handleAcceptAll(): void {
94
+ if (isResolved || isSubmitting) return;
95
+ decisions = Object.fromEntries(config.changes.map((c) => [c.field, true]));
96
+ }
97
+
98
+ /**
99
+ * Reject all changes
100
+ */
101
+ function handleRejectAll(): void {
102
+ if (isResolved || isSubmitting) return;
103
+ decisions = Object.fromEntries(config.changes.map((c) => [c.field, false]));
104
+ }
105
+
106
+ /**
107
+ * Submit the review
108
+ */
109
+ function handleSubmit(): void {
110
+ if (isResolved || isSubmitting) return;
111
+
112
+ const fieldDecisions: Record<string, ReviewFieldDecision> = {};
113
+ for (const change of config.changes) {
114
+ const accepted = decisions[change.field] ?? true;
115
+ fieldDecisions[change.field] = {
116
+ accepted,
117
+ value: accepted ? change.proposed : change.original,
118
+ };
119
+ }
120
+
121
+ const resolution: ReviewResolution = {
122
+ decisions: fieldDecisions,
123
+ summary: {
124
+ accepted: acceptedCount,
125
+ rejected: rejectedCount,
126
+ total: totalCount,
127
+ },
128
+ };
129
+
130
+ onSubmit(resolution);
131
+ }
132
+
133
+ /**
134
+ * Toggle HTML view mode between rendered and raw for a field.
135
+ */
136
+ function toggleHtmlView(field: string): void {
137
+ htmlViewMode = {
138
+ ...htmlViewMode,
139
+ [field]: htmlViewMode[field] === "rendered" ? "raw" : "rendered",
140
+ };
141
+ }
142
+
143
+ /**
144
+ * Check if a string contains HTML tags.
145
+ */
146
+ function containsHtml(value: unknown): boolean {
147
+ return typeof value === "string" && /<[a-z][\s\S]*?>/i.test(value);
148
+ }
149
+
150
+ /**
151
+ * Strip HTML tags from a string, preserving text content.
152
+ * Collapses whitespace and trims the result.
153
+ */
154
+ function stripHtmlTags(html: string): string {
155
+ return html
156
+ .replace(/<br\s*\/?>/gi, "\n")
157
+ .replace(/<\/(?:p|div|li|h[1-6])>/gi, "\n")
158
+ .replace(/<[^>]+>/g, "")
159
+ .replace(/&amp;/g, "&")
160
+ .replace(/&lt;/g, "<")
161
+ .replace(/&gt;/g, ">")
162
+ .replace(/&quot;/g, '"')
163
+ .replace(/&#39;/g, "'")
164
+ .replace(/&nbsp;/g, " ")
165
+ .replace(/\n{3,}/g, "\n\n")
166
+ .trim();
167
+ }
168
+
169
+ /**
170
+ * Format a value for display
171
+ */
172
+ function formatValue(value: unknown): string {
173
+ if (value === null || value === undefined) return "(empty)";
174
+ if (typeof value === "string") return value;
175
+ if (typeof value === "boolean") return value ? "Yes" : "No";
176
+ if (typeof value === "object") return JSON.stringify(value, null, 2);
177
+ return String(value);
178
+ }
179
+
180
+ /**
181
+ * Compute a diff between two values.
182
+ * Supports strings (word-level), arrays (element-level), and objects (JSON line-level).
183
+ * For HTML strings, strips tags and diffs the plain text content.
184
+ */
185
+ function computeDiff(
186
+ original: unknown,
187
+ proposed: unknown,
188
+ rawMode: boolean = false,
189
+ ): Change[] | null {
190
+ if (typeof original === "string" && typeof proposed === "string") {
191
+ const origText =
192
+ !rawMode && containsHtml(original) ? stripHtmlTags(original) : original;
193
+ const propText =
194
+ !rawMode && containsHtml(proposed) ? stripHtmlTags(proposed) : proposed;
195
+ return diffWords(origText, propText);
196
+ }
197
+ if (Array.isArray(original) && Array.isArray(proposed)) {
198
+ const arrayChanges = diffArrays(original, proposed);
199
+ return arrayChanges.map((part) => ({
200
+ value: part.value.map((v: unknown) => JSON.stringify(v)).join(", "),
201
+ added: part.added,
202
+ removed: part.removed,
203
+ count: part.count,
204
+ }));
205
+ }
206
+ if (
207
+ typeof original === "object" &&
208
+ original !== null &&
209
+ !Array.isArray(original) &&
210
+ typeof proposed === "object" &&
211
+ proposed !== null &&
212
+ !Array.isArray(proposed)
213
+ ) {
214
+ return diffJson(original, proposed);
215
+ }
216
+ return null;
217
+ }
218
+
219
+ /**
220
+ * Check if a diff result contains multi-line content (e.g. JSON diffs).
221
+ */
222
+ function isMultiLineDiff(changes: Change[]): boolean {
223
+ return changes.some((part) => part.value.includes("\n"));
224
+ }
219
225
  </script>
220
226
 
221
227
  <div
222
- class="review-prompt"
223
- class:review-prompt--resolved={isResolved}
224
- class:review-prompt--submitting={isSubmitting}
228
+ class="review-prompt"
229
+ class:review-prompt--resolved={isResolved}
230
+ class:review-prompt--submitting={isSubmitting}
225
231
  >
226
- <!-- Message -->
227
- <p class="review-prompt__message">{config.message}</p>
228
-
229
- <!-- Error message -->
230
- {#if error}
231
- <div class="review-prompt__error">
232
- <Icon icon="mdi:alert-circle" />
233
- <span>{error}</span>
234
- </div>
235
- {/if}
236
-
237
- <!-- Bulk actions & counter (pending state only) -->
238
- {#if !isResolved}
239
- <div class="review-prompt__toolbar">
240
- <div class="review-prompt__bulk-actions">
241
- <button
242
- type="button"
243
- class="review-prompt__bulk-btn review-prompt__bulk-btn--accept"
244
- onclick={handleAcceptAll}
245
- disabled={isSubmitting}
246
- >
247
- <Icon icon="mdi:check-all" />
248
- <span>{acceptAllLabel}</span>
249
- </button>
250
- <button
251
- type="button"
252
- class="review-prompt__bulk-btn review-prompt__bulk-btn--reject"
253
- onclick={handleRejectAll}
254
- disabled={isSubmitting}
255
- >
256
- <Icon icon="mdi:close-circle-multiple-outline" />
257
- <span>{rejectAllLabel}</span>
258
- </button>
259
- </div>
260
- <span class="review-prompt__counter">
261
- {acceptedCount} of {totalCount} accepted
262
- </span>
263
- </div>
264
- {/if}
265
-
266
- <!-- Changes list -->
267
- <div class="review-prompt__changes">
268
- {#each config.changes as change (change.field)}
269
- {@const isAccepted = isResolved
270
- ? (resolvedValue?.decisions[change.field]?.accepted ?? true)
271
- : (decisions[change.field] ?? true)}
272
- {@const isHtml = containsHtml(change.original) || containsHtml(change.proposed)}
273
- {@const isRawView = htmlViewMode[change.field] === 'raw'}
274
- {@const diff = computeDiff(change.original, change.proposed, isRawView)}
275
- <div
276
- class="review-prompt__change"
277
- class:review-prompt__change--accepted={isAccepted}
278
- class:review-prompt__change--rejected={!isAccepted}
279
- >
280
- <!-- Change header: label + toggle -->
281
- <div class="review-prompt__change-header">
282
- <span class="review-prompt__change-label">{change.label}</span>
283
- {#if !isResolved}
284
- <div class="review-prompt__toggle-group">
285
- <button
286
- type="button"
287
- class="review-prompt__toggle-btn review-prompt__toggle-btn--accept"
288
- class:review-prompt__toggle-btn--active={isAccepted}
289
- onclick={() => setFieldDecision(change.field, true)}
290
- disabled={isSubmitting}
291
- aria-label="Accept {change.label}"
292
- title="Accept"
293
- >
294
- <Icon icon="mdi:check" />
295
- <span>Accept</span>
296
- </button>
297
- <button
298
- type="button"
299
- class="review-prompt__toggle-btn review-prompt__toggle-btn--reject"
300
- class:review-prompt__toggle-btn--active={!isAccepted}
301
- onclick={() => setFieldDecision(change.field, false)}
302
- disabled={isSubmitting}
303
- aria-label="Reject {change.label}"
304
- title="Reject"
305
- >
306
- <Icon icon="mdi:close" />
307
- <span>Reject</span>
308
- </button>
309
- </div>
310
- {:else}
311
- <span
312
- class="review-prompt__decision-badge"
313
- class:review-prompt__decision-badge--accepted={isAccepted}
314
- class:review-prompt__decision-badge--rejected={!isAccepted}
315
- >
316
- {#if isAccepted}
317
- <Icon icon="mdi:check-circle" />
318
- <span>Accepted</span>
319
- {:else}
320
- <Icon icon="mdi:close-circle" />
321
- <span>Rejected</span>
322
- {/if}
323
- </span>
324
- {/if}
325
- </div>
326
-
327
- <!-- Change diff content -->
328
- <div class="review-prompt__change-body">
329
- {#if isHtml}
330
- <div class="review-prompt__html-toggle-row">
331
- <button
332
- type="button"
333
- class="review-prompt__html-toggle-btn"
334
- onclick={() => toggleHtmlView(change.field)}
335
- >
336
- <Icon icon={isRawView ? 'mdi:eye' : 'mdi:code-tags'} />
337
- <span>{isRawView ? 'Rendered' : 'Raw HTML'}</span>
338
- </button>
339
- </div>
340
- {/if}
341
- <div class="review-prompt__diff-row">
342
- <span class="review-prompt__diff-label">Original:</span>
343
- {#if isHtml && !isRawView}
344
- <span class="review-prompt__diff-value review-prompt__html-content"
345
- >{@html sanitizeHtml(String(change.original))}</span
346
- >
347
- {:else if isHtml && isRawView}
348
- <code class="review-prompt__diff-value review-prompt__raw-html"
349
- >{change.original}</code
350
- >
351
- {:else}
352
- <span class="review-prompt__diff-value">
353
- {formatValue(change.original)}
354
- </span>
355
- {/if}
356
- </div>
357
- <div class="review-prompt__diff-row">
358
- <span class="review-prompt__diff-label">Proposed:</span>
359
- {#if isHtml && !isRawView}
360
- <span
361
- class="review-prompt__diff-value review-prompt__diff-value--proposed review-prompt__html-content"
362
- >{@html sanitizeHtml(String(change.proposed))}</span
363
- >
364
- {:else if isHtml && isRawView}
365
- <code
366
- class="review-prompt__diff-value review-prompt__diff-value--proposed review-prompt__raw-html"
367
- >{change.proposed}</code
368
- >
369
- {:else}
370
- <span class="review-prompt__diff-value review-prompt__diff-value--proposed">
371
- {formatValue(change.proposed)}
372
- </span>
373
- {/if}
374
- </div>
375
- {#if diff}
376
- <div class="review-prompt__diff-row">
377
- <span class="review-prompt__diff-label">Diff:</span>
378
- {#if isMultiLineDiff(diff)}
379
- <pre
380
- class="review-prompt__diff-value review-prompt__diff-block">{#each diff as part}{#if part.added}<span
381
- class="review-prompt__diff-token--added">{part.value}</span
382
- >{:else if part.removed}<span class="review-prompt__diff-token--removed"
383
- >{part.value}</span
384
- >{:else}<span>{part.value}</span>{/if}{/each}</pre>
385
- {:else}
386
- <span class="review-prompt__diff-value review-prompt__diff-inline">
387
- {#each diff as part}
388
- {#if part.added}
389
- <span class="review-prompt__diff-token--added">{part.value}</span>
390
- {:else if part.removed}
391
- <span class="review-prompt__diff-token--removed">{part.value}</span>
392
- {:else}
393
- <span>{part.value}</span>
394
- {/if}
395
- {/each}
396
- </span>
397
- {/if}
398
- </div>
399
- {/if}
400
- </div>
401
- </div>
402
- {/each}
403
- </div>
404
-
405
- <!-- Submit button (pending state only) -->
406
- {#if !isResolved}
407
- <div class="review-prompt__actions">
408
- <button
409
- type="button"
410
- class="review-prompt__submit"
411
- onclick={handleSubmit}
412
- disabled={isSubmitting}
413
- >
414
- {#if isSubmitting}
415
- <span class="review-prompt__spinner"></span>
416
- {:else}
417
- <Icon icon="mdi:check" />
418
- {/if}
419
- <span>{submitLabel}</span>
420
- </button>
421
- </div>
422
- {/if}
423
-
424
- <!-- Resolved summary -->
425
- {#if isResolved && resolvedValue}
426
- <div class="review-prompt__summary">
427
- <span class="review-prompt__summary-text">
428
- {resolvedValue.summary.accepted} accepted, {resolvedValue.summary.rejected} rejected out of {resolvedValue
429
- .summary.total} changes
430
- </span>
431
- </div>
432
- {/if}
433
-
434
- <!-- Resolved indicator -->
435
- {#if isResolved}
436
- <div class="review-prompt__resolved-badge">
437
- <Icon icon="mdi:check-circle" />
438
- <span>
439
- {resolvedByUserName ? `Response submitted by ${resolvedByUserName}` : 'Response submitted'}
440
- </span>
441
- </div>
442
- {/if}
232
+ <!-- Message -->
233
+ <p class="review-prompt__message">{config.message}</p>
234
+
235
+ <!-- Error message -->
236
+ {#if error}
237
+ <div class="review-prompt__error">
238
+ <Icon icon="mdi:alert-circle" />
239
+ <span>{error}</span>
240
+ </div>
241
+ {/if}
242
+
243
+ <!-- Bulk actions & counter (pending state only) -->
244
+ {#if !isResolved}
245
+ <div class="review-prompt__toolbar">
246
+ <div class="review-prompt__bulk-actions">
247
+ <button
248
+ type="button"
249
+ class="review-prompt__bulk-btn review-prompt__bulk-btn--accept"
250
+ onclick={handleAcceptAll}
251
+ disabled={isSubmitting}
252
+ >
253
+ <Icon icon="mdi:check-all" />
254
+ <span>{acceptAllLabel}</span>
255
+ </button>
256
+ <button
257
+ type="button"
258
+ class="review-prompt__bulk-btn review-prompt__bulk-btn--reject"
259
+ onclick={handleRejectAll}
260
+ disabled={isSubmitting}
261
+ >
262
+ <Icon icon="mdi:close-circle-multiple-outline" />
263
+ <span>{rejectAllLabel}</span>
264
+ </button>
265
+ </div>
266
+ <span class="review-prompt__counter">
267
+ {acceptedCount} of {totalCount} accepted
268
+ </span>
269
+ </div>
270
+ {/if}
271
+
272
+ <!-- Changes list -->
273
+ <div class="review-prompt__changes">
274
+ {#each config.changes as change (change.field)}
275
+ {@const isAccepted = isResolved
276
+ ? (resolvedValue?.decisions[change.field]?.accepted ?? true)
277
+ : (decisions[change.field] ?? true)}
278
+ {@const isHtml =
279
+ containsHtml(change.original) || containsHtml(change.proposed)}
280
+ {@const isRawView = htmlViewMode[change.field] === "raw"}
281
+ {@const diff = computeDiff(change.original, change.proposed, isRawView)}
282
+ <div
283
+ class="review-prompt__change"
284
+ class:review-prompt__change--accepted={isAccepted}
285
+ class:review-prompt__change--rejected={!isAccepted}
286
+ >
287
+ <!-- Change header: label + toggle -->
288
+ <div class="review-prompt__change-header">
289
+ <span class="review-prompt__change-label">{change.label}</span>
290
+ {#if !isResolved}
291
+ <div class="review-prompt__toggle-group">
292
+ <button
293
+ type="button"
294
+ class="review-prompt__toggle-btn review-prompt__toggle-btn--accept"
295
+ class:review-prompt__toggle-btn--active={isAccepted}
296
+ onclick={() => setFieldDecision(change.field, true)}
297
+ disabled={isSubmitting}
298
+ aria-label="Accept {change.label}"
299
+ title="Accept"
300
+ >
301
+ <Icon icon="mdi:check" />
302
+ <span>Accept</span>
303
+ </button>
304
+ <button
305
+ type="button"
306
+ class="review-prompt__toggle-btn review-prompt__toggle-btn--reject"
307
+ class:review-prompt__toggle-btn--active={!isAccepted}
308
+ onclick={() => setFieldDecision(change.field, false)}
309
+ disabled={isSubmitting}
310
+ aria-label="Reject {change.label}"
311
+ title="Reject"
312
+ >
313
+ <Icon icon="mdi:close" />
314
+ <span>Reject</span>
315
+ </button>
316
+ </div>
317
+ {:else}
318
+ <span
319
+ class="review-prompt__decision-badge"
320
+ class:review-prompt__decision-badge--accepted={isAccepted}
321
+ class:review-prompt__decision-badge--rejected={!isAccepted}
322
+ >
323
+ {#if isAccepted}
324
+ <Icon icon="mdi:check-circle" />
325
+ <span>Accepted</span>
326
+ {:else}
327
+ <Icon icon="mdi:close-circle" />
328
+ <span>Rejected</span>
329
+ {/if}
330
+ </span>
331
+ {/if}
332
+ </div>
333
+
334
+ <!-- Change diff content -->
335
+ <div class="review-prompt__change-body">
336
+ {#if isHtml}
337
+ <div class="review-prompt__html-toggle-row">
338
+ <button
339
+ type="button"
340
+ class="review-prompt__html-toggle-btn"
341
+ onclick={() => toggleHtmlView(change.field)}
342
+ >
343
+ <Icon icon={isRawView ? "mdi:eye" : "mdi:code-tags"} />
344
+ <span>{isRawView ? "Rendered" : "Raw HTML"}</span>
345
+ </button>
346
+ </div>
347
+ {/if}
348
+ <div class="review-prompt__diff-row">
349
+ <span class="review-prompt__diff-label">Original:</span>
350
+ {#if isHtml && !isRawView}
351
+ <span
352
+ class="review-prompt__diff-value review-prompt__html-content"
353
+ >{@html sanitizeHtml(String(change.original))}</span
354
+ >
355
+ {:else if isHtml && isRawView}
356
+ <code class="review-prompt__diff-value review-prompt__raw-html"
357
+ >{change.original}</code
358
+ >
359
+ {:else}
360
+ <span class="review-prompt__diff-value">
361
+ {formatValue(change.original)}
362
+ </span>
363
+ {/if}
364
+ </div>
365
+ <div class="review-prompt__diff-row">
366
+ <span class="review-prompt__diff-label">Proposed:</span>
367
+ {#if isHtml && !isRawView}
368
+ <span
369
+ class="review-prompt__diff-value review-prompt__diff-value--proposed review-prompt__html-content"
370
+ >{@html sanitizeHtml(String(change.proposed))}</span
371
+ >
372
+ {:else if isHtml && isRawView}
373
+ <code
374
+ class="review-prompt__diff-value review-prompt__diff-value--proposed review-prompt__raw-html"
375
+ >{change.proposed}</code
376
+ >
377
+ {:else}
378
+ <span
379
+ class="review-prompt__diff-value review-prompt__diff-value--proposed"
380
+ >
381
+ {formatValue(change.proposed)}
382
+ </span>
383
+ {/if}
384
+ </div>
385
+ {#if diff}
386
+ <div class="review-prompt__diff-row">
387
+ <span class="review-prompt__diff-label">Diff:</span>
388
+ {#if isMultiLineDiff(diff)}
389
+ <pre
390
+ class="review-prompt__diff-value review-prompt__diff-block">{#each diff as part}{#if part.added}<span
391
+ class="review-prompt__diff-token--added"
392
+ >{part.value}</span
393
+ >{:else if part.removed}<span
394
+ class="review-prompt__diff-token--removed"
395
+ >{part.value}</span
396
+ >{:else}<span>{part.value}</span>{/if}{/each}</pre>
397
+ {:else}
398
+ <span
399
+ class="review-prompt__diff-value review-prompt__diff-inline"
400
+ >
401
+ {#each diff as part}
402
+ {#if part.added}
403
+ <span class="review-prompt__diff-token--added"
404
+ >{part.value}</span
405
+ >
406
+ {:else if part.removed}
407
+ <span class="review-prompt__diff-token--removed"
408
+ >{part.value}</span
409
+ >
410
+ {:else}
411
+ <span>{part.value}</span>
412
+ {/if}
413
+ {/each}
414
+ </span>
415
+ {/if}
416
+ </div>
417
+ {/if}
418
+ </div>
419
+ </div>
420
+ {/each}
421
+ </div>
422
+
423
+ <!-- Submit button (pending state only) -->
424
+ {#if !isResolved}
425
+ <div class="review-prompt__actions">
426
+ <button
427
+ type="button"
428
+ class="review-prompt__submit"
429
+ onclick={handleSubmit}
430
+ disabled={isSubmitting}
431
+ >
432
+ {#if isSubmitting}
433
+ <span class="review-prompt__spinner"></span>
434
+ {:else}
435
+ <Icon icon="mdi:check" />
436
+ {/if}
437
+ <span>{submitLabel}</span>
438
+ </button>
439
+ </div>
440
+ {/if}
441
+
442
+ <!-- Resolved summary -->
443
+ {#if isResolved && resolvedValue}
444
+ <div class="review-prompt__summary">
445
+ <span class="review-prompt__summary-text">
446
+ {resolvedValue.summary.accepted} accepted, {resolvedValue.summary
447
+ .rejected} rejected out of {resolvedValue.summary.total} changes
448
+ </span>
449
+ </div>
450
+ {/if}
451
+
452
+ <!-- Resolved indicator -->
453
+ {#if isResolved}
454
+ <div class="review-prompt__resolved-badge">
455
+ <Icon icon="mdi:check-circle" />
456
+ <span>
457
+ {resolvedByUserName
458
+ ? `Response submitted by ${resolvedByUserName}`
459
+ : "Response submitted"}
460
+ </span>
461
+ </div>
462
+ {/if}
443
463
  </div>
444
464
 
445
465
  <style>
446
- /* Uses design tokens from tokens.css / base.css
466
+ /* Uses design tokens from tokens.css / base.css
447
467
  Component tokens: --fd-review-* defined in base.css */
448
- .review-prompt {
449
- display: flex;
450
- flex-direction: column;
451
- gap: var(--fd-space-md);
452
- }
453
-
454
- .review-prompt--resolved {
455
- opacity: 0.85;
456
- }
457
-
458
- .review-prompt--submitting {
459
- pointer-events: none;
460
- }
461
-
462
- .review-prompt__message {
463
- margin: 0;
464
- font-size: var(--fd-review-font-size-message);
465
- line-height: var(--fd-review-line-height);
466
- color: var(--fd-foreground);
467
- }
468
-
469
- .review-prompt__error {
470
- display: flex;
471
- align-items: center;
472
- gap: var(--fd-review-space-sm);
473
- padding: var(--fd-space-xs) var(--fd-space-md);
474
- background-color: var(--fd-error-muted);
475
- border-radius: var(--fd-radius-md);
476
- color: var(--fd-error);
477
- font-size: var(--fd-review-font-size-error);
478
- }
479
-
480
- /* Toolbar: bulk actions + counter */
481
- .review-prompt__toolbar {
482
- display: flex;
483
- align-items: center;
484
- justify-content: space-between;
485
- gap: var(--fd-space-md);
486
- flex-wrap: wrap;
487
- }
488
-
489
- .review-prompt__bulk-actions {
490
- display: flex;
491
- gap: var(--fd-space-xs);
492
- }
493
-
494
- .review-prompt__bulk-btn {
495
- display: inline-flex;
496
- align-items: center;
497
- gap: var(--fd-review-space-sm);
498
- padding: var(--fd-review-space-sm) var(--fd-space-md);
499
- font-size: var(--fd-text-xs);
500
- font-weight: 500;
501
- font-family: inherit;
502
- border-radius: var(--fd-radius-md);
503
- cursor: pointer;
504
- transition: all var(--fd-transition-fast);
505
- border: 1px solid var(--fd-border);
506
- background-color: var(--fd-muted);
507
- color: var(--fd-foreground);
508
- }
509
-
510
- .review-prompt__bulk-btn:hover:not(:disabled) {
511
- border-color: var(--fd-border-strong);
512
- }
513
-
514
- .review-prompt__bulk-btn--accept:hover:not(:disabled) {
515
- background-color: var(--fd-success-muted);
516
- border-color: var(--fd-success);
517
- color: var(--fd-success);
518
- }
519
-
520
- .review-prompt__bulk-btn--reject:hover:not(:disabled) {
521
- background-color: var(--fd-error-muted);
522
- border-color: var(--fd-error);
523
- color: var(--fd-error);
524
- }
525
-
526
- .review-prompt__bulk-btn:disabled {
527
- opacity: 0.5;
528
- cursor: not-allowed;
529
- }
530
-
531
- .review-prompt__counter {
532
- font-size: var(--fd-text-xs);
533
- color: var(--fd-muted-foreground);
534
- }
535
-
536
- /* Change cards */
537
- .review-prompt__changes {
538
- display: flex;
539
- flex-direction: column;
540
- gap: var(--fd-space-xs);
541
- }
542
-
543
- .review-prompt__change {
544
- border: 1px solid var(--fd-border);
545
- border-radius: var(--fd-radius-lg);
546
- background-color: var(--fd-background);
547
- overflow: hidden;
548
- transition: all var(--fd-transition-fast);
549
- }
550
-
551
- .review-prompt__change--accepted {
552
- border-color: var(--fd-success);
553
- }
554
-
555
- .review-prompt__change--rejected {
556
- border-color: var(--fd-error);
557
- }
558
-
559
- .review-prompt__change-header {
560
- display: flex;
561
- align-items: center;
562
- justify-content: space-between;
563
- padding: var(--fd-review-space-md) var(--fd-review-space-lg);
564
- border-bottom: 1px solid var(--fd-border);
565
- }
566
-
567
- .review-prompt__change--accepted .review-prompt__change-header {
568
- background-color: var(--fd-success-muted);
569
- border-bottom-color: var(--fd-success);
570
- }
571
-
572
- .review-prompt__change--rejected .review-prompt__change-header {
573
- background-color: var(--fd-error-muted);
574
- border-bottom-color: var(--fd-error);
575
- }
576
-
577
- .review-prompt__change-label {
578
- font-size: var(--fd-text-sm);
579
- font-weight: 600;
580
- color: var(--fd-foreground);
581
- }
582
-
583
- /* Accept/Reject toggle buttons */
584
- .review-prompt__toggle-group {
585
- display: flex;
586
- gap: var(--fd-space-3xs);
587
- }
588
-
589
- .review-prompt__toggle-btn {
590
- display: inline-flex;
591
- align-items: center;
592
- justify-content: center;
593
- gap: var(--fd-space-3xs);
594
- height: var(--fd-review-toggle-height);
595
- padding: 0 var(--fd-space-xs);
596
- border-radius: var(--fd-radius-md);
597
- border: 1px solid var(--fd-border);
598
- background-color: var(--fd-background);
599
- color: var(--fd-muted-foreground);
600
- cursor: pointer;
601
- transition: all var(--fd-transition-fast);
602
- font-size: var(--fd-text-xs);
603
- font-weight: 500;
604
- font-family: inherit;
605
- }
606
-
607
- .review-prompt__toggle-btn:hover:not(:disabled) {
608
- border-color: var(--fd-border-strong);
609
- }
610
-
611
- .review-prompt__toggle-btn--accept.review-prompt__toggle-btn--active {
612
- background-color: var(--fd-success);
613
- border-color: var(--fd-success);
614
- color: var(--fd-success-foreground);
615
- }
616
-
617
- .review-prompt__toggle-btn--reject.review-prompt__toggle-btn--active {
618
- background-color: var(--fd-error);
619
- border-color: var(--fd-error);
620
- color: var(--fd-error-foreground);
621
- }
622
-
623
- .review-prompt__toggle-btn:disabled {
624
- opacity: 0.5;
625
- cursor: not-allowed;
626
- }
627
-
628
- /* Decision badge (resolved state) */
629
- .review-prompt__decision-badge {
630
- display: inline-flex;
631
- align-items: center;
632
- gap: var(--fd-space-3xs);
633
- font-size: var(--fd-text-xs);
634
- font-weight: 500;
635
- }
636
-
637
- .review-prompt__decision-badge--accepted {
638
- color: var(--fd-success);
639
- }
640
-
641
- .review-prompt__decision-badge--rejected {
642
- color: var(--fd-error);
643
- }
644
-
645
- /* Diff content */
646
- .review-prompt__change-body {
647
- display: flex;
648
- flex-direction: column;
649
- }
650
-
651
- .review-prompt__diff-row {
652
- display: flex;
653
- align-items: baseline;
654
- gap: var(--fd-space-xs);
655
- padding: var(--fd-space-xs) var(--fd-review-space-lg);
656
- border-bottom: 1px solid var(--fd-border);
657
- }
658
-
659
- .review-prompt__diff-row:last-child {
660
- border-bottom: none;
661
- }
662
-
663
- .review-prompt__diff-label {
664
- font-size: var(--fd-text-xs);
665
- font-weight: 500;
666
- color: var(--fd-muted-foreground);
667
- min-width: var(--fd-review-diff-label-width);
668
- flex-shrink: 0;
669
- }
670
-
671
- .review-prompt__diff-value {
672
- font-size: var(--fd-text-sm);
673
- color: var(--fd-foreground);
674
- word-break: break-word;
675
- white-space: pre-wrap;
676
- }
677
-
678
- .review-prompt__diff-value--proposed {
679
- font-weight: 500;
680
- }
681
-
682
- /* Inline diff display */
683
- .review-prompt__diff-inline {
684
- line-height: var(--fd-review-line-height-content);
685
- }
686
-
687
- /* HTML view toggle */
688
- .review-prompt__html-toggle-row {
689
- display: flex;
690
- justify-content: flex-end;
691
- padding: var(--fd-review-space-sm) var(--fd-review-space-lg) 0;
692
- }
693
-
694
- .review-prompt__html-toggle-btn {
695
- display: inline-flex;
696
- align-items: center;
697
- gap: var(--fd-space-3xs);
698
- padding: var(--fd-review-space-xs) var(--fd-space-xs);
699
- font-size: var(--fd-review-font-size-html-toggle);
700
- font-weight: 500;
701
- font-family: inherit;
702
- color: var(--fd-muted-foreground);
703
- background: none;
704
- border: 1px solid var(--fd-border);
705
- border-radius: var(--fd-radius-md);
706
- cursor: pointer;
707
- transition: all var(--fd-transition-fast);
708
- }
709
-
710
- .review-prompt__html-toggle-btn:hover {
711
- color: var(--fd-foreground);
712
- border-color: var(--fd-border-strong);
713
- }
714
-
715
- /* Raw HTML code display */
716
- .review-prompt__raw-html {
717
- font-family: var(--fd-review-font-mono);
718
- font-size: var(--fd-text-xs);
719
- line-height: var(--fd-review-line-height);
720
- white-space: pre-wrap;
721
- word-break: break-word;
722
- }
723
-
724
- /* Rendered HTML content */
725
- .review-prompt__html-content {
726
- font-size: var(--fd-text-sm);
727
- line-height: var(--fd-review-line-height-content);
728
- }
729
-
730
- .review-prompt__html-content :global(p) {
731
- margin: 0 0 0.5em 0;
732
- }
733
-
734
- .review-prompt__html-content :global(p:last-child) {
735
- margin-bottom: 0;
736
- }
737
-
738
- .review-prompt__html-content :global(ul),
739
- .review-prompt__html-content :global(ol) {
740
- margin: 0 0 0.5em 0;
741
- padding-left: 1.25em;
742
- }
743
-
744
- .review-prompt__html-content :global(h1),
745
- .review-prompt__html-content :global(h2),
746
- .review-prompt__html-content :global(h3),
747
- .review-prompt__html-content :global(h4),
748
- .review-prompt__html-content :global(h5),
749
- .review-prompt__html-content :global(h6) {
750
- margin: 0 0 0.25em 0;
751
- font-size: 1em;
752
- font-weight: 600;
753
- }
754
-
755
- /* Block diff display (for JSON/multi-line diffs) */
756
- .review-prompt__diff-block {
757
- margin: 0;
758
- font-family: var(--fd-review-font-mono);
759
- font-size: var(--fd-text-xs);
760
- line-height: var(--fd-review-line-height);
761
- white-space: pre-wrap;
762
- word-break: break-word;
763
- overflow-x: auto;
764
- }
765
-
766
- .review-prompt__diff-token--added {
767
- background-color: var(--fd-success-muted);
768
- color: var(--fd-success);
769
- padding: var(--fd-review-diff-token-padding);
770
- border-radius: var(--fd-radius-sm);
771
- }
772
-
773
- .review-prompt__diff-token--removed {
774
- background-color: var(--fd-error-muted);
775
- color: var(--fd-error);
776
- text-decoration: line-through;
777
- padding: var(--fd-review-diff-token-padding);
778
- border-radius: var(--fd-radius-sm);
779
- }
780
-
781
- /* Actions */
782
- .review-prompt__actions {
783
- display: flex;
784
- gap: var(--fd-space-md);
785
- margin-top: var(--fd-space-3xs);
786
- }
787
-
788
- .review-prompt__submit {
789
- display: inline-flex;
790
- align-items: center;
791
- justify-content: center;
792
- gap: var(--fd-space-xs);
793
- padding: var(--fd-review-space-md) var(--fd-space-2xl);
794
- border-radius: var(--fd-radius-lg);
795
- font-size: var(--fd-text-sm);
796
- font-weight: 600;
797
- font-family: inherit;
798
- cursor: pointer;
799
- transition: all var(--fd-transition-normal);
800
- border: none;
801
- min-height: var(--fd-space-5xl);
802
- background: var(--fd-interrupt-btn-primary-bg);
803
- color: var(--fd-primary-foreground);
804
- box-shadow: var(--fd-shadow-sm);
805
- }
806
-
807
- .review-prompt__submit:hover:not(:disabled) {
808
- background: var(--fd-interrupt-btn-primary-bg-hover);
809
- box-shadow: var(--fd-shadow-md);
810
- transform: translateY(-1px);
811
- }
812
-
813
- .review-prompt__submit:disabled {
814
- opacity: 0.5;
815
- cursor: not-allowed;
816
- transform: none;
817
- box-shadow: none;
818
- }
819
-
820
- .review-prompt__spinner {
821
- width: var(--fd-space-xl);
822
- height: var(--fd-space-xl);
823
- border: 2px solid var(--fd-border);
824
- border-top-color: currentColor;
825
- border-radius: 50%;
826
- animation: review-spin 0.6s linear infinite;
827
- }
828
-
829
- @keyframes review-spin {
830
- to {
831
- transform: rotate(360deg);
832
- }
833
- }
834
-
835
- /* Summary */
836
- .review-prompt__summary {
837
- padding: var(--fd-space-xs) var(--fd-space-md);
838
- background-color: var(--fd-primary-muted);
839
- border: 1px solid var(--fd-interrupt-completed-border);
840
- border-radius: var(--fd-radius-md);
841
- }
842
-
843
- .review-prompt__summary-text {
844
- font-size: var(--fd-text-sm);
845
- color: var(--fd-interrupt-completed-text);
846
- }
847
-
848
- /* Resolved badge - neutral blue theme */
849
- .review-prompt__resolved-badge {
850
- display: inline-flex;
851
- align-items: center;
852
- gap: var(--fd-review-space-sm);
853
- padding: var(--fd-review-space-sm) var(--fd-space-md);
854
- background-color: var(--fd-interrupt-badge-completed-bg);
855
- border-radius: var(--fd-radius-full);
856
- color: var(--fd-interrupt-badge-completed-text);
857
- font-size: var(--fd-text-xs);
858
- font-weight: 500;
859
- align-self: flex-start;
860
- }
468
+ .review-prompt {
469
+ display: flex;
470
+ flex-direction: column;
471
+ gap: var(--fd-space-md);
472
+ }
473
+
474
+ .review-prompt--resolved {
475
+ opacity: 0.85;
476
+ }
477
+
478
+ .review-prompt--submitting {
479
+ pointer-events: none;
480
+ }
481
+
482
+ .review-prompt__message {
483
+ margin: 0;
484
+ font-size: var(--fd-review-font-size-message);
485
+ line-height: var(--fd-review-line-height);
486
+ color: var(--fd-foreground);
487
+ }
488
+
489
+ .review-prompt__error {
490
+ display: flex;
491
+ align-items: center;
492
+ gap: var(--fd-review-space-sm);
493
+ padding: var(--fd-space-xs) var(--fd-space-md);
494
+ background-color: var(--fd-error-muted);
495
+ border-radius: var(--fd-radius-md);
496
+ color: var(--fd-error);
497
+ font-size: var(--fd-review-font-size-error);
498
+ }
499
+
500
+ /* Toolbar: bulk actions + counter */
501
+ .review-prompt__toolbar {
502
+ display: flex;
503
+ align-items: center;
504
+ justify-content: space-between;
505
+ gap: var(--fd-space-md);
506
+ flex-wrap: wrap;
507
+ }
508
+
509
+ .review-prompt__bulk-actions {
510
+ display: flex;
511
+ gap: var(--fd-space-xs);
512
+ }
513
+
514
+ .review-prompt__bulk-btn {
515
+ display: inline-flex;
516
+ align-items: center;
517
+ gap: var(--fd-review-space-sm);
518
+ padding: var(--fd-review-space-sm) var(--fd-space-md);
519
+ font-size: var(--fd-text-xs);
520
+ font-weight: 500;
521
+ font-family: inherit;
522
+ border-radius: var(--fd-radius-md);
523
+ cursor: pointer;
524
+ transition: all var(--fd-transition-fast);
525
+ border: 1px solid var(--fd-border);
526
+ background-color: var(--fd-muted);
527
+ color: var(--fd-foreground);
528
+ }
529
+
530
+ .review-prompt__bulk-btn:hover:not(:disabled) {
531
+ border-color: var(--fd-border-strong);
532
+ }
533
+
534
+ .review-prompt__bulk-btn--accept:hover:not(:disabled) {
535
+ background-color: var(--fd-success-muted);
536
+ border-color: var(--fd-success);
537
+ color: var(--fd-success);
538
+ }
539
+
540
+ .review-prompt__bulk-btn--reject:hover:not(:disabled) {
541
+ background-color: var(--fd-error-muted);
542
+ border-color: var(--fd-error);
543
+ color: var(--fd-error);
544
+ }
545
+
546
+ .review-prompt__bulk-btn:disabled {
547
+ opacity: 0.5;
548
+ cursor: not-allowed;
549
+ }
550
+
551
+ .review-prompt__counter {
552
+ font-size: var(--fd-text-xs);
553
+ color: var(--fd-muted-foreground);
554
+ }
555
+
556
+ /* Change cards */
557
+ .review-prompt__changes {
558
+ display: flex;
559
+ flex-direction: column;
560
+ gap: var(--fd-space-xs);
561
+ }
562
+
563
+ .review-prompt__change {
564
+ border: 1px solid var(--fd-border);
565
+ border-radius: var(--fd-radius-lg);
566
+ background-color: var(--fd-background);
567
+ overflow: hidden;
568
+ transition: all var(--fd-transition-fast);
569
+ }
570
+
571
+ .review-prompt__change--accepted {
572
+ border-color: var(--fd-success);
573
+ }
574
+
575
+ .review-prompt__change--rejected {
576
+ border-color: var(--fd-error);
577
+ }
578
+
579
+ .review-prompt__change-header {
580
+ display: flex;
581
+ align-items: center;
582
+ justify-content: space-between;
583
+ padding: var(--fd-review-space-md) var(--fd-review-space-lg);
584
+ border-bottom: 1px solid var(--fd-border);
585
+ }
586
+
587
+ .review-prompt__change--accepted .review-prompt__change-header {
588
+ background-color: var(--fd-success-muted);
589
+ border-bottom-color: var(--fd-success);
590
+ }
591
+
592
+ .review-prompt__change--rejected .review-prompt__change-header {
593
+ background-color: var(--fd-error-muted);
594
+ border-bottom-color: var(--fd-error);
595
+ }
596
+
597
+ .review-prompt__change-label {
598
+ font-size: var(--fd-text-sm);
599
+ font-weight: 600;
600
+ color: var(--fd-foreground);
601
+ }
602
+
603
+ /* Accept/Reject toggle buttons */
604
+ .review-prompt__toggle-group {
605
+ display: flex;
606
+ gap: var(--fd-space-3xs);
607
+ }
608
+
609
+ .review-prompt__toggle-btn {
610
+ display: inline-flex;
611
+ align-items: center;
612
+ justify-content: center;
613
+ gap: var(--fd-space-3xs);
614
+ height: var(--fd-review-toggle-height);
615
+ padding: 0 var(--fd-space-xs);
616
+ border-radius: var(--fd-radius-md);
617
+ border: 1px solid var(--fd-border);
618
+ background-color: var(--fd-background);
619
+ color: var(--fd-muted-foreground);
620
+ cursor: pointer;
621
+ transition: all var(--fd-transition-fast);
622
+ font-size: var(--fd-text-xs);
623
+ font-weight: 500;
624
+ font-family: inherit;
625
+ }
626
+
627
+ .review-prompt__toggle-btn:hover:not(:disabled) {
628
+ border-color: var(--fd-border-strong);
629
+ }
630
+
631
+ .review-prompt__toggle-btn--accept.review-prompt__toggle-btn--active {
632
+ background-color: var(--fd-success);
633
+ border-color: var(--fd-success);
634
+ color: var(--fd-success-foreground);
635
+ }
636
+
637
+ .review-prompt__toggle-btn--reject.review-prompt__toggle-btn--active {
638
+ background-color: var(--fd-error);
639
+ border-color: var(--fd-error);
640
+ color: var(--fd-error-foreground);
641
+ }
642
+
643
+ .review-prompt__toggle-btn:disabled {
644
+ opacity: 0.5;
645
+ cursor: not-allowed;
646
+ }
647
+
648
+ /* Decision badge (resolved state) */
649
+ .review-prompt__decision-badge {
650
+ display: inline-flex;
651
+ align-items: center;
652
+ gap: var(--fd-space-3xs);
653
+ font-size: var(--fd-text-xs);
654
+ font-weight: 500;
655
+ }
656
+
657
+ .review-prompt__decision-badge--accepted {
658
+ color: var(--fd-success);
659
+ }
660
+
661
+ .review-prompt__decision-badge--rejected {
662
+ color: var(--fd-error);
663
+ }
664
+
665
+ /* Diff content */
666
+ .review-prompt__change-body {
667
+ display: flex;
668
+ flex-direction: column;
669
+ }
670
+
671
+ .review-prompt__diff-row {
672
+ display: flex;
673
+ align-items: baseline;
674
+ gap: var(--fd-space-xs);
675
+ padding: var(--fd-space-xs) var(--fd-review-space-lg);
676
+ border-bottom: 1px solid var(--fd-border);
677
+ }
678
+
679
+ .review-prompt__diff-row:last-child {
680
+ border-bottom: none;
681
+ }
682
+
683
+ .review-prompt__diff-label {
684
+ font-size: var(--fd-text-xs);
685
+ font-weight: 500;
686
+ color: var(--fd-muted-foreground);
687
+ min-width: var(--fd-review-diff-label-width);
688
+ flex-shrink: 0;
689
+ }
690
+
691
+ .review-prompt__diff-value {
692
+ font-size: var(--fd-text-sm);
693
+ color: var(--fd-foreground);
694
+ word-break: break-word;
695
+ white-space: pre-wrap;
696
+ }
697
+
698
+ .review-prompt__diff-value--proposed {
699
+ font-weight: 500;
700
+ }
701
+
702
+ /* Inline diff display */
703
+ .review-prompt__diff-inline {
704
+ line-height: var(--fd-review-line-height-content);
705
+ }
706
+
707
+ /* HTML view toggle */
708
+ .review-prompt__html-toggle-row {
709
+ display: flex;
710
+ justify-content: flex-end;
711
+ padding: var(--fd-review-space-sm) var(--fd-review-space-lg) 0;
712
+ }
713
+
714
+ .review-prompt__html-toggle-btn {
715
+ display: inline-flex;
716
+ align-items: center;
717
+ gap: var(--fd-space-3xs);
718
+ padding: var(--fd-review-space-xs) var(--fd-space-xs);
719
+ font-size: var(--fd-review-font-size-html-toggle);
720
+ font-weight: 500;
721
+ font-family: inherit;
722
+ color: var(--fd-muted-foreground);
723
+ background: none;
724
+ border: 1px solid var(--fd-border);
725
+ border-radius: var(--fd-radius-md);
726
+ cursor: pointer;
727
+ transition: all var(--fd-transition-fast);
728
+ }
729
+
730
+ .review-prompt__html-toggle-btn:hover {
731
+ color: var(--fd-foreground);
732
+ border-color: var(--fd-border-strong);
733
+ }
734
+
735
+ /* Raw HTML code display */
736
+ .review-prompt__raw-html {
737
+ font-family: var(--fd-review-font-mono);
738
+ font-size: var(--fd-text-xs);
739
+ line-height: var(--fd-review-line-height);
740
+ white-space: pre-wrap;
741
+ word-break: break-word;
742
+ }
743
+
744
+ /* Rendered HTML content */
745
+ .review-prompt__html-content {
746
+ font-size: var(--fd-text-sm);
747
+ line-height: var(--fd-review-line-height-content);
748
+ }
749
+
750
+ .review-prompt__html-content :global(p) {
751
+ margin: 0 0 0.5em 0;
752
+ }
753
+
754
+ .review-prompt__html-content :global(p:last-child) {
755
+ margin-bottom: 0;
756
+ }
757
+
758
+ .review-prompt__html-content :global(ul),
759
+ .review-prompt__html-content :global(ol) {
760
+ margin: 0 0 0.5em 0;
761
+ padding-left: 1.25em;
762
+ }
763
+
764
+ .review-prompt__html-content :global(h1),
765
+ .review-prompt__html-content :global(h2),
766
+ .review-prompt__html-content :global(h3),
767
+ .review-prompt__html-content :global(h4),
768
+ .review-prompt__html-content :global(h5),
769
+ .review-prompt__html-content :global(h6) {
770
+ margin: 0 0 0.25em 0;
771
+ font-size: 1em;
772
+ font-weight: 600;
773
+ }
774
+
775
+ /* Block diff display (for JSON/multi-line diffs) */
776
+ .review-prompt__diff-block {
777
+ margin: 0;
778
+ font-family: var(--fd-review-font-mono);
779
+ font-size: var(--fd-text-xs);
780
+ line-height: var(--fd-review-line-height);
781
+ white-space: pre-wrap;
782
+ word-break: break-word;
783
+ overflow-x: auto;
784
+ }
785
+
786
+ .review-prompt__diff-token--added {
787
+ background-color: var(--fd-success-muted);
788
+ color: var(--fd-success);
789
+ padding: var(--fd-review-diff-token-padding);
790
+ border-radius: var(--fd-radius-sm);
791
+ }
792
+
793
+ .review-prompt__diff-token--removed {
794
+ background-color: var(--fd-error-muted);
795
+ color: var(--fd-error);
796
+ text-decoration: line-through;
797
+ padding: var(--fd-review-diff-token-padding);
798
+ border-radius: var(--fd-radius-sm);
799
+ }
800
+
801
+ /* Actions */
802
+ .review-prompt__actions {
803
+ display: flex;
804
+ gap: var(--fd-space-md);
805
+ margin-top: var(--fd-space-3xs);
806
+ }
807
+
808
+ .review-prompt__submit {
809
+ display: inline-flex;
810
+ align-items: center;
811
+ justify-content: center;
812
+ gap: var(--fd-space-xs);
813
+ padding: var(--fd-review-space-md) var(--fd-space-2xl);
814
+ border-radius: var(--fd-radius-lg);
815
+ font-size: var(--fd-text-sm);
816
+ font-weight: 600;
817
+ font-family: inherit;
818
+ cursor: pointer;
819
+ transition: all var(--fd-transition-normal);
820
+ border: none;
821
+ min-height: var(--fd-space-5xl);
822
+ background: var(--fd-interrupt-btn-primary-bg);
823
+ color: var(--fd-primary-foreground);
824
+ box-shadow: var(--fd-shadow-sm);
825
+ }
826
+
827
+ .review-prompt__submit:hover:not(:disabled) {
828
+ background: var(--fd-interrupt-btn-primary-bg-hover);
829
+ box-shadow: var(--fd-shadow-md);
830
+ transform: translateY(-1px);
831
+ }
832
+
833
+ .review-prompt__submit:disabled {
834
+ opacity: 0.5;
835
+ cursor: not-allowed;
836
+ transform: none;
837
+ box-shadow: none;
838
+ }
839
+
840
+ .review-prompt__spinner {
841
+ width: var(--fd-space-xl);
842
+ height: var(--fd-space-xl);
843
+ border: 2px solid var(--fd-border);
844
+ border-top-color: currentColor;
845
+ border-radius: 50%;
846
+ animation: review-spin 0.6s linear infinite;
847
+ }
848
+
849
+ @keyframes review-spin {
850
+ to {
851
+ transform: rotate(360deg);
852
+ }
853
+ }
854
+
855
+ /* Summary */
856
+ .review-prompt__summary {
857
+ padding: var(--fd-space-xs) var(--fd-space-md);
858
+ background-color: var(--fd-primary-muted);
859
+ border: 1px solid var(--fd-interrupt-completed-border);
860
+ border-radius: var(--fd-radius-md);
861
+ }
862
+
863
+ .review-prompt__summary-text {
864
+ font-size: var(--fd-text-sm);
865
+ color: var(--fd-interrupt-completed-text);
866
+ }
867
+
868
+ /* Resolved badge - neutral blue theme */
869
+ .review-prompt__resolved-badge {
870
+ display: inline-flex;
871
+ align-items: center;
872
+ gap: var(--fd-review-space-sm);
873
+ padding: var(--fd-review-space-sm) var(--fd-space-md);
874
+ background-color: var(--fd-interrupt-badge-completed-bg);
875
+ border-radius: var(--fd-radius-full);
876
+ color: var(--fd-interrupt-badge-completed-text);
877
+ font-size: var(--fd-text-xs);
878
+ font-weight: 500;
879
+ align-self: flex-start;
880
+ }
861
881
  </style>