@jini-ai/admin 0.4.2 → 0.4.3

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 (360) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/README.md +7 -0
  3. package/dist/agent-plugins/react/components/AgentPluginListPanel.d.ts +1 -1
  4. package/dist/agent-plugins/react/hooks/AgentPluginInspector.hooks.js +1 -1
  5. package/dist/agent-plugins/react/hooks/AgentPluginPanel.hooks.d.ts +1 -1
  6. package/dist/agent-plugins/react/hooks/AgentPluginsPage.hooks.d.ts +1 -1
  7. package/dist/agent-plugins/react/hooks/AgentPluginsPage.hooks.js +1 -1
  8. package/dist/agent-plugins/react/hooks/MarketplaceTab.hooks.d.ts +1 -1
  9. package/dist/agent-plugins/react/index.js +1 -1
  10. package/dist/agent-plugins/react/pages/AgentPluginsPage.d.ts +1 -1
  11. package/dist/agent-plugins/react/tabs/DownloadedTab.d.ts +1 -1
  12. package/dist/agent-plugins/react/tabs/InstalledTab.d.ts +1 -1
  13. package/dist/agent-plugins/react/tabs/MarketplaceTab.d.ts +1 -1
  14. package/dist/comments/adapters/http.d.ts +29 -0
  15. package/dist/comments/adapters/http.js +50 -0
  16. package/dist/comments/adapters/memory.d.ts +17 -0
  17. package/dist/comments/adapters/memory.js +61 -0
  18. package/dist/comments/comments.module.d.ts +73 -0
  19. package/dist/comments/comments.module.js +16 -0
  20. package/dist/comments/conformance/comments-api.conformance.d.ts +9 -0
  21. package/dist/comments/conformance/comments-api.conformance.js +63 -0
  22. package/dist/comments/controllers/comment-queue.controller.d.ts +48 -0
  23. package/dist/comments/controllers/comment-queue.controller.js +164 -0
  24. package/dist/comments/controllers/comment-settings.controller.d.ts +32 -0
  25. package/dist/comments/controllers/comment-settings.controller.js +77 -0
  26. package/dist/comments/controllers/comments.controller.d.ts +16 -0
  27. package/dist/comments/controllers/comments.controller.js +16 -0
  28. package/dist/comments/index.d.ts +13 -0
  29. package/dist/comments/index.js +8 -0
  30. package/dist/comments/messages.en.d.ts +54 -0
  31. package/dist/comments/messages.en.js +56 -0
  32. package/dist/comments/models.d.ts +22 -0
  33. package/dist/comments/models.js +2 -0
  34. package/dist/comments/ports.d.ts +14 -0
  35. package/dist/comments/ports.js +5 -0
  36. package/dist/comments/react/components/QueueSection.d.ts +30 -0
  37. package/dist/comments/react/components/QueueSection.js +57 -0
  38. package/dist/comments/react/components/SettingsSection.d.ts +14 -0
  39. package/dist/comments/react/components/SettingsSection.js +23 -0
  40. package/dist/comments/react/hooks/CommentsPage.hooks.d.ts +9 -0
  41. package/dist/comments/react/hooks/CommentsPage.hooks.js +10 -0
  42. package/dist/comments/react/hooks/CommentsPorts.hooks.d.ts +13 -0
  43. package/dist/comments/react/hooks/CommentsPorts.hooks.js +15 -0
  44. package/dist/comments/react/hooks/QueueSection.hooks.d.ts +62 -0
  45. package/dist/comments/react/hooks/QueueSection.hooks.js +57 -0
  46. package/dist/comments/react/hooks/SettingsSection.hooks.d.ts +12 -0
  47. package/dist/comments/react/hooks/SettingsSection.hooks.js +21 -0
  48. package/dist/comments/react/hooks/use-comment-queue.hooks.d.ts +34 -0
  49. package/dist/comments/react/hooks/use-comment-queue.hooks.js +47 -0
  50. package/dist/comments/react/hooks/use-comment-settings.hooks.d.ts +22 -0
  51. package/dist/comments/react/hooks/use-comment-settings.hooks.js +30 -0
  52. package/dist/comments/react/hooks/use-comments.hooks.d.ts +15 -0
  53. package/dist/comments/react/hooks/use-comments.hooks.js +20 -0
  54. package/dist/comments/react/index.d.ts +316 -0
  55. package/dist/comments/react/index.js +35 -0
  56. package/dist/comments/react/pages/CommentsPage.d.ts +12 -0
  57. package/dist/comments/react/pages/CommentsPage.js +15 -0
  58. package/dist/comments/rules.d.ts +140 -0
  59. package/dist/comments/rules.js +199 -0
  60. package/dist/core/index.d.ts +3 -1
  61. package/dist/core/index.js +1 -0
  62. package/dist/core/ledger-slice.d.ts +90 -0
  63. package/dist/core/ledger-slice.js +81 -0
  64. package/dist/core/ports/comments.d.ts +2 -0
  65. package/dist/core/ports/forms.d.ts +19 -7
  66. package/dist/core/ports/forms.js +4 -4
  67. package/dist/core/ports/index.d.ts +1 -1
  68. package/dist/core/ports/seo.d.ts +33 -6
  69. package/dist/core/react/bind-react.d.ts +46 -0
  70. package/dist/core/react/bind-react.js +28 -0
  71. package/dist/core/react/index.d.ts +3 -0
  72. package/dist/core/react/index.js +3 -0
  73. package/dist/core/react/use-controller.d.ts +16 -0
  74. package/dist/core/react/use-controller.js +18 -0
  75. package/dist/forms/adapters/http.d.ts +26 -0
  76. package/dist/forms/adapters/http.js +43 -0
  77. package/dist/forms/adapters/memory.d.ts +14 -0
  78. package/dist/forms/adapters/memory.js +77 -0
  79. package/dist/forms/conformance/forms-api.conformance.d.ts +17 -0
  80. package/dist/forms/conformance/forms-api.conformance.js +71 -0
  81. package/dist/forms/controllers/draft-store.d.ts +18 -0
  82. package/dist/forms/controllers/draft-store.js +17 -0
  83. package/dist/forms/controllers/field-attributes-dialog.controller.d.ts +37 -0
  84. package/dist/forms/controllers/field-attributes-dialog.controller.js +27 -0
  85. package/dist/forms/controllers/form-editor.controller.d.ts +36 -0
  86. package/dist/forms/controllers/form-editor.controller.js +22 -0
  87. package/dist/forms/controllers/form-fields-editor.controller.d.ts +20 -0
  88. package/dist/forms/controllers/form-fields-editor.controller.js +10 -0
  89. package/dist/forms/controllers/form-submission-detail.controller.d.ts +20 -0
  90. package/dist/forms/controllers/form-submission-detail.controller.js +10 -0
  91. package/dist/forms/controllers/form-submissions.controller.d.ts +25 -0
  92. package/dist/forms/controllers/form-submissions.controller.js +10 -0
  93. package/dist/forms/controllers/forms-list.controller.d.ts +22 -0
  94. package/dist/forms/controllers/forms-list.controller.js +10 -0
  95. package/dist/forms/forms.module.d.ts +137 -0
  96. package/dist/forms/forms.module.js +17 -0
  97. package/dist/forms/html-rules.d.ts +20 -0
  98. package/dist/forms/html-rules.js +24 -0
  99. package/dist/forms/index.d.ts +14 -0
  100. package/dist/forms/index.js +12 -0
  101. package/dist/forms/messages.en.d.ts +100 -0
  102. package/dist/forms/messages.en.js +104 -0
  103. package/dist/forms/models.d.ts +29 -0
  104. package/dist/forms/models.js +8 -0
  105. package/dist/forms/ports.d.ts +26 -0
  106. package/dist/forms/ports.js +6 -0
  107. package/dist/forms/react/components/FieldAttributesDialog.d.ts +14 -0
  108. package/dist/forms/react/components/FieldAttributesDialog.js +47 -0
  109. package/dist/forms/react/components/FormEditorFieldsBody.d.ts +28 -0
  110. package/dist/forms/react/components/FormEditorFieldsBody.js +24 -0
  111. package/dist/forms/react/components/FormEditorHeaderText.d.ts +7 -0
  112. package/dist/forms/react/components/FormEditorHeaderText.js +8 -0
  113. package/dist/forms/react/components/FormEditorMainPanel.d.ts +12 -0
  114. package/dist/forms/react/components/FormEditorMainPanel.js +13 -0
  115. package/dist/forms/react/components/FormEditorTabStrip.d.ts +13 -0
  116. package/dist/forms/react/components/FormEditorTabStrip.js +14 -0
  117. package/dist/forms/react/components/FormFieldsEditor.d.ts +13 -0
  118. package/dist/forms/react/components/FormFieldsEditor.js +39 -0
  119. package/dist/forms/react/components/FormSubmissionDate.d.ts +8 -0
  120. package/dist/forms/react/components/FormSubmissionDate.js +5 -0
  121. package/dist/forms/react/components/FormSubmissionDetail.d.ts +13 -0
  122. package/dist/forms/react/components/FormSubmissionDetail.js +29 -0
  123. package/dist/forms/react/components/FormSubmissions.d.ts +12 -0
  124. package/dist/forms/react/components/FormSubmissions.js +46 -0
  125. package/dist/forms/react/hooks/FormsPorts.hooks.d.ts +41 -0
  126. package/dist/forms/react/hooks/FormsPorts.hooks.js +16 -0
  127. package/dist/forms/react/hooks/forms-view.hooks.d.ts +122 -0
  128. package/dist/forms/react/hooks/forms-view.hooks.js +79 -0
  129. package/dist/forms/react/hooks/use-field-attributes-dialog.hooks.d.ts +31 -0
  130. package/dist/forms/react/hooks/use-field-attributes-dialog.hooks.js +22 -0
  131. package/dist/forms/react/hooks/use-form-editor.hooks.d.ts +118 -0
  132. package/dist/forms/react/hooks/use-form-editor.hooks.js +208 -0
  133. package/dist/forms/react/hooks/use-form-fields-editor.hooks.d.ts +34 -0
  134. package/dist/forms/react/hooks/use-form-fields-editor.hooks.js +36 -0
  135. package/dist/forms/react/hooks/use-form-submission-date.hooks.d.ts +12 -0
  136. package/dist/forms/react/hooks/use-form-submission-date.hooks.js +9 -0
  137. package/dist/forms/react/hooks/use-form-submission-detail.hooks.d.ts +68 -0
  138. package/dist/forms/react/hooks/use-form-submission-detail.hooks.js +81 -0
  139. package/dist/forms/react/hooks/use-form-submissions.hooks.d.ts +67 -0
  140. package/dist/forms/react/hooks/use-form-submissions.hooks.js +110 -0
  141. package/dist/forms/react/hooks/use-forms-list.hooks.d.ts +78 -0
  142. package/dist/forms/react/hooks/use-forms-list.hooks.js +103 -0
  143. package/dist/forms/react/index.d.ts +449 -0
  144. package/dist/forms/react/index.js +35 -0
  145. package/dist/forms/react/pages/FormEditor.d.ts +19 -0
  146. package/dist/forms/react/pages/FormEditor.js +40 -0
  147. package/dist/forms/react/pages/FormsList.d.ts +39 -0
  148. package/dist/forms/react/pages/FormsList.js +55 -0
  149. package/dist/forms/rules.d.ts +291 -0
  150. package/dist/forms/rules.js +338 -0
  151. package/dist/media/react/hooks/EditMediaPanel.hooks.js +1 -1
  152. package/dist/media/react/hooks/LibraryTab.hooks.d.ts +1 -1
  153. package/dist/media/react/hooks/LibraryTab.hooks.js +1 -1
  154. package/dist/media/react/hooks/MediaCard.hooks.js +6 -20
  155. package/dist/media/react/hooks/MediaGrid.hooks.d.ts +2 -2
  156. package/dist/media/react/hooks/MediaPage.hooks.d.ts +1 -1
  157. package/dist/media/react/hooks/MediaPage.hooks.js +1 -1
  158. package/dist/media/react/hooks/MediaPicker.hooks.js +1 -1
  159. package/dist/media/react/index.js +1 -1
  160. package/dist/media/react/tabs/LibraryTab.d.ts +1 -1
  161. package/dist/media/react/tabs/ProvidersTab.d.ts +1 -1
  162. package/dist/playground/react/components/Canvas.d.ts +1 -1
  163. package/dist/playground/react/hooks/Canvas.hooks.d.ts +1 -1
  164. package/dist/playground/react/hooks/Canvas.hooks.js +1 -1
  165. package/dist/playground/react/hooks/PlaygroundPage.hooks.d.ts +1 -1
  166. package/dist/playground/react/index.js +1 -1
  167. package/dist/playground/react/pages/PlaygroundPage.d.ts +1 -1
  168. package/dist/playground/react/tabs/CanvasTab.d.ts +1 -1
  169. package/dist/react/bind-react.d.ts +1 -45
  170. package/dist/react/bind-react.js +2 -27
  171. package/dist/react/components/ConfirmDialog/ConfirmDialog.d.ts +22 -5
  172. package/dist/react/components/ConfirmDialog/ConfirmDialog.hooks.d.ts +2 -2
  173. package/dist/react/components/ConfirmDialog/ConfirmDialog.hooks.js +17 -55
  174. package/dist/react/components/ConfirmDialog/ConfirmDialog.js +33 -70
  175. package/dist/react/use-controller.d.ts +1 -15
  176. package/dist/react/use-controller.js +2 -17
  177. package/dist/redirects/adapters/http.d.ts +20 -0
  178. package/dist/redirects/adapters/http.js +31 -0
  179. package/dist/redirects/adapters/memory.d.ts +13 -0
  180. package/dist/redirects/adapters/memory.js +83 -0
  181. package/dist/redirects/conformance/redirects-api.conformance.d.ts +12 -0
  182. package/dist/redirects/conformance/redirects-api.conformance.js +66 -0
  183. package/dist/redirects/controllers/hit-count.controller.d.ts +14 -0
  184. package/dist/redirects/controllers/hit-count.controller.js +10 -0
  185. package/dist/redirects/controllers/import-redirects.controller.d.ts +28 -0
  186. package/dist/redirects/controllers/import-redirects.controller.js +29 -0
  187. package/dist/redirects/controllers/redirects.controller.d.ts +37 -0
  188. package/dist/redirects/controllers/redirects.controller.js +38 -0
  189. package/dist/redirects/index.d.ts +11 -0
  190. package/dist/redirects/index.js +10 -0
  191. package/dist/redirects/messages.en.d.ts +56 -0
  192. package/dist/redirects/messages.en.js +55 -0
  193. package/dist/redirects/models.d.ts +14 -0
  194. package/dist/redirects/models.js +2 -0
  195. package/dist/redirects/ports.d.ts +9 -0
  196. package/dist/redirects/ports.js +4 -0
  197. package/dist/redirects/react/components/HitCountCell.d.ts +19 -0
  198. package/dist/redirects/react/components/HitCountCell.js +19 -0
  199. package/dist/redirects/react/components/ImportRedirectsForm.d.ts +17 -0
  200. package/dist/redirects/react/components/ImportRedirectsForm.js +12 -0
  201. package/dist/redirects/react/hooks/RedirectsOptions.hooks.d.ts +27 -0
  202. package/dist/redirects/react/hooks/RedirectsOptions.hooks.js +15 -0
  203. package/dist/redirects/react/hooks/RedirectsPage.hooks.d.ts +50 -0
  204. package/dist/redirects/react/hooks/RedirectsPage.hooks.js +30 -0
  205. package/dist/redirects/react/hooks/RedirectsPorts.hooks.d.ts +10 -0
  206. package/dist/redirects/react/hooks/RedirectsPorts.hooks.js +11 -0
  207. package/dist/redirects/react/hooks/use-hit-count-cell.hooks.d.ts +19 -0
  208. package/dist/redirects/react/hooks/use-hit-count-cell.hooks.js +15 -0
  209. package/dist/redirects/react/hooks/use-import-redirects-form.hooks.d.ts +21 -0
  210. package/dist/redirects/react/hooks/use-import-redirects-form.hooks.js +25 -0
  211. package/dist/redirects/react/hooks/use-redirects.hooks.d.ts +34 -0
  212. package/dist/redirects/react/hooks/use-redirects.hooks.js +63 -0
  213. package/dist/redirects/react/hooks/wired.hooks.d.ts +55 -0
  214. package/dist/redirects/react/hooks/wired.hooks.js +31 -0
  215. package/dist/redirects/react/index.d.ts +316 -0
  216. package/dist/redirects/react/index.js +28 -0
  217. package/dist/redirects/react/pages/RedirectsPage.d.ts +15 -0
  218. package/dist/redirects/react/pages/RedirectsPage.js +20 -0
  219. package/dist/redirects/redirects.module.d.ts +75 -0
  220. package/dist/redirects/redirects.module.js +13 -0
  221. package/dist/redirects/rules.d.ts +131 -0
  222. package/dist/redirects/rules.js +134 -0
  223. package/dist/security/react/hooks/AccessTokensTab.hooks.d.ts +1 -1
  224. package/dist/security/react/hooks/AccessTokensTab.hooks.js +1 -1
  225. package/dist/security/react/hooks/RootKeyTab.hooks.d.ts +1 -1
  226. package/dist/security/react/hooks/RootKeyTab.hooks.js +1 -1
  227. package/dist/security/react/hooks/SecurityPage.hooks.d.ts +1 -1
  228. package/dist/security/react/index.js +1 -1
  229. package/dist/security/react/pages/SecurityPage.d.ts +1 -1
  230. package/dist/security/react/tabs/AccessTokensTab.d.ts +1 -1
  231. package/dist/security/react/tabs/RootKeyTab.d.ts +1 -1
  232. package/dist/seo/adapters/http.d.ts +31 -0
  233. package/dist/seo/adapters/http.js +37 -0
  234. package/dist/seo/adapters/memory.d.ts +28 -0
  235. package/dist/seo/adapters/memory.js +129 -0
  236. package/dist/seo/conformance/seo-api.conformance.d.ts +8 -0
  237. package/dist/seo/conformance/seo-api.conformance.js +44 -0
  238. package/dist/seo/controllers/entry-picker.controller.d.ts +21 -0
  239. package/dist/seo/controllers/entry-picker.controller.js +17 -0
  240. package/dist/seo/controllers/entry-section.controller.d.ts +20 -0
  241. package/dist/seo/controllers/entry-section.controller.js +7 -0
  242. package/dist/seo/controllers/media-ref.controller.d.ts +26 -0
  243. package/dist/seo/controllers/media-ref.controller.js +14 -0
  244. package/dist/seo/controllers/seo-entry.controller.d.ts +31 -0
  245. package/dist/seo/controllers/seo-entry.controller.js +52 -0
  246. package/dist/seo/controllers/seo.controller.d.ts +29 -0
  247. package/dist/seo/controllers/seo.controller.js +50 -0
  248. package/dist/seo/controllers/sitemap.controller.d.ts +25 -0
  249. package/dist/seo/controllers/sitemap.controller.js +27 -0
  250. package/dist/seo/index.d.ts +14 -0
  251. package/dist/seo/index.js +12 -0
  252. package/dist/seo/messages.en.d.ts +78 -0
  253. package/dist/seo/messages.en.js +78 -0
  254. package/dist/seo/models.d.ts +179 -0
  255. package/dist/seo/models.js +8 -0
  256. package/dist/seo/ports.d.ts +11 -0
  257. package/dist/seo/ports.js +4 -0
  258. package/dist/seo/react/components/MediaPickerBridge.d.ts +4 -0
  259. package/dist/seo/react/components/MediaPickerBridge.js +8 -0
  260. package/dist/seo/react/components/MediaRefField.d.ts +36 -0
  261. package/dist/seo/react/components/MediaRefField.js +12 -0
  262. package/dist/seo/react/components/SeoIcons.d.ts +13 -0
  263. package/dist/seo/react/components/SeoIcons.js +32 -0
  264. package/dist/seo/react/components/SitemapModal.d.ts +48 -0
  265. package/dist/seo/react/components/SitemapModal.js +70 -0
  266. package/dist/seo/react/hooks/MediaPickerBridge.hooks.d.ts +6 -0
  267. package/dist/seo/react/hooks/MediaPickerBridge.hooks.js +27 -0
  268. package/dist/seo/react/hooks/MediaRefField.hooks.d.ts +22 -0
  269. package/dist/seo/react/hooks/MediaRefField.hooks.js +30 -0
  270. package/dist/seo/react/hooks/SeoModuleTabs.d.ts +14 -0
  271. package/dist/seo/react/hooks/SeoModuleTabs.js +18 -0
  272. package/dist/seo/react/hooks/SeoPage.hooks.d.ts +69 -0
  273. package/dist/seo/react/hooks/SeoPage.hooks.js +37 -0
  274. package/dist/seo/react/hooks/SeoPorts.hooks.d.ts +19 -0
  275. package/dist/seo/react/hooks/SeoPorts.hooks.js +22 -0
  276. package/dist/seo/react/hooks/SitemapModal.hooks.d.ts +26 -0
  277. package/dist/seo/react/hooks/SitemapModal.hooks.js +20 -0
  278. package/dist/seo/react/hooks/use-entry-picker.hooks.d.ts +11 -0
  279. package/dist/seo/react/hooks/use-entry-picker.hooks.js +20 -0
  280. package/dist/seo/react/hooks/use-seo-entry-panel.hooks.d.ts +14 -0
  281. package/dist/seo/react/hooks/use-seo-entry-panel.hooks.js +26 -0
  282. package/dist/seo/react/hooks/use-seo-entry-section.hooks.d.ts +4 -0
  283. package/dist/seo/react/hooks/use-seo-entry-section.hooks.js +7 -0
  284. package/dist/seo/react/hooks/use-seo.hooks.d.ts +11 -0
  285. package/dist/seo/react/hooks/use-seo.hooks.js +29 -0
  286. package/dist/seo/react/hooks/use-sitemap-modal.hooks.d.ts +10 -0
  287. package/dist/seo/react/hooks/use-sitemap-modal.hooks.js +18 -0
  288. package/dist/seo/react/index.d.ts +366 -0
  289. package/dist/seo/react/index.js +30 -0
  290. package/dist/seo/react/options.d.ts +19 -0
  291. package/dist/seo/react/options.js +2 -0
  292. package/dist/seo/react/pages/SeoPage.d.ts +161 -0
  293. package/dist/seo/react/pages/SeoPage.js +215 -0
  294. package/dist/seo/rules.d.ts +136 -0
  295. package/dist/seo/rules.js +212 -0
  296. package/dist/seo/seo.module.d.ts +114 -0
  297. package/dist/seo/seo.module.js +14 -0
  298. package/dist/source-control/react/hooks/ProvidersTab.hooks.d.ts +1 -1
  299. package/dist/source-control/react/hooks/ProvidersTab.hooks.js +1 -1
  300. package/dist/source-control/react/hooks/SourceControlPage.hooks.d.ts +1 -1
  301. package/dist/source-control/react/index.js +1 -1
  302. package/dist/source-control/react/pages/SourceControlPage.d.ts +1 -1
  303. package/dist/source-control/react/tabs/ProvidersTab.d.ts +1 -1
  304. package/dist/widgets/adapters/http.d.ts +19 -0
  305. package/dist/widgets/adapters/http.js +33 -0
  306. package/dist/widgets/adapters/memory.d.ts +22 -0
  307. package/dist/widgets/adapters/memory.js +93 -0
  308. package/dist/widgets/conformance/widgets-api.conformance.d.ts +6 -0
  309. package/dist/widgets/conformance/widgets-api.conformance.js +55 -0
  310. package/dist/widgets/controllers/instance-editor.controller.d.ts +49 -0
  311. package/dist/widgets/controllers/instance-editor.controller.js +87 -0
  312. package/dist/widgets/controllers/library.controller.d.ts +33 -0
  313. package/dist/widgets/controllers/library.controller.js +53 -0
  314. package/dist/widgets/controllers/region-editor.controller.d.ts +42 -0
  315. package/dist/widgets/controllers/region-editor.controller.js +69 -0
  316. package/dist/widgets/controllers/regions.controller.d.ts +27 -0
  317. package/dist/widgets/controllers/regions.controller.js +44 -0
  318. package/dist/widgets/index.d.ts +11 -0
  319. package/dist/widgets/index.js +9 -0
  320. package/dist/widgets/messages.en.d.ts +78 -0
  321. package/dist/widgets/messages.en.js +83 -0
  322. package/dist/widgets/models.d.ts +62 -0
  323. package/dist/widgets/models.js +2 -0
  324. package/dist/widgets/ports.d.ts +79 -0
  325. package/dist/widgets/ports.js +5 -0
  326. package/dist/widgets/react/components/WidgetInstanceNotices.d.ts +14 -0
  327. package/dist/widgets/react/components/WidgetInstanceNotices.js +25 -0
  328. package/dist/widgets/react/components/WidgetRegionEditorHeaderActions.d.ts +22 -0
  329. package/dist/widgets/react/components/WidgetRegionEditorHeaderActions.js +18 -0
  330. package/dist/widgets/react/components/WidgetsLibraryNotices.d.ts +13 -0
  331. package/dist/widgets/react/components/WidgetsLibraryNotices.js +10 -0
  332. package/dist/widgets/react/hooks/WidgetsPorts.hooks.d.ts +270 -0
  333. package/dist/widgets/react/hooks/WidgetsPorts.hooks.js +17 -0
  334. package/dist/widgets/react/hooks/navigation.hooks.d.ts +9 -0
  335. package/dist/widgets/react/hooks/navigation.hooks.js +6 -0
  336. package/dist/widgets/react/hooks/page-views.hooks.d.ts +87 -0
  337. package/dist/widgets/react/hooks/page-views.hooks.js +30 -0
  338. package/dist/widgets/react/hooks/use-widget-instance-editor.hooks.d.ts +56 -0
  339. package/dist/widgets/react/hooks/use-widget-instance-editor.hooks.js +38 -0
  340. package/dist/widgets/react/hooks/use-widget-region-editor.hooks.d.ts +32 -0
  341. package/dist/widgets/react/hooks/use-widget-region-editor.hooks.js +22 -0
  342. package/dist/widgets/react/hooks/use-widget-regions.hooks.d.ts +23 -0
  343. package/dist/widgets/react/hooks/use-widget-regions.hooks.js +22 -0
  344. package/dist/widgets/react/hooks/use-widgets-library.hooks.d.ts +37 -0
  345. package/dist/widgets/react/hooks/use-widgets-library.hooks.js +23 -0
  346. package/dist/widgets/react/index.d.ts +391 -0
  347. package/dist/widgets/react/index.js +31 -0
  348. package/dist/widgets/react/pages/WidgetInstanceEditor.d.ts +23 -0
  349. package/dist/widgets/react/pages/WidgetInstanceEditor.js +37 -0
  350. package/dist/widgets/react/pages/WidgetRegionEditor.d.ts +22 -0
  351. package/dist/widgets/react/pages/WidgetRegionEditor.js +25 -0
  352. package/dist/widgets/react/pages/WidgetRegions.d.ts +21 -0
  353. package/dist/widgets/react/pages/WidgetRegions.js +31 -0
  354. package/dist/widgets/react/pages/WidgetsLibrary.d.ts +24 -0
  355. package/dist/widgets/react/pages/WidgetsLibrary.js +61 -0
  356. package/dist/widgets/rules.d.ts +94 -0
  357. package/dist/widgets/rules.js +83 -0
  358. package/dist/widgets/widgets.module.d.ts +122 -0
  359. package/dist/widgets/widgets.module.js +21 -0
  360. package/package.json +206 -9
@@ -0,0 +1,118 @@
1
+ import type { AdminFormsPort } from "../../../core/ports/forms.js";
2
+ import { type FormAnswerColumn } from "../../html-rules.js";
3
+ import type { AdminFormDefinition, AdminFormField } from "../../models.js";
4
+ /**
5
+ * @file Everything the FormEditor SCREEN does — load, save, status toggle, and the Fields/
6
+ * Submissions tab strip's roving-tabindex focus management — so `FormEditor`'s exported component
7
+ * in `FormEditor.tsx` is only markup.
8
+ *
9
+ * Moved from the host — same load effect, same save/status-toggle error strings, same "later failure
10
+ * keeps the editor on screen" guard (the audit-blocker fix this screen's file header describes —
11
+ * see `FormEditor.tsx`'s own header for the full rationale, which stays with the guard in the view
12
+ * since it describes render behaviour, not this hook's state).
13
+ *
14
+ * `tab` (ADR-063, 2026-08-31): no longer local state — it is `props.tab`, derived from the route
15
+ * (`/forms/:formId` vs `/forms/:formId/submissions`) by `panels.tsx`/`FormEditor.tsx`. Switching
16
+ * tabs calls the injected `navigate` (real app router), the same idiom `Deployment.tsx`'s tab strip
17
+ * uses, rather than a local `setTab` — Submissions has its own independent fetch, so a tab switch
18
+ * is a genuine route change, not a display-layer filter over data already in hand.
19
+ *
20
+ * `tabRefs` moves here too, per Pattern 1 (every `useRef` moves with state/effects, not just
21
+ * `useState`) — the view still attaches each button via its own `ref` callback (an unavoidably
22
+ * DOM-side operation), but the ref array itself and the keydown-to-focus-change logic
23
+ * (`onTabsKeyDown`) are behaviour, not markup.
24
+ *
25
+ * Naming follows `hooks/use-settings-slice.hooks.ts`: `use-<thing>.hooks.ts`. Feature-local because
26
+ * nothing outside `features/forms` needs it.
27
+ *
28
+ * `port`/`navigate` are injected — see `core/ports/forms.ts` (shared with `use-forms-list.hooks.ts`,
29
+ * since both read/write the same `AdminFormDefinition` resource) — rather than reaching `lib/api`/
30
+ * `lib/router` directly, so a test can describe load/save outcomes against `the memory adapter`
31
+ * instead of stubbing global `fetch`. `useWiredFormEditor` below is the zero-argument pair
32
+ * `FormEditor.tsx` actually mounts.
33
+ *
34
+ * `t` (standing i18n rule — a component with a hook gets a BOUND `t` from that hook, not its own
35
+ * `useAdminLocale()`/dictionary import, same shape `use-post-editor.hooks.ts` established for this
36
+ * conversion): injected alongside `port`/`navigate` because `FormEditor.tsx` itself (the copy
37
+ * around this hook's own state — tab labels, Save button, etc.) DOES need translated strings, even
38
+ * though this hook's own error messages don't. Pre-bound to `(key: string) => string`.
39
+ * `useAdminLocale()` and `FORMS_DICT` are called/read only inside {@link useWiredFormEditor}.
40
+ *
41
+ * `@jini-ai/ui/fetch-query` migration (2026-08-12): the load is one `useFetchQuery` keyed on
42
+ * `KEYS.form(formId)` (disabled for `isNew`, matching the original `if (isNew) return;` early-out).
43
+ * `form`/`name`/`slug`/`fields`/`notify` live in the section controller — the operator edits `name`/`slug`/
44
+ * `fields`; `notify` has no UI of its own (owner ask 2026-09-22 removed the notify checkbox/
45
+ * recipients input — see this file's own `notify` state comment) and is only ever carried through
46
+ * unchanged. All are seeded from `list.data` exactly once per `formId` via `seededFormIdRef`, the
47
+ * same shape `collections/hooks/use-collection-entry-editor.hooks.ts`'s `seededIdentityRef`
48
+ * establishes (see that file's header for the regression it guards against: a background refetch of
49
+ * the SAME identity must not clobber in-progress edits). `handleSave`/`handleStatusToggle` set `form`
50
+ * (and, for save, the rest of the seeded fields) directly from each MUTATION's own response, and
51
+ * neither mutation invalidates this hook's OWN `KEYS.form(formId)` read (only the sibling
52
+ * `KEYS.list`) — mirroring `save()`/`toggleLifecycle()` in that same collections hook, which
53
+ * invalidate only the sibling `KEYS.entries(...)`, never their own `KEYS.entry(...)`, for the
54
+ * identical reason: a response already in hand needs no redundant background refetch of itself. This
55
+ * eliminates the load race an external audit flagged at this file's old line 117 (`useEffect(load,
56
+ * [props.formId, port])` with no cancellation guard, so a formId change mid-flight could commit a
57
+ * stale response): a keyed query cannot commit a response belonging to a prior key, by construction.
58
+ */
59
+ export interface FormEditorController {
60
+ isNew: boolean;
61
+ /** `null` until the initial load settles (or always, for `isNew`) — the caller renders a loading
62
+ * state or the empty create form accordingly. */
63
+ form: AdminFormDefinition | null;
64
+ name: string;
65
+ setName: (value: string) => void;
66
+ slug: string;
67
+ setSlug: (value: string) => void;
68
+ mode: "builder" | "html";
69
+ onModeChange: (mode: "builder" | "html") => void;
70
+ html: string;
71
+ setHtml: (html: string) => void;
72
+ copyEmbed: () => void;
73
+ copyFeedback: string | null;
74
+ answerColumns: FormAnswerColumn[];
75
+ fields: AdminFormField[];
76
+ setFields: (fields: AdminFormField[]) => void;
77
+ tab: "fields" | "submissions";
78
+ /** Navigates to this form's Fields or Submissions route — real `navigate()`, not local state
79
+ * (ADR-063: Submissions has its own independent fetch, so a tab switch is a genuine route
80
+ * change, the same idiom `Deployment.tsx`'s tab strip uses). Pushes a history entry (no
81
+ * `replace`) so browser back/forward move naturally between the two routes, unlike the
82
+ * `?tab=` screens' `replace: true` view-filter switches. */
83
+ onTabChange: (tab: "fields" | "submissions") => void;
84
+ error: string | null;
85
+ saving: boolean;
86
+ /** Already-persisted field ids on the loaded form — see `existingFieldIdsOf`. */
87
+ existingFieldIds: string[];
88
+ /** Tabs render only for an existing, loaded form — never for `isNew`, and never before `form`
89
+ * has loaded. */
90
+ showTabs: boolean;
91
+ /** Per-tab-button refs, indexed the same as `FORM_TABS` — attach via each button's own `ref`
92
+ * callback in the view. */
93
+ tabRefs: React.MutableRefObject<Array<HTMLButtonElement | null>>;
94
+ /** Roving-tabindex keydown handler for the tablist `<div>` — ArrowLeft/ArrowRight/Home/End move
95
+ * both the selected tab and DOM focus together. */
96
+ onTabsKeyDown: (e: React.KeyboardEvent) => void;
97
+ handleSave: () => void;
98
+ handleStatusToggle: () => void;
99
+ /** Bound translator — see this file's own header for why it arrives via the hook rather than
100
+ * `FormEditor.tsx` calling `useAdminLocale()`/`FORMS_DICT` directly. */
101
+ t: (key: string) => string;
102
+ }
103
+ export declare function useFormEditor(props: {
104
+ formId: string;
105
+ tab: "fields" | "submissions";
106
+ port: AdminFormsPort;
107
+ navigate: (path: string) => void;
108
+ t: (key: string) => string;
109
+ }, { clipboard }?: {
110
+ clipboard?: {
111
+ writeText: (text: string) => Promise<void>;
112
+ };
113
+ }): FormEditorController;
114
+ export declare function useWiredFormEditor(props: {
115
+ formId: string;
116
+ tab: "fields" | "submissions";
117
+ }, _optional?: {}): FormEditorController;
118
+ //# sourceMappingURL=use-form-editor.hooks.d.ts.map
@@ -0,0 +1,208 @@
1
+ import { formView } from "../../models.js";
2
+ import { useFormsPorts, useFormsOptions } from "./FormsPorts.hooks.js";
3
+ import { useController } from "../../../core/react/use-controller.js";
4
+ import { createFormEditorController, initialFormEditorState } from "../../controllers/form-editor.controller.js";
5
+ import { formHtmlEmbed, formAnswerColumns } from "../../html-rules.js";
6
+ import { useEffect, useRef } from "react";
7
+ import { useFetchMutation, useFetchQuery } from "@jini-ai/ui/fetch-query";
8
+ import { FORM_TABS, KEYS, existingFieldIdsOf, nextTabIndex, visibleFormEditorError } from "../../rules.js";
9
+ export function useFormEditor(props, { clipboard } = {}) {
10
+ const { port, navigate, t } = props;
11
+ const { tab } = props;
12
+ const isNew = props.formId === "new";
13
+ const { controller: stateController, snapshot: stateSnapshot } = useController({ create: () => createFormEditorController({}), dependencies: [] });
14
+ const state = stateSnapshot ?? initialFormEditorState({});
15
+ const form = state.form;
16
+ const setForm = (value) => stateController?.update({ key: "form", value });
17
+ const mode = state.mode;
18
+ const html = state.html;
19
+ const setHtml = (value) => stateController?.update({ key: "html", value });
20
+ const copyFeedback = state.copyFeedback;
21
+ const setCopyFeedback = (value) => stateController?.update({ key: "copyFeedback", value });
22
+ const name = state.name;
23
+ const setName = (value) => stateController?.update({ key: "name", value });
24
+ const slug = state.slug;
25
+ const setSlug = (value) => stateController?.update({ key: "slug", value });
26
+ const fields = state.fields;
27
+ const setFields = (value) => stateController?.update({ key: "fields", value });
28
+ // No UI edits this (owner ask 2026-09-22 removed the notify checkbox/recipients input from the
29
+ // Fields tab — a future outside mail integration will design its own way to set it). Seeded from
30
+ // the loaded form and carried through unchanged on every save, so an operator saving a form never
31
+ // wipes out a `notify` setting that predates this UI removal. Lives in the section controller, not a
32
+ // `const`, only so `handleSave`'s existing-form branch can resync it from the write's own response
33
+ // exactly like `form`/`name`/`slug`/`fields` already do below.
34
+ const notify = state.notify;
35
+ // Roving-tabindex focus targets for the tab strip below, indexed the same as `FORM_TABS` — see
36
+ // `nextTabIndex`'s doc comment for why the index math itself lives outside the component.
37
+ const tabRefs = useRef([]);
38
+ const list = useFetchQuery({ key: KEYS.form(props.formId), fetch: () => port.getFormDefinition({ id: props.formId }).then(form => ({ data: formView({ form }) })) }, { enabled: !isNew });
39
+ // Seeds `form`/`name`/`slug`/`fields`/`notify` from `list.data` exactly once per `formId` — see
40
+ // this file's own header for the regression this guards against (a background refetch of the SAME
41
+ // formId must not clobber in-progress edits).
42
+ const seededFormIdRef = useRef(null);
43
+ const seededControllerRef = useRef(null);
44
+ useEffect(() => {
45
+ if (seededControllerRef.current !== stateController) {
46
+ seededControllerRef.current = stateController;
47
+ seededFormIdRef.current = null;
48
+ }
49
+ if (seededFormIdRef.current !== props.formId)
50
+ seededFormIdRef.current = null;
51
+ if (!stateController)
52
+ return;
53
+ if (isNew || list.status === "loading" || !list.data)
54
+ return;
55
+ if (seededFormIdRef.current === props.formId)
56
+ return;
57
+ seededFormIdRef.current = props.formId;
58
+ const loaded = list.data.data;
59
+ stateController.seed({ form: loaded });
60
+ }, [props.formId, isNew, list.status, list.data, stateController]);
61
+ // None of these invalidate `KEYS.form(props.formId)` — only `KEYS.list`. `handleSave`/
62
+ // `handleStatusToggle` below already set `form` (and, for save, the rest of the seeded fields)
63
+ // directly from each mutation's own response, so invalidating this hook's OWN read key would only
64
+ // buy a redundant background refetch of data already in hand — the same reasoning
65
+ // `use-collection-entry-editor.hooks.ts`'s `save()`/`toggleLifecycle()` document for why THEIR
66
+ // `invalidates` names only the sibling `KEYS.entries(...)`, never their own `KEYS.entry(...)`.
67
+ const updateMutation = useFetchMutation({
68
+ run: ({ input }) =>
69
+ // Targets the loaded record's real id, never `props.formId` directly — the admin URL now
70
+ // carries the form's slug when one resolves (ui-fixes-backlog.md #8), so `props.formId` may
71
+ // itself BE that slug. `form.id` is always the real id regardless of which one the URL held,
72
+ // which is what lets the PUT route stay id-only (no matching slug support needed — see
73
+ // `get-by-id.ts`'s own comment on why only the GET route resolves either). The `?? props
74
+ // .formId` fallback only matters if this ever fired before `form` loaded, which it can't:
75
+ // `FormEditor.tsx`'s `!isNew && !form` guards keep the whole editor (Save button included)
76
+ // off-screen until `form` is set.
77
+ port.updateFormDefinition({ id: form?.id ?? props.formId }, input),
78
+ }, {
79
+ invalidates: [KEYS.list],
80
+ });
81
+ const createMutation = useFetchMutation({
82
+ run: ({ input }) => port.createFormDefinition({ name: input.name, slug: input.slug, fields: input.fields, ...(input.mode ? { mode: input.mode, html: input.html } : {}) }, { notify: input.notify }),
83
+ }, {
84
+ invalidates: [KEYS.list],
85
+ });
86
+ const statusMutation = useFetchMutation({
87
+ run: ({ input }) => port.updateFormDefinition({ id: input.id }, { status: input.status }),
88
+ }, {
89
+ invalidates: [KEYS.list],
90
+ });
91
+ function onModeChange(next) {
92
+ stateController?.changeMode({ mode: next }, { submitLabel: t("Send") });
93
+ }
94
+ async function copyEmbed() {
95
+ if (!form)
96
+ return;
97
+ try {
98
+ await (clipboard ?? navigator.clipboard).writeText(formHtmlEmbed({ slug: form.slug }));
99
+ setCopyFeedback(t("Copied!"));
100
+ }
101
+ catch {
102
+ setCopyFeedback(t("Could not copy embed"));
103
+ }
104
+ }
105
+ async function handleSave() {
106
+ // Ordinary Builder saves keep their existing endpoint/permissions. A mode change is explicit.
107
+ const authoring = mode === "html" ? { mode, html } : form?.mode === "html" ? { mode } : {};
108
+ try {
109
+ if (isNew) {
110
+ // `notify` here is always this hook's own blank default — a new form has no earlier value
111
+ // to carry through, and there is no UI on this screen to set one instead.
112
+ const created = await createMutation.mutate({ input: { name, slug, fields, notify, ...authoring } });
113
+ // Slug, not id — see this hook's own file header / `get-by-id.ts` for the id-or-slug
114
+ // resolution this now lands on (ui-fixes-backlog.md #8).
115
+ navigate(`/forms/${created.slug}`);
116
+ }
117
+ else {
118
+ // `notify` is the value this hook seeded from the loaded form and has never changed since —
119
+ // sent back unchanged so saving name/slug/field edits can never wipe a stored notify setting
120
+ // (see this hook's own `notify` state comment).
121
+ // Set directly from the write's own response — `updateMutation` doesn't invalidate this
122
+ // hook's own `KEYS.form(id)` read (see the mutations' own comment above), so there is no
123
+ // background refetch to wait for or to accidentally clobber an in-progress edit with.
124
+ // Mirrors `use-collection-entry-editor.hooks.ts`'s `save()`.
125
+ const updatedCore = await updateMutation.mutate({ input: { name, fields, notify, ...authoring } });
126
+ const updated = formView({ form: updatedCore });
127
+ stateController?.seed({ form: updated });
128
+ }
129
+ }
130
+ catch {
131
+ // already surfaced through updateMutation.error/createMutation.error -> error below
132
+ }
133
+ }
134
+ async function handleStatusToggle() {
135
+ if (!form)
136
+ return;
137
+ try {
138
+ const updatedCore = await statusMutation.mutate({ input: {
139
+ id: form.id,
140
+ status: form.status === "active" ? "disabled" : "active",
141
+ } });
142
+ setForm(formView({ form: updatedCore }));
143
+ }
144
+ catch {
145
+ // already surfaced through statusMutation.error -> error below
146
+ }
147
+ }
148
+ const saving = updateMutation.status === "pending" || createMutation.status === "pending" || statusMutation.status === "pending";
149
+ const error = visibleFormEditorError({
150
+ updateError: updateMutation.error,
151
+ createError: createMutation.error,
152
+ statusError: statusMutation.error,
153
+ listError: list.error,
154
+ hasForm: form !== null,
155
+ saveFallback: t("save failed"),
156
+ statusUpdateFallback: t("status update failed"),
157
+ loadFormFallback: t("failed to load form"),
158
+ });
159
+ // Navigates to `/forms/:formId` or `/forms/:formId/submissions` (ADR-063) — `panels.tsx`'s
160
+ // `forms` panel keys `FormEditor` off `ctx.params.formId` on BOTH routes, so this is a route
161
+ // change, not a remount: in-progress Fields edits survive a trip to Submissions and back.
162
+ function onTabChange(nextTab) {
163
+ navigate(nextTab === "submissions" ? `/forms/${props.formId}/submissions` : `/forms/${props.formId}`);
164
+ }
165
+ function onTabsKeyDown(e) {
166
+ const currentIndex = FORM_TABS.findIndex((t) => t.id === tab);
167
+ const index = nextTabIndex({ key: e.key, currentIndex });
168
+ if (index === null)
169
+ return;
170
+ e.preventDefault();
171
+ onTabChange(FORM_TABS[index].id);
172
+ tabRefs.current[index]?.focus();
173
+ }
174
+ return {
175
+ isNew,
176
+ form,
177
+ mode, onModeChange, html, setHtml, copyEmbed, copyFeedback,
178
+ answerColumns: formAnswerColumns({ fields: form?.fields ?? [] }),
179
+ name,
180
+ setName,
181
+ slug,
182
+ setSlug,
183
+ fields,
184
+ setFields,
185
+ tab,
186
+ onTabChange,
187
+ error,
188
+ saving,
189
+ existingFieldIds: existingFieldIdsOf({ form }),
190
+ showTabs: !isNew && form !== null,
191
+ tabRefs,
192
+ onTabsKeyDown,
193
+ handleSave,
194
+ handleStatusToggle,
195
+ t,
196
+ };
197
+ }
198
+ export function useWiredFormEditor(props, _optional = {}) {
199
+ const { formsApi, formsNavigation } = useFormsPorts();
200
+ const { t, clipboard, adminBase } = useFormsOptions();
201
+ const navigate = (routePath) => {
202
+ if (!formsNavigation)
203
+ throw new Error('Missing forms navigation port');
204
+ formsNavigation.navigate({ base: adminBase, routePath });
205
+ };
206
+ return useFormEditor({ ...props, port: formsApi, navigate, t }, clipboard ? { clipboard } : {});
207
+ }
208
+ //# sourceMappingURL=use-form-editor.hooks.js.map
@@ -0,0 +1,34 @@
1
+ import type { AdminFormField } from "../../models.js";
2
+ /**
3
+ * @file `FormFieldsEditor`'s own state (which row's attributes modal is open, plus the per-row
4
+ * kebab-trigger refs for WCAG focus-return), so the fields table in `FormEditor.tsx` is only
5
+ * markup.
6
+ *
7
+ * Extracted verbatim, including the `useRef` array — `Pattern 1` moves every `useRef` out of the
8
+ * component along with state/effects, not just `useState`. The field-list edits themselves
9
+ * (`updateField`/`addField`/`removeField`) are thin wrappers around `rules.ts`'s pure array
10
+ * transforms, applied through the parent-owned `onChange` (this component does not own `fields`
11
+ * itself — `FormEditor`'s own `fields` state does).
12
+ *
13
+ * Naming follows `hooks/use-settings-slice.hooks.ts`: `use-<thing>.hooks.ts`. Feature-local because
14
+ * nothing outside `features/forms` needs it.
15
+ */
16
+ export interface FormFieldsEditorController {
17
+ /** Which field's `FieldAttributesDialog` is open, by index — `null` when none is. */
18
+ editingAttrsIndex: number | null;
19
+ openAttrsDialog: (index: number) => void;
20
+ /** Closes the attributes dialog and returns focus to the kebab trigger that opened it (WCAG 2.1
21
+ * AA "focus returns to trigger element when modal closes"). */
22
+ closeAttrsDialog: () => void;
23
+ /** Per-row kebab-trigger refs, indexed the same as `fields` — attach via each row's own `ref`
24
+ * callback in the view. */
25
+ kebabRefs: React.MutableRefObject<Array<HTMLButtonElement | null>>;
26
+ updateField: (index: number, patch: Partial<AdminFormField>) => void;
27
+ addField: () => void;
28
+ removeField: (index: number) => void;
29
+ }
30
+ export declare function useFormFieldsEditor(props: {
31
+ fields: AdminFormField[];
32
+ onChange: (fields: AdminFormField[]) => void;
33
+ }, _optional?: Record<string, never>): FormFieldsEditorController;
34
+ //# sourceMappingURL=use-form-fields-editor.hooks.d.ts.map
@@ -0,0 +1,36 @@
1
+ import { useController } from "../../../core/react/use-controller.js";
2
+ import { createFormFieldsEditorController, initialFormFieldsEditorState } from "../../controllers/form-fields-editor.controller.js";
3
+ import { useRef } from "react";
4
+ import { addFormField, removeFormField, updateFormField } from "../../rules.js";
5
+ export function useFormFieldsEditor(props, _optional = {}) {
6
+ const { controller: stateController, snapshot: stateSnapshot } = useController({ create: () => createFormFieldsEditorController({}), dependencies: [] });
7
+ const state = stateSnapshot ?? initialFormFieldsEditorState({});
8
+ const editingAttrsIndex = state.editingAttrsIndex;
9
+ const setEditingAttrsIndex = (value) => stateController?.update({ key: "editingAttrsIndex", value });
10
+ const kebabRefs = useRef([]);
11
+ function closeAttrsDialog() {
12
+ const index = editingAttrsIndex;
13
+ setEditingAttrsIndex(null);
14
+ if (index !== null)
15
+ kebabRefs.current[index]?.focus();
16
+ }
17
+ function updateField(index, patch) {
18
+ props.onChange(updateFormField({ fields: props.fields, index, patch }));
19
+ }
20
+ function addField() {
21
+ props.onChange(addFormField({ fields: props.fields }));
22
+ }
23
+ function removeField(index) {
24
+ props.onChange(removeFormField({ fields: props.fields, index }));
25
+ }
26
+ return {
27
+ editingAttrsIndex,
28
+ openAttrsDialog: setEditingAttrsIndex,
29
+ closeAttrsDialog,
30
+ kebabRefs,
31
+ updateField,
32
+ addField,
33
+ removeField,
34
+ };
35
+ }
36
+ //# sourceMappingURL=use-form-fields-editor.hooks.js.map
@@ -0,0 +1,12 @@
1
+ /** Bind submission timestamps to the same operator locale and local time as the Forms list. */
2
+ export declare function useFormSubmissionDate(_required: Record<string, never>, { locale: localeOverride, timeZone }?: {
3
+ locale?: string;
4
+ timeZone?: string;
5
+ }): ({ iso }: {
6
+ iso: string;
7
+ }, _optional?: Record<string, never>) => {
8
+ text: string;
9
+ full: string;
10
+ dateTime: string | undefined;
11
+ };
12
+ //# sourceMappingURL=use-form-submission-date.hooks.d.ts.map
@@ -0,0 +1,9 @@
1
+ import { useFormsOptions } from "./FormsPorts.hooks.js";
2
+ import { formDateDisplay } from "../../rules.js";
3
+ /** Bind submission timestamps to the same operator locale and local time as the Forms list. */
4
+ export function useFormSubmissionDate(_required, { locale: localeOverride, timeZone } = {}) {
5
+ const { locale } = useFormsOptions();
6
+ // One locale subscription per submissions panel, rather than one per timestamp cell.
7
+ return ({ iso }, _optional = {}) => formDateDisplay({ iso, locale: localeOverride ?? locale }, timeZone === undefined ? {} : { timeZone });
8
+ }
9
+ //# sourceMappingURL=use-form-submission-date.hooks.js.map
@@ -0,0 +1,68 @@
1
+ import type { AdminFormsPort } from "../../../core/ports/forms.js";
2
+ import type { FormsTrashPort } from "../../ports.js";
3
+ import type { AdminFormSubmission } from "../../models.js";
4
+ /**
5
+ * @file `FormSubmissionDetail`'s own state and delete action, so the detail view in
6
+ * `FormEditor.tsx` is only markup.
7
+ *
8
+ * Permanent delete now confirms through a modal (S5 fix, 2026-09-20), not an inline two-click
9
+ * button: the old `confirming`/`handleDelete` shape flipped a click's own label to "Confirm
10
+ * delete", so a real double-click deleted the submission outright with no way to back out — the
11
+ * same bug widgets' `trashOrPurge` had before its own `pendingPurge`/`ConfirmDialog` fix. This
12
+ * hook now mirrors that shape one-for-one: `requestDelete` only opens the dialog (no network),
13
+ * `cancelDelete` closes it with no request, and `confirmDelete` runs the mutation.
14
+ *
15
+ * Naming follows `hooks/use-settings-slice.hooks.ts`: `use-<thing>.hooks.ts`. Feature-local because
16
+ * nothing outside `features/forms` needs it.
17
+ *
18
+ * `port` is injected — see `core/ports/forms.ts` (shared with `use-form-
19
+ * submissions.hooks.ts`, since both read/write the same submissions list for a form) — rather than
20
+ * importing `lib/api` directly, so a test can describe load/delete outcomes against
21
+ * `the memory adapter` instead of stubbing global `fetch`.
22
+ * `useWiredFormSubmissionDetail` below is the zero-argument pair `FormEditor.tsx` actually mounts.
23
+ *
24
+ * `@jini-ai/ui/fetch-query` migration (2026-08-12): the load is one `useFetchQuery` keyed on
25
+ * `KEYS.submissionDetail(formId, submissionId)` — a query cannot commit a response belonging to a
26
+ * prior key, which eliminates the load race an external audit flagged at this file's old line 48
27
+ * (a plain `.then()`/`.catch()` effect with no cancellation guard) by construction. `confirmDelete`
28
+ * is a `useFetchMutation` that `invalidates: [KEYS.submissionsList(formId)]`, so the sibling list
29
+ * (`use-form-submissions.hooks.ts`) refreshes on its own — `props.onDeleted()` now only needs to
30
+ * clear the caller's `selectedId` (a UI-navigation concern this hook can't own), not also trigger a
31
+ * reload, so `FormEditor.tsx`'s `onDeleted` callback drops its own `load()` call.
32
+ */
33
+ export interface FormSubmissionDetailController {
34
+ /** `null` until the initial load settles — the caller renders a loading state. */
35
+ submission: AdminFormSubmission | null;
36
+ error: string | null;
37
+ /** True while the "Delete permanently?" confirm dialog should be open — opened by
38
+ * {@link FormSubmissionDetailController.requestDelete}, closed by
39
+ * {@link FormSubmissionDetailController.cancelDelete} or once
40
+ * {@link FormSubmissionDetailController.confirmDelete} settles. */
41
+ confirmOpen: boolean;
42
+ deleting: boolean;
43
+ /** Opens the confirm dialog. No network call — a click alone can never delete. */
44
+ requestDelete: () => void;
45
+ /** Closes the confirm dialog with no request. */
46
+ cancelDelete: () => void;
47
+ /** Runs the delete. On success, calls `props.onDeleted()`. Closes the dialog in `finally`
48
+ * either way, so a failed delete doesn't leave the operator stuck behind it — the failure is
49
+ * still visible via `error` below. */
50
+ confirmDelete: () => Promise<void>;
51
+ }
52
+ export declare function useFormSubmissionDetail(props: {
53
+ port: AdminFormsPort;
54
+ trash: FormsTrashPort;
55
+ formId: string;
56
+ submissionId: string;
57
+ onDeleted: () => void;
58
+ /** Bound translator — see `use-forms-list.hooks.ts`'s own header for why this arrives via
59
+ * injection rather than this hook calling `useAdminLocale()` itself. Optional (defaults to
60
+ * identity) so existing callers/tests that don't pass one keep seeing the raw English copy. */
61
+ t?: (key: string) => string;
62
+ }, _optional?: Record<string, never>): FormSubmissionDetailController;
63
+ export declare function useWiredFormSubmissionDetail(props: {
64
+ formId: string;
65
+ submissionId: string;
66
+ onDeleted: () => void;
67
+ }, _optional?: {}): FormSubmissionDetailController;
68
+ //# sourceMappingURL=use-form-submission-detail.hooks.d.ts.map
@@ -0,0 +1,81 @@
1
+ import { submissionView } from "../../models.js";
2
+ import { useFormsPorts, useFormsOptions } from "./FormsPorts.hooks.js";
3
+ import { useController } from "../../../core/react/use-controller.js";
4
+ import { createFormSubmissionDetailController, initialFormSubmissionDetailState } from "../../controllers/form-submission-detail.controller.js";
5
+ import { describeApiError as describeCoreApiError } from "../../../core/transport/errors.js";
6
+ const describeApiError = (e, fallback) => describeCoreApiError({ e, fallback });
7
+ import { useFetchMutation, useFetchQuery, useInvalidate } from "@jini-ai/ui/fetch-query";
8
+ import { KEYS, describeTrashError } from "../../rules.js";
9
+ export function useFormSubmissionDetail(props, _optional = {}) {
10
+ const { port, trash } = props;
11
+ const t = props.t ?? ((key) => key);
12
+ const { controller: stateController, snapshot: stateSnapshot } = useController({ create: () => createFormSubmissionDetailController({}), dependencies: [] });
13
+ const state = stateSnapshot ?? initialFormSubmissionDetailState({});
14
+ const confirmOpen = state.confirmOpen;
15
+ const setConfirmOpen = (value) => stateController?.update({ key: "confirmOpen", value });
16
+ const invalidate = useInvalidate();
17
+ const list = useFetchQuery({
18
+ key: KEYS.submissionDetail(props.formId, props.submissionId),
19
+ fetch: () => port.getFormSubmission({ formId: props.formId, submissionId: props.submissionId }).then(submission => ({ data: submissionView({ submission }) })),
20
+ });
21
+ const deleteMutation = useFetchMutation({
22
+ run: ({ input: _ }) => trash.trash({ type: "form_submission", id: props.submissionId }),
23
+ }, {
24
+ invalidates: [KEYS.submissionsList(props.formId)],
25
+ });
26
+ function requestDelete() {
27
+ setConfirmOpen(true);
28
+ }
29
+ function cancelDelete() {
30
+ setConfirmOpen(false);
31
+ }
32
+ /** T7a (2026-09-21): the confirmation mutation moves the submission to Trash through the generic
33
+ * `POST /trash/items` endpoint — see `adapters/http.ts`'s own doc. A 404
34
+ * (`describeTrashError`'s `alreadyGone`) means the submission is already gone: from
35
+ * the operator's point of view that's the same outcome as a successful delete, so this still calls
36
+ * `onDeleted()` and invalidates the list directly — `deleteMutation`'s own `invalidates` only fires
37
+ * on success, and a failed mutation would otherwise leave the sibling list showing a row that's
38
+ * already gone. */
39
+ async function confirmDelete() {
40
+ try {
41
+ await deleteMutation.mutate({ input: undefined });
42
+ props.onDeleted();
43
+ }
44
+ catch (e) {
45
+ if (describeTrashError({ error: e instanceof Error ? e : null, fallback: "delete failed", versionChangedMessage: t("This item changed since you loaded it. Reload and try again.") }).alreadyGone) {
46
+ invalidate({ key: KEYS.submissionsList(props.formId) });
47
+ props.onDeleted();
48
+ }
49
+ // otherwise: already surfaced through deleteMutation.error -> error below
50
+ }
51
+ finally {
52
+ setConfirmOpen(false);
53
+ }
54
+ }
55
+ const submission = list.data?.data ?? null;
56
+ // The delete's own failure outranks a background load-refresh failure — flat `if`s rather than a
57
+ // nested ternary, per `@jini-ai/ui/fetch-query`'s `resolveFetchQueryStatus` doc on why the two carry
58
+ // a different complexity-gate weight for the same branch count.
59
+ let error = null;
60
+ if (deleteMutation.error) {
61
+ error = describeTrashError({ error: deleteMutation.error, fallback: "delete failed", versionChangedMessage: t("This item changed since you loaded it. Reload and try again.") }).message;
62
+ }
63
+ else if (list.error) {
64
+ error = describeApiError(list.error, "failed to load submission");
65
+ }
66
+ return {
67
+ submission,
68
+ error,
69
+ confirmOpen,
70
+ deleting: deleteMutation.status === "pending",
71
+ requestDelete,
72
+ cancelDelete,
73
+ confirmDelete,
74
+ };
75
+ }
76
+ export function useWiredFormSubmissionDetail(props, _optional = {}) {
77
+ const { formsApi, formsTrash } = useFormsPorts();
78
+ const { t } = useFormsOptions();
79
+ return useFormSubmissionDetail({ ...props, port: formsApi, trash: formsTrash, t });
80
+ }
81
+ //# sourceMappingURL=use-form-submission-detail.hooks.js.map
@@ -0,0 +1,67 @@
1
+ import type { AdminFormsPort } from "../../../core/ports/forms.js";
2
+ import type { AdminFormSubmission } from "../../models.js";
3
+ /**
4
+ * @file `FormSubmissions`'s own state and paginated load, so the submissions list in
5
+ * `FormEditor.tsx` is only markup.
6
+ *
7
+ * Moved from the host — same cursor-append load shape, same error strings. `load` keeps its original
8
+ * `(cursor?: string) => void` signature rather than being split into separate "load"/"loadMore"
9
+ * functions, so both call sites (`load(nextCursor)` for "Load more", `load()` after a submission
10
+ * delete) carry over unchanged.
11
+ *
12
+ * Naming follows `hooks/use-settings-slice.hooks.ts`: `use-<thing>.hooks.ts`. Feature-local because
13
+ * nothing outside `features/forms` needs it.
14
+ *
15
+ * `port` is injected — see `core/ports/forms.ts` (shared with `use-form-submission-
16
+ * detail.hooks.ts`, since both read/write the same submissions list for a form) — rather than
17
+ * importing `lib/api` directly, so a test can describe list outcomes against
18
+ * `the memory adapter` instead of stubbing global `fetch`. `useWiredFormSubmissions`
19
+ * below is the zero-argument pair `FormEditor.tsx` actually mounts.
20
+ *
21
+ * `@jini-ai/ui/fetch-query` migration (2026-08-12): the FIRST page is one `useFetchQuery` keyed on
22
+ * `KEYS.submissionsList(formId)` — a query cannot commit a response belonging to a prior key, which
23
+ * eliminates the load race an external audit flagged at this file's old line 56 (a plain
24
+ * `.then()`/`.catch()` effect with no cancellation guard) for that page. Subsequent "Load more"
25
+ * pages are NOT folded into that same query: `@jini-ai/ui/fetch-query`'s `QueryKey` doc binds one
26
+ * hook to one FIXED key, and a cursor-appended page list is exactly the "moving-target key" shape
27
+ * that doc's own Skip precedent (`useSettingsContainer`, see this migration's dispatch brief) warns
28
+ * against faking — so accumulated pages live in the section controller, fetched directly through `port`
29
+ * (bypassing the cache, since an appended page is not a cacheable "the current state of X", it's an
30
+ * accumulating view built by this one screen). `pageSettlement` (`useSettlementGeneration`) guards
31
+ * that accumulation against the SAME class of race the base query gets for free: a `loadMore` in
32
+ * flight when `formId` changes, or when a first-page refetch (e.g. a delete's invalidate) resets
33
+ * the list, must not append its page once it resolves — see `resetMorePages` below, which mints a
34
+ * fresh generation on every reset so any older in-flight page fetch is superseded. A synchronous
35
+ * `loadingMoreRef` lock, checked before minting a generation, covers the other half: two `loadMore`
36
+ * calls issued in the SAME tick (a double click) must send only one request
37
+ * (2026-09-20, `plan-content2.md` #3/#5/S2).
38
+ *
39
+ * The audit's second, more serious finding at this file — `selectedId` surviving a `formId` change
40
+ * untouched, so a delete could fire against a submission id belonging to the PREVIOUS form while its
41
+ * stale rows were still on screen — is fixed by the identity-reset effect below, which clears both
42
+ * `selectedId` and the accumulated "more" pages whenever `formId` changes.
43
+ */
44
+ export interface FormSubmissionsController {
45
+ /** `null` until the initial load settles — the caller renders a loading state. */
46
+ submissions: AdminFormSubmission[] | null;
47
+ nextCursor: string | null;
48
+ error: string | null;
49
+ /** The submission `FormSubmissions` is showing `FormSubmissionDetail` for — `null` shows the
50
+ * plain list. */
51
+ selectedId: string | null;
52
+ setSelectedId: (id: string | null) => void;
53
+ /** Re-fetches. Passing a cursor appends to `submissions`; omitting it replaces the list from the
54
+ * start (used after a submission is deleted, so the list reflects the removal). */
55
+ load: (cursor?: string) => void;
56
+ /** True while a "Load more" page fetch is in flight — drives the button's `disabled` and
57
+ * "Loading…" label in `FormEditor.tsx`. */
58
+ loadingMore: boolean;
59
+ }
60
+ export declare function useFormSubmissions(props: {
61
+ formId: string;
62
+ port: AdminFormsPort;
63
+ }, _optional?: {}): FormSubmissionsController;
64
+ export declare function useWiredFormSubmissions(props: {
65
+ formId: string;
66
+ }, _optional?: {}): FormSubmissionsController;
67
+ //# sourceMappingURL=use-form-submissions.hooks.d.ts.map