@conduction/nextcloud-vue 2.56.0-beta.4 → 2.56.0-beta.5

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 (300) hide show
  1. package/dist/esm/components/CnActionsBar/CnActionsBar.vue2.js +12 -2
  2. package/dist/esm/components/CnActionsBar/CnActionsBar.vue2.js.map +1 -1
  3. package/dist/esm/components/CnActionsBar/CnActionsBar.vue3.js +1 -2
  4. package/dist/esm/components/CnActionsBar/CnActionsBar.vue3.js.map +1 -1
  5. package/dist/esm/components/CnActionsMenu/CnActionsMenu.vue2.js.map +1 -1
  6. package/dist/esm/components/CnActionsMenu/CnActionsMenu.vue3.js +0 -3
  7. package/dist/esm/components/CnActionsMenu/CnActionsMenu.vue3.js.map +1 -1
  8. package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue2.js.map +1 -1
  9. package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue3.js +1 -2
  10. package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue3.js.map +1 -1
  11. package/dist/esm/components/CnBoardView/CnBoardView.vue2.js +12 -5
  12. package/dist/esm/components/CnBoardView/CnBoardView.vue2.js.map +1 -1
  13. package/dist/esm/components/CnBoardView/CnBoardView.vue3.js +2 -1
  14. package/dist/esm/components/CnBoardView/CnBoardView.vue3.js.map +1 -1
  15. package/dist/esm/components/CnCardGrid/CnCardGrid.vue2.js +9 -1
  16. package/dist/esm/components/CnCardGrid/CnCardGrid.vue2.js.map +1 -1
  17. package/dist/esm/components/CnCardGrid/CnCardGrid.vue3.js.map +1 -1
  18. package/dist/esm/components/CnContextMenu/CnContextMenu.vue2.js +6 -1
  19. package/dist/esm/components/CnContextMenu/CnContextMenu.vue2.js.map +1 -1
  20. package/dist/esm/components/CnContextMenu/CnContextMenu.vue3.js.map +1 -1
  21. package/dist/esm/components/CnDataTable/CnDataTable.vue2.js +116 -15
  22. package/dist/esm/components/CnDataTable/CnDataTable.vue2.js.map +1 -1
  23. package/dist/esm/components/CnDataTable/CnDataTable.vue3.js +27 -14
  24. package/dist/esm/components/CnDataTable/CnDataTable.vue3.js.map +1 -1
  25. package/dist/esm/components/CnDateAxisView/CnDateAxisView.vue2.js +13 -6
  26. package/dist/esm/components/CnDateAxisView/CnDateAxisView.vue2.js.map +1 -1
  27. package/dist/esm/components/CnDateAxisView/CnDateAxisView.vue3.js +2 -0
  28. package/dist/esm/components/CnDateAxisView/CnDateAxisView.vue3.js.map +1 -1
  29. package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js +29 -1
  30. package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js.map +1 -1
  31. package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js.map +1 -1
  32. package/dist/esm/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue2.js.map +1 -1
  33. package/dist/esm/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue3.js +1 -2
  34. package/dist/esm/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue3.js.map +1 -1
  35. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js +3 -1
  36. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js.map +1 -1
  37. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js +17 -17
  38. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js.map +1 -1
  39. package/dist/esm/components/CnFilesWidget/CnFilesWidget.vue2.js +4 -21
  40. package/dist/esm/components/CnFilesWidget/CnFilesWidget.vue2.js.map +1 -1
  41. package/dist/esm/components/CnFilesWidget/CnFilesWidget.vue3.js.map +1 -1
  42. package/dist/esm/components/CnFlowRunsWidget/CnFlowRunsWidget.vue2.js +0 -13
  43. package/dist/esm/components/CnFlowRunsWidget/CnFlowRunsWidget.vue2.js.map +1 -1
  44. package/dist/esm/components/CnFlowRunsWidget/CnFlowRunsWidget.vue3.js +8 -8
  45. package/dist/esm/components/CnFlowRunsWidget/CnFlowRunsWidget.vue3.js.map +1 -1
  46. package/dist/esm/components/CnFlowsPage/CnFlowsPage.vue2.js.map +1 -1
  47. package/dist/esm/components/CnFlowsPage/CnFlowsPage.vue3.js +3 -2
  48. package/dist/esm/components/CnFlowsPage/CnFlowsPage.vue3.js.map +1 -1
  49. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +67 -13
  50. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
  51. package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js +15 -8
  52. package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
  53. package/dist/esm/components/CnIndexPage/manifestActionDispatch.js +31 -11
  54. package/dist/esm/components/CnIndexPage/manifestActionDispatch.js.map +1 -1
  55. package/dist/esm/components/CnIntegrationWidget/CnIntegrationWidgetEmpty.vue2.js.map +1 -1
  56. package/dist/esm/components/CnIntegrationWidget/CnIntegrationWidgetEmpty.vue3.js +1 -2
  57. package/dist/esm/components/CnIntegrationWidget/CnIntegrationWidgetEmpty.vue3.js.map +1 -1
  58. package/dist/esm/components/CnInteractionFormWidget/CnInteractionFormWidget.vue2.js.map +1 -1
  59. package/dist/esm/components/CnInteractionFormWidget/CnInteractionFormWidget.vue3.js +0 -1
  60. package/dist/esm/components/CnInteractionFormWidget/CnInteractionFormWidget.vue3.js.map +1 -1
  61. package/dist/esm/components/CnLinkButtonWidget/CnLinkButtonWidget.vue2.js +2 -17
  62. package/dist/esm/components/CnLinkButtonWidget/CnLinkButtonWidget.vue2.js.map +1 -1
  63. package/dist/esm/components/CnLinkButtonWidget/CnLinkButtonWidget.vue3.js.map +1 -1
  64. package/dist/esm/components/CnLogsPage/CnLogsPage.vue2.js +35 -11
  65. package/dist/esm/components/CnLogsPage/CnLogsPage.vue2.js.map +1 -1
  66. package/dist/esm/components/CnLogsPage/CnLogsPage.vue3.js +3 -2
  67. package/dist/esm/components/CnLogsPage/CnLogsPage.vue3.js.map +1 -1
  68. package/dist/esm/components/CnObjectCard/CnObjectCard.vue2.js +23 -5
  69. package/dist/esm/components/CnObjectCard/CnObjectCard.vue2.js.map +1 -1
  70. package/dist/esm/components/CnObjectCard/CnObjectCard.vue3.js +1 -1
  71. package/dist/esm/components/CnObjectCard/CnObjectCard.vue3.js.map +1 -1
  72. package/dist/esm/components/CnObjectList/CnObjectList.vue2.js +19 -3
  73. package/dist/esm/components/CnObjectList/CnObjectList.vue2.js.map +1 -1
  74. package/dist/esm/components/CnObjectList/CnObjectList.vue3.js.map +1 -1
  75. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js +45 -15
  76. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js.map +1 -1
  77. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue3.js +4 -2
  78. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue3.js.map +1 -1
  79. package/dist/esm/components/CnObjectRow/CnObjectRow.vue2.js +24 -6
  80. package/dist/esm/components/CnObjectRow/CnObjectRow.vue2.js.map +1 -1
  81. package/dist/esm/components/CnObjectRow/CnObjectRow.vue3.js +1 -1
  82. package/dist/esm/components/CnObjectRow/CnObjectRow.vue3.js.map +1 -1
  83. package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue2.js.map +1 -1
  84. package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue3.js +0 -1
  85. package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue3.js.map +1 -1
  86. package/dist/esm/components/CnPageRenderer/CnPageRenderer.vue2.js.map +1 -1
  87. package/dist/esm/components/CnPageRenderer/CnPageRenderer.vue3.js +4 -2
  88. package/dist/esm/components/CnPageRenderer/CnPageRenderer.vue3.js.map +1 -1
  89. package/dist/esm/components/CnRowActions/CnRowActions.vue2.js +7 -2
  90. package/dist/esm/components/CnRowActions/CnRowActions.vue2.js.map +1 -1
  91. package/dist/esm/components/CnRowActions/CnRowActions.vue3.js.map +1 -1
  92. package/dist/esm/components/CnSpendAnalyticsWidget/CnSpendAnalyticsWidget.vue2.js +5 -3
  93. package/dist/esm/components/CnSpendAnalyticsWidget/CnSpendAnalyticsWidget.vue2.js.map +1 -1
  94. package/dist/esm/components/CnSpendAnalyticsWidget/CnSpendAnalyticsWidget.vue3.js.map +1 -1
  95. package/dist/esm/components/CnTabs/CnTabs.vue2.js.map +1 -1
  96. package/dist/esm/components/CnTabs/CnTabs.vue3.js.map +1 -1
  97. package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue2.js +3 -1
  98. package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue2.js.map +1 -1
  99. package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue3.js +1 -0
  100. package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue3.js.map +1 -1
  101. package/dist/esm/integrations/builtin/analytics/CnAnalyticsCard.vue2.js +3 -1
  102. package/dist/esm/integrations/builtin/analytics/CnAnalyticsCard.vue2.js.map +1 -1
  103. package/dist/esm/integrations/builtin/analytics/CnAnalyticsCard.vue3.js.map +1 -1
  104. package/dist/esm/integrations/builtin/analytics/CnAnalyticsTab.vue2.js +3 -1
  105. package/dist/esm/integrations/builtin/analytics/CnAnalyticsTab.vue2.js.map +1 -1
  106. package/dist/esm/integrations/builtin/analytics/CnAnalyticsTab.vue3.js +2 -4
  107. package/dist/esm/integrations/builtin/analytics/CnAnalyticsTab.vue3.js.map +1 -1
  108. package/dist/esm/integrations/builtin/bookmarks/CnBookmarksCard.vue2.js +6 -0
  109. package/dist/esm/integrations/builtin/bookmarks/CnBookmarksCard.vue2.js.map +1 -1
  110. package/dist/esm/integrations/builtin/bookmarks/CnBookmarksCard.vue3.js +68 -53
  111. package/dist/esm/integrations/builtin/bookmarks/CnBookmarksCard.vue3.js.map +1 -1
  112. package/dist/esm/integrations/builtin/bookmarks/CnBookmarksTab.vue2.js +17 -0
  113. package/dist/esm/integrations/builtin/bookmarks/CnBookmarksTab.vue2.js.map +1 -1
  114. package/dist/esm/integrations/builtin/bookmarks/CnBookmarksTab.vue3.js +21 -19
  115. package/dist/esm/integrations/builtin/bookmarks/CnBookmarksTab.vue3.js.map +1 -1
  116. package/dist/esm/integrations/builtin/collectives/CnCollectivesCard.vue2.js +3 -1
  117. package/dist/esm/integrations/builtin/collectives/CnCollectivesCard.vue2.js.map +1 -1
  118. package/dist/esm/integrations/builtin/collectives/CnCollectivesCard.vue3.js.map +1 -1
  119. package/dist/esm/integrations/builtin/collectives/CnCollectivesTab.vue2.js +3 -1
  120. package/dist/esm/integrations/builtin/collectives/CnCollectivesTab.vue2.js.map +1 -1
  121. package/dist/esm/integrations/builtin/collectives/CnCollectivesTab.vue3.js +2 -4
  122. package/dist/esm/integrations/builtin/collectives/CnCollectivesTab.vue3.js.map +1 -1
  123. package/dist/esm/integrations/builtin/cospend/CnCospendCard.vue2.js +2 -1
  124. package/dist/esm/integrations/builtin/cospend/CnCospendCard.vue2.js.map +1 -1
  125. package/dist/esm/integrations/builtin/cospend/CnCospendCard.vue3.js.map +1 -1
  126. package/dist/esm/integrations/builtin/cospend/CnCospendTab.vue2.js +2 -1
  127. package/dist/esm/integrations/builtin/cospend/CnCospendTab.vue2.js.map +1 -1
  128. package/dist/esm/integrations/builtin/cospend/CnCospendTab.vue3.js +1 -2
  129. package/dist/esm/integrations/builtin/cospend/CnCospendTab.vue3.js.map +1 -1
  130. package/dist/esm/integrations/builtin/deck/CnDeckCard.vue2.js +2 -1
  131. package/dist/esm/integrations/builtin/deck/CnDeckCard.vue2.js.map +1 -1
  132. package/dist/esm/integrations/builtin/deck/CnDeckCard.vue3.js.map +1 -1
  133. package/dist/esm/integrations/builtin/deck/CnDeckTab.vue2.js +2 -1
  134. package/dist/esm/integrations/builtin/deck/CnDeckTab.vue2.js.map +1 -1
  135. package/dist/esm/integrations/builtin/deck/CnDeckTab.vue3.js +1 -2
  136. package/dist/esm/integrations/builtin/deck/CnDeckTab.vue3.js.map +1 -1
  137. package/dist/esm/integrations/builtin/email/CnEmailCard.vue2.js.map +1 -1
  138. package/dist/esm/integrations/builtin/email/CnEmailCard.vue3.js.map +1 -1
  139. package/dist/esm/integrations/builtin/email/CnEmailTab.vue2.js.map +1 -1
  140. package/dist/esm/integrations/builtin/email/CnEmailTab.vue3.js +1 -2
  141. package/dist/esm/integrations/builtin/email/CnEmailTab.vue3.js.map +1 -1
  142. package/dist/esm/integrations/builtin/flow/CnFlowCard.vue2.js +2 -1
  143. package/dist/esm/integrations/builtin/flow/CnFlowCard.vue2.js.map +1 -1
  144. package/dist/esm/integrations/builtin/flow/CnFlowCard.vue3.js.map +1 -1
  145. package/dist/esm/integrations/builtin/flow/CnFlowTab.vue2.js +2 -1
  146. package/dist/esm/integrations/builtin/flow/CnFlowTab.vue2.js.map +1 -1
  147. package/dist/esm/integrations/builtin/flow/CnFlowTab.vue3.js +1 -2
  148. package/dist/esm/integrations/builtin/flow/CnFlowTab.vue3.js.map +1 -1
  149. package/dist/esm/integrations/builtin/forms/CnFormsCard.vue2.js +3 -1
  150. package/dist/esm/integrations/builtin/forms/CnFormsCard.vue2.js.map +1 -1
  151. package/dist/esm/integrations/builtin/forms/CnFormsCard.vue3.js.map +1 -1
  152. package/dist/esm/integrations/builtin/forms/CnFormsTab.vue2.js +3 -1
  153. package/dist/esm/integrations/builtin/forms/CnFormsTab.vue2.js.map +1 -1
  154. package/dist/esm/integrations/builtin/forms/CnFormsTab.vue3.js +2 -4
  155. package/dist/esm/integrations/builtin/forms/CnFormsTab.vue3.js.map +1 -1
  156. package/dist/esm/integrations/builtin/maps/CnMapsCard.vue2.js +3 -1
  157. package/dist/esm/integrations/builtin/maps/CnMapsCard.vue2.js.map +1 -1
  158. package/dist/esm/integrations/builtin/maps/CnMapsCard.vue3.js.map +1 -1
  159. package/dist/esm/integrations/builtin/maps/CnMapsTab.vue2.js +3 -1
  160. package/dist/esm/integrations/builtin/maps/CnMapsTab.vue2.js.map +1 -1
  161. package/dist/esm/integrations/builtin/maps/CnMapsTab.vue3.js +2 -4
  162. package/dist/esm/integrations/builtin/maps/CnMapsTab.vue3.js.map +1 -1
  163. package/dist/esm/integrations/builtin/openproject/CnOpenprojectCard.vue2.js +3 -1
  164. package/dist/esm/integrations/builtin/openproject/CnOpenprojectCard.vue2.js.map +1 -1
  165. package/dist/esm/integrations/builtin/openproject/CnOpenprojectCard.vue3.js.map +1 -1
  166. package/dist/esm/integrations/builtin/openproject/CnOpenprojectTab.vue2.js +3 -1
  167. package/dist/esm/integrations/builtin/openproject/CnOpenprojectTab.vue2.js.map +1 -1
  168. package/dist/esm/integrations/builtin/openproject/CnOpenprojectTab.vue3.js +2 -4
  169. package/dist/esm/integrations/builtin/openproject/CnOpenprojectTab.vue3.js.map +1 -1
  170. package/dist/esm/integrations/builtin/photos/CnPhotosCard.vue2.js +2 -1
  171. package/dist/esm/integrations/builtin/photos/CnPhotosCard.vue2.js.map +1 -1
  172. package/dist/esm/integrations/builtin/photos/CnPhotosCard.vue3.js.map +1 -1
  173. package/dist/esm/integrations/builtin/photos/CnPhotosTab.vue2.js +2 -1
  174. package/dist/esm/integrations/builtin/photos/CnPhotosTab.vue2.js.map +1 -1
  175. package/dist/esm/integrations/builtin/photos/CnPhotosTab.vue3.js +1 -2
  176. package/dist/esm/integrations/builtin/photos/CnPhotosTab.vue3.js.map +1 -1
  177. package/dist/esm/integrations/builtin/polls/CnPollsCard.vue2.js +2 -1
  178. package/dist/esm/integrations/builtin/polls/CnPollsCard.vue2.js.map +1 -1
  179. package/dist/esm/integrations/builtin/polls/CnPollsCard.vue3.js.map +1 -1
  180. package/dist/esm/integrations/builtin/polls/CnPollsTab.vue2.js +2 -1
  181. package/dist/esm/integrations/builtin/polls/CnPollsTab.vue2.js.map +1 -1
  182. package/dist/esm/integrations/builtin/polls/CnPollsTab.vue3.js +1 -2
  183. package/dist/esm/integrations/builtin/polls/CnPollsTab.vue3.js.map +1 -1
  184. package/dist/esm/integrations/builtin/shares/CnSharesTab.vue2.js.map +1 -1
  185. package/dist/esm/integrations/builtin/shares/CnSharesTab.vue3.js +3 -6
  186. package/dist/esm/integrations/builtin/shares/CnSharesTab.vue3.js.map +1 -1
  187. package/dist/esm/integrations/builtin/talk/CnTalkCard.vue2.js +3 -1
  188. package/dist/esm/integrations/builtin/talk/CnTalkCard.vue2.js.map +1 -1
  189. package/dist/esm/integrations/builtin/talk/CnTalkCard.vue3.js.map +1 -1
  190. package/dist/esm/integrations/builtin/talk/CnTalkTab.vue2.js +3 -1
  191. package/dist/esm/integrations/builtin/talk/CnTalkTab.vue2.js.map +1 -1
  192. package/dist/esm/integrations/builtin/talk/CnTalkTab.vue3.js +2 -4
  193. package/dist/esm/integrations/builtin/talk/CnTalkTab.vue3.js.map +1 -1
  194. package/dist/esm/integrations/builtin/time-tracker/CnTimeTrackerCard.vue2.js +2 -1
  195. package/dist/esm/integrations/builtin/time-tracker/CnTimeTrackerCard.vue2.js.map +1 -1
  196. package/dist/esm/integrations/builtin/time-tracker/CnTimeTrackerCard.vue3.js.map +1 -1
  197. package/dist/esm/integrations/builtin/time-tracker/CnTimeTrackerTab.vue2.js +2 -1
  198. package/dist/esm/integrations/builtin/time-tracker/CnTimeTrackerTab.vue2.js.map +1 -1
  199. package/dist/esm/integrations/builtin/time-tracker/CnTimeTrackerTab.vue3.js +1 -2
  200. package/dist/esm/integrations/builtin/time-tracker/CnTimeTrackerTab.vue3.js.map +1 -1
  201. package/dist/esm/integrations/builtin/xwiki/CnXwikiCard.vue2.js +4 -1
  202. package/dist/esm/integrations/builtin/xwiki/CnXwikiCard.vue2.js.map +1 -1
  203. package/dist/esm/integrations/builtin/xwiki/CnXwikiCard.vue3.js.map +1 -1
  204. package/dist/esm/integrations/builtin/xwiki/CnXwikiTab.vue2.js +6 -3
  205. package/dist/esm/integrations/builtin/xwiki/CnXwikiTab.vue2.js.map +1 -1
  206. package/dist/esm/integrations/builtin/xwiki/CnXwikiTab.vue3.js +2 -4
  207. package/dist/esm/integrations/builtin/xwiki/CnXwikiTab.vue3.js.map +1 -1
  208. package/dist/esm/l10n/en.json.js +1 -0
  209. package/dist/esm/l10n/en.json.js.map +1 -1
  210. package/dist/esm/l10n/nl.json.js +1 -0
  211. package/dist/esm/l10n/nl.json.js.map +1 -1
  212. package/dist/esm/nextcloud-vue.css +71 -7
  213. package/dist/esm/utils/actionLink.js +5 -0
  214. package/dist/esm/utils/actionLink.js.map +1 -1
  215. package/dist/esm/utils/actionsDispatcher.js +16 -1
  216. package/dist/esm/utils/actionsDispatcher.js.map +1 -1
  217. package/dist/esm/utils/linkNavigation.js +6 -3
  218. package/dist/esm/utils/linkNavigation.js.map +1 -1
  219. package/dist/esm/utils/rowAuxClick.js +30 -5
  220. package/dist/esm/utils/rowAuxClick.js.map +1 -1
  221. package/dist/esm/utils/safeHref.js +18 -3
  222. package/dist/esm/utils/safeHref.js.map +1 -1
  223. package/dist/nextcloud-vue.cjs.js +809 -383
  224. package/dist/nextcloud-vue.cjs.js.map +2 -2
  225. package/dist/nextcloud-vue.css +71 -7
  226. package/l10n/en.json +1 -0
  227. package/l10n/nl.json +1 -0
  228. package/package.json +1 -1
  229. package/src/components/CnActionsBar/CnActionsBar.vue +14 -5
  230. package/src/components/CnActionsMenu/CnActionsMenu.vue +0 -3
  231. package/src/components/CnAdminSettingsShell/CnAdminSettingsShell.vue +1 -2
  232. package/src/components/CnBoardView/CnBoardView.vue +13 -5
  233. package/src/components/CnCardGrid/CnCardGrid.vue +9 -1
  234. package/src/components/CnContextMenu/CnContextMenu.vue +6 -1
  235. package/src/components/CnDataTable/CnDataTable.md +1 -1
  236. package/src/components/CnDataTable/CnDataTable.vue +131 -17
  237. package/src/components/CnDateAxisView/CnDateAxisView.vue +15 -6
  238. package/src/components/CnDetailPage/CnDetailPage.md +1 -1
  239. package/src/components/CnDetailPage/CnDetailPage.vue +29 -1
  240. package/src/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue +1 -2
  241. package/src/components/CnFilesBrowser/CnFilesBrowser.vue +5 -3
  242. package/src/components/CnFilesWidget/CnFilesWidget.vue +4 -21
  243. package/src/components/CnFlowRunsWidget/CnFlowRunsWidget.vue +8 -21
  244. package/src/components/CnFlowsPage/CnFlowsPage.vue +2 -1
  245. package/src/components/CnIndexPage/CnIndexPage.vue +75 -14
  246. package/src/components/CnIndexPage/manifestActionDispatch.js +31 -11
  247. package/src/components/CnIntegrationWidget/CnIntegrationWidgetEmpty.vue +1 -2
  248. package/src/components/CnInteractionFormWidget/CnInteractionFormWidget.vue +0 -1
  249. package/src/components/CnLinkButtonWidget/CnLinkButtonWidget.vue +2 -17
  250. package/src/components/CnLogsPage/CnLogsPage.vue +37 -12
  251. package/src/components/CnObjectCard/CnObjectCard.vue +24 -6
  252. package/src/components/CnObjectList/CnObjectList.vue +19 -3
  253. package/src/components/CnObjectListWidget/CnObjectListWidget.vue +47 -15
  254. package/src/components/CnObjectRow/CnObjectRow.vue +25 -7
  255. package/src/components/CnObjectSidebar/CnFilesTab.vue +0 -1
  256. package/src/components/CnPageRenderer/CnPageRenderer.vue +2 -0
  257. package/src/components/CnRowActions/CnRowActions.vue +7 -2
  258. package/src/components/CnSpendAnalyticsWidget/CnSpendAnalyticsWidget.vue +5 -3
  259. package/src/components/CnTabs/CnTabs.vue +7 -3
  260. package/src/components/CnTasksWidget/CnTasksWidget.vue +4 -1
  261. package/src/css/table.css +26 -0
  262. package/src/integrations/builtin/analytics/CnAnalyticsCard.vue +3 -2
  263. package/src/integrations/builtin/analytics/CnAnalyticsTab.vue +5 -6
  264. package/src/integrations/builtin/bookmarks/CnBookmarksCard.vue +12 -1
  265. package/src/integrations/builtin/bookmarks/CnBookmarksTab.vue +23 -6
  266. package/src/integrations/builtin/bookmarks/__tests__/CnBookmarksTab.spec.js +7 -2
  267. package/src/integrations/builtin/collectives/CnCollectivesCard.vue +3 -2
  268. package/src/integrations/builtin/collectives/CnCollectivesTab.vue +5 -6
  269. package/src/integrations/builtin/cospend/CnCospendCard.vue +2 -2
  270. package/src/integrations/builtin/cospend/CnCospendTab.vue +3 -4
  271. package/src/integrations/builtin/deck/CnDeckCard.vue +2 -2
  272. package/src/integrations/builtin/deck/CnDeckTab.vue +3 -4
  273. package/src/integrations/builtin/email/CnEmailCard.vue +6 -2
  274. package/src/integrations/builtin/email/CnEmailTab.vue +7 -4
  275. package/src/integrations/builtin/flow/CnFlowCard.vue +2 -2
  276. package/src/integrations/builtin/flow/CnFlowTab.vue +3 -4
  277. package/src/integrations/builtin/forms/CnFormsCard.vue +3 -2
  278. package/src/integrations/builtin/forms/CnFormsTab.vue +5 -6
  279. package/src/integrations/builtin/maps/CnMapsCard.vue +3 -2
  280. package/src/integrations/builtin/maps/CnMapsTab.vue +5 -6
  281. package/src/integrations/builtin/maps/__tests__/CnMapsTab.spec.js +9 -0
  282. package/src/integrations/builtin/openproject/CnOpenprojectCard.vue +3 -2
  283. package/src/integrations/builtin/openproject/CnOpenprojectTab.vue +5 -6
  284. package/src/integrations/builtin/photos/CnPhotosCard.vue +2 -2
  285. package/src/integrations/builtin/photos/CnPhotosTab.vue +3 -4
  286. package/src/integrations/builtin/polls/CnPollsCard.vue +2 -2
  287. package/src/integrations/builtin/polls/CnPollsTab.vue +3 -4
  288. package/src/integrations/builtin/shares/CnSharesTab.vue +3 -6
  289. package/src/integrations/builtin/talk/CnTalkCard.vue +3 -2
  290. package/src/integrations/builtin/talk/CnTalkTab.vue +5 -6
  291. package/src/integrations/builtin/time-tracker/CnTimeTrackerCard.vue +2 -2
  292. package/src/integrations/builtin/time-tracker/CnTimeTrackerTab.vue +3 -4
  293. package/src/integrations/builtin/xwiki/CnXwikiCard.vue +4 -2
  294. package/src/integrations/builtin/xwiki/CnXwikiTab.vue +7 -7
  295. package/src/integrations/builtin/xwiki/__tests__/CnXwikiTab.spec.js +9 -0
  296. package/src/utils/actionLink.js +5 -0
  297. package/src/utils/actionsDispatcher.js +15 -0
  298. package/src/utils/linkNavigation.js +6 -3
  299. package/src/utils/rowAuxClick.js +29 -4
  300. package/src/utils/safeHref.js +18 -3
@@ -37,19 +37,39 @@ function resolveRowToken(value, row) {
37
37
  }
38
38
 
39
39
  /**
40
- * The route params a `handler: "navigate"` action pushes for a row: the row id,
41
- * overridden by the declared `params` after the `{field}` token grammar. A
42
- * token naming a field the row lacks is dropped.
40
+ * The implicit `{ id }` param for a row, only when the named route declares
41
+ * `:id`: vue-router warns about (and drops) a param its path does not take.
42
+ * Without a router to ask, or for a route it does not know, the id is kept.
43
43
  *
44
- * @param {object} action Manifest action descriptor.
44
+ * @param {object} [router] The app's router.
45
+ * @param {string} name The route name.
45
46
  * @param {object} row The row.
46
47
  * @param {string} rowKey The row's id field.
48
+ * @return {object} `{ id }`, or an empty object.
49
+ */
50
+ function rowIdParam(router, name, row, rowKey) {
51
+ const routes = typeof router?.getRoutes === 'function' ? router.getRoutes() : null;
52
+ const route = routes ? routes.find((r) => r.name === name) : null;
53
+ if (route && !/:id\b/.test(route.path)) {
54
+ return {}
55
+ }
56
+ return { id: row?.[rowKey] }
57
+ }
58
+
59
+ /**
60
+ * The route params a `handler: "navigate"` action pushes for a row: the row id
61
+ * (when the route takes one), overridden by the declared `params` after the
62
+ * `{field}` token grammar. A token naming a field the row lacks is dropped.
63
+ *
64
+ * @param {object} action Manifest action descriptor.
65
+ * @param {object} row The row.
66
+ * @param {object} ctx Dispatch context (`rowKey`, `router`).
47
67
  * @param {boolean} warn Whether to warn about a dropped param.
48
68
  * @return {object} The params.
49
69
  */
50
- function navigateParams(action, row, rowKey, warn) {
70
+ function navigateParams(action, row, ctx, warn) {
51
71
  const declaredParams = (action.params && typeof action.params === 'object') ? action.params : null;
52
- const params = { id: row?.[rowKey] };
72
+ const params = rowIdParam(ctx.router, action.route, row, ctx.rowKey);
53
73
  for (const [key, declared] of Object.entries(declaredParams || {})) {
54
74
  const { resolved, value } = resolveRowToken(declared, row);
55
75
  if (resolved) {
@@ -88,7 +108,7 @@ function resolveActionTarget(action, row, ctx, warn = false) {
88
108
  return null
89
109
  }
90
110
  if (type === 'open-page') {
91
- return { target: { name: target, params: { id: row?.[ctx.rowKey] } }, external: false }
111
+ return { target: { name: target, params: rowIdParam(ctx.router, target, row, ctx.rowKey) }, external: false }
92
112
  }
93
113
  return { target, external: isExternalActionTarget(target) }
94
114
  }
@@ -96,7 +116,7 @@ function resolveActionTarget(action, row, ctx, warn = false) {
96
116
  if (typeof action.route !== 'string' || action.route.length === 0) {
97
117
  return null
98
118
  }
99
- return { target: { name: action.route, params: navigateParams(action, row, ctx.rowKey, warn) }, external: false }
119
+ return { target: { name: action.route, params: navigateParams(action, row, ctx, warn) }, external: false }
100
120
  }
101
121
  return null
102
122
  }
@@ -115,8 +135,8 @@ function resolveActionTarget(action, row, ctx, warn = false) {
115
135
  * - `open-modal` → not wired for index actions; falls back to `@action`.
116
136
  *
117
137
  * Handler dispatch (`type: 'handler'`, the default) reads `action.handler`:
118
- * - `navigate` → $router.push to `action.route` with `{ id: row[rowKey] }`,
119
- * merged with the `action.params` map (declared params win — so a
138
+ * - `navigate` → $router.push to `action.route` with `{ id: row[rowKey] }`
139
+ * (when the route declares `:id`), merged with the `action.params` map (declared params win — so a
120
140
  * "New X" action can navigate to a detail route with `{ id: "new" }`).
121
141
  * Param strings run the `{field}` row-token grammar: `"{id}"` resolves to
122
142
  * `row.id` (type preserved), `"item-{id}"` interpolates, and a brace-less
@@ -187,7 +207,7 @@ function resolveActionHandler(action, ctx) {
187
207
  // `{field}` row-token grammar first — an unresolved token is dropped
188
208
  // rather than pushed as a literal `%7Bid%7D` path segment.
189
209
  return (row) => {
190
- ctx.router.push({ name: route, params: navigateParams(action, row, ctx.rowKey, true) });
210
+ ctx.router.push({ name: route, params: navigateParams(action, row, ctx, true) });
191
211
  }
192
212
  }
193
213
 
@@ -1 +1 @@
1
- {"version":3,"file":"manifestActionDispatch.js","sources":["../../../../src/components/CnIndexPage/manifestActionDispatch.js"],"sourcesContent":["import { isExternalActionTarget, resolveRegisteredHandler } from '../../utils/actionsDispatcher.js'\n\n/**\n * Substitute `{field}` row tokens in a single manifest param value.\n *\n * A value that is exactly one token (`\"{id}\"`) resolves to `row.id` with its\n * type preserved, so numeric ids stay numbers. Tokens embedded in a longer\n * string (`\"item-{id}\"`) interpolate as text. Values without braces\n * (`\"new\"`) pass through verbatim — that is what keeps a literal\n * `params: { id: \"new\" }` working.\n *\n * @param {unknown} value The declared param value.\n * @param {object} row The row the action was triggered on.\n * @return {{ resolved: boolean, value: unknown }} `resolved` is false when a token names a field the row does not carry.\n */\nfunction resolveRowToken(value, row) {\n\tif (typeof value !== 'string' || !value.includes('{')) {\n\t\treturn { resolved: true, value }\n\t}\n\n\tconst exact = value.match(/^\\{([^{}]+)\\}$/)\n\tif (exact) {\n\t\tconst found = row?.[exact[1]]\n\t\treturn found === undefined ? { resolved: false, value } : { resolved: true, value: found }\n\t}\n\n\tlet resolved = true\n\tconst interpolated = value.replace(/\\{([^{}]+)\\}/g, (token, field) => {\n\t\tconst found = row?.[field]\n\t\tif (found === undefined) {\n\t\t\tresolved = false\n\t\t\treturn token\n\t\t}\n\t\treturn String(found)\n\t})\n\treturn { resolved, value: resolved ? interpolated : value }\n}\n\n/**\n * The route params a `handler: \"navigate\"` action pushes for a row: the row id,\n * overridden by the declared `params` after the `{field}` token grammar. A\n * token naming a field the row lacks is dropped.\n *\n * @param {object} action Manifest action descriptor.\n * @param {object} row The row.\n * @param {string} rowKey The row's id field.\n * @param {boolean} warn Whether to warn about a dropped param.\n * @return {object} The params.\n */\nfunction navigateParams(action, row, rowKey, warn) {\n\tconst declaredParams = (action.params && typeof action.params === 'object') ? action.params : null\n\tconst params = { id: row?.[rowKey] }\n\tfor (const [key, declared] of Object.entries(declaredParams || {})) {\n\t\tconst { resolved, value } = resolveRowToken(declared, row)\n\t\tif (resolved) {\n\t\t\tparams[key] = value\n\t\t} else if (warn) {\n\t\t\t// eslint-disable-next-line no-console\n\t\t\tconsole.warn(`[CnIndexPage] action \"${action.id}\" param \"${key}\" references `\n\t\t\t\t+ `\"${declared}\" but the row carries no such field; dropping the param`\n\t\t\t\t+ (key === 'id' ? ' (\"id\" falls back to the row id).' : '.'))\n\t\t}\n\t}\n\treturn params\n}\n\n/**\n * Where a navigating manifest action goes for a row, or null when the action\n * does not navigate (or is missing its target). Same resolution the\n * dispatcher uses: `type: \"navigate\"` → `target` (external when it leaves the\n * app), `type: \"open-page\"` → `{ name: target, params: { id } }`,\n * `handler: \"navigate\"` → `{ name: route, params }`.\n *\n * @param {object} action Manifest action descriptor.\n * @param {object} row The row.\n * @param {{rowKey: string}} ctx Dispatch context.\n * @param {boolean} [warn] Warn about params dropped for an unresolved token.\n * @return {{target: (string|object), external: boolean}|null} The target, or null.\n */\nexport function resolveActionTarget(action, row, ctx, warn = false) {\n\tif (!action || typeof action !== 'object') {\n\t\treturn null\n\t}\n\tconst type = (typeof action.type === 'string' && action.type.length > 0) ? action.type : 'handler'\n\tif (type === 'navigate' || type === 'open-page') {\n\t\tconst target = action.target\n\t\tif (typeof target !== 'string' || target.length === 0) {\n\t\t\treturn null\n\t\t}\n\t\tif (type === 'open-page') {\n\t\t\treturn { target: { name: target, params: { id: row?.[ctx.rowKey] } }, external: false }\n\t\t}\n\t\treturn { target, external: isExternalActionTarget(target) }\n\t}\n\tif (type === 'handler' && action.handler === 'navigate') {\n\t\tif (typeof action.route !== 'string' || action.route.length === 0) {\n\t\t\treturn null\n\t\t}\n\t\treturn { target: { name: action.route, params: navigateParams(action, row, ctx.rowKey, warn) }, external: false }\n\t}\n\treturn null\n}\n\n/**\n * Resolve a manifest-declared action into a `(row) => void` function. Returns\n * null when the action should fall back to the page's `@action`-event-only path.\n *\n * Dispatch is chosen by the v2 `type` discriminator (app-manifest-v2 schema);\n * when `type` is absent it defaults to `'handler'` for v1.3.0 back-compat.\n *\n * Typed dispatch (`action.type`):\n * - `navigate` → `action.target` is a URL. External/absolute URLs open in a\n * new tab (`window.open`, `noopener`); in-app paths go through `$router.push`.\n * - `open-page` → `action.target` is a named route; `$router.push({ name, params:{ id } })`.\n * - `open-modal` → not wired for index actions; falls back to `@action`.\n *\n * Handler dispatch (`type: 'handler'`, the default) reads `action.handler`:\n * - `navigate` → $router.push to `action.route` with `{ id: row[rowKey] }`,\n * merged with the `action.params` map (declared params win — so a\n * \"New X\" action can navigate to a detail route with `{ id: \"new\" }`).\n * Param strings run the `{field}` row-token grammar: `\"{id}\"` resolves to\n * `row.id` (type preserved), `\"item-{id}\"` interpolates, and a brace-less\n * `\"new\"` stays literal. A token naming a field the row lacks is dropped\n * with a warning instead of being pushed as a literal `%7Bid%7D` segment.\n * - `emit` → null (page still bubbles `@action`).\n * - `none` → no-op handler. Caller must also suppress the `@action` emit\n * (handled via the `_dispatchSuppress` flag set in dispatchAction).\n * - Anything else → looked up in the v2 registry, then `customComponents`;\n * wrapped if a function.\n *\n * @param {object} action Manifest action descriptor.\n * @param {{ router: object, rowKey: string, registry?: object, customComponents: object }} ctx Dispatch context (router, rowKey, the v2 registry and the legacy customComponents map).\n * @return {((row?: object) => void)|null}\n */\nexport function resolveActionHandler(action, ctx) {\n\tconst type = (typeof action.type === 'string' && action.type.length > 0) ? action.type : 'handler'\n\n\t// v2 typed dispatch (schema: type ∈ handler | open-modal | open-page | navigate).\n\tif (type === 'navigate') {\n\t\tconst target = action.target\n\t\tif (typeof target !== 'string' || target.length === 0) {\n\t\t\t// eslint-disable-next-line no-console\n\t\t\tconsole.warn(`[CnIndexPage] action \"${action.id}\" declares type:\"navigate\" `\n\t\t\t\t+ 'but target is missing; falling back to @action-only.')\n\t\t\treturn null\n\t\t}\n\t\tif (isExternalActionTarget(target)) {\n\t\t\treturn () => window.open(target, '_blank', 'noopener,noreferrer')\n\t\t}\n\t\treturn () => ctx.router.push(target)\n\t}\n\n\tif (type === 'open-page') {\n\t\tconst target = action.target\n\t\tif (typeof target !== 'string' || target.length === 0) {\n\t\t\t// eslint-disable-next-line no-console\n\t\t\tconsole.warn(`[CnIndexPage] action \"${action.id}\" declares type:\"open-page\" `\n\t\t\t\t+ 'but target is missing; falling back to @action-only.')\n\t\t\treturn null\n\t\t}\n\t\treturn (row) => ctx.router.push(resolveActionTarget(action, row, ctx).target)\n\t}\n\n\tif (type === 'open-modal') {\n\t\t// eslint-disable-next-line no-console\n\t\tconsole.warn(`[CnIndexPage] action \"${action.id}\" type:\"open-modal\" is not `\n\t\t\t+ 'supported for index-page actions; falling back to @action-only.')\n\t\treturn null\n\t}\n\n\t// type === 'handler' (default): the v1.3.0 handler-string path.\n\tconst name = action.handler\n\tif (typeof name !== 'string' || name.length === 0) {\n\t\treturn null\n\t}\n\n\tif (name === 'navigate') {\n\t\tconst route = action.route\n\t\tif (typeof route !== 'string' || route.length === 0) {\n\t\t\t// eslint-disable-next-line no-console\n\t\t\tconsole.warn(`[CnIndexPage] action \"${action.id}\" declares handler:\"navigate\" `\n\t\t\t\t+ 'but route is missing; falling back to @action-only.')\n\t\t\treturn null\n\t\t}\n\t\t// Declared params override the default row-id param, so \"New X → detail\n\t\t// with id:'new'\" is expressible declaratively. String values run the\n\t\t// `{field}` row-token grammar first — an unresolved token is dropped\n\t\t// rather than pushed as a literal `%7Bid%7D` path segment.\n\t\treturn (row) => {\n\t\t\tctx.router.push({ name: route, params: navigateParams(action, row, ctx.rowKey, true) })\n\t\t}\n\t}\n\n\tif (name === 'emit') {\n\t\treturn null\n\t}\n\tif (name === 'none') {\n\t\treturn () => {}\n\t}\n\n\tconst fn = resolveRegisteredHandler(name, ctx.registry, ctx.customComponents)\n\tif (typeof fn === 'function') {\n\t\treturn (row) => fn({ actionId: action.id, item: row })\n\t}\n\tif ((ctx.registry || {})[name] !== undefined || (ctx.customComponents || {})[name] !== undefined) {\n\t\t// eslint-disable-next-line no-console\n\t\tconsole.warn(`[CnIndexPage] action.handler \"${name}\" resolved to a non-function in `\n\t\t\t+ 'the registry or customComponents — components belong to slot '\n\t\t\t+ 'overrides; falling back to @action-only.')\n\t}\n\treturn null\n}\n\n/**\n * The CnRowActions link fields for a navigating action, so it renders as a\n * real link: `href` + `linkTarget` for an external URL, a per-row `to` for an\n * in-app target. Empty for anything else, or when the action already carries\n * its own `href` / `to`.\n *\n * @param {object} action Manifest action descriptor.\n * @param {{rowKey: string}} ctx Dispatch context.\n * @return {object} The fields to merge onto the dispatched action.\n */\nfunction linkFields(action, ctx) {\n\tif (action.href || action.to) {\n\t\treturn {}\n\t}\n\tconst probe = resolveActionTarget(action, null, ctx)\n\tif (!probe) {\n\t\treturn {}\n\t}\n\tif (probe.external) {\n\t\treturn { href: probe.target, linkTarget: '_blank' }\n\t}\n\treturn { to: (row) => resolveActionTarget(action, row, ctx)?.target ?? null }\n}\n\n/**\n * Clone an action with its handler-string resolved to a function. Function-\n * typed handlers pass through unchanged. When the resolution fails (unknown\n * registry name, `emit` keyword), the handler is stripped so CnRowActions\n * falls through to the @action-only path.\n *\n * @param {object} action Manifest action descriptor.\n * @param {{ router: object, rowKey: string, customComponents: object }} ctx Dispatch context (router, rowKey, customComponents registry).\n * @return {object} The action with its handler resolved (or stripped on failure).\n */\nexport function dispatchAction(action, ctx) {\n\tif (typeof action.handler === 'function') {\n\t\treturn action\n\t}\n\n\tconst type = (typeof action.type === 'string' && action.type.length > 0) ? action.type : 'handler'\n\t// Nothing to resolve: the default `handler` type with no handler string\n\t// (a pure `@action`-emit action). Typed actions (navigate / open-page /\n\t// open-modal) resolve below even though they carry no `handler` string.\n\tif (type === 'handler' && (typeof action.handler !== 'string' || action.handler.length === 0)) {\n\t\treturn action\n\t}\n\n\tconst isNone = action.handler === 'none'\n\tconst resolved = resolveActionHandler(action, ctx)\n\tif (resolved) {\n\t\tif (isNone) {\n\t\t\treturn { ...action, handler: resolved, _dispatchSuppress: true }\n\t\t}\n\t\treturn { ...action, handler: resolved, ...linkFields(action, ctx) }\n\t}\n\tconst { handler, ...rest } = action\n\treturn rest\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"manifestActionDispatch.js","sources":["../../../../src/components/CnIndexPage/manifestActionDispatch.js"],"sourcesContent":["import { isExternalActionTarget, resolveRegisteredHandler } from '../../utils/actionsDispatcher.js'\n\n/**\n * Substitute `{field}` row tokens in a single manifest param value.\n *\n * A value that is exactly one token (`\"{id}\"`) resolves to `row.id` with its\n * type preserved, so numeric ids stay numbers. Tokens embedded in a longer\n * string (`\"item-{id}\"`) interpolate as text. Values without braces\n * (`\"new\"`) pass through verbatim — that is what keeps a literal\n * `params: { id: \"new\" }` working.\n *\n * @param {unknown} value The declared param value.\n * @param {object} row The row the action was triggered on.\n * @return {{ resolved: boolean, value: unknown }} `resolved` is false when a token names a field the row does not carry.\n */\nfunction resolveRowToken(value, row) {\n\tif (typeof value !== 'string' || !value.includes('{')) {\n\t\treturn { resolved: true, value }\n\t}\n\n\tconst exact = value.match(/^\\{([^{}]+)\\}$/)\n\tif (exact) {\n\t\tconst found = row?.[exact[1]]\n\t\treturn found === undefined ? { resolved: false, value } : { resolved: true, value: found }\n\t}\n\n\tlet resolved = true\n\tconst interpolated = value.replace(/\\{([^{}]+)\\}/g, (token, field) => {\n\t\tconst found = row?.[field]\n\t\tif (found === undefined) {\n\t\t\tresolved = false\n\t\t\treturn token\n\t\t}\n\t\treturn String(found)\n\t})\n\treturn { resolved, value: resolved ? interpolated : value }\n}\n\n/**\n * The implicit `{ id }` param for a row, only when the named route declares\n * `:id`: vue-router warns about (and drops) a param its path does not take.\n * Without a router to ask, or for a route it does not know, the id is kept.\n *\n * @param {object} [router] The app's router.\n * @param {string} name The route name.\n * @param {object} row The row.\n * @param {string} rowKey The row's id field.\n * @return {object} `{ id }`, or an empty object.\n */\nfunction rowIdParam(router, name, row, rowKey) {\n\tconst routes = typeof router?.getRoutes === 'function' ? router.getRoutes() : null\n\tconst route = routes ? routes.find((r) => r.name === name) : null\n\tif (route && !/:id\\b/.test(route.path)) {\n\t\treturn {}\n\t}\n\treturn { id: row?.[rowKey] }\n}\n\n/**\n * The route params a `handler: \"navigate\"` action pushes for a row: the row id\n * (when the route takes one), overridden by the declared `params` after the\n * `{field}` token grammar. A token naming a field the row lacks is dropped.\n *\n * @param {object} action Manifest action descriptor.\n * @param {object} row The row.\n * @param {object} ctx Dispatch context (`rowKey`, `router`).\n * @param {boolean} warn Whether to warn about a dropped param.\n * @return {object} The params.\n */\nfunction navigateParams(action, row, ctx, warn) {\n\tconst declaredParams = (action.params && typeof action.params === 'object') ? action.params : null\n\tconst params = rowIdParam(ctx.router, action.route, row, ctx.rowKey)\n\tfor (const [key, declared] of Object.entries(declaredParams || {})) {\n\t\tconst { resolved, value } = resolveRowToken(declared, row)\n\t\tif (resolved) {\n\t\t\tparams[key] = value\n\t\t} else if (warn) {\n\t\t\t// eslint-disable-next-line no-console\n\t\t\tconsole.warn(`[CnIndexPage] action \"${action.id}\" param \"${key}\" references `\n\t\t\t\t+ `\"${declared}\" but the row carries no such field; dropping the param`\n\t\t\t\t+ (key === 'id' ? ' (\"id\" falls back to the row id).' : '.'))\n\t\t}\n\t}\n\treturn params\n}\n\n/**\n * Where a navigating manifest action goes for a row, or null when the action\n * does not navigate (or is missing its target). Same resolution the\n * dispatcher uses: `type: \"navigate\"` → `target` (external when it leaves the\n * app), `type: \"open-page\"` → `{ name: target, params: { id } }`,\n * `handler: \"navigate\"` → `{ name: route, params }`.\n *\n * @param {object} action Manifest action descriptor.\n * @param {object} row The row.\n * @param {{rowKey: string}} ctx Dispatch context.\n * @param {boolean} [warn] Warn about params dropped for an unresolved token.\n * @return {{target: (string|object), external: boolean}|null} The target, or null.\n */\nexport function resolveActionTarget(action, row, ctx, warn = false) {\n\tif (!action || typeof action !== 'object') {\n\t\treturn null\n\t}\n\tconst type = (typeof action.type === 'string' && action.type.length > 0) ? action.type : 'handler'\n\tif (type === 'navigate' || type === 'open-page') {\n\t\tconst target = action.target\n\t\tif (typeof target !== 'string' || target.length === 0) {\n\t\t\treturn null\n\t\t}\n\t\tif (type === 'open-page') {\n\t\t\treturn { target: { name: target, params: rowIdParam(ctx.router, target, row, ctx.rowKey) }, external: false }\n\t\t}\n\t\treturn { target, external: isExternalActionTarget(target) }\n\t}\n\tif (type === 'handler' && action.handler === 'navigate') {\n\t\tif (typeof action.route !== 'string' || action.route.length === 0) {\n\t\t\treturn null\n\t\t}\n\t\treturn { target: { name: action.route, params: navigateParams(action, row, ctx, warn) }, external: false }\n\t}\n\treturn null\n}\n\n/**\n * Resolve a manifest-declared action into a `(row) => void` function. Returns\n * null when the action should fall back to the page's `@action`-event-only path.\n *\n * Dispatch is chosen by the v2 `type` discriminator (app-manifest-v2 schema);\n * when `type` is absent it defaults to `'handler'` for v1.3.0 back-compat.\n *\n * Typed dispatch (`action.type`):\n * - `navigate` → `action.target` is a URL. External/absolute URLs open in a\n * new tab (`window.open`, `noopener`); in-app paths go through `$router.push`.\n * - `open-page` → `action.target` is a named route; `$router.push({ name, params:{ id } })`.\n * - `open-modal` → not wired for index actions; falls back to `@action`.\n *\n * Handler dispatch (`type: 'handler'`, the default) reads `action.handler`:\n * - `navigate` → $router.push to `action.route` with `{ id: row[rowKey] }`\n * (when the route declares `:id`), merged with the `action.params` map (declared params win — so a\n * \"New X\" action can navigate to a detail route with `{ id: \"new\" }`).\n * Param strings run the `{field}` row-token grammar: `\"{id}\"` resolves to\n * `row.id` (type preserved), `\"item-{id}\"` interpolates, and a brace-less\n * `\"new\"` stays literal. A token naming a field the row lacks is dropped\n * with a warning instead of being pushed as a literal `%7Bid%7D` segment.\n * - `emit` → null (page still bubbles `@action`).\n * - `none` → no-op handler. Caller must also suppress the `@action` emit\n * (handled via the `_dispatchSuppress` flag set in dispatchAction).\n * - Anything else → looked up in the v2 registry, then `customComponents`;\n * wrapped if a function.\n *\n * @param {object} action Manifest action descriptor.\n * @param {{ router: object, rowKey: string, registry?: object, customComponents: object }} ctx Dispatch context (router, rowKey, the v2 registry and the legacy customComponents map).\n * @return {((row?: object) => void)|null}\n */\nexport function resolveActionHandler(action, ctx) {\n\tconst type = (typeof action.type === 'string' && action.type.length > 0) ? action.type : 'handler'\n\n\t// v2 typed dispatch (schema: type ∈ handler | open-modal | open-page | navigate).\n\tif (type === 'navigate') {\n\t\tconst target = action.target\n\t\tif (typeof target !== 'string' || target.length === 0) {\n\t\t\t// eslint-disable-next-line no-console\n\t\t\tconsole.warn(`[CnIndexPage] action \"${action.id}\" declares type:\"navigate\" `\n\t\t\t\t+ 'but target is missing; falling back to @action-only.')\n\t\t\treturn null\n\t\t}\n\t\tif (isExternalActionTarget(target)) {\n\t\t\treturn () => window.open(target, '_blank', 'noopener,noreferrer')\n\t\t}\n\t\treturn () => ctx.router.push(target)\n\t}\n\n\tif (type === 'open-page') {\n\t\tconst target = action.target\n\t\tif (typeof target !== 'string' || target.length === 0) {\n\t\t\t// eslint-disable-next-line no-console\n\t\t\tconsole.warn(`[CnIndexPage] action \"${action.id}\" declares type:\"open-page\" `\n\t\t\t\t+ 'but target is missing; falling back to @action-only.')\n\t\t\treturn null\n\t\t}\n\t\treturn (row) => ctx.router.push(resolveActionTarget(action, row, ctx).target)\n\t}\n\n\tif (type === 'open-modal') {\n\t\t// eslint-disable-next-line no-console\n\t\tconsole.warn(`[CnIndexPage] action \"${action.id}\" type:\"open-modal\" is not `\n\t\t\t+ 'supported for index-page actions; falling back to @action-only.')\n\t\treturn null\n\t}\n\n\t// type === 'handler' (default): the v1.3.0 handler-string path.\n\tconst name = action.handler\n\tif (typeof name !== 'string' || name.length === 0) {\n\t\treturn null\n\t}\n\n\tif (name === 'navigate') {\n\t\tconst route = action.route\n\t\tif (typeof route !== 'string' || route.length === 0) {\n\t\t\t// eslint-disable-next-line no-console\n\t\t\tconsole.warn(`[CnIndexPage] action \"${action.id}\" declares handler:\"navigate\" `\n\t\t\t\t+ 'but route is missing; falling back to @action-only.')\n\t\t\treturn null\n\t\t}\n\t\t// Declared params override the default row-id param, so \"New X → detail\n\t\t// with id:'new'\" is expressible declaratively. String values run the\n\t\t// `{field}` row-token grammar first — an unresolved token is dropped\n\t\t// rather than pushed as a literal `%7Bid%7D` path segment.\n\t\treturn (row) => {\n\t\t\tctx.router.push({ name: route, params: navigateParams(action, row, ctx, true) })\n\t\t}\n\t}\n\n\tif (name === 'emit') {\n\t\treturn null\n\t}\n\tif (name === 'none') {\n\t\treturn () => {}\n\t}\n\n\tconst fn = resolveRegisteredHandler(name, ctx.registry, ctx.customComponents)\n\tif (typeof fn === 'function') {\n\t\treturn (row) => fn({ actionId: action.id, item: row })\n\t}\n\tif ((ctx.registry || {})[name] !== undefined || (ctx.customComponents || {})[name] !== undefined) {\n\t\t// eslint-disable-next-line no-console\n\t\tconsole.warn(`[CnIndexPage] action.handler \"${name}\" resolved to a non-function in `\n\t\t\t+ 'the registry or customComponents — components belong to slot '\n\t\t\t+ 'overrides; falling back to @action-only.')\n\t}\n\treturn null\n}\n\n/**\n * The CnRowActions link fields for a navigating action, so it renders as a\n * real link: `href` + `linkTarget` for an external URL, a per-row `to` for an\n * in-app target. Empty for anything else, or when the action already carries\n * its own `href` / `to`.\n *\n * @param {object} action Manifest action descriptor.\n * @param {{rowKey: string}} ctx Dispatch context.\n * @return {object} The fields to merge onto the dispatched action.\n */\nfunction linkFields(action, ctx) {\n\tif (action.href || action.to) {\n\t\treturn {}\n\t}\n\tconst probe = resolveActionTarget(action, null, ctx)\n\tif (!probe) {\n\t\treturn {}\n\t}\n\tif (probe.external) {\n\t\treturn { href: probe.target, linkTarget: '_blank' }\n\t}\n\treturn { to: (row) => resolveActionTarget(action, row, ctx)?.target ?? null }\n}\n\n/**\n * Clone an action with its handler-string resolved to a function. Function-\n * typed handlers pass through unchanged. When the resolution fails (unknown\n * registry name, `emit` keyword), the handler is stripped so CnRowActions\n * falls through to the @action-only path.\n *\n * @param {object} action Manifest action descriptor.\n * @param {{ router: object, rowKey: string, customComponents: object }} ctx Dispatch context (router, rowKey, customComponents registry).\n * @return {object} The action with its handler resolved (or stripped on failure).\n */\nexport function dispatchAction(action, ctx) {\n\tif (typeof action.handler === 'function') {\n\t\treturn action\n\t}\n\n\tconst type = (typeof action.type === 'string' && action.type.length > 0) ? action.type : 'handler'\n\t// Nothing to resolve: the default `handler` type with no handler string\n\t// (a pure `@action`-emit action). Typed actions (navigate / open-page /\n\t// open-modal) resolve below even though they carry no `handler` string.\n\tif (type === 'handler' && (typeof action.handler !== 'string' || action.handler.length === 0)) {\n\t\treturn action\n\t}\n\n\tconst isNone = action.handler === 'none'\n\tconst resolved = resolveActionHandler(action, ctx)\n\tif (resolved) {\n\t\tif (isNone) {\n\t\t\treturn { ...action, handler: resolved, _dispatchSuppress: true }\n\t\t}\n\t\treturn { ...action, handler: resolved, ...linkFields(action, ctx) }\n\t}\n\tconst { handler, ...rest } = action\n\treturn rest\n}\n"],"names":[],"mappings":";;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS,eAAe,CAAC,KAAK,EAAE,GAAG,EAAE;AACrC,CAAC,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE;AACxD,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE;AAClC,EAAE;AACF;AACA,CAAC,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,gBAAgB,EAAC;AAC5C,CAAC,IAAI,KAAK,EAAE;AACZ,EAAE,MAAM,KAAK,GAAG,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC,EAAC;AAC/B,EAAE,OAAO,KAAK,KAAK,SAAS,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE;AAC5F,EAAE;AACF;AACA,CAAC,IAAI,QAAQ,GAAG,KAAI;AACpB,CAAC,MAAM,YAAY,GAAG,KAAK,CAAC,OAAO,CAAC,eAAe,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK;AACvE,EAAE,MAAM,KAAK,GAAG,GAAG,GAAG,KAAK,EAAC;AAC5B,EAAE,IAAI,KAAK,KAAK,SAAS,EAAE;AAC3B,GAAG,QAAQ,GAAG,MAAK;AACnB,GAAG,OAAO,KAAK;AACf,GAAG;AACH,EAAE,OAAO,MAAM,CAAC,KAAK,CAAC;AACtB,EAAE,EAAC;AACH,CAAC,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,GAAG,YAAY,GAAG,KAAK,EAAE;AAC5D,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS,UAAU,CAAC,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,EAAE;AAC/C,CAAC,MAAM,MAAM,GAAG,OAAO,MAAM,EAAE,SAAS,KAAK,UAAU,GAAG,MAAM,CAAC,SAAS,EAAE,GAAG,KAAI;AACnF,CAAC,MAAM,KAAK,GAAG,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,GAAG,KAAI;AAClE,CAAC,IAAI,KAAK,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE;AACzC,EAAE,OAAO,EAAE;AACX,EAAE;AACF,CAAC,OAAO,EAAE,EAAE,EAAE,GAAG,GAAG,MAAM,CAAC,EAAE;AAC7B,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS,cAAc,CAAC,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE;AAChD,CAAC,MAAM,cAAc,GAAG,CAAC,MAAM,CAAC,MAAM,IAAI,OAAO,MAAM,CAAC,MAAM,KAAK,QAAQ,IAAI,MAAM,CAAC,MAAM,GAAG,KAAI;AACnG,CAAC,MAAM,MAAM,GAAG,UAAU,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,CAAC,MAAM,EAAC;AACrE,CAAC,KAAK,MAAM,CAAC,GAAG,EAAE,QAAQ,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,cAAc,IAAI,EAAE,CAAC,EAAE;AACrE,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,GAAG,eAAe,CAAC,QAAQ,EAAE,GAAG,EAAC;AAC5D,EAAE,IAAI,QAAQ,EAAE;AAChB,GAAG,MAAM,CAAC,GAAG,CAAC,GAAG,MAAK;AACtB,GAAG,MAAM,IAAI,IAAI,EAAE;AACnB;AACA,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,sBAAsB,EAAE,MAAM,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,CAAC,aAAa,CAAC;AAChF,MAAM,CAAC,CAAC,EAAE,QAAQ,CAAC,uDAAuD,CAAC;AAC3E,OAAO,GAAG,KAAK,IAAI,GAAG,mCAAmC,GAAG,GAAG,CAAC,EAAC;AACjE,GAAG;AACH,EAAE;AACF,CAAC,OAAO,MAAM;AACd,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,mBAAmB,CAAC,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,GAAG,KAAK,EAAE;AACpE,CAAC,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE;AAC5C,EAAE,OAAO,IAAI;AACb,EAAE;AACF,CAAC,MAAM,IAAI,GAAG,CAAC,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,IAAI,MAAM,CAAC,IAAI,GAAG,UAAS;AACnG,CAAC,IAAI,IAAI,KAAK,UAAU,IAAI,IAAI,KAAK,WAAW,EAAE;AAClD,EAAE,MAAM,MAAM,GAAG,MAAM,CAAC,OAAM;AAC9B,EAAE,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE;AACzD,GAAG,OAAO,IAAI;AACd,GAAG;AACH,EAAE,IAAI,IAAI,KAAK,WAAW,EAAE;AAC5B,GAAG,OAAO,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE;AAChH,GAAG;AACH,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,sBAAsB,CAAC,MAAM,CAAC,EAAE;AAC7D,EAAE;AACF,CAAC,IAAI,IAAI,KAAK,SAAS,IAAI,MAAM,CAAC,OAAO,KAAK,UAAU,EAAE;AAC1D,EAAE,IAAI,OAAO,MAAM,CAAC,KAAK,KAAK,QAAQ,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE;AACrE,GAAG,OAAO,IAAI;AACd,GAAG;AACH,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,cAAc,CAAC,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE;AAC5G,EAAE;AACF,CAAC,OAAO,IAAI;AACZ,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,oBAAoB,CAAC,MAAM,EAAE,GAAG,EAAE;AAClD,CAAC,MAAM,IAAI,GAAG,CAAC,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,IAAI,MAAM,CAAC,IAAI,GAAG,UAAS;AACnG;AACA;AACA,CAAC,IAAI,IAAI,KAAK,UAAU,EAAE;AAC1B,EAAE,MAAM,MAAM,GAAG,MAAM,CAAC,OAAM;AAC9B,EAAE,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE;AACzD;AACA,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,sBAAsB,EAAE,MAAM,CAAC,EAAE,CAAC,2BAA2B,CAAC;AAC/E,MAAM,sDAAsD,EAAC;AAC7D,GAAG,OAAO,IAAI;AACd,GAAG;AACH,EAAE,IAAI,sBAAsB,CAAC,MAAM,CAAC,EAAE;AACtC,GAAG,OAAO,MAAM,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,EAAE,qBAAqB,CAAC;AACpE,GAAG;AACH,EAAE,OAAO,MAAM,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC;AACtC,EAAE;AACF;AACA,CAAC,IAAI,IAAI,KAAK,WAAW,EAAE;AAC3B,EAAE,MAAM,MAAM,GAAG,MAAM,CAAC,OAAM;AAC9B,EAAE,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE;AACzD;AACA,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,sBAAsB,EAAE,MAAM,CAAC,EAAE,CAAC,4BAA4B,CAAC;AAChF,MAAM,sDAAsD,EAAC;AAC7D,GAAG,OAAO,IAAI;AACd,GAAG;AACH,EAAE,OAAO,CAAC,GAAG,KAAK,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,mBAAmB,CAAC,MAAM,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,MAAM,CAAC;AAC/E,EAAE;AACF;AACA,CAAC,IAAI,IAAI,KAAK,YAAY,EAAE;AAC5B;AACA,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,sBAAsB,EAAE,MAAM,CAAC,EAAE,CAAC,2BAA2B,CAAC;AAC9E,KAAK,iEAAiE,EAAC;AACvE,EAAE,OAAO,IAAI;AACb,EAAE;AACF;AACA;AACA,CAAC,MAAM,IAAI,GAAG,MAAM,CAAC,QAAO;AAC5B,CAAC,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE;AACpD,EAAE,OAAO,IAAI;AACb,EAAE;AACF;AACA,CAAC,IAAI,IAAI,KAAK,UAAU,EAAE;AAC1B,EAAE,MAAM,KAAK,GAAG,MAAM,CAAC,MAAK;AAC5B,EAAE,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE;AACvD;AACA,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,sBAAsB,EAAE,MAAM,CAAC,EAAE,CAAC,8BAA8B,CAAC;AAClF,MAAM,qDAAqD,EAAC;AAC5D,GAAG,OAAO,IAAI;AACd,GAAG;AACH;AACA;AACA;AACA;AACA,EAAE,OAAO,CAAC,GAAG,KAAK;AAClB,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,cAAc,CAAC,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,EAAE,EAAC;AACnF,GAAG;AACH,EAAE;AACF;AACA,CAAC,IAAI,IAAI,KAAK,MAAM,EAAE;AACtB,EAAE,OAAO,IAAI;AACb,EAAE;AACF,CAAC,IAAI,IAAI,KAAK,MAAM,EAAE;AACtB,EAAE,OAAO,MAAM,EAAE;AACjB,EAAE;AACF;AACA,CAAC,MAAM,EAAE,GAAG,wBAAwB,CAAC,IAAI,EAAE,GAAG,CAAC,QAAQ,EAAE,GAAG,CAAC,gBAAgB,EAAC;AAC9E,CAAC,IAAI,OAAO,EAAE,KAAK,UAAU,EAAE;AAC/B,EAAE,OAAO,CAAC,GAAG,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC;AACxD,EAAE;AACF,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,IAAI,EAAE,EAAE,IAAI,CAAC,KAAK,SAAS,IAAI,CAAC,GAAG,CAAC,gBAAgB,IAAI,EAAE,EAAE,IAAI,CAAC,KAAK,SAAS,EAAE;AACnG;AACA,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,8BAA8B,EAAE,IAAI,CAAC,gCAAgC,CAAC;AACtF,KAAK,+DAA+D;AACpE,KAAK,0CAA0C,EAAC;AAChD,EAAE;AACF,CAAC,OAAO,IAAI;AACZ,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS,UAAU,CAAC,MAAM,EAAE,GAAG,EAAE;AACjC,CAAC,IAAI,MAAM,CAAC,IAAI,IAAI,MAAM,CAAC,EAAE,EAAE;AAC/B,EAAE,OAAO,EAAE;AACX,EAAE;AACF,CAAC,MAAM,KAAK,GAAG,mBAAmB,CAAC,MAAM,EAAE,IAAI,EAAE,GAAG,EAAC;AACrD,CAAC,IAAI,CAAC,KAAK,EAAE;AACb,EAAE,OAAO,EAAE;AACX,EAAE;AACF,CAAC,IAAI,KAAK,CAAC,QAAQ,EAAE;AACrB,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE;AACrD,EAAE;AACF,CAAC,OAAO,EAAE,EAAE,EAAE,CAAC,GAAG,KAAK,mBAAmB,CAAC,MAAM,EAAE,GAAG,EAAE,GAAG,CAAC,EAAE,MAAM,IAAI,IAAI,EAAE;AAC9E,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,cAAc,CAAC,MAAM,EAAE,GAAG,EAAE;AAC5C,CAAC,IAAI,OAAO,MAAM,CAAC,OAAO,KAAK,UAAU,EAAE;AAC3C,EAAE,OAAO,MAAM;AACf,EAAE;AACF;AACA,CAAC,MAAM,IAAI,GAAG,CAAC,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,IAAI,MAAM,CAAC,IAAI,GAAG,UAAS;AACnG;AACA;AACA;AACA,CAAC,IAAI,IAAI,KAAK,SAAS,KAAK,OAAO,MAAM,CAAC,OAAO,KAAK,QAAQ,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,EAAE;AAChG,EAAE,OAAO,MAAM;AACf,EAAE;AACF;AACA,CAAC,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,KAAK,OAAM;AACzC,CAAC,MAAM,QAAQ,GAAG,oBAAoB,CAAC,MAAM,EAAE,GAAG,EAAC;AACnD,CAAC,IAAI,QAAQ,EAAE;AACf,EAAE,IAAI,MAAM,EAAE;AACd,GAAG,OAAO,EAAE,GAAG,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,iBAAiB,EAAE,IAAI,EAAE;AACnE,GAAG;AACH,EAAE,OAAO,EAAE,GAAG,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,UAAU,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE;AACrE,EAAE;AACF,CAAC,MAAM,EAAE,OAAO,EAAE,GAAG,IAAI,EAAE,GAAG,OAAM;AACpC,CAAC,OAAO,IAAI;AACZ;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"CnIntegrationWidgetEmpty.vue2.js","sources":["../../../../src/components/CnIntegrationWidget/CnIntegrationWidgetEmpty.vue"],"sourcesContent":["<!--\n CnIntegrationWidgetEmpty — the per-integration \"not available / not\n configured\" state rendered by CnIntegrationWidget when a leaf's\n backing app is missing or unconfigured.\n\n Renders NcEmptyContent with:\n - name : \"{App} not available\" (or \"{App} not configured\" for\n external integrations with no Integriq source).\n - icon slot : the integration's app icon (descriptor `icon`,\n resolved via CnIcon).\n - description : a short \"this integration isn't set up\" line.\n - action slot : an NcButton linking to the leaf's setup docs\n (descriptor `docsUrl`, defaulting to\n https://openregister.conduction.nl/docs/Integrations/{id}/).\n\n Split out from CnIntegrationWidget per ADR-004 (component isolation) so\n the widget template stays focused on tab/panel orchestration.\n-->\n<template>\n\t<NcEmptyContent :name=\"name\" :description=\"description\">\n\t\t<template #icon>\n\t\t\t<CnIcon v-if=\"provider.icon\" :name=\"provider.icon\" :size=\"64\" />\n\t\t</template>\n\t\t<template #action>\n\t\t\t<NcButton\n\t\t\t\tvariant=\"primary\"\n\t\t\t\t:href=\"docsUrl\"\n\t\t\t\ttarget=\"_blank\"\n\t\t\t\trel=\"noopener\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<OpenInNew :size=\"18\" />\n\t\t\t\t</template>\n\t\t\t\t{{ setupLabel }}\n\t\t\t</NcButton>\n\t\t</template>\n\t</NcEmptyContent>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcButton, NcEmptyContent } from '@nextcloud/vue'\nimport OpenInNew from 'vue-material-design-icons/OpenInNew.vue'\nimport CnIcon from '../CnIcon/CnIcon.vue'\nimport { registerIntegrationIcons } from '../../integrations/icons.js'\n\n// The empty state can render before the widget's tab strip (single\n// mode / standalone), so register the integration icon set here too.\nregisterIntegrationIcons()\n\n/**\n * CnIntegrationWidgetEmpty — NcEmptyContent set-up state for an\n * unavailable / unconfigured integration leaf.\n */\nexport default {\n\tname: 'CnIntegrationWidgetEmpty',\n\n\tcomponents: { NcEmptyContent, NcButton, CnIcon, OpenInNew },\n\n\tprops: {\n\t\t/** Normalised registry descriptor for the unavailable leaf. */\n\t\tprovider: {\n\t\t\ttype: Object,\n\t\t\trequired: true,\n\t\t},\n\n\t\t/**\n\t\t * Why it's unavailable: 'missing-app' | 'not-configured' |\n\t\t * 'unknown'. Drives the name + description copy.\n\t\t */\n\t\treason: {\n\t\t\ttype: String,\n\t\t\tdefault: 'unknown',\n\t\t},\n\t},\n\n\tcomputed: {\n\t\t/** Backing-app display name (descriptor `appName`, falls back to `label`). */\n\t\tappName() {\n\t\t\treturn this.provider.appName || this.provider.label || this.provider.id\n\t\t},\n\n\t\t/**\n\t\t * Empty-state title. \"{App} not configured\" for not-configured\n\t\t * (external) integrations, \"{App} not available\" otherwise.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tname() {\n\t\t\tif (this.reason === 'not-configured') {\n\t\t\t\treturn t('nextcloud-vue', '{app} not configured', { app: this.appName })\n\t\t\t}\n\t\t\treturn t('nextcloud-vue', '{app} not available', { app: this.appName })\n\t\t},\n\n\t\t/**\n\t\t * Empty-state description tailored to the reason.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tdescription() {\n\t\t\tif (this.reason === 'not-configured') {\n\t\t\t\treturn t('nextcloud-vue', 'This integration is not set up yet. Configure a connection to start using it.')\n\t\t\t}\n\t\t\tif (this.reason === 'missing-app') {\n\t\t\t\treturn t('nextcloud-vue', 'This integration is not set up yet. Install and enable the {app} app to start using it.', { app: this.appName })\n\t\t\t}\n\t\t\treturn t('nextcloud-vue', 'This integration is not available or not configured yet.')\n\t\t},\n\n\t\t/** Setup-docs URL (descriptor `docsUrl`, normalised by the registry). */\n\t\tdocsUrl() {\n\t\t\treturn this.provider.docsUrl || `https://openregister.conduction.nl/docs/Integrations/${this.provider.id}/`\n\t\t},\n\n\t\t/** Pre-translated CTA label. */\n\t\tsetupLabel() {\n\t\t\treturn t('nextcloud-vue', 'Set up {app}', { app: this.appName })\n\t\t},\n\t},\n}\n</script>\n"],"names":["CnIcon","t"],"mappings":";;;;;;AA6CA;AACA;AACA,wBAAwB,GAAC;;AAEzB;;AAEC;;AAED,aAAe;AACd,CAAA,IAAI,EAAE,0BAA0B;;CAEhC,UAAU,EAAE,EAAE,cAAc,EAAE,QAAQ,UAAEA,UAAM,EAAE,SAAQ,EAAG;;AAE3D,CAAA,KAAK,EAAE;;AAEN,EAAA,QAAQ,EAAE;GACT,IAAI,EAAE,MAAM;GACZ,QAAQ,EAAE,IAAI;GACd;;AAED;;AAEC;;AAED,EAAA,MAAM,EAAE;GACP,IAAI,EAAE,MAAM;AACZ,GAAA,OAAO,EAAE,SAAS;GAClB;EACD;;AAED,CAAA,QAAQ,EAAE;AACT;AACA,EAAA,OAAO,GAAG;AACT,GAAA,OAAO,IAAI,CAAC,QAAQ,CAAC,OAAM,IAAK,IAAI,CAAC,QAAQ,CAAC,KAAM,IAAG,IAAI,CAAC,QAAQ,CAAC,EAAC;GACtE;;AAED;;;AAGC;AACA;;AAED,EAAA,IAAI,GAAG;AACN,GAAA,IAAI,IAAI,CAAC,MAAK,KAAM,gBAAgB,EAAE;AACrC,IAAA,OAAOC,SAAC,CAAC,eAAe,EAAE,sBAAsB,EAAE,EAAE,GAAG,EAAE,IAAI,CAAC,SAAS,CAAA;AACxE,IAAA;AACA,GAAA,OAAOA,SAAC,CAAC,eAAe,EAAE,qBAAqB,EAAE,EAAE,GAAG,EAAE,IAAI,CAAC,OAAM,EAAG,CAAA;GACtE;;AAED;AACC;AACA;AACA;;EAED,WAAW,GAAG;AACb,GAAA,IAAI,IAAI,CAAC,MAAK,KAAM,gBAAgB,EAAE;AACrC,IAAA,OAAOA,SAAC,CAAC,eAAe,EAAE,+EAA+E,CAAA;AAC1G,IAAA;AACA,GAAA,IAAI,IAAI,CAAC,MAAO,KAAI,aAAa,EAAE;IAClC,OAAOA,SAAC,CAAC,eAAe,EAAE,yFAAyF,EAAE,EAAE,GAAG,EAAE,IAAI,CAAC,OAAM,EAAG,CAAA;AAC3I,IAAA;AACA,GAAA,OAAOA,SAAC,CAAC,eAAe,EAAE,0DAA0D,CAAA;GACpF;;AAED;AACA,EAAA,OAAO,GAAG;GACT,OAAO,IAAI,CAAC,QAAQ,CAAC,OAAQ,IAAG,CAAC,qDAAqD,EAAE,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAA;GAC1G;;;EAGD,UAAU,GAAG;GACZ,OAAOA,SAAC,CAAC,eAAe,EAAE,cAAc,EAAE,EAAE,GAAG,EAAE,IAAI,CAAC,OAAM,EAAG,CAAA;GAC/D;EACD;AACF;;;;"}
1
+ {"version":3,"file":"CnIntegrationWidgetEmpty.vue2.js","sources":["../../../../src/components/CnIntegrationWidget/CnIntegrationWidgetEmpty.vue"],"sourcesContent":["<!--\n CnIntegrationWidgetEmpty — the per-integration \"not available / not\n configured\" state rendered by CnIntegrationWidget when a leaf's\n backing app is missing or unconfigured.\n\n Renders NcEmptyContent with:\n - name : \"{App} not available\" (or \"{App} not configured\" for\n external integrations with no Integriq source).\n - icon slot : the integration's app icon (descriptor `icon`,\n resolved via CnIcon).\n - description : a short \"this integration isn't set up\" line.\n - action slot : an NcButton linking to the leaf's setup docs\n (descriptor `docsUrl`, defaulting to\n https://openregister.conduction.nl/docs/Integrations/{id}/).\n\n Split out from CnIntegrationWidget per ADR-004 (component isolation) so\n the widget template stays focused on tab/panel orchestration.\n-->\n<template>\n\t<NcEmptyContent :name=\"name\" :description=\"description\">\n\t\t<template #icon>\n\t\t\t<CnIcon v-if=\"provider.icon\" :name=\"provider.icon\" :size=\"64\" />\n\t\t</template>\n\t\t<template #action>\n\t\t\t<NcButton\n\t\t\t\tvariant=\"primary\"\n\t\t\t\t:href=\"docsUrl\"\n\t\t\t\ttarget=\"_blank\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<OpenInNew :size=\"18\" />\n\t\t\t\t</template>\n\t\t\t\t{{ setupLabel }}\n\t\t\t</NcButton>\n\t\t</template>\n\t</NcEmptyContent>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcButton, NcEmptyContent } from '@nextcloud/vue'\nimport OpenInNew from 'vue-material-design-icons/OpenInNew.vue'\nimport CnIcon from '../CnIcon/CnIcon.vue'\nimport { registerIntegrationIcons } from '../../integrations/icons.js'\n\n// The empty state can render before the widget's tab strip (single\n// mode / standalone), so register the integration icon set here too.\nregisterIntegrationIcons()\n\n/**\n * CnIntegrationWidgetEmpty — NcEmptyContent set-up state for an\n * unavailable / unconfigured integration leaf.\n */\nexport default {\n\tname: 'CnIntegrationWidgetEmpty',\n\n\tcomponents: { NcEmptyContent, NcButton, CnIcon, OpenInNew },\n\n\tprops: {\n\t\t/** Normalised registry descriptor for the unavailable leaf. */\n\t\tprovider: {\n\t\t\ttype: Object,\n\t\t\trequired: true,\n\t\t},\n\n\t\t/**\n\t\t * Why it's unavailable: 'missing-app' | 'not-configured' |\n\t\t * 'unknown'. Drives the name + description copy.\n\t\t */\n\t\treason: {\n\t\t\ttype: String,\n\t\t\tdefault: 'unknown',\n\t\t},\n\t},\n\n\tcomputed: {\n\t\t/** Backing-app display name (descriptor `appName`, falls back to `label`). */\n\t\tappName() {\n\t\t\treturn this.provider.appName || this.provider.label || this.provider.id\n\t\t},\n\n\t\t/**\n\t\t * Empty-state title. \"{App} not configured\" for not-configured\n\t\t * (external) integrations, \"{App} not available\" otherwise.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tname() {\n\t\t\tif (this.reason === 'not-configured') {\n\t\t\t\treturn t('nextcloud-vue', '{app} not configured', { app: this.appName })\n\t\t\t}\n\t\t\treturn t('nextcloud-vue', '{app} not available', { app: this.appName })\n\t\t},\n\n\t\t/**\n\t\t * Empty-state description tailored to the reason.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tdescription() {\n\t\t\tif (this.reason === 'not-configured') {\n\t\t\t\treturn t('nextcloud-vue', 'This integration is not set up yet. Configure a connection to start using it.')\n\t\t\t}\n\t\t\tif (this.reason === 'missing-app') {\n\t\t\t\treturn t('nextcloud-vue', 'This integration is not set up yet. Install and enable the {app} app to start using it.', { app: this.appName })\n\t\t\t}\n\t\t\treturn t('nextcloud-vue', 'This integration is not available or not configured yet.')\n\t\t},\n\n\t\t/** Setup-docs URL (descriptor `docsUrl`, normalised by the registry). */\n\t\tdocsUrl() {\n\t\t\treturn this.provider.docsUrl || `https://openregister.conduction.nl/docs/Integrations/${this.provider.id}/`\n\t\t},\n\n\t\t/** Pre-translated CTA label. */\n\t\tsetupLabel() {\n\t\t\treturn t('nextcloud-vue', 'Set up {app}', { app: this.appName })\n\t\t},\n\t},\n}\n</script>\n"],"names":["CnIcon","t"],"mappings":";;;;;;AA4CA;AACA;AACA,wBAAwB,GAAC;;AAEzB;;AAEC;;AAED,aAAe;AACd,CAAA,IAAI,EAAE,0BAA0B;;CAEhC,UAAU,EAAE,EAAE,cAAc,EAAE,QAAQ,UAAEA,UAAM,EAAE,SAAQ,EAAG;;AAE3D,CAAA,KAAK,EAAE;;AAEN,EAAA,QAAQ,EAAE;GACT,IAAI,EAAE,MAAM;GACZ,QAAQ,EAAE,IAAI;GACd;;AAED;;AAEC;;AAED,EAAA,MAAM,EAAE;GACP,IAAI,EAAE,MAAM;AACZ,GAAA,OAAO,EAAE,SAAS;GAClB;EACD;;AAED,CAAA,QAAQ,EAAE;AACT;AACA,EAAA,OAAO,GAAG;AACT,GAAA,OAAO,IAAI,CAAC,QAAQ,CAAC,OAAM,IAAK,IAAI,CAAC,QAAQ,CAAC,KAAM,IAAG,IAAI,CAAC,QAAQ,CAAC,EAAC;GACtE;;AAED;;;AAGC;AACA;;AAED,EAAA,IAAI,GAAG;AACN,GAAA,IAAI,IAAI,CAAC,MAAK,KAAM,gBAAgB,EAAE;AACrC,IAAA,OAAOC,SAAC,CAAC,eAAe,EAAE,sBAAsB,EAAE,EAAE,GAAG,EAAE,IAAI,CAAC,SAAS,CAAA;AACxE,IAAA;AACA,GAAA,OAAOA,SAAC,CAAC,eAAe,EAAE,qBAAqB,EAAE,EAAE,GAAG,EAAE,IAAI,CAAC,OAAM,EAAG,CAAA;GACtE;;AAED;AACC;AACA;AACA;;EAED,WAAW,GAAG;AACb,GAAA,IAAI,IAAI,CAAC,MAAK,KAAM,gBAAgB,EAAE;AACrC,IAAA,OAAOA,SAAC,CAAC,eAAe,EAAE,+EAA+E,CAAA;AAC1G,IAAA;AACA,GAAA,IAAI,IAAI,CAAC,MAAO,KAAI,aAAa,EAAE;IAClC,OAAOA,SAAC,CAAC,eAAe,EAAE,yFAAyF,EAAE,EAAE,GAAG,EAAE,IAAI,CAAC,OAAM,EAAG,CAAA;AAC3I,IAAA;AACA,GAAA,OAAOA,SAAC,CAAC,eAAe,EAAE,0DAA0D,CAAA;GACpF;;AAED;AACA,EAAA,OAAO,GAAG;GACT,OAAO,IAAI,CAAC,QAAQ,CAAC,OAAQ,IAAG,CAAC,qDAAqD,EAAE,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAA;GAC1G;;;EAGD,UAAU,GAAG;GACZ,OAAOA,SAAC,CAAC,eAAe,EAAE,cAAc,EAAE,EAAE,GAAG,EAAE,IAAI,CAAC,OAAM,EAAG,CAAA;GAC/D;EACD;AACF;;;;"}
@@ -23,8 +23,7 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
23
23
  createVNode(_component_NcButton, {
24
24
  variant: "primary",
25
25
  href: $options.docsUrl,
26
- target: "_blank",
27
- rel: "noopener"
26
+ target: "_blank"
28
27
  }, {
29
28
  icon: withCtx(() => [
30
29
  createVNode(_component_OpenInNew, { size: 18 })
@@ -1 +1 @@
1
- {"version":3,"file":"CnIntegrationWidgetEmpty.vue3.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"CnIntegrationWidgetEmpty.vue3.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"CnInteractionFormWidget.vue2.js","sources":["../../../../src/components/CnInteractionFormWidget/CnInteractionFormWidget.vue"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n<template>\n\t<CnFormWidgetBase\n\t\tblockClass=\"cn-interaction-form-widget\"\n\t\t:fields=\"formFields\"\n\t\t:model=\"form\"\n\t\t:errors=\"{ subject: subjectError }\"\n\t\t:canSubmit=\"canRegister\"\n\t\t:submitting=\"saving\"\n\t\t:submitLabel=\"registerLabel\"\n\t\t:submittingLabel=\"savingLabel\"\n\t\t:errorMessage=\"errorMessage\"\n\t\t@update:field=\"onFieldUpdate\"\n\t\t@submit=\"onRegister\">\n\t\t<!-- The client picker is the one control the base does not know about:\n\t\t a CnResourceSelect, so typing a name that does not exist yet offers\n\t\t \"Create '<name>'\" inline rather than a dead \"no results\" path. The\n\t\t base still supplies its field wrapper and spacing. -->\n\t\t<template #field-client>\n\t\t\t<CnResourceSelect\n\t\t\t\t:register=\"register\"\n\t\t\t\t:schema=\"clientSchema\"\n\t\t\t\t:labelField=\"clientLabelField\"\n\t\t\t\t:modelValue=\"form.client\"\n\t\t\t\t:inputLabel=\"clientLabel\"\n\t\t\t\t:preload=\"true\"\n\t\t\t\t@update:modelValue=\"onClientChange\"\n\t\t\t\t@create=\"onClientCreated\" />\n\t\t</template>\n\n\t\t<!-- Opens what was just saved in a new tab, beside the submit button. -->\n\t\t<template #actions-start>\n\t\t\t<NcButton\n\t\t\t\tv-if=\"savedHref\"\n\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t:href=\"savedHref\"\n\t\t\t\ttarget=\"_blank\"\n\t\t\t\trel=\"noopener noreferrer\"\n\t\t\t\tdata-testid=\"cn-interaction-form-open\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<OpenInNew :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ openLabel }}\n\t\t\t</NcButton>\n\t\t</template>\n\t</CnFormWidgetBase>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcButton } from '@nextcloud/vue'\nimport OpenInNew from 'vue-material-design-icons/OpenInNew.vue'\nimport CnFormWidgetBase from '../CnFormWidgetBase/CnFormWidgetBase.vue'\nimport CnResourceSelect from '../CnResourceSelect/CnResourceSelect.vue'\nimport { useObjectStore } from '../../store/index.js'\n\n/**\n * CnInteractionFormWidget — the \"active interaction\" quick-log form of a\n * workspace page.\n *\n * Persists a contactmoment (channel / client / subject / summary / outcome) to\n * OpenRegister via `useObjectStore().saveObject`. It reads `selectedClient`\n * from the page-level workspace context (the page's client in focus, set by a\n * page-level picker) to pre-fill its Client field.\n *\n * By default it also writes the chosen client to `selectedClient` and the live\n * summary text to `activeSummary`, so sibling widgets react: a client list\n * filtered on `@workspace.selectedClient`, or a `CnKbSearchWidget` bound to\n * `activeSummary`. A page whose client in focus comes from its own picker sets\n * `writeWorkspace: false`, which keeps the form's values to the submission.\n *\n * The Client field belongs to this submission only. It is a\n * `CnResourceSelect`, so typing a name that doesn't exist yet offers\n * \"Create '<name>'\" inline — no dead \"no results\" path.\n *\n * Resolved by its registry type key `interaction-form`. All schema/field/enum\n * choices come from `content`, so the widget carries no app-specific vocabulary.\n *\n * Example content blob:\n * ```js\n * content: {\n * register: 'pipelinq',\n * schema: 'ticket',\n * defaults: { ticketType: 'contactmoment' }, // fixed fields stamped on every create\n * clientSchema: 'client',\n * clientField: 'client',\n * summaryField: 'description',\n * channels: [{ value: 'telefoon', label: 'Phone' }, …],\n * }\n * ```\n *\n * The outcome options are read from the target schema on load: the enum of\n * its `outcomeField` property, labelled by that property's `x-enum-labels`.\n * `outcomes: [{ value, label }]` is only a fallback for a schema that has no\n * enum there.\n *\n * With `detailRoute` set (a route name taking `:id`, like an object list's\n * `rowRoute`), a save puts an \"Open\" button left of the submit button that\n * opens the saved object in a new tab.\n *\n * `defaults` covers the case where the target schema requires a value the form\n * has no input for — typically a discriminator on a supertype schema. It is\n * merged before the mapped fields, so those always take precedence.\n */\nexport default {\n\tname: 'CnInteractionFormWidget',\n\n\tcomponents: { CnFormWidgetBase, CnResourceSelect, NcButton, OpenInNew },\n\n\tinject: {\n\t\t/**\n\t\t * Page-level workspace context (reactive `ref({})`) from CnDashboardPage.\n\t\t * The widget reads `selectedClient` from it and, unless\n\t\t * `content.writeWorkspace` is false, writes `selectedClient` and\n\t\t * `activeSummary` back. Null on pages that don't provide one (the form\n\t\t * still saves).\n\t\t */\n\t\tcnWorkspaceContext: { default: null },\n\t\t/**\n\t\t * Host translate function from CnAppRoot, bound to the host app's id.\n\t\t * Translates the schema's outcome labels.\n\t\t */\n\t\tcnTranslate: { default: () => (key) => key },\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * Persisted configuration blob (see component description for the shape).\n\t\t *\n\t\t * @type {{register?: string, schema?: string, defaults?: object, clientSchema?: string, clientField?: string, clientLabelField?: string, subjectField?: string, summaryField?: string, channelField?: string, outcomeField?: string, channels?: Array, outcomes?: Array, submitLabel?: string, detailRoute?: string, writeWorkspace?: boolean}}\n\t\t */\n\t\tcontent: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\t},\n\n\temits: ['saved'],\n\n\tdata() {\n\t\treturn {\n\t\t\tform: {\n\t\t\t\tchannel: this.firstChannel(),\n\t\t\t\tclient: '',\n\t\t\t\tsubject: '',\n\t\t\t\tsummary: '',\n\t\t\t\toutcome: '',\n\t\t\t},\n\n\t\t\tsaving: false,\n\t\t\terrorMessage: '',\n\t\t\tsubjectError: '',\n\t\t\t// The target schema, fetched on load for its outcome enum.\n\t\t\tschemaDef: null,\n\t\t\t// The last saved object, `{ id, title }`, until the next save.\n\t\t\tsaved: null,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\tregister() {\n\t\t\treturn this.content.register || 'pipelinq'\n\t\t},\n\n\t\tschema() {\n\t\t\treturn this.content.schema || 'contactmoment'\n\t\t},\n\n\t\tclientSchema() {\n\t\t\treturn this.content.clientSchema || 'client'\n\t\t},\n\n\t\tclientLabelField() {\n\t\t\treturn this.content.clientLabelField || 'name'\n\t\t},\n\n\t\ttypeSlug() {\n\t\t\treturn `${this.register}-${this.schema}`\n\t\t},\n\n\t\t/** Channel options `{ value, label }`. */\n\t\tchannelOptions() {\n\t\t\treturn Array.isArray(this.content.channels) && this.content.channels.length > 0\n\t\t\t\t? this.content.channels\n\t\t\t\t: [\n\t\t\t\t\t\t{ value: 'telefoon', label: t('nextcloud-vue', 'Phone') },\n\t\t\t\t\t\t{ value: 'email', label: t('nextcloud-vue', 'Email') },\n\t\t\t\t\t\t{ value: 'chat', label: t('nextcloud-vue', 'Chat') },\n\t\t\t\t\t]\n\t\t},\n\n\t\t/**\n\t\t * Outcome options `{ value, label }`, from the target schema's enum so\n\t\t * the form can only offer values the schema accepts. Labels come from\n\t\t * the property's `x-enum-labels`, translated. `content.outcomes` is the\n\t\t * fallback for a schema without an enum on that property.\n\t\t *\n\t\t * @return {Array<{value: string, label: string}>}\n\t\t */\n\t\toutcomeOptions() {\n\t\t\tconst properties = (this.schemaDef && this.schemaDef.properties) || {}\n\t\t\tconst prop = properties[this.content.outcomeField || 'outcome']\n\t\t\tif (prop && Array.isArray(prop.enum) && prop.enum.length > 0) {\n\t\t\t\tconst labels = prop['x-enum-labels'] || prop.enumLabels || {}\n\t\t\t\tconst tr = typeof this.cnTranslate === 'function' ? this.cnTranslate : (k) => k\n\t\t\t\treturn prop.enum.map((value) => ({ value, label: tr(labels[value] || String(value)) }))\n\t\t\t}\n\t\t\treturn Array.isArray(this.content.outcomes) ? this.content.outcomes : []\n\t\t},\n\n\t\t/**\n\t\t * The field descriptors handed to CnFormWidgetBase — the whole of this\n\t\t * widget's form, declared rather than drawn. Order matters: it is the\n\t\t * render order.\n\t\t *\n\t\t * `client` is declared here so it keeps its place in the stack and its\n\t\t * field wrapper, but its control comes from the `#field-client` slot\n\t\t * (a CnResourceSelect, which the base has no type for).\n\t\t *\n\t\t * @return {Array<object>}\n\t\t */\n\t\tformFields() {\n\t\t\treturn [\n\t\t\t\t{ key: 'channel', type: 'select', label: this.channelLabel, options: this.channelOptions },\n\t\t\t\t{ key: 'client', type: 'custom', label: this.clientLabel },\n\t\t\t\t{ key: 'subject', type: 'text', label: this.subjectLabel },\n\t\t\t\t{ key: 'summary', type: 'textarea', label: this.summaryLabel, rows: 4 },\n\t\t\t\t{ key: 'outcome', type: 'select', label: this.outcomeLabel, options: this.outcomeOptions, clearable: true },\n\t\t\t]\n\t\t},\n\n\t\tobjectStore() {\n\t\t\ttry {\n\t\t\t\treturn useObjectStore()\n\t\t\t} catch {\n\t\t\t\treturn null\n\t\t\t}\n\t\t},\n\n\t\tworkspaceCtx() {\n\t\t\tconst c = this.cnWorkspaceContext\n\t\t\tif (!c) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\treturn (typeof c === 'object' && 'value' in c) ? c.value : c\n\t\t},\n\n\t\t/** The page's client in focus, or an empty string. */\n\t\tpageClient() {\n\t\t\tconst id = this.workspaceCtx && this.workspaceCtx.selectedClient\n\t\t\treturn id ? String(id) : ''\n\t\t},\n\n\t\tcanRegister() {\n\t\t\treturn Boolean(this.form.subject && this.form.subject.trim() && this.form.channel)\n\t\t},\n\n\t\tchannelLabel() {\n\t\t\treturn t('nextcloud-vue', 'Channel')\n\t\t},\n\n\t\tclientLabel() {\n\t\t\treturn t('nextcloud-vue', 'Client')\n\t\t},\n\n\t\tsubjectLabel() {\n\t\t\treturn t('nextcloud-vue', 'Subject')\n\t\t},\n\n\t\tsummaryLabel() {\n\t\t\treturn t('nextcloud-vue', 'Summary')\n\t\t},\n\n\t\toutcomeLabel() {\n\t\t\treturn t('nextcloud-vue', 'Outcome')\n\t\t},\n\n\t\t// `content.submitLabel` names what the form creates, e.g. \"Save contact moment\".\n\t\tregisterLabel() {\n\t\t\tif (this.content.submitLabel) {\n\t\t\t\tconst tr = typeof this.cnTranslate === 'function' ? this.cnTranslate : (k) => k\n\t\t\t\treturn tr(this.content.submitLabel)\n\t\t\t}\n\t\t\treturn t('nextcloud-vue', 'Register')\n\t\t},\n\n\t\tsavingLabel() {\n\t\t\treturn t('nextcloud-vue', 'Saving…')\n\t\t},\n\n\t\t/**\n\t\t * URL of the saved object's page, from `content.detailRoute`. Empty\n\t\t * without a route or router, and then no Open button is shown.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tsavedHref() {\n\t\t\tconst route = this.content.detailRoute\n\t\t\tif (!this.saved || !this.saved.id || !route || !this.$router) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\ttry {\n\t\t\t\treturn this.$router.resolve({ name: route, params: { id: this.saved.id } }).href || ''\n\t\t\t} catch {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t},\n\n\t\t// `escape: false` because the label renders through `{{ }}`, which escapes.\n\t\topenLabel() {\n\t\t\treturn t('nextcloud-vue', 'Open \"{title}\"', { title: (this.saved && this.saved.title) || '' }, undefined, { escape: false })\n\t\t},\n\n\t\t/** Whether the form writes its client and summary to the workspace context. */\n\t\twritesWorkspace() {\n\t\t\treturn this.content.writeWorkspace !== false\n\t\t},\n\t},\n\n\twatch: {\n\t\t// A new page client pre-fills the field; the field stays editable.\n\t\tpageClient: {\n\t\t\timmediate: true,\n\t\t\thandler(id) {\n\t\t\t\tif (id) {\n\t\t\t\t\tthis.form.client = id\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t},\n\n\tcreated() {\n\t\tthis.loadSchema()\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * Fetch the target schema, which the outcome options derive from. A\n\t\t * failure leaves the `content.outcomes` fallback in place.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync loadSchema() {\n\t\t\tconst store = this.objectStore\n\t\t\tif (!store || typeof store.fetchSchema !== 'function') {\n\t\t\t\treturn\n\t\t\t}\n\t\t\ttry {\n\t\t\t\t// Re-registering an existing type resets its cached objects and schema.\n\t\t\t\tif (typeof store.registerObjectType === 'function' && !store.objectTypeRegistry?.[this.typeSlug]) {\n\t\t\t\t\tstore.registerObjectType(this.typeSlug, this.schema, this.register)\n\t\t\t\t}\n\t\t\t\tthis.schemaDef = await store.fetchSchema(this.typeSlug)\n\t\t\t} catch {\n\t\t\t\tthis.schemaDef = null\n\t\t\t}\n\t\t},\n\n\t\t/** The default channel value (first configured channel, else `telefoon`). */\n\t\tfirstChannel() {\n\t\t\tconst ch = (this.content && this.content.channels) || []\n\t\t\treturn (Array.isArray(ch) && ch.length > 0 && ch[0].value) || 'telefoon'\n\t\t},\n\n\t\t/**\n\t\t * A field edit from CnFormWidgetBase. `summary` also streams into the\n\t\t * workspace context. `client` never arrives here: its control is the\n\t\t * `#field-client` slot, which calls onClientChange.\n\t\t *\n\t\t * @param {{key: string, value: unknown}} payload The changed field.\n\t\t * @return {void}\n\t\t */\n\t\tonFieldUpdate({ key, value }) {\n\t\t\tthis.form[key] = value\n\t\t\tif (key === 'summary') {\n\t\t\t\tthis.writeWorkspace('activeSummary', value)\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * The submission's client, also written to the workspace context.\n\t\t *\n\t\t * @param {string} id The selected client id.\n\t\t */\n\t\tonClientChange(id) {\n\t\t\tthis.form.client = id || ''\n\t\t\tthis.writeWorkspace('selectedClient', this.form.client)\n\t\t},\n\n\t\t/**\n\t\t * A client created inline via \"Create '<name>'\" — select it.\n\t\t *\n\t\t * @param {object} client The created client object.\n\t\t */\n\t\tonClientCreated(client) {\n\t\t\tconst id = String((client && (client.id || (client['@self'] && client['@self'].id))) || '')\n\t\t\tif (id) {\n\t\t\t\tthis.form.client = id\n\t\t\t\tthis.writeWorkspace('selectedClient', id)\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Write a key into the workspace context, unless `content.writeWorkspace`\n\t\t * is false.\n\t\t *\n\t\t * Vue 2.7's Options-API `inject` auto-unwraps the provided ref, so the\n\t\t * holder is usually the plain reactive object; the raw-ref shape\n\t\t * (`.value`) is supported for Composition-API consumers.\n\t\t *\n\t\t * @param {string} key The context key.\n\t\t * @param {unknown} value The value.\n\t\t */\n\t\twriteWorkspace(key, value) {\n\t\t\tconst holder = this.cnWorkspaceContext\n\t\t\tif (!this.writesWorkspace || !holder || typeof holder !== 'object') {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif ('value' in holder) {\n\t\t\t\tholder.value = { ...(holder.value || {}), [key]: value }\n\t\t\t\treturn\n\t\t\t}\n\t\t\tholder[key] = value\n\t\t},\n\n\t\t/**\n\t\t * Persist the contactmoment. The agent identity is left to the server\n\t\t * (never sent from the client). Surfaces errors inline.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync onRegister() {\n\t\t\tthis.subjectError = ''\n\t\t\tthis.errorMessage = ''\n\t\t\tif (!this.form.subject || !this.form.subject.trim()) {\n\t\t\t\tthis.subjectError = t('nextcloud-vue', 'Subject is required')\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (!this.objectStore) {\n\t\t\t\tthis.errorMessage = t('nextcloud-vue', 'Cannot save right now')\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst c = this.content || {}\n\t\t\t// `defaults` is spread FIRST so the mapped fields below always win.\n\t\t\t// It exists for schemas that need a fixed value on every create the\n\t\t\t// form itself has no input for — e.g. a discriminator on a supertype\n\t\t\t// schema (`{ ticketType: 'contactmoment' }`), which would otherwise be\n\t\t\t// omitted and fail validation.\n\t\t\tconst payload = {\n\t\t\t\t...(c.defaults || {}),\n\t\t\t\t[c.subjectField || 'subject']: this.form.subject.trim(),\n\t\t\t\t[c.channelField || 'channel']: this.form.channel,\n\t\t\t\t[c.contactedAtField || 'contactedAt']: new Date().toISOString(),\n\t\t\t}\n\t\t\tif (this.form.client) {\n\t\t\t\tpayload[c.clientField || 'client'] = this.form.client\n\t\t\t}\n\t\t\tif (this.form.summary) {\n\t\t\t\tpayload[c.summaryField || 'summary'] = this.form.summary\n\t\t\t}\n\t\t\tif (this.form.outcome) {\n\t\t\t\tpayload[c.outcomeField || 'outcome'] = this.form.outcome\n\t\t\t}\n\n\t\t\tthis.saving = true\n\t\t\tthis.saved = null\n\t\t\ttry {\n\t\t\t\tif (typeof this.objectStore.registerObjectType === 'function' && !this.objectStore.objectTypeRegistry?.[this.typeSlug]) {\n\t\t\t\t\tthis.objectStore.registerObjectType(this.typeSlug, this.schema, this.register)\n\t\t\t\t}\n\t\t\t\tconst result = await this.objectStore.saveObject(this.typeSlug, payload)\n\t\t\t\tif (!result) {\n\t\t\t\t\tthis.errorMessage = t('nextcloud-vue', 'Failed to save interaction')\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\t/**\n\t\t\t\t * @event saved A contactmoment was persisted.\n\t\t\t\t * @type {object} The saved object.\n\t\t\t\t */\n\t\t\t\tthis.$emit('saved', result)\n\t\t\t\tthis.saved = {\n\t\t\t\t\tid: String(result.id || (result['@self'] && result['@self'].id) || ''),\n\t\t\t\t\ttitle: payload[c.subjectField || 'subject'],\n\t\t\t\t}\n\t\t\t\t// Reset the per-interaction fields; keep the client for follow-ups.\n\t\t\t\tthis.form.subject = ''\n\t\t\t\tthis.form.summary = ''\n\t\t\t\tthis.form.outcome = ''\n\t\t\t\tthis.writeWorkspace('activeSummary', '')\n\t\t\t} catch (e) {\n\t\t\t\tthis.errorMessage = (e && e.message) || t('nextcloud-vue', 'Failed to save interaction')\n\t\t\t} finally {\n\t\t\t\tthis.saving = false\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<!--\n The scoped style block is gone on purpose. The markup now lives in\n CnFormWidgetBase, so a scoped rule here would carry THIS component's\n data-v attribute and match none of it. The rules moved verbatim to\n src/css/form-widget.css, keyed on `cn-form-widget*`; the base also emits\n the `cn-interaction-form-widget*` names on the same elements, so app CSS\n targeting those keeps matching.\n-->\n"],"names":["CnFormWidgetBase","CnResourceSelect","t"],"mappings":"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"}
1
+ {"version":3,"file":"CnInteractionFormWidget.vue2.js","sources":["../../../../src/components/CnInteractionFormWidget/CnInteractionFormWidget.vue"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n<template>\n\t<CnFormWidgetBase\n\t\tblockClass=\"cn-interaction-form-widget\"\n\t\t:fields=\"formFields\"\n\t\t:model=\"form\"\n\t\t:errors=\"{ subject: subjectError }\"\n\t\t:canSubmit=\"canRegister\"\n\t\t:submitting=\"saving\"\n\t\t:submitLabel=\"registerLabel\"\n\t\t:submittingLabel=\"savingLabel\"\n\t\t:errorMessage=\"errorMessage\"\n\t\t@update:field=\"onFieldUpdate\"\n\t\t@submit=\"onRegister\">\n\t\t<!-- The client picker is the one control the base does not know about:\n\t\t a CnResourceSelect, so typing a name that does not exist yet offers\n\t\t \"Create '<name>'\" inline rather than a dead \"no results\" path. The\n\t\t base still supplies its field wrapper and spacing. -->\n\t\t<template #field-client>\n\t\t\t<CnResourceSelect\n\t\t\t\t:register=\"register\"\n\t\t\t\t:schema=\"clientSchema\"\n\t\t\t\t:labelField=\"clientLabelField\"\n\t\t\t\t:modelValue=\"form.client\"\n\t\t\t\t:inputLabel=\"clientLabel\"\n\t\t\t\t:preload=\"true\"\n\t\t\t\t@update:modelValue=\"onClientChange\"\n\t\t\t\t@create=\"onClientCreated\" />\n\t\t</template>\n\n\t\t<!-- Opens what was just saved in a new tab, beside the submit button. -->\n\t\t<template #actions-start>\n\t\t\t<NcButton\n\t\t\t\tv-if=\"savedHref\"\n\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t:href=\"savedHref\"\n\t\t\t\ttarget=\"_blank\"\n\t\t\t\tdata-testid=\"cn-interaction-form-open\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<OpenInNew :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ openLabel }}\n\t\t\t</NcButton>\n\t\t</template>\n\t</CnFormWidgetBase>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcButton } from '@nextcloud/vue'\nimport OpenInNew from 'vue-material-design-icons/OpenInNew.vue'\nimport CnFormWidgetBase from '../CnFormWidgetBase/CnFormWidgetBase.vue'\nimport CnResourceSelect from '../CnResourceSelect/CnResourceSelect.vue'\nimport { useObjectStore } from '../../store/index.js'\n\n/**\n * CnInteractionFormWidget — the \"active interaction\" quick-log form of a\n * workspace page.\n *\n * Persists a contactmoment (channel / client / subject / summary / outcome) to\n * OpenRegister via `useObjectStore().saveObject`. It reads `selectedClient`\n * from the page-level workspace context (the page's client in focus, set by a\n * page-level picker) to pre-fill its Client field.\n *\n * By default it also writes the chosen client to `selectedClient` and the live\n * summary text to `activeSummary`, so sibling widgets react: a client list\n * filtered on `@workspace.selectedClient`, or a `CnKbSearchWidget` bound to\n * `activeSummary`. A page whose client in focus comes from its own picker sets\n * `writeWorkspace: false`, which keeps the form's values to the submission.\n *\n * The Client field belongs to this submission only. It is a\n * `CnResourceSelect`, so typing a name that doesn't exist yet offers\n * \"Create '<name>'\" inline — no dead \"no results\" path.\n *\n * Resolved by its registry type key `interaction-form`. All schema/field/enum\n * choices come from `content`, so the widget carries no app-specific vocabulary.\n *\n * Example content blob:\n * ```js\n * content: {\n * register: 'pipelinq',\n * schema: 'ticket',\n * defaults: { ticketType: 'contactmoment' }, // fixed fields stamped on every create\n * clientSchema: 'client',\n * clientField: 'client',\n * summaryField: 'description',\n * channels: [{ value: 'telefoon', label: 'Phone' }, …],\n * }\n * ```\n *\n * The outcome options are read from the target schema on load: the enum of\n * its `outcomeField` property, labelled by that property's `x-enum-labels`.\n * `outcomes: [{ value, label }]` is only a fallback for a schema that has no\n * enum there.\n *\n * With `detailRoute` set (a route name taking `:id`, like an object list's\n * `rowRoute`), a save puts an \"Open\" button left of the submit button that\n * opens the saved object in a new tab.\n *\n * `defaults` covers the case where the target schema requires a value the form\n * has no input for — typically a discriminator on a supertype schema. It is\n * merged before the mapped fields, so those always take precedence.\n */\nexport default {\n\tname: 'CnInteractionFormWidget',\n\n\tcomponents: { CnFormWidgetBase, CnResourceSelect, NcButton, OpenInNew },\n\n\tinject: {\n\t\t/**\n\t\t * Page-level workspace context (reactive `ref({})`) from CnDashboardPage.\n\t\t * The widget reads `selectedClient` from it and, unless\n\t\t * `content.writeWorkspace` is false, writes `selectedClient` and\n\t\t * `activeSummary` back. Null on pages that don't provide one (the form\n\t\t * still saves).\n\t\t */\n\t\tcnWorkspaceContext: { default: null },\n\t\t/**\n\t\t * Host translate function from CnAppRoot, bound to the host app's id.\n\t\t * Translates the schema's outcome labels.\n\t\t */\n\t\tcnTranslate: { default: () => (key) => key },\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * Persisted configuration blob (see component description for the shape).\n\t\t *\n\t\t * @type {{register?: string, schema?: string, defaults?: object, clientSchema?: string, clientField?: string, clientLabelField?: string, subjectField?: string, summaryField?: string, channelField?: string, outcomeField?: string, channels?: Array, outcomes?: Array, submitLabel?: string, detailRoute?: string, writeWorkspace?: boolean}}\n\t\t */\n\t\tcontent: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\t},\n\n\temits: ['saved'],\n\n\tdata() {\n\t\treturn {\n\t\t\tform: {\n\t\t\t\tchannel: this.firstChannel(),\n\t\t\t\tclient: '',\n\t\t\t\tsubject: '',\n\t\t\t\tsummary: '',\n\t\t\t\toutcome: '',\n\t\t\t},\n\n\t\t\tsaving: false,\n\t\t\terrorMessage: '',\n\t\t\tsubjectError: '',\n\t\t\t// The target schema, fetched on load for its outcome enum.\n\t\t\tschemaDef: null,\n\t\t\t// The last saved object, `{ id, title }`, until the next save.\n\t\t\tsaved: null,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\tregister() {\n\t\t\treturn this.content.register || 'pipelinq'\n\t\t},\n\n\t\tschema() {\n\t\t\treturn this.content.schema || 'contactmoment'\n\t\t},\n\n\t\tclientSchema() {\n\t\t\treturn this.content.clientSchema || 'client'\n\t\t},\n\n\t\tclientLabelField() {\n\t\t\treturn this.content.clientLabelField || 'name'\n\t\t},\n\n\t\ttypeSlug() {\n\t\t\treturn `${this.register}-${this.schema}`\n\t\t},\n\n\t\t/** Channel options `{ value, label }`. */\n\t\tchannelOptions() {\n\t\t\treturn Array.isArray(this.content.channels) && this.content.channels.length > 0\n\t\t\t\t? this.content.channels\n\t\t\t\t: [\n\t\t\t\t\t\t{ value: 'telefoon', label: t('nextcloud-vue', 'Phone') },\n\t\t\t\t\t\t{ value: 'email', label: t('nextcloud-vue', 'Email') },\n\t\t\t\t\t\t{ value: 'chat', label: t('nextcloud-vue', 'Chat') },\n\t\t\t\t\t]\n\t\t},\n\n\t\t/**\n\t\t * Outcome options `{ value, label }`, from the target schema's enum so\n\t\t * the form can only offer values the schema accepts. Labels come from\n\t\t * the property's `x-enum-labels`, translated. `content.outcomes` is the\n\t\t * fallback for a schema without an enum on that property.\n\t\t *\n\t\t * @return {Array<{value: string, label: string}>}\n\t\t */\n\t\toutcomeOptions() {\n\t\t\tconst properties = (this.schemaDef && this.schemaDef.properties) || {}\n\t\t\tconst prop = properties[this.content.outcomeField || 'outcome']\n\t\t\tif (prop && Array.isArray(prop.enum) && prop.enum.length > 0) {\n\t\t\t\tconst labels = prop['x-enum-labels'] || prop.enumLabels || {}\n\t\t\t\tconst tr = typeof this.cnTranslate === 'function' ? this.cnTranslate : (k) => k\n\t\t\t\treturn prop.enum.map((value) => ({ value, label: tr(labels[value] || String(value)) }))\n\t\t\t}\n\t\t\treturn Array.isArray(this.content.outcomes) ? this.content.outcomes : []\n\t\t},\n\n\t\t/**\n\t\t * The field descriptors handed to CnFormWidgetBase — the whole of this\n\t\t * widget's form, declared rather than drawn. Order matters: it is the\n\t\t * render order.\n\t\t *\n\t\t * `client` is declared here so it keeps its place in the stack and its\n\t\t * field wrapper, but its control comes from the `#field-client` slot\n\t\t * (a CnResourceSelect, which the base has no type for).\n\t\t *\n\t\t * @return {Array<object>}\n\t\t */\n\t\tformFields() {\n\t\t\treturn [\n\t\t\t\t{ key: 'channel', type: 'select', label: this.channelLabel, options: this.channelOptions },\n\t\t\t\t{ key: 'client', type: 'custom', label: this.clientLabel },\n\t\t\t\t{ key: 'subject', type: 'text', label: this.subjectLabel },\n\t\t\t\t{ key: 'summary', type: 'textarea', label: this.summaryLabel, rows: 4 },\n\t\t\t\t{ key: 'outcome', type: 'select', label: this.outcomeLabel, options: this.outcomeOptions, clearable: true },\n\t\t\t]\n\t\t},\n\n\t\tobjectStore() {\n\t\t\ttry {\n\t\t\t\treturn useObjectStore()\n\t\t\t} catch {\n\t\t\t\treturn null\n\t\t\t}\n\t\t},\n\n\t\tworkspaceCtx() {\n\t\t\tconst c = this.cnWorkspaceContext\n\t\t\tif (!c) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\treturn (typeof c === 'object' && 'value' in c) ? c.value : c\n\t\t},\n\n\t\t/** The page's client in focus, or an empty string. */\n\t\tpageClient() {\n\t\t\tconst id = this.workspaceCtx && this.workspaceCtx.selectedClient\n\t\t\treturn id ? String(id) : ''\n\t\t},\n\n\t\tcanRegister() {\n\t\t\treturn Boolean(this.form.subject && this.form.subject.trim() && this.form.channel)\n\t\t},\n\n\t\tchannelLabel() {\n\t\t\treturn t('nextcloud-vue', 'Channel')\n\t\t},\n\n\t\tclientLabel() {\n\t\t\treturn t('nextcloud-vue', 'Client')\n\t\t},\n\n\t\tsubjectLabel() {\n\t\t\treturn t('nextcloud-vue', 'Subject')\n\t\t},\n\n\t\tsummaryLabel() {\n\t\t\treturn t('nextcloud-vue', 'Summary')\n\t\t},\n\n\t\toutcomeLabel() {\n\t\t\treturn t('nextcloud-vue', 'Outcome')\n\t\t},\n\n\t\t// `content.submitLabel` names what the form creates, e.g. \"Save contact moment\".\n\t\tregisterLabel() {\n\t\t\tif (this.content.submitLabel) {\n\t\t\t\tconst tr = typeof this.cnTranslate === 'function' ? this.cnTranslate : (k) => k\n\t\t\t\treturn tr(this.content.submitLabel)\n\t\t\t}\n\t\t\treturn t('nextcloud-vue', 'Register')\n\t\t},\n\n\t\tsavingLabel() {\n\t\t\treturn t('nextcloud-vue', 'Saving…')\n\t\t},\n\n\t\t/**\n\t\t * URL of the saved object's page, from `content.detailRoute`. Empty\n\t\t * without a route or router, and then no Open button is shown.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tsavedHref() {\n\t\t\tconst route = this.content.detailRoute\n\t\t\tif (!this.saved || !this.saved.id || !route || !this.$router) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\ttry {\n\t\t\t\treturn this.$router.resolve({ name: route, params: { id: this.saved.id } }).href || ''\n\t\t\t} catch {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t},\n\n\t\t// `escape: false` because the label renders through `{{ }}`, which escapes.\n\t\topenLabel() {\n\t\t\treturn t('nextcloud-vue', 'Open \"{title}\"', { title: (this.saved && this.saved.title) || '' }, undefined, { escape: false })\n\t\t},\n\n\t\t/** Whether the form writes its client and summary to the workspace context. */\n\t\twritesWorkspace() {\n\t\t\treturn this.content.writeWorkspace !== false\n\t\t},\n\t},\n\n\twatch: {\n\t\t// A new page client pre-fills the field; the field stays editable.\n\t\tpageClient: {\n\t\t\timmediate: true,\n\t\t\thandler(id) {\n\t\t\t\tif (id) {\n\t\t\t\t\tthis.form.client = id\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t},\n\n\tcreated() {\n\t\tthis.loadSchema()\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * Fetch the target schema, which the outcome options derive from. A\n\t\t * failure leaves the `content.outcomes` fallback in place.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync loadSchema() {\n\t\t\tconst store = this.objectStore\n\t\t\tif (!store || typeof store.fetchSchema !== 'function') {\n\t\t\t\treturn\n\t\t\t}\n\t\t\ttry {\n\t\t\t\t// Re-registering an existing type resets its cached objects and schema.\n\t\t\t\tif (typeof store.registerObjectType === 'function' && !store.objectTypeRegistry?.[this.typeSlug]) {\n\t\t\t\t\tstore.registerObjectType(this.typeSlug, this.schema, this.register)\n\t\t\t\t}\n\t\t\t\tthis.schemaDef = await store.fetchSchema(this.typeSlug)\n\t\t\t} catch {\n\t\t\t\tthis.schemaDef = null\n\t\t\t}\n\t\t},\n\n\t\t/** The default channel value (first configured channel, else `telefoon`). */\n\t\tfirstChannel() {\n\t\t\tconst ch = (this.content && this.content.channels) || []\n\t\t\treturn (Array.isArray(ch) && ch.length > 0 && ch[0].value) || 'telefoon'\n\t\t},\n\n\t\t/**\n\t\t * A field edit from CnFormWidgetBase. `summary` also streams into the\n\t\t * workspace context. `client` never arrives here: its control is the\n\t\t * `#field-client` slot, which calls onClientChange.\n\t\t *\n\t\t * @param {{key: string, value: unknown}} payload The changed field.\n\t\t * @return {void}\n\t\t */\n\t\tonFieldUpdate({ key, value }) {\n\t\t\tthis.form[key] = value\n\t\t\tif (key === 'summary') {\n\t\t\t\tthis.writeWorkspace('activeSummary', value)\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * The submission's client, also written to the workspace context.\n\t\t *\n\t\t * @param {string} id The selected client id.\n\t\t */\n\t\tonClientChange(id) {\n\t\t\tthis.form.client = id || ''\n\t\t\tthis.writeWorkspace('selectedClient', this.form.client)\n\t\t},\n\n\t\t/**\n\t\t * A client created inline via \"Create '<name>'\" — select it.\n\t\t *\n\t\t * @param {object} client The created client object.\n\t\t */\n\t\tonClientCreated(client) {\n\t\t\tconst id = String((client && (client.id || (client['@self'] && client['@self'].id))) || '')\n\t\t\tif (id) {\n\t\t\t\tthis.form.client = id\n\t\t\t\tthis.writeWorkspace('selectedClient', id)\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Write a key into the workspace context, unless `content.writeWorkspace`\n\t\t * is false.\n\t\t *\n\t\t * Vue 2.7's Options-API `inject` auto-unwraps the provided ref, so the\n\t\t * holder is usually the plain reactive object; the raw-ref shape\n\t\t * (`.value`) is supported for Composition-API consumers.\n\t\t *\n\t\t * @param {string} key The context key.\n\t\t * @param {unknown} value The value.\n\t\t */\n\t\twriteWorkspace(key, value) {\n\t\t\tconst holder = this.cnWorkspaceContext\n\t\t\tif (!this.writesWorkspace || !holder || typeof holder !== 'object') {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif ('value' in holder) {\n\t\t\t\tholder.value = { ...(holder.value || {}), [key]: value }\n\t\t\t\treturn\n\t\t\t}\n\t\t\tholder[key] = value\n\t\t},\n\n\t\t/**\n\t\t * Persist the contactmoment. The agent identity is left to the server\n\t\t * (never sent from the client). Surfaces errors inline.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync onRegister() {\n\t\t\tthis.subjectError = ''\n\t\t\tthis.errorMessage = ''\n\t\t\tif (!this.form.subject || !this.form.subject.trim()) {\n\t\t\t\tthis.subjectError = t('nextcloud-vue', 'Subject is required')\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (!this.objectStore) {\n\t\t\t\tthis.errorMessage = t('nextcloud-vue', 'Cannot save right now')\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst c = this.content || {}\n\t\t\t// `defaults` is spread FIRST so the mapped fields below always win.\n\t\t\t// It exists for schemas that need a fixed value on every create the\n\t\t\t// form itself has no input for — e.g. a discriminator on a supertype\n\t\t\t// schema (`{ ticketType: 'contactmoment' }`), which would otherwise be\n\t\t\t// omitted and fail validation.\n\t\t\tconst payload = {\n\t\t\t\t...(c.defaults || {}),\n\t\t\t\t[c.subjectField || 'subject']: this.form.subject.trim(),\n\t\t\t\t[c.channelField || 'channel']: this.form.channel,\n\t\t\t\t[c.contactedAtField || 'contactedAt']: new Date().toISOString(),\n\t\t\t}\n\t\t\tif (this.form.client) {\n\t\t\t\tpayload[c.clientField || 'client'] = this.form.client\n\t\t\t}\n\t\t\tif (this.form.summary) {\n\t\t\t\tpayload[c.summaryField || 'summary'] = this.form.summary\n\t\t\t}\n\t\t\tif (this.form.outcome) {\n\t\t\t\tpayload[c.outcomeField || 'outcome'] = this.form.outcome\n\t\t\t}\n\n\t\t\tthis.saving = true\n\t\t\tthis.saved = null\n\t\t\ttry {\n\t\t\t\tif (typeof this.objectStore.registerObjectType === 'function' && !this.objectStore.objectTypeRegistry?.[this.typeSlug]) {\n\t\t\t\t\tthis.objectStore.registerObjectType(this.typeSlug, this.schema, this.register)\n\t\t\t\t}\n\t\t\t\tconst result = await this.objectStore.saveObject(this.typeSlug, payload)\n\t\t\t\tif (!result) {\n\t\t\t\t\tthis.errorMessage = t('nextcloud-vue', 'Failed to save interaction')\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\t/**\n\t\t\t\t * @event saved A contactmoment was persisted.\n\t\t\t\t * @type {object} The saved object.\n\t\t\t\t */\n\t\t\t\tthis.$emit('saved', result)\n\t\t\t\tthis.saved = {\n\t\t\t\t\tid: String(result.id || (result['@self'] && result['@self'].id) || ''),\n\t\t\t\t\ttitle: payload[c.subjectField || 'subject'],\n\t\t\t\t}\n\t\t\t\t// Reset the per-interaction fields; keep the client for follow-ups.\n\t\t\t\tthis.form.subject = ''\n\t\t\t\tthis.form.summary = ''\n\t\t\t\tthis.form.outcome = ''\n\t\t\t\tthis.writeWorkspace('activeSummary', '')\n\t\t\t} catch (e) {\n\t\t\t\tthis.errorMessage = (e && e.message) || t('nextcloud-vue', 'Failed to save interaction')\n\t\t\t} finally {\n\t\t\t\tthis.saving = false\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<!--\n The scoped style block is gone on purpose. The markup now lives in\n CnFormWidgetBase, so a scoped rule here would carry THIS component's\n data-v attribute and match none of it. The rules moved verbatim to\n src/css/form-widget.css, keyed on `cn-form-widget*`; the base also emits\n the `cn-interaction-form-widget*` names on the same elements, so app CSS\n targeting those keeps matching.\n-->\n"],"names":["CnFormWidgetBase","CnResourceSelect","t"],"mappings":"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"}
@@ -38,7 +38,6 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
38
38
  variant: "tertiary",
39
39
  href: $options.savedHref,
40
40
  target: "_blank",
41
- rel: "noopener noreferrer",
42
41
  "data-testid": "cn-interaction-form-open"
43
42
  }, {
44
43
  icon: withCtx(() => [
@@ -1 +1 @@
1
- {"version":3,"file":"CnInteractionFormWidget.vue3.js","sources":["../../../../src/components/CnInteractionFormWidget/CnInteractionFormWidget.vue?vue&type=template&id=0650dea2&lang.js"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n<template>\n\t<CnFormWidgetBase\n\t\tblockClass=\"cn-interaction-form-widget\"\n\t\t:fields=\"formFields\"\n\t\t:model=\"form\"\n\t\t:errors=\"{ subject: subjectError }\"\n\t\t:canSubmit=\"canRegister\"\n\t\t:submitting=\"saving\"\n\t\t:submitLabel=\"registerLabel\"\n\t\t:submittingLabel=\"savingLabel\"\n\t\t:errorMessage=\"errorMessage\"\n\t\t@update:field=\"onFieldUpdate\"\n\t\t@submit=\"onRegister\">\n\t\t<!-- The client picker is the one control the base does not know about:\n\t\t a CnResourceSelect, so typing a name that does not exist yet offers\n\t\t \"Create '<name>'\" inline rather than a dead \"no results\" path. The\n\t\t base still supplies its field wrapper and spacing. -->\n\t\t<template #field-client>\n\t\t\t<CnResourceSelect\n\t\t\t\t:register=\"register\"\n\t\t\t\t:schema=\"clientSchema\"\n\t\t\t\t:labelField=\"clientLabelField\"\n\t\t\t\t:modelValue=\"form.client\"\n\t\t\t\t:inputLabel=\"clientLabel\"\n\t\t\t\t:preload=\"true\"\n\t\t\t\t@update:modelValue=\"onClientChange\"\n\t\t\t\t@create=\"onClientCreated\" />\n\t\t</template>\n\n\t\t<!-- Opens what was just saved in a new tab, beside the submit button. -->\n\t\t<template #actions-start>\n\t\t\t<NcButton\n\t\t\t\tv-if=\"savedHref\"\n\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t:href=\"savedHref\"\n\t\t\t\ttarget=\"_blank\"\n\t\t\t\trel=\"noopener noreferrer\"\n\t\t\t\tdata-testid=\"cn-interaction-form-open\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<OpenInNew :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ openLabel }}\n\t\t\t</NcButton>\n\t\t</template>\n\t</CnFormWidgetBase>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcButton } from '@nextcloud/vue'\nimport OpenInNew from 'vue-material-design-icons/OpenInNew.vue'\nimport CnFormWidgetBase from '../CnFormWidgetBase/CnFormWidgetBase.vue'\nimport CnResourceSelect from '../CnResourceSelect/CnResourceSelect.vue'\nimport { useObjectStore } from '../../store/index.js'\n\n/**\n * CnInteractionFormWidget — the \"active interaction\" quick-log form of a\n * workspace page.\n *\n * Persists a contactmoment (channel / client / subject / summary / outcome) to\n * OpenRegister via `useObjectStore().saveObject`. It reads `selectedClient`\n * from the page-level workspace context (the page's client in focus, set by a\n * page-level picker) to pre-fill its Client field.\n *\n * By default it also writes the chosen client to `selectedClient` and the live\n * summary text to `activeSummary`, so sibling widgets react: a client list\n * filtered on `@workspace.selectedClient`, or a `CnKbSearchWidget` bound to\n * `activeSummary`. A page whose client in focus comes from its own picker sets\n * `writeWorkspace: false`, which keeps the form's values to the submission.\n *\n * The Client field belongs to this submission only. It is a\n * `CnResourceSelect`, so typing a name that doesn't exist yet offers\n * \"Create '<name>'\" inline — no dead \"no results\" path.\n *\n * Resolved by its registry type key `interaction-form`. All schema/field/enum\n * choices come from `content`, so the widget carries no app-specific vocabulary.\n *\n * Example content blob:\n * ```js\n * content: {\n * register: 'pipelinq',\n * schema: 'ticket',\n * defaults: { ticketType: 'contactmoment' }, // fixed fields stamped on every create\n * clientSchema: 'client',\n * clientField: 'client',\n * summaryField: 'description',\n * channels: [{ value: 'telefoon', label: 'Phone' }, …],\n * }\n * ```\n *\n * The outcome options are read from the target schema on load: the enum of\n * its `outcomeField` property, labelled by that property's `x-enum-labels`.\n * `outcomes: [{ value, label }]` is only a fallback for a schema that has no\n * enum there.\n *\n * With `detailRoute` set (a route name taking `:id`, like an object list's\n * `rowRoute`), a save puts an \"Open\" button left of the submit button that\n * opens the saved object in a new tab.\n *\n * `defaults` covers the case where the target schema requires a value the form\n * has no input for — typically a discriminator on a supertype schema. It is\n * merged before the mapped fields, so those always take precedence.\n */\nexport default {\n\tname: 'CnInteractionFormWidget',\n\n\tcomponents: { CnFormWidgetBase, CnResourceSelect, NcButton, OpenInNew },\n\n\tinject: {\n\t\t/**\n\t\t * Page-level workspace context (reactive `ref({})`) from CnDashboardPage.\n\t\t * The widget reads `selectedClient` from it and, unless\n\t\t * `content.writeWorkspace` is false, writes `selectedClient` and\n\t\t * `activeSummary` back. Null on pages that don't provide one (the form\n\t\t * still saves).\n\t\t */\n\t\tcnWorkspaceContext: { default: null },\n\t\t/**\n\t\t * Host translate function from CnAppRoot, bound to the host app's id.\n\t\t * Translates the schema's outcome labels.\n\t\t */\n\t\tcnTranslate: { default: () => (key) => key },\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * Persisted configuration blob (see component description for the shape).\n\t\t *\n\t\t * @type {{register?: string, schema?: string, defaults?: object, clientSchema?: string, clientField?: string, clientLabelField?: string, subjectField?: string, summaryField?: string, channelField?: string, outcomeField?: string, channels?: Array, outcomes?: Array, submitLabel?: string, detailRoute?: string, writeWorkspace?: boolean}}\n\t\t */\n\t\tcontent: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\t},\n\n\temits: ['saved'],\n\n\tdata() {\n\t\treturn {\n\t\t\tform: {\n\t\t\t\tchannel: this.firstChannel(),\n\t\t\t\tclient: '',\n\t\t\t\tsubject: '',\n\t\t\t\tsummary: '',\n\t\t\t\toutcome: '',\n\t\t\t},\n\n\t\t\tsaving: false,\n\t\t\terrorMessage: '',\n\t\t\tsubjectError: '',\n\t\t\t// The target schema, fetched on load for its outcome enum.\n\t\t\tschemaDef: null,\n\t\t\t// The last saved object, `{ id, title }`, until the next save.\n\t\t\tsaved: null,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\tregister() {\n\t\t\treturn this.content.register || 'pipelinq'\n\t\t},\n\n\t\tschema() {\n\t\t\treturn this.content.schema || 'contactmoment'\n\t\t},\n\n\t\tclientSchema() {\n\t\t\treturn this.content.clientSchema || 'client'\n\t\t},\n\n\t\tclientLabelField() {\n\t\t\treturn this.content.clientLabelField || 'name'\n\t\t},\n\n\t\ttypeSlug() {\n\t\t\treturn `${this.register}-${this.schema}`\n\t\t},\n\n\t\t/** Channel options `{ value, label }`. */\n\t\tchannelOptions() {\n\t\t\treturn Array.isArray(this.content.channels) && this.content.channels.length > 0\n\t\t\t\t? this.content.channels\n\t\t\t\t: [\n\t\t\t\t\t\t{ value: 'telefoon', label: t('nextcloud-vue', 'Phone') },\n\t\t\t\t\t\t{ value: 'email', label: t('nextcloud-vue', 'Email') },\n\t\t\t\t\t\t{ value: 'chat', label: t('nextcloud-vue', 'Chat') },\n\t\t\t\t\t]\n\t\t},\n\n\t\t/**\n\t\t * Outcome options `{ value, label }`, from the target schema's enum so\n\t\t * the form can only offer values the schema accepts. Labels come from\n\t\t * the property's `x-enum-labels`, translated. `content.outcomes` is the\n\t\t * fallback for a schema without an enum on that property.\n\t\t *\n\t\t * @return {Array<{value: string, label: string}>}\n\t\t */\n\t\toutcomeOptions() {\n\t\t\tconst properties = (this.schemaDef && this.schemaDef.properties) || {}\n\t\t\tconst prop = properties[this.content.outcomeField || 'outcome']\n\t\t\tif (prop && Array.isArray(prop.enum) && prop.enum.length > 0) {\n\t\t\t\tconst labels = prop['x-enum-labels'] || prop.enumLabels || {}\n\t\t\t\tconst tr = typeof this.cnTranslate === 'function' ? this.cnTranslate : (k) => k\n\t\t\t\treturn prop.enum.map((value) => ({ value, label: tr(labels[value] || String(value)) }))\n\t\t\t}\n\t\t\treturn Array.isArray(this.content.outcomes) ? this.content.outcomes : []\n\t\t},\n\n\t\t/**\n\t\t * The field descriptors handed to CnFormWidgetBase — the whole of this\n\t\t * widget's form, declared rather than drawn. Order matters: it is the\n\t\t * render order.\n\t\t *\n\t\t * `client` is declared here so it keeps its place in the stack and its\n\t\t * field wrapper, but its control comes from the `#field-client` slot\n\t\t * (a CnResourceSelect, which the base has no type for).\n\t\t *\n\t\t * @return {Array<object>}\n\t\t */\n\t\tformFields() {\n\t\t\treturn [\n\t\t\t\t{ key: 'channel', type: 'select', label: this.channelLabel, options: this.channelOptions },\n\t\t\t\t{ key: 'client', type: 'custom', label: this.clientLabel },\n\t\t\t\t{ key: 'subject', type: 'text', label: this.subjectLabel },\n\t\t\t\t{ key: 'summary', type: 'textarea', label: this.summaryLabel, rows: 4 },\n\t\t\t\t{ key: 'outcome', type: 'select', label: this.outcomeLabel, options: this.outcomeOptions, clearable: true },\n\t\t\t]\n\t\t},\n\n\t\tobjectStore() {\n\t\t\ttry {\n\t\t\t\treturn useObjectStore()\n\t\t\t} catch {\n\t\t\t\treturn null\n\t\t\t}\n\t\t},\n\n\t\tworkspaceCtx() {\n\t\t\tconst c = this.cnWorkspaceContext\n\t\t\tif (!c) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\treturn (typeof c === 'object' && 'value' in c) ? c.value : c\n\t\t},\n\n\t\t/** The page's client in focus, or an empty string. */\n\t\tpageClient() {\n\t\t\tconst id = this.workspaceCtx && this.workspaceCtx.selectedClient\n\t\t\treturn id ? String(id) : ''\n\t\t},\n\n\t\tcanRegister() {\n\t\t\treturn Boolean(this.form.subject && this.form.subject.trim() && this.form.channel)\n\t\t},\n\n\t\tchannelLabel() {\n\t\t\treturn t('nextcloud-vue', 'Channel')\n\t\t},\n\n\t\tclientLabel() {\n\t\t\treturn t('nextcloud-vue', 'Client')\n\t\t},\n\n\t\tsubjectLabel() {\n\t\t\treturn t('nextcloud-vue', 'Subject')\n\t\t},\n\n\t\tsummaryLabel() {\n\t\t\treturn t('nextcloud-vue', 'Summary')\n\t\t},\n\n\t\toutcomeLabel() {\n\t\t\treturn t('nextcloud-vue', 'Outcome')\n\t\t},\n\n\t\t// `content.submitLabel` names what the form creates, e.g. \"Save contact moment\".\n\t\tregisterLabel() {\n\t\t\tif (this.content.submitLabel) {\n\t\t\t\tconst tr = typeof this.cnTranslate === 'function' ? this.cnTranslate : (k) => k\n\t\t\t\treturn tr(this.content.submitLabel)\n\t\t\t}\n\t\t\treturn t('nextcloud-vue', 'Register')\n\t\t},\n\n\t\tsavingLabel() {\n\t\t\treturn t('nextcloud-vue', 'Saving…')\n\t\t},\n\n\t\t/**\n\t\t * URL of the saved object's page, from `content.detailRoute`. Empty\n\t\t * without a route or router, and then no Open button is shown.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tsavedHref() {\n\t\t\tconst route = this.content.detailRoute\n\t\t\tif (!this.saved || !this.saved.id || !route || !this.$router) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\ttry {\n\t\t\t\treturn this.$router.resolve({ name: route, params: { id: this.saved.id } }).href || ''\n\t\t\t} catch {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t},\n\n\t\t// `escape: false` because the label renders through `{{ }}`, which escapes.\n\t\topenLabel() {\n\t\t\treturn t('nextcloud-vue', 'Open \"{title}\"', { title: (this.saved && this.saved.title) || '' }, undefined, { escape: false })\n\t\t},\n\n\t\t/** Whether the form writes its client and summary to the workspace context. */\n\t\twritesWorkspace() {\n\t\t\treturn this.content.writeWorkspace !== false\n\t\t},\n\t},\n\n\twatch: {\n\t\t// A new page client pre-fills the field; the field stays editable.\n\t\tpageClient: {\n\t\t\timmediate: true,\n\t\t\thandler(id) {\n\t\t\t\tif (id) {\n\t\t\t\t\tthis.form.client = id\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t},\n\n\tcreated() {\n\t\tthis.loadSchema()\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * Fetch the target schema, which the outcome options derive from. A\n\t\t * failure leaves the `content.outcomes` fallback in place.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync loadSchema() {\n\t\t\tconst store = this.objectStore\n\t\t\tif (!store || typeof store.fetchSchema !== 'function') {\n\t\t\t\treturn\n\t\t\t}\n\t\t\ttry {\n\t\t\t\t// Re-registering an existing type resets its cached objects and schema.\n\t\t\t\tif (typeof store.registerObjectType === 'function' && !store.objectTypeRegistry?.[this.typeSlug]) {\n\t\t\t\t\tstore.registerObjectType(this.typeSlug, this.schema, this.register)\n\t\t\t\t}\n\t\t\t\tthis.schemaDef = await store.fetchSchema(this.typeSlug)\n\t\t\t} catch {\n\t\t\t\tthis.schemaDef = null\n\t\t\t}\n\t\t},\n\n\t\t/** The default channel value (first configured channel, else `telefoon`). */\n\t\tfirstChannel() {\n\t\t\tconst ch = (this.content && this.content.channels) || []\n\t\t\treturn (Array.isArray(ch) && ch.length > 0 && ch[0].value) || 'telefoon'\n\t\t},\n\n\t\t/**\n\t\t * A field edit from CnFormWidgetBase. `summary` also streams into the\n\t\t * workspace context. `client` never arrives here: its control is the\n\t\t * `#field-client` slot, which calls onClientChange.\n\t\t *\n\t\t * @param {{key: string, value: unknown}} payload The changed field.\n\t\t * @return {void}\n\t\t */\n\t\tonFieldUpdate({ key, value }) {\n\t\t\tthis.form[key] = value\n\t\t\tif (key === 'summary') {\n\t\t\t\tthis.writeWorkspace('activeSummary', value)\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * The submission's client, also written to the workspace context.\n\t\t *\n\t\t * @param {string} id The selected client id.\n\t\t */\n\t\tonClientChange(id) {\n\t\t\tthis.form.client = id || ''\n\t\t\tthis.writeWorkspace('selectedClient', this.form.client)\n\t\t},\n\n\t\t/**\n\t\t * A client created inline via \"Create '<name>'\" — select it.\n\t\t *\n\t\t * @param {object} client The created client object.\n\t\t */\n\t\tonClientCreated(client) {\n\t\t\tconst id = String((client && (client.id || (client['@self'] && client['@self'].id))) || '')\n\t\t\tif (id) {\n\t\t\t\tthis.form.client = id\n\t\t\t\tthis.writeWorkspace('selectedClient', id)\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Write a key into the workspace context, unless `content.writeWorkspace`\n\t\t * is false.\n\t\t *\n\t\t * Vue 2.7's Options-API `inject` auto-unwraps the provided ref, so the\n\t\t * holder is usually the plain reactive object; the raw-ref shape\n\t\t * (`.value`) is supported for Composition-API consumers.\n\t\t *\n\t\t * @param {string} key The context key.\n\t\t * @param {unknown} value The value.\n\t\t */\n\t\twriteWorkspace(key, value) {\n\t\t\tconst holder = this.cnWorkspaceContext\n\t\t\tif (!this.writesWorkspace || !holder || typeof holder !== 'object') {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif ('value' in holder) {\n\t\t\t\tholder.value = { ...(holder.value || {}), [key]: value }\n\t\t\t\treturn\n\t\t\t}\n\t\t\tholder[key] = value\n\t\t},\n\n\t\t/**\n\t\t * Persist the contactmoment. The agent identity is left to the server\n\t\t * (never sent from the client). Surfaces errors inline.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync onRegister() {\n\t\t\tthis.subjectError = ''\n\t\t\tthis.errorMessage = ''\n\t\t\tif (!this.form.subject || !this.form.subject.trim()) {\n\t\t\t\tthis.subjectError = t('nextcloud-vue', 'Subject is required')\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (!this.objectStore) {\n\t\t\t\tthis.errorMessage = t('nextcloud-vue', 'Cannot save right now')\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst c = this.content || {}\n\t\t\t// `defaults` is spread FIRST so the mapped fields below always win.\n\t\t\t// It exists for schemas that need a fixed value on every create the\n\t\t\t// form itself has no input for — e.g. a discriminator on a supertype\n\t\t\t// schema (`{ ticketType: 'contactmoment' }`), which would otherwise be\n\t\t\t// omitted and fail validation.\n\t\t\tconst payload = {\n\t\t\t\t...(c.defaults || {}),\n\t\t\t\t[c.subjectField || 'subject']: this.form.subject.trim(),\n\t\t\t\t[c.channelField || 'channel']: this.form.channel,\n\t\t\t\t[c.contactedAtField || 'contactedAt']: new Date().toISOString(),\n\t\t\t}\n\t\t\tif (this.form.client) {\n\t\t\t\tpayload[c.clientField || 'client'] = this.form.client\n\t\t\t}\n\t\t\tif (this.form.summary) {\n\t\t\t\tpayload[c.summaryField || 'summary'] = this.form.summary\n\t\t\t}\n\t\t\tif (this.form.outcome) {\n\t\t\t\tpayload[c.outcomeField || 'outcome'] = this.form.outcome\n\t\t\t}\n\n\t\t\tthis.saving = true\n\t\t\tthis.saved = null\n\t\t\ttry {\n\t\t\t\tif (typeof this.objectStore.registerObjectType === 'function' && !this.objectStore.objectTypeRegistry?.[this.typeSlug]) {\n\t\t\t\t\tthis.objectStore.registerObjectType(this.typeSlug, this.schema, this.register)\n\t\t\t\t}\n\t\t\t\tconst result = await this.objectStore.saveObject(this.typeSlug, payload)\n\t\t\t\tif (!result) {\n\t\t\t\t\tthis.errorMessage = t('nextcloud-vue', 'Failed to save interaction')\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\t/**\n\t\t\t\t * @event saved A contactmoment was persisted.\n\t\t\t\t * @type {object} The saved object.\n\t\t\t\t */\n\t\t\t\tthis.$emit('saved', result)\n\t\t\t\tthis.saved = {\n\t\t\t\t\tid: String(result.id || (result['@self'] && result['@self'].id) || ''),\n\t\t\t\t\ttitle: payload[c.subjectField || 'subject'],\n\t\t\t\t}\n\t\t\t\t// Reset the per-interaction fields; keep the client for follow-ups.\n\t\t\t\tthis.form.subject = ''\n\t\t\t\tthis.form.summary = ''\n\t\t\t\tthis.form.outcome = ''\n\t\t\t\tthis.writeWorkspace('activeSummary', '')\n\t\t\t} catch (e) {\n\t\t\t\tthis.errorMessage = (e && e.message) || t('nextcloud-vue', 'Failed to save interaction')\n\t\t\t} finally {\n\t\t\t\tthis.saving = false\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<!--\n The scoped style block is gone on purpose. The markup now lives in\n CnFormWidgetBase, so a scoped rule here would carry THIS component's\n data-v attribute and match none of it. The rules moved verbatim to\n src/css/form-widget.css, keyed on `cn-form-widget*`; the base also emits\n the `cn-interaction-form-widget*` names on the same elements, so app CSS\n targeting those keeps matching.\n-->\n"],"names":["_createBlock","_createVNode","_createTextVNode"],"mappings":";;;;;;;;uBASEA;AACA,IAAA,UAAU,EAAC,4BAAY;AACtB,IAAA,MAAM,EAAE,QAAU,CAAA,UAAA;AAClB,IAAA,KAAK,EAAE,KAAI,CAAA,IAAA;AACX,IAAA,MAAM,aAAa,KAAS,CAAA,YAAA,EAAA;AAC5B,IAAA,SAAS,EAAE,QAAW,CAAA,WAAA;AACtB,IAAA,UAAU,EAAE,KAAM,CAAA,MAAA;AAClB,IAAA,WAAW,EAAE,QAAM,CAAA,aAAA;AACnB,IAAA,eAAe,EAAE,QAAU,CAAA,WAAA;gBACf,EAAE,KAAW,CAAA,YAAA;oBACb,EAAE,QAAa,CAAA,aAAA;AACvB,IAAA,QAAE,EAAC,QAAW,CAAA,UAAA;;AAKR,IAAA,cAAY,gBASC;iBAAA,CAAA,2BAAA,EAAA;AAPrB,QAAA,QAAQ,EAAE,QAAQ,CAAA,QAAA;AAClB,QAAA,MAAM,EAAE,QAAK,CAAA,YAAA;AACb,QAAA,UAAU,EAAE,QAAgB,CAAA,gBAAA;QAC5B,UAAU,EAAE,KAAI,CAAA,IAAA,CAAC,MAAM;AACvB,QAAA,UAAO,EAAA,QAAA,CAAA,WAAA;;AAEP,QAAA,qBAAiB,EAAE,QAAc,CAAA,cAAA;AACjC,QAAA,UAAQ,QAAa,CAAA,eAAA;;;AAIb,IAAA,eAAO,UAChB;OACM,QAAS,CAAA,SAAA;wBADfA;;AAEA,YAAA,OAAO,EAAC,UAAU;AACjB,YAAA,IAAI,EAAE,QAAQ,CAAA,SAAA;AACd,YAAA,MAAK,EAAC,QAAQ;AACf,YAAA,GAAG,EAAC,qBAAM;AACV,YAAA,aAAW,EAAA,0BAAG;;AACL,YAAA,IAAA,UACR,MAAO;cAAPC,WAAO,CAAA,oBAAA,EAAA,EAAA,IAAA,EAAA,EAAA,EAAA,CAAA;;6BACG;AAAA,cAAAC,eAAA,CAAA;;;;;;;;;;;;"}
1
+ {"version":3,"file":"CnInteractionFormWidget.vue3.js","sources":["../../../../src/components/CnInteractionFormWidget/CnInteractionFormWidget.vue?vue&type=template&id=0650dea2&lang.js"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n<template>\n\t<CnFormWidgetBase\n\t\tblockClass=\"cn-interaction-form-widget\"\n\t\t:fields=\"formFields\"\n\t\t:model=\"form\"\n\t\t:errors=\"{ subject: subjectError }\"\n\t\t:canSubmit=\"canRegister\"\n\t\t:submitting=\"saving\"\n\t\t:submitLabel=\"registerLabel\"\n\t\t:submittingLabel=\"savingLabel\"\n\t\t:errorMessage=\"errorMessage\"\n\t\t@update:field=\"onFieldUpdate\"\n\t\t@submit=\"onRegister\">\n\t\t<!-- The client picker is the one control the base does not know about:\n\t\t a CnResourceSelect, so typing a name that does not exist yet offers\n\t\t \"Create '<name>'\" inline rather than a dead \"no results\" path. The\n\t\t base still supplies its field wrapper and spacing. -->\n\t\t<template #field-client>\n\t\t\t<CnResourceSelect\n\t\t\t\t:register=\"register\"\n\t\t\t\t:schema=\"clientSchema\"\n\t\t\t\t:labelField=\"clientLabelField\"\n\t\t\t\t:modelValue=\"form.client\"\n\t\t\t\t:inputLabel=\"clientLabel\"\n\t\t\t\t:preload=\"true\"\n\t\t\t\t@update:modelValue=\"onClientChange\"\n\t\t\t\t@create=\"onClientCreated\" />\n\t\t</template>\n\n\t\t<!-- Opens what was just saved in a new tab, beside the submit button. -->\n\t\t<template #actions-start>\n\t\t\t<NcButton\n\t\t\t\tv-if=\"savedHref\"\n\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t:href=\"savedHref\"\n\t\t\t\ttarget=\"_blank\"\n\t\t\t\tdata-testid=\"cn-interaction-form-open\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<OpenInNew :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ openLabel }}\n\t\t\t</NcButton>\n\t\t</template>\n\t</CnFormWidgetBase>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcButton } from '@nextcloud/vue'\nimport OpenInNew from 'vue-material-design-icons/OpenInNew.vue'\nimport CnFormWidgetBase from '../CnFormWidgetBase/CnFormWidgetBase.vue'\nimport CnResourceSelect from '../CnResourceSelect/CnResourceSelect.vue'\nimport { useObjectStore } from '../../store/index.js'\n\n/**\n * CnInteractionFormWidget — the \"active interaction\" quick-log form of a\n * workspace page.\n *\n * Persists a contactmoment (channel / client / subject / summary / outcome) to\n * OpenRegister via `useObjectStore().saveObject`. It reads `selectedClient`\n * from the page-level workspace context (the page's client in focus, set by a\n * page-level picker) to pre-fill its Client field.\n *\n * By default it also writes the chosen client to `selectedClient` and the live\n * summary text to `activeSummary`, so sibling widgets react: a client list\n * filtered on `@workspace.selectedClient`, or a `CnKbSearchWidget` bound to\n * `activeSummary`. A page whose client in focus comes from its own picker sets\n * `writeWorkspace: false`, which keeps the form's values to the submission.\n *\n * The Client field belongs to this submission only. It is a\n * `CnResourceSelect`, so typing a name that doesn't exist yet offers\n * \"Create '<name>'\" inline — no dead \"no results\" path.\n *\n * Resolved by its registry type key `interaction-form`. All schema/field/enum\n * choices come from `content`, so the widget carries no app-specific vocabulary.\n *\n * Example content blob:\n * ```js\n * content: {\n * register: 'pipelinq',\n * schema: 'ticket',\n * defaults: { ticketType: 'contactmoment' }, // fixed fields stamped on every create\n * clientSchema: 'client',\n * clientField: 'client',\n * summaryField: 'description',\n * channels: [{ value: 'telefoon', label: 'Phone' }, …],\n * }\n * ```\n *\n * The outcome options are read from the target schema on load: the enum of\n * its `outcomeField` property, labelled by that property's `x-enum-labels`.\n * `outcomes: [{ value, label }]` is only a fallback for a schema that has no\n * enum there.\n *\n * With `detailRoute` set (a route name taking `:id`, like an object list's\n * `rowRoute`), a save puts an \"Open\" button left of the submit button that\n * opens the saved object in a new tab.\n *\n * `defaults` covers the case where the target schema requires a value the form\n * has no input for — typically a discriminator on a supertype schema. It is\n * merged before the mapped fields, so those always take precedence.\n */\nexport default {\n\tname: 'CnInteractionFormWidget',\n\n\tcomponents: { CnFormWidgetBase, CnResourceSelect, NcButton, OpenInNew },\n\n\tinject: {\n\t\t/**\n\t\t * Page-level workspace context (reactive `ref({})`) from CnDashboardPage.\n\t\t * The widget reads `selectedClient` from it and, unless\n\t\t * `content.writeWorkspace` is false, writes `selectedClient` and\n\t\t * `activeSummary` back. Null on pages that don't provide one (the form\n\t\t * still saves).\n\t\t */\n\t\tcnWorkspaceContext: { default: null },\n\t\t/**\n\t\t * Host translate function from CnAppRoot, bound to the host app's id.\n\t\t * Translates the schema's outcome labels.\n\t\t */\n\t\tcnTranslate: { default: () => (key) => key },\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * Persisted configuration blob (see component description for the shape).\n\t\t *\n\t\t * @type {{register?: string, schema?: string, defaults?: object, clientSchema?: string, clientField?: string, clientLabelField?: string, subjectField?: string, summaryField?: string, channelField?: string, outcomeField?: string, channels?: Array, outcomes?: Array, submitLabel?: string, detailRoute?: string, writeWorkspace?: boolean}}\n\t\t */\n\t\tcontent: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\t},\n\n\temits: ['saved'],\n\n\tdata() {\n\t\treturn {\n\t\t\tform: {\n\t\t\t\tchannel: this.firstChannel(),\n\t\t\t\tclient: '',\n\t\t\t\tsubject: '',\n\t\t\t\tsummary: '',\n\t\t\t\toutcome: '',\n\t\t\t},\n\n\t\t\tsaving: false,\n\t\t\terrorMessage: '',\n\t\t\tsubjectError: '',\n\t\t\t// The target schema, fetched on load for its outcome enum.\n\t\t\tschemaDef: null,\n\t\t\t// The last saved object, `{ id, title }`, until the next save.\n\t\t\tsaved: null,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\tregister() {\n\t\t\treturn this.content.register || 'pipelinq'\n\t\t},\n\n\t\tschema() {\n\t\t\treturn this.content.schema || 'contactmoment'\n\t\t},\n\n\t\tclientSchema() {\n\t\t\treturn this.content.clientSchema || 'client'\n\t\t},\n\n\t\tclientLabelField() {\n\t\t\treturn this.content.clientLabelField || 'name'\n\t\t},\n\n\t\ttypeSlug() {\n\t\t\treturn `${this.register}-${this.schema}`\n\t\t},\n\n\t\t/** Channel options `{ value, label }`. */\n\t\tchannelOptions() {\n\t\t\treturn Array.isArray(this.content.channels) && this.content.channels.length > 0\n\t\t\t\t? this.content.channels\n\t\t\t\t: [\n\t\t\t\t\t\t{ value: 'telefoon', label: t('nextcloud-vue', 'Phone') },\n\t\t\t\t\t\t{ value: 'email', label: t('nextcloud-vue', 'Email') },\n\t\t\t\t\t\t{ value: 'chat', label: t('nextcloud-vue', 'Chat') },\n\t\t\t\t\t]\n\t\t},\n\n\t\t/**\n\t\t * Outcome options `{ value, label }`, from the target schema's enum so\n\t\t * the form can only offer values the schema accepts. Labels come from\n\t\t * the property's `x-enum-labels`, translated. `content.outcomes` is the\n\t\t * fallback for a schema without an enum on that property.\n\t\t *\n\t\t * @return {Array<{value: string, label: string}>}\n\t\t */\n\t\toutcomeOptions() {\n\t\t\tconst properties = (this.schemaDef && this.schemaDef.properties) || {}\n\t\t\tconst prop = properties[this.content.outcomeField || 'outcome']\n\t\t\tif (prop && Array.isArray(prop.enum) && prop.enum.length > 0) {\n\t\t\t\tconst labels = prop['x-enum-labels'] || prop.enumLabels || {}\n\t\t\t\tconst tr = typeof this.cnTranslate === 'function' ? this.cnTranslate : (k) => k\n\t\t\t\treturn prop.enum.map((value) => ({ value, label: tr(labels[value] || String(value)) }))\n\t\t\t}\n\t\t\treturn Array.isArray(this.content.outcomes) ? this.content.outcomes : []\n\t\t},\n\n\t\t/**\n\t\t * The field descriptors handed to CnFormWidgetBase — the whole of this\n\t\t * widget's form, declared rather than drawn. Order matters: it is the\n\t\t * render order.\n\t\t *\n\t\t * `client` is declared here so it keeps its place in the stack and its\n\t\t * field wrapper, but its control comes from the `#field-client` slot\n\t\t * (a CnResourceSelect, which the base has no type for).\n\t\t *\n\t\t * @return {Array<object>}\n\t\t */\n\t\tformFields() {\n\t\t\treturn [\n\t\t\t\t{ key: 'channel', type: 'select', label: this.channelLabel, options: this.channelOptions },\n\t\t\t\t{ key: 'client', type: 'custom', label: this.clientLabel },\n\t\t\t\t{ key: 'subject', type: 'text', label: this.subjectLabel },\n\t\t\t\t{ key: 'summary', type: 'textarea', label: this.summaryLabel, rows: 4 },\n\t\t\t\t{ key: 'outcome', type: 'select', label: this.outcomeLabel, options: this.outcomeOptions, clearable: true },\n\t\t\t]\n\t\t},\n\n\t\tobjectStore() {\n\t\t\ttry {\n\t\t\t\treturn useObjectStore()\n\t\t\t} catch {\n\t\t\t\treturn null\n\t\t\t}\n\t\t},\n\n\t\tworkspaceCtx() {\n\t\t\tconst c = this.cnWorkspaceContext\n\t\t\tif (!c) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\treturn (typeof c === 'object' && 'value' in c) ? c.value : c\n\t\t},\n\n\t\t/** The page's client in focus, or an empty string. */\n\t\tpageClient() {\n\t\t\tconst id = this.workspaceCtx && this.workspaceCtx.selectedClient\n\t\t\treturn id ? String(id) : ''\n\t\t},\n\n\t\tcanRegister() {\n\t\t\treturn Boolean(this.form.subject && this.form.subject.trim() && this.form.channel)\n\t\t},\n\n\t\tchannelLabel() {\n\t\t\treturn t('nextcloud-vue', 'Channel')\n\t\t},\n\n\t\tclientLabel() {\n\t\t\treturn t('nextcloud-vue', 'Client')\n\t\t},\n\n\t\tsubjectLabel() {\n\t\t\treturn t('nextcloud-vue', 'Subject')\n\t\t},\n\n\t\tsummaryLabel() {\n\t\t\treturn t('nextcloud-vue', 'Summary')\n\t\t},\n\n\t\toutcomeLabel() {\n\t\t\treturn t('nextcloud-vue', 'Outcome')\n\t\t},\n\n\t\t// `content.submitLabel` names what the form creates, e.g. \"Save contact moment\".\n\t\tregisterLabel() {\n\t\t\tif (this.content.submitLabel) {\n\t\t\t\tconst tr = typeof this.cnTranslate === 'function' ? this.cnTranslate : (k) => k\n\t\t\t\treturn tr(this.content.submitLabel)\n\t\t\t}\n\t\t\treturn t('nextcloud-vue', 'Register')\n\t\t},\n\n\t\tsavingLabel() {\n\t\t\treturn t('nextcloud-vue', 'Saving…')\n\t\t},\n\n\t\t/**\n\t\t * URL of the saved object's page, from `content.detailRoute`. Empty\n\t\t * without a route or router, and then no Open button is shown.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tsavedHref() {\n\t\t\tconst route = this.content.detailRoute\n\t\t\tif (!this.saved || !this.saved.id || !route || !this.$router) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\ttry {\n\t\t\t\treturn this.$router.resolve({ name: route, params: { id: this.saved.id } }).href || ''\n\t\t\t} catch {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t},\n\n\t\t// `escape: false` because the label renders through `{{ }}`, which escapes.\n\t\topenLabel() {\n\t\t\treturn t('nextcloud-vue', 'Open \"{title}\"', { title: (this.saved && this.saved.title) || '' }, undefined, { escape: false })\n\t\t},\n\n\t\t/** Whether the form writes its client and summary to the workspace context. */\n\t\twritesWorkspace() {\n\t\t\treturn this.content.writeWorkspace !== false\n\t\t},\n\t},\n\n\twatch: {\n\t\t// A new page client pre-fills the field; the field stays editable.\n\t\tpageClient: {\n\t\t\timmediate: true,\n\t\t\thandler(id) {\n\t\t\t\tif (id) {\n\t\t\t\t\tthis.form.client = id\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t},\n\n\tcreated() {\n\t\tthis.loadSchema()\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * Fetch the target schema, which the outcome options derive from. A\n\t\t * failure leaves the `content.outcomes` fallback in place.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync loadSchema() {\n\t\t\tconst store = this.objectStore\n\t\t\tif (!store || typeof store.fetchSchema !== 'function') {\n\t\t\t\treturn\n\t\t\t}\n\t\t\ttry {\n\t\t\t\t// Re-registering an existing type resets its cached objects and schema.\n\t\t\t\tif (typeof store.registerObjectType === 'function' && !store.objectTypeRegistry?.[this.typeSlug]) {\n\t\t\t\t\tstore.registerObjectType(this.typeSlug, this.schema, this.register)\n\t\t\t\t}\n\t\t\t\tthis.schemaDef = await store.fetchSchema(this.typeSlug)\n\t\t\t} catch {\n\t\t\t\tthis.schemaDef = null\n\t\t\t}\n\t\t},\n\n\t\t/** The default channel value (first configured channel, else `telefoon`). */\n\t\tfirstChannel() {\n\t\t\tconst ch = (this.content && this.content.channels) || []\n\t\t\treturn (Array.isArray(ch) && ch.length > 0 && ch[0].value) || 'telefoon'\n\t\t},\n\n\t\t/**\n\t\t * A field edit from CnFormWidgetBase. `summary` also streams into the\n\t\t * workspace context. `client` never arrives here: its control is the\n\t\t * `#field-client` slot, which calls onClientChange.\n\t\t *\n\t\t * @param {{key: string, value: unknown}} payload The changed field.\n\t\t * @return {void}\n\t\t */\n\t\tonFieldUpdate({ key, value }) {\n\t\t\tthis.form[key] = value\n\t\t\tif (key === 'summary') {\n\t\t\t\tthis.writeWorkspace('activeSummary', value)\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * The submission's client, also written to the workspace context.\n\t\t *\n\t\t * @param {string} id The selected client id.\n\t\t */\n\t\tonClientChange(id) {\n\t\t\tthis.form.client = id || ''\n\t\t\tthis.writeWorkspace('selectedClient', this.form.client)\n\t\t},\n\n\t\t/**\n\t\t * A client created inline via \"Create '<name>'\" — select it.\n\t\t *\n\t\t * @param {object} client The created client object.\n\t\t */\n\t\tonClientCreated(client) {\n\t\t\tconst id = String((client && (client.id || (client['@self'] && client['@self'].id))) || '')\n\t\t\tif (id) {\n\t\t\t\tthis.form.client = id\n\t\t\t\tthis.writeWorkspace('selectedClient', id)\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Write a key into the workspace context, unless `content.writeWorkspace`\n\t\t * is false.\n\t\t *\n\t\t * Vue 2.7's Options-API `inject` auto-unwraps the provided ref, so the\n\t\t * holder is usually the plain reactive object; the raw-ref shape\n\t\t * (`.value`) is supported for Composition-API consumers.\n\t\t *\n\t\t * @param {string} key The context key.\n\t\t * @param {unknown} value The value.\n\t\t */\n\t\twriteWorkspace(key, value) {\n\t\t\tconst holder = this.cnWorkspaceContext\n\t\t\tif (!this.writesWorkspace || !holder || typeof holder !== 'object') {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif ('value' in holder) {\n\t\t\t\tholder.value = { ...(holder.value || {}), [key]: value }\n\t\t\t\treturn\n\t\t\t}\n\t\t\tholder[key] = value\n\t\t},\n\n\t\t/**\n\t\t * Persist the contactmoment. The agent identity is left to the server\n\t\t * (never sent from the client). Surfaces errors inline.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync onRegister() {\n\t\t\tthis.subjectError = ''\n\t\t\tthis.errorMessage = ''\n\t\t\tif (!this.form.subject || !this.form.subject.trim()) {\n\t\t\t\tthis.subjectError = t('nextcloud-vue', 'Subject is required')\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (!this.objectStore) {\n\t\t\t\tthis.errorMessage = t('nextcloud-vue', 'Cannot save right now')\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst c = this.content || {}\n\t\t\t// `defaults` is spread FIRST so the mapped fields below always win.\n\t\t\t// It exists for schemas that need a fixed value on every create the\n\t\t\t// form itself has no input for — e.g. a discriminator on a supertype\n\t\t\t// schema (`{ ticketType: 'contactmoment' }`), which would otherwise be\n\t\t\t// omitted and fail validation.\n\t\t\tconst payload = {\n\t\t\t\t...(c.defaults || {}),\n\t\t\t\t[c.subjectField || 'subject']: this.form.subject.trim(),\n\t\t\t\t[c.channelField || 'channel']: this.form.channel,\n\t\t\t\t[c.contactedAtField || 'contactedAt']: new Date().toISOString(),\n\t\t\t}\n\t\t\tif (this.form.client) {\n\t\t\t\tpayload[c.clientField || 'client'] = this.form.client\n\t\t\t}\n\t\t\tif (this.form.summary) {\n\t\t\t\tpayload[c.summaryField || 'summary'] = this.form.summary\n\t\t\t}\n\t\t\tif (this.form.outcome) {\n\t\t\t\tpayload[c.outcomeField || 'outcome'] = this.form.outcome\n\t\t\t}\n\n\t\t\tthis.saving = true\n\t\t\tthis.saved = null\n\t\t\ttry {\n\t\t\t\tif (typeof this.objectStore.registerObjectType === 'function' && !this.objectStore.objectTypeRegistry?.[this.typeSlug]) {\n\t\t\t\t\tthis.objectStore.registerObjectType(this.typeSlug, this.schema, this.register)\n\t\t\t\t}\n\t\t\t\tconst result = await this.objectStore.saveObject(this.typeSlug, payload)\n\t\t\t\tif (!result) {\n\t\t\t\t\tthis.errorMessage = t('nextcloud-vue', 'Failed to save interaction')\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\t/**\n\t\t\t\t * @event saved A contactmoment was persisted.\n\t\t\t\t * @type {object} The saved object.\n\t\t\t\t */\n\t\t\t\tthis.$emit('saved', result)\n\t\t\t\tthis.saved = {\n\t\t\t\t\tid: String(result.id || (result['@self'] && result['@self'].id) || ''),\n\t\t\t\t\ttitle: payload[c.subjectField || 'subject'],\n\t\t\t\t}\n\t\t\t\t// Reset the per-interaction fields; keep the client for follow-ups.\n\t\t\t\tthis.form.subject = ''\n\t\t\t\tthis.form.summary = ''\n\t\t\t\tthis.form.outcome = ''\n\t\t\t\tthis.writeWorkspace('activeSummary', '')\n\t\t\t} catch (e) {\n\t\t\t\tthis.errorMessage = (e && e.message) || t('nextcloud-vue', 'Failed to save interaction')\n\t\t\t} finally {\n\t\t\t\tthis.saving = false\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<!--\n The scoped style block is gone on purpose. The markup now lives in\n CnFormWidgetBase, so a scoped rule here would carry THIS component's\n data-v attribute and match none of it. The rules moved verbatim to\n src/css/form-widget.css, keyed on `cn-form-widget*`; the base also emits\n the `cn-interaction-form-widget*` names on the same elements, so app CSS\n targeting those keeps matching.\n-->\n"],"names":["_createBlock","_createVNode","_createTextVNode"],"mappings":";;;;;;;;uBASEA;AACA,IAAA,UAAU,EAAC,4BAAY;AACtB,IAAA,MAAM,EAAE,QAAU,CAAA,UAAA;AAClB,IAAA,KAAK,EAAE,KAAI,CAAA,IAAA;AACX,IAAA,MAAM,aAAa,KAAS,CAAA,YAAA,EAAA;AAC5B,IAAA,SAAS,EAAE,QAAW,CAAA,WAAA;AACtB,IAAA,UAAU,EAAE,KAAM,CAAA,MAAA;AAClB,IAAA,WAAW,EAAE,QAAM,CAAA,aAAA;AACnB,IAAA,eAAe,EAAE,QAAU,CAAA,WAAA;gBACf,EAAE,KAAW,CAAA,YAAA;oBACb,EAAE,QAAa,CAAA,aAAA;AACvB,IAAA,QAAE,EAAC,QAAW,CAAA,UAAA;;AAKR,IAAA,cAAY,gBASC;iBAAA,CAAA,2BAAA,EAAA;AAPrB,QAAA,QAAQ,EAAE,QAAQ,CAAA,QAAA;AAClB,QAAA,MAAM,EAAE,QAAK,CAAA,YAAA;AACb,QAAA,UAAU,EAAE,QAAgB,CAAA,gBAAA;QAC5B,UAAU,EAAE,KAAI,CAAA,IAAA,CAAC,MAAM;AACvB,QAAA,UAAO,EAAA,QAAA,CAAA,WAAA;;AAEP,QAAA,qBAAiB,EAAE,QAAc,CAAA,cAAA;AACjC,QAAA,UAAQ,QAAa,CAAA,eAAA;;;AAIb,IAAA,eAAO,UAChB;OACM,QAAS,CAAA,SAAA;wBADfA;;AAEA,YAAA,OAAO,EAAC,UAAO;AACd,YAAA,IAAI,EAAE,QAAS,CAAA,SAAA;AAChB,YAAA,MAAM,EAAC,QAAG;AACV,YAAA,aAAW,EAAA,0BAAG;;AACL,YAAA,IAAA,UACR,MAAO;cAAPC,WAAO,CAAA,oBAAA,EAAA,EAAA,IAAA,EAAA,EAAA,EAAA,CAAA;;6BACG;AAAA,cAAAC,eAAA,CAAA;;;;;;;;;;;;"}
@@ -343,10 +343,9 @@ var script = {
343
343
  * @return {void}
344
344
  */
345
345
  dispatchAction({ actionType, url, value }) {
346
+ // An `external` entry with a URL is a real link (see linkAttrsFor);
347
+ // one without a URL has nothing to open.
346
348
  switch (actionType) {
347
- case ACTION_TYPES.EXTERNAL:
348
- this.handleExternal(url);
349
- break
350
349
  case ACTION_TYPES.INTERNAL:
351
350
  this.$emit('internal-action', url);
352
351
  break
@@ -357,20 +356,6 @@ var script = {
357
356
  break
358
357
  }
359
358
  },
360
-
361
- /**
362
- * Open an external URL in a new tab; `noopener,noreferrer` prevents
363
- * the opened page reaching back via `window.opener`.
364
- *
365
- * @param {string} url the URL to open.
366
- * @return {void}
367
- */
368
- handleExternal(url) {
369
- if (typeof url !== 'string' || url === '') {
370
- return
371
- }
372
- window.open(url, '_blank', 'noopener,noreferrer');
373
- },
374
359
  },
375
360
  };
376
361