@conduction/nextcloud-vue 2.79.0 → 2.81.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (390) hide show
  1. package/dist/esm/components/CnActionButtons/CnActionButtons.vue2.js.map +1 -1
  2. package/dist/esm/components/CnActionButtons/CnActionButtons.vue3.js +3 -1
  3. package/dist/esm/components/CnActionButtons/CnActionButtons.vue3.js.map +1 -1
  4. package/dist/esm/components/CnActionsBar/CnActionsBar.vue2.js +32 -3
  5. package/dist/esm/components/CnActionsBar/CnActionsBar.vue2.js.map +1 -1
  6. package/dist/esm/components/CnActionsBar/CnActionsBar.vue3.js +13 -11
  7. package/dist/esm/components/CnActionsBar/CnActionsBar.vue3.js.map +1 -1
  8. package/dist/esm/components/CnAppRoot/CnAppRoot.vue2.js +80 -4
  9. package/dist/esm/components/CnAppRoot/CnAppRoot.vue2.js.map +1 -1
  10. package/dist/esm/components/CnAppRoot/CnAppRoot.vue3.js +95 -91
  11. package/dist/esm/components/CnAppRoot/CnAppRoot.vue3.js.map +1 -1
  12. package/dist/esm/components/CnBannerWidget/CnBannerWidget.vue2.js +179 -13
  13. package/dist/esm/components/CnBannerWidget/CnBannerWidget.vue2.js.map +1 -1
  14. package/dist/esm/components/CnBannerWidget/CnBannerWidget.vue3.js +52 -16
  15. package/dist/esm/components/CnBannerWidget/CnBannerWidget.vue3.js.map +1 -1
  16. package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue2.js +96 -4
  17. package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue2.js.map +1 -1
  18. package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue3.js +158 -110
  19. package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue3.js.map +1 -1
  20. package/dist/esm/components/CnChipsFieldWidget/CnChipsFieldWidget.vue.js +10 -0
  21. package/dist/esm/components/CnChipsFieldWidget/CnChipsFieldWidget.vue.js.map +1 -0
  22. package/dist/esm/components/CnChipsFieldWidget/CnChipsFieldWidget.vue2.js +252 -0
  23. package/dist/esm/components/CnChipsFieldWidget/CnChipsFieldWidget.vue2.js.map +1 -0
  24. package/dist/esm/components/CnChipsFieldWidget/CnChipsFieldWidget.vue3.js +140 -0
  25. package/dist/esm/components/CnChipsFieldWidget/CnChipsFieldWidget.vue3.js.map +1 -0
  26. package/dist/esm/components/CnChipsFieldWidget/index.js +26 -0
  27. package/dist/esm/components/CnChipsFieldWidget/index.js.map +1 -0
  28. package/dist/esm/components/CnChoicePickerWidget/CnChoicePickerWidget.vue.js +10 -0
  29. package/dist/esm/components/CnChoicePickerWidget/CnChoicePickerWidget.vue.js.map +1 -0
  30. package/dist/esm/components/CnChoicePickerWidget/CnChoicePickerWidget.vue2.js +354 -0
  31. package/dist/esm/components/CnChoicePickerWidget/CnChoicePickerWidget.vue2.js.map +1 -0
  32. package/dist/esm/components/CnChoicePickerWidget/CnChoicePickerWidget.vue3.js +172 -0
  33. package/dist/esm/components/CnChoicePickerWidget/CnChoicePickerWidget.vue3.js.map +1 -0
  34. package/dist/esm/components/CnChoicePickerWidget/index.js +27 -0
  35. package/dist/esm/components/CnChoicePickerWidget/index.js.map +1 -0
  36. package/dist/esm/components/CnConversationThread/CnConversationWidget.vue2.js +1 -1
  37. package/dist/esm/components/CnConversationThread/CnConversationWidget.vue2.js.map +1 -1
  38. package/dist/esm/components/CnConversationThread/CnConversationWidget.vue3.js.map +1 -1
  39. package/dist/esm/components/CnDashboardGrid/CnDashboardGrid.vue2.js +2 -2
  40. package/dist/esm/components/CnDashboardGrid/CnDashboardGrid.vue2.js.map +1 -1
  41. package/dist/esm/components/CnDashboardGrid/CnDashboardGrid.vue3.js.map +1 -1
  42. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js +65 -5
  43. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js.map +1 -1
  44. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js +2 -1
  45. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js.map +1 -1
  46. package/dist/esm/components/CnDataTable/CnDataTable.vue2.js +19 -11
  47. package/dist/esm/components/CnDataTable/CnDataTable.vue2.js.map +1 -1
  48. package/dist/esm/components/CnDataTable/CnDataTable.vue3.js +4 -2
  49. package/dist/esm/components/CnDataTable/CnDataTable.vue3.js.map +1 -1
  50. package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js +134 -4
  51. package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js.map +1 -1
  52. package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js +21 -4
  53. package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js.map +1 -1
  54. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue2.js +24 -0
  55. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue2.js.map +1 -1
  56. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue3.js +43 -4
  57. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue3.js.map +1 -1
  58. package/dist/esm/components/CnDocumentReviewList/CnDocumentReviewWidget.vue2.js +1 -1
  59. package/dist/esm/components/CnDocumentReviewList/CnDocumentReviewWidget.vue2.js.map +1 -1
  60. package/dist/esm/components/CnDocumentReviewList/CnDocumentReviewWidget.vue3.js.map +1 -1
  61. package/dist/esm/components/CnFacetSidebar/CnFacetSidebar.vue2.js +7 -7
  62. package/dist/esm/components/CnFacetSidebar/CnFacetSidebar.vue2.js.map +1 -1
  63. package/dist/esm/components/CnFacetSidebar/CnFacetSidebar.vue3.js.map +1 -1
  64. package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue.js +11 -0
  65. package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue.js.map +1 -0
  66. package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue2.js +867 -0
  67. package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue2.js.map +1 -0
  68. package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue3.js +238 -0
  69. package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue3.js.map +1 -0
  70. package/dist/esm/components/CnFactsWidget/index.js +30 -0
  71. package/dist/esm/components/CnFactsWidget/index.js.map +1 -0
  72. package/dist/esm/components/CnFieldListWidget/CnFieldListWidget.vue.js +10 -0
  73. package/dist/esm/components/CnFieldListWidget/CnFieldListWidget.vue.js.map +1 -0
  74. package/dist/esm/components/CnFieldListWidget/CnFieldListWidget.vue2.js +626 -0
  75. package/dist/esm/components/CnFieldListWidget/CnFieldListWidget.vue2.js.map +1 -0
  76. package/dist/esm/components/CnFieldListWidget/CnFieldListWidget.vue3.js +396 -0
  77. package/dist/esm/components/CnFieldListWidget/CnFieldListWidget.vue3.js.map +1 -0
  78. package/dist/esm/components/CnFieldListWidget/index.js +29 -0
  79. package/dist/esm/components/CnFieldListWidget/index.js.map +1 -0
  80. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js +302 -4
  81. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js.map +1 -1
  82. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js +417 -244
  83. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js.map +1 -1
  84. package/dist/esm/components/CnFilesBrowser/filesBrowser.js +101 -1
  85. package/dist/esm/components/CnFilesBrowser/filesBrowser.js.map +1 -1
  86. package/dist/esm/components/CnFilesBrowser/filesBrowserColumns.js +141 -1
  87. package/dist/esm/components/CnFilesBrowser/filesBrowserColumns.js.map +1 -1
  88. package/dist/esm/components/CnFormDialog/CnFormDialog.vue2.js +65 -17
  89. package/dist/esm/components/CnFormDialog/CnFormDialog.vue2.js.map +1 -1
  90. package/dist/esm/components/CnFormDialog/CnFormDialog.vue3.js +4 -4
  91. package/dist/esm/components/CnFormDialog/CnFormDialog.vue3.js.map +1 -1
  92. package/dist/esm/components/CnFormPage/CnFormPage.vue2.js +78 -3
  93. package/dist/esm/components/CnFormPage/CnFormPage.vue2.js.map +1 -1
  94. package/dist/esm/components/CnFormPage/CnFormPage.vue3.js +74 -49
  95. package/dist/esm/components/CnFormPage/CnFormPage.vue3.js.map +1 -1
  96. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +333 -73
  97. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
  98. package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js +79 -17
  99. package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
  100. package/dist/esm/components/CnIndexPage/CnIndexPageWidgets.vue.js +10 -0
  101. package/dist/esm/components/CnIndexPage/CnIndexPageWidgets.vue.js.map +1 -0
  102. package/dist/esm/components/CnIndexPage/CnIndexPageWidgets.vue2.js +99 -0
  103. package/dist/esm/components/CnIndexPage/CnIndexPageWidgets.vue2.js.map +1 -0
  104. package/dist/esm/components/CnIndexPage/CnIndexPageWidgets.vue3.js +48 -0
  105. package/dist/esm/components/CnIndexPage/CnIndexPageWidgets.vue3.js.map +1 -0
  106. package/dist/esm/components/CnIndexSidebar/CnIndexSidebar.vue2.js +7 -7
  107. package/dist/esm/components/CnIndexSidebar/CnIndexSidebar.vue2.js.map +1 -1
  108. package/dist/esm/components/CnIndexSidebar/CnIndexSidebar.vue3.js.map +1 -1
  109. package/dist/esm/components/CnNextStepCard/CnNextStepWidget.vue2.js +1 -1
  110. package/dist/esm/components/CnNextStepCard/CnNextStepWidget.vue2.js.map +1 -1
  111. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js +65 -2
  112. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js.map +1 -1
  113. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue3.js +6 -2
  114. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue3.js.map +1 -1
  115. package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue2.js +63 -1
  116. package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue2.js.map +1 -1
  117. package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue3.js +8 -1
  118. package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue3.js.map +1 -1
  119. package/dist/esm/components/CnObjectSidebar/CnNotesTab.vue2.js +14 -0
  120. package/dist/esm/components/CnObjectSidebar/CnNotesTab.vue2.js.map +1 -1
  121. package/dist/esm/components/CnObjectSidebar/CnNotesTab.vue3.js +5 -1
  122. package/dist/esm/components/CnObjectSidebar/CnNotesTab.vue3.js.map +1 -1
  123. package/dist/esm/components/CnPageRenderer/CnPageRenderer.vue2.js +29 -1
  124. package/dist/esm/components/CnPageRenderer/CnPageRenderer.vue2.js.map +1 -1
  125. package/dist/esm/components/CnPageRenderer/CnPageRenderer.vue3.js.map +1 -1
  126. package/dist/esm/components/CnRadioCardsWidget/CnRadioCardsWidget.vue.js +10 -0
  127. package/dist/esm/components/CnRadioCardsWidget/CnRadioCardsWidget.vue.js.map +1 -0
  128. package/dist/esm/components/CnRadioCardsWidget/CnRadioCardsWidget.vue2.js +174 -0
  129. package/dist/esm/components/CnRadioCardsWidget/CnRadioCardsWidget.vue2.js.map +1 -0
  130. package/dist/esm/components/CnRadioCardsWidget/CnRadioCardsWidget.vue3.js +75 -0
  131. package/dist/esm/components/CnRadioCardsWidget/CnRadioCardsWidget.vue3.js.map +1 -0
  132. package/dist/esm/components/CnRadioCardsWidget/index.js +28 -0
  133. package/dist/esm/components/CnRadioCardsWidget/index.js.map +1 -0
  134. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue.js +10 -0
  135. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue.js.map +1 -0
  136. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js +411 -0
  137. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js.map +1 -0
  138. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js +178 -0
  139. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js.map +1 -0
  140. package/dist/esm/components/CnRecordListWidget/index.js +31 -0
  141. package/dist/esm/components/CnRecordListWidget/index.js.map +1 -0
  142. package/dist/esm/components/CnSavedViewsWidget/CnSavedViewsWidget.vue.js +10 -0
  143. package/dist/esm/components/CnSavedViewsWidget/CnSavedViewsWidget.vue.js.map +1 -0
  144. package/dist/esm/components/CnSavedViewsWidget/CnSavedViewsWidget.vue2.js +222 -0
  145. package/dist/esm/components/CnSavedViewsWidget/CnSavedViewsWidget.vue2.js.map +1 -0
  146. package/dist/esm/components/CnSavedViewsWidget/CnSavedViewsWidget.vue3.js +64 -0
  147. package/dist/esm/components/CnSavedViewsWidget/CnSavedViewsWidget.vue3.js.map +1 -0
  148. package/dist/esm/components/CnSavedViewsWidget/index.js +30 -0
  149. package/dist/esm/components/CnSavedViewsWidget/index.js.map +1 -0
  150. package/dist/esm/components/CnSectionsWidget/CnSectionsWidget.vue.js +10 -0
  151. package/dist/esm/components/CnSectionsWidget/CnSectionsWidget.vue.js.map +1 -0
  152. package/dist/esm/components/CnSectionsWidget/CnSectionsWidget.vue2.js +351 -0
  153. package/dist/esm/components/CnSectionsWidget/CnSectionsWidget.vue2.js.map +1 -0
  154. package/dist/esm/components/CnSectionsWidget/CnSectionsWidget.vue3.js +71 -0
  155. package/dist/esm/components/CnSectionsWidget/CnSectionsWidget.vue3.js.map +1 -0
  156. package/dist/esm/components/CnSectionsWidget/index.js +35 -0
  157. package/dist/esm/components/CnSectionsWidget/index.js.map +1 -0
  158. package/dist/esm/components/CnSegmentedControl/CnSegmentedControl.vue2.js.map +1 -1
  159. package/dist/esm/components/CnSegmentedControl/CnSegmentedControl.vue3.js.map +1 -1
  160. package/dist/esm/components/CnSettingsFormWidget/CnSettingsFormWidget.vue.js +10 -0
  161. package/dist/esm/components/CnSettingsFormWidget/CnSettingsFormWidget.vue.js.map +1 -0
  162. package/dist/esm/components/CnSettingsFormWidget/CnSettingsFormWidget.vue2.js +347 -0
  163. package/dist/esm/components/CnSettingsFormWidget/CnSettingsFormWidget.vue2.js.map +1 -0
  164. package/dist/esm/components/CnSettingsFormWidget/CnSettingsFormWidget.vue3.js +184 -0
  165. package/dist/esm/components/CnSettingsFormWidget/CnSettingsFormWidget.vue3.js.map +1 -0
  166. package/dist/esm/components/CnSettingsFormWidget/index.js +27 -0
  167. package/dist/esm/components/CnSettingsFormWidget/index.js.map +1 -0
  168. package/dist/esm/components/CnStagesWidget/CnStagesWidget.vue2.js +81 -2
  169. package/dist/esm/components/CnStagesWidget/CnStagesWidget.vue2.js.map +1 -1
  170. package/dist/esm/components/CnStagesWidget/CnStagesWidget.vue3.js.map +1 -1
  171. package/dist/esm/components/CnStatWidget/CnStatWidget.vue2.js +87 -6
  172. package/dist/esm/components/CnStatWidget/CnStatWidget.vue2.js.map +1 -1
  173. package/dist/esm/components/CnStatWidget/CnStatWidget.vue3.js +1 -0
  174. package/dist/esm/components/CnStatWidget/CnStatWidget.vue3.js.map +1 -1
  175. package/dist/esm/components/CnStatsBlockWidget/CnStatsBlockWidget.vue2.js +84 -1
  176. package/dist/esm/components/CnStatsBlockWidget/CnStatsBlockWidget.vue2.js.map +1 -1
  177. package/dist/esm/components/CnStatsBlockWidget/CnStatsBlockWidget.vue3.js +85 -41
  178. package/dist/esm/components/CnStatsBlockWidget/CnStatsBlockWidget.vue3.js.map +1 -1
  179. package/dist/esm/components/CnSwitchRowsWidget/CnSwitchRowsWidget.vue.js +10 -0
  180. package/dist/esm/components/CnSwitchRowsWidget/CnSwitchRowsWidget.vue.js.map +1 -0
  181. package/dist/esm/components/CnSwitchRowsWidget/CnSwitchRowsWidget.vue2.js +159 -0
  182. package/dist/esm/components/CnSwitchRowsWidget/CnSwitchRowsWidget.vue2.js.map +1 -0
  183. package/dist/esm/components/CnSwitchRowsWidget/CnSwitchRowsWidget.vue3.js +60 -0
  184. package/dist/esm/components/CnSwitchRowsWidget/CnSwitchRowsWidget.vue3.js.map +1 -0
  185. package/dist/esm/components/CnSwitchRowsWidget/index.js +26 -0
  186. package/dist/esm/components/CnSwitchRowsWidget/index.js.map +1 -0
  187. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js +168 -7
  188. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js.map +1 -1
  189. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue3.js +86 -23
  190. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue3.js.map +1 -1
  191. package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue2.js +80 -1
  192. package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue2.js.map +1 -1
  193. package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue3.js +75 -32
  194. package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue3.js.map +1 -1
  195. package/dist/esm/components/CnToggleTableWidget/CnToggleTableWidget.vue.js +10 -0
  196. package/dist/esm/components/CnToggleTableWidget/CnToggleTableWidget.vue.js.map +1 -0
  197. package/dist/esm/components/CnToggleTableWidget/CnToggleTableWidget.vue2.js +269 -0
  198. package/dist/esm/components/CnToggleTableWidget/CnToggleTableWidget.vue2.js.map +1 -0
  199. package/dist/esm/components/CnToggleTableWidget/CnToggleTableWidget.vue3.js +106 -0
  200. package/dist/esm/components/CnToggleTableWidget/CnToggleTableWidget.vue3.js.map +1 -0
  201. package/dist/esm/components/CnToggleTableWidget/index.js +27 -0
  202. package/dist/esm/components/CnToggleTableWidget/index.js.map +1 -0
  203. package/dist/esm/components/CnWidgetGrid/registerDashboardWidgets.js +11 -0
  204. package/dist/esm/components/CnWidgetGrid/registerDashboardWidgets.js.map +1 -1
  205. package/dist/esm/components/CnWidgetObjectTable/CnWidgetObjectTable.vue2.js +7 -2
  206. package/dist/esm/components/CnWidgetObjectTable/CnWidgetObjectTable.vue2.js.map +1 -1
  207. package/dist/esm/components/CnWidgetObjectTable/CnWidgetObjectTable.vue3.js.map +1 -1
  208. package/dist/esm/components/CnWidgetObjectTable/dashboardRegistration.js +5 -0
  209. package/dist/esm/components/CnWidgetObjectTable/dashboardRegistration.js.map +1 -1
  210. package/dist/esm/components/CnWorkspaceFilterWidget/CnWorkspaceFilterWidget.vue2.js +301 -6
  211. package/dist/esm/components/CnWorkspaceFilterWidget/CnWorkspaceFilterWidget.vue2.js.map +1 -1
  212. package/dist/esm/components/CnWorkspaceFilterWidget/CnWorkspaceFilterWidget.vue3.js +153 -55
  213. package/dist/esm/components/CnWorkspaceFilterWidget/CnWorkspaceFilterWidget.vue3.js.map +1 -1
  214. package/dist/esm/composables/useFormDraft.js +140 -9
  215. package/dist/esm/composables/useFormDraft.js.map +1 -1
  216. package/dist/esm/composables/useListView.js +4 -4
  217. package/dist/esm/composables/useListView.js.map +1 -1
  218. package/dist/esm/index.js +21 -1
  219. package/dist/esm/index.js.map +1 -1
  220. package/dist/esm/integrations/builtin/field-inspection/CnFieldInspectionCard.vue2.js +28 -20
  221. package/dist/esm/integrations/builtin/field-inspection/CnFieldInspectionCard.vue2.js.map +1 -1
  222. package/dist/esm/integrations/builtin/field-inspection/CnFieldInspectionCard.vue3.js +9 -0
  223. package/dist/esm/integrations/builtin/field-inspection/CnFieldInspectionCard.vue3.js.map +1 -1
  224. package/dist/esm/integrations/builtin/field-inspection.js +21 -0
  225. package/dist/esm/integrations/builtin/field-inspection.js.map +1 -1
  226. package/dist/esm/integrations/offline/checklistSubmission.js +141 -0
  227. package/dist/esm/integrations/offline/checklistSubmission.js.map +1 -0
  228. package/dist/esm/integrations/offline/fieldCollectionHelpers.js +70 -5
  229. package/dist/esm/integrations/offline/fieldCollectionHelpers.js.map +1 -1
  230. package/dist/esm/integrations/offline/index.js +2 -1
  231. package/dist/esm/integrations/offline/index.js.map +1 -1
  232. package/dist/esm/integrations/offline/offlineDb.js +6 -1
  233. package/dist/esm/integrations/offline/offlineDb.js.map +1 -1
  234. package/dist/esm/integrations/offline/syncReplayService.js +8 -2
  235. package/dist/esm/integrations/offline/syncReplayService.js.map +1 -1
  236. package/dist/esm/l10n/en.json.js +20 -1
  237. package/dist/esm/l10n/en.json.js.map +1 -1
  238. package/dist/esm/l10n/nl.json.js +70 -2
  239. package/dist/esm/l10n/nl.json.js.map +1 -1
  240. package/dist/esm/nextcloud-vue.css +2192 -222
  241. package/dist/esm/utils/contentHeaderLink.js +51 -0
  242. package/dist/esm/utils/contentHeaderLink.js.map +1 -0
  243. package/dist/esm/utils/detailActionModel.js +60 -3
  244. package/dist/esm/utils/detailActionModel.js.map +1 -1
  245. package/dist/esm/utils/facets.js +75 -3
  246. package/dist/esm/utils/facets.js.map +1 -1
  247. package/dist/esm/utils/fetchFilterCounts.js +40 -5
  248. package/dist/esm/utils/fetchFilterCounts.js.map +1 -1
  249. package/dist/esm/utils/fillTemplate.js +120 -0
  250. package/dist/esm/utils/fillTemplate.js.map +1 -0
  251. package/dist/esm/utils/initials.js +32 -0
  252. package/dist/esm/utils/initials.js.map +1 -0
  253. package/dist/esm/utils/libraryWidgetKeys.js +11 -0
  254. package/dist/esm/utils/libraryWidgetKeys.js.map +1 -1
  255. package/dist/esm/utils/objectWrite.js +59 -0
  256. package/dist/esm/utils/objectWrite.js.map +1 -0
  257. package/dist/esm/utils/pageControls.js +81 -0
  258. package/dist/esm/utils/pageControls.js.map +1 -0
  259. package/dist/esm/utils/personalLenses.js +40 -3
  260. package/dist/esm/utils/personalLenses.js.map +1 -1
  261. package/dist/esm/utils/queryPresets.js +96 -0
  262. package/dist/esm/utils/queryPresets.js.map +1 -0
  263. package/dist/esm/utils/resolveFilterTokens.js +12 -1
  264. package/dist/esm/utils/resolveFilterTokens.js.map +1 -1
  265. package/dist/esm/utils/resolveManifestTokens.js +2 -0
  266. package/dist/esm/utils/resolveManifestTokens.js.map +1 -1
  267. package/dist/esm/utils/schema.js +21 -0
  268. package/dist/esm/utils/schema.js.map +1 -1
  269. package/dist/esm/utils/sentinelTokens.js +22 -4
  270. package/dist/esm/utils/sentinelTokens.js.map +1 -1
  271. package/dist/esm/utils/userGroupsPeek.js +91 -0
  272. package/dist/esm/utils/userGroupsPeek.js.map +1 -0
  273. package/dist/esm/utils/validateManifestV2.compiled.js +3 -3
  274. package/dist/esm/utils/validateManifestV2.compiled.js.map +1 -1
  275. package/dist/esm/utils/visibleWhen.js +57 -5
  276. package/dist/esm/utils/visibleWhen.js.map +1 -1
  277. package/dist/esm/utils/widgetDispatch.js +7 -1
  278. package/dist/esm/utils/widgetDispatch.js.map +1 -1
  279. package/dist/esm/utils/widgetVisibility.js +4 -57
  280. package/dist/esm/utils/widgetVisibility.js.map +1 -1
  281. package/dist/nextcloud-vue.cjs.js +19708 -9301
  282. package/dist/nextcloud-vue.cjs.js.map +2 -2
  283. package/dist/nextcloud-vue.css +2192 -222
  284. package/l10n/en.json +20 -1
  285. package/l10n/nl.json +70 -2
  286. package/package.json +2 -1
  287. package/scripts/check-docs-mdx.mjs +108 -0
  288. package/src/components/CnActionButtons/CnActionButtons.vue +2 -0
  289. package/src/components/CnActionsBar/CnActionsBar.md +4 -0
  290. package/src/components/CnActionsBar/CnActionsBar.vue +48 -11
  291. package/src/components/CnAppRoot/CnAppRoot.md +4 -2
  292. package/src/components/CnAppRoot/CnAppRoot.vue +151 -59
  293. package/src/components/CnBannerWidget/CnBannerWidget.vue +244 -23
  294. package/src/components/CnCellRenderer/CnCellRenderer.md +2 -0
  295. package/src/components/CnCellRenderer/CnCellRenderer.vue +235 -5
  296. package/src/components/CnChipsFieldWidget/CnChipsFieldWidget.vue +433 -0
  297. package/src/components/CnChipsFieldWidget/index.js +25 -0
  298. package/src/components/CnChoicePickerWidget/CnChoicePickerWidget.vue +556 -0
  299. package/src/components/CnChoicePickerWidget/index.js +26 -0
  300. package/src/components/CnConversationThread/CnConversationWidget.vue +1 -1
  301. package/src/components/CnDashboardGrid/CnDashboardGrid.vue +2 -2
  302. package/src/components/CnDashboardPage/CnDashboardPage.vue +78 -5
  303. package/src/components/CnDataTable/CnDataTable.vue +22 -12
  304. package/src/components/CnDetailPage/CnDetailPage.md +1 -1
  305. package/src/components/CnDetailPage/CnDetailPage.vue +152 -6
  306. package/src/components/CnDetailWidgetHost/CnDetailWidgetHost.vue +66 -0
  307. package/src/components/CnDocumentReviewList/CnDocumentReviewWidget.vue +1 -1
  308. package/src/components/CnFacetSidebar/CnFacetSidebar.vue +7 -7
  309. package/src/components/CnFactsWidget/CnFactsWidget.vue +1190 -0
  310. package/src/components/CnFactsWidget/index.js +29 -0
  311. package/src/components/CnFieldListWidget/CnFieldListWidget.vue +1008 -0
  312. package/src/components/CnFieldListWidget/index.js +28 -0
  313. package/src/components/CnFilesBrowser/CnFilesBrowser.vue +588 -117
  314. package/src/components/CnFilesBrowser/filesBrowser.js +100 -0
  315. package/src/components/CnFilesBrowser/filesBrowserColumns.js +140 -0
  316. package/src/components/CnFormDialog/CnFormDialog.md +9 -3
  317. package/src/components/CnFormDialog/CnFormDialog.vue +69 -21
  318. package/src/components/CnFormPage/CnFormPage.vue +99 -3
  319. package/src/components/CnIndexPage/CnIndexPage.vue +309 -9
  320. package/src/components/CnIndexPage/CnIndexPageWidgets.vue +169 -0
  321. package/src/components/CnIndexSidebar/CnIndexSidebar.vue +7 -7
  322. package/src/components/CnNextStepCard/CnNextStepWidget.vue +1 -1
  323. package/src/components/CnObjectListWidget/CnObjectListWidget.vue +69 -2
  324. package/src/components/CnObjectSidebar/CnFilesTab.vue +70 -1
  325. package/src/components/CnObjectSidebar/CnNotesTab.vue +16 -0
  326. package/src/components/CnPageRenderer/CnPageRenderer.vue +29 -1
  327. package/src/components/CnRadioCardsWidget/CnRadioCardsWidget.vue +313 -0
  328. package/src/components/CnRadioCardsWidget/index.js +27 -0
  329. package/src/components/CnRecordListWidget/CnRecordListWidget.vue +652 -0
  330. package/src/components/CnRecordListWidget/index.js +30 -0
  331. package/src/components/CnSavedViewsWidget/CnSavedViewsWidget.vue +296 -0
  332. package/src/components/CnSavedViewsWidget/index.js +29 -0
  333. package/src/components/CnSectionsWidget/CnSectionsWidget.vue +489 -0
  334. package/src/components/CnSectionsWidget/index.js +34 -0
  335. package/src/components/CnSegmentedControl/CnSegmentedControl.vue +13 -0
  336. package/src/components/CnSettingsFormWidget/CnSettingsFormWidget.vue +555 -0
  337. package/src/components/CnSettingsFormWidget/index.js +26 -0
  338. package/src/components/CnStagesWidget/CnStagesWidget.vue +81 -2
  339. package/src/components/CnStatWidget/CnStatWidget.vue +88 -7
  340. package/src/components/CnStatsBlockWidget/CnStatsBlockWidget.vue +180 -3
  341. package/src/components/CnSwitchRowsWidget/CnSwitchRowsWidget.vue +226 -0
  342. package/src/components/CnSwitchRowsWidget/index.js +25 -0
  343. package/src/components/CnTabsWidget/CnTabsWidget.vue +263 -8
  344. package/src/components/CnTasksWidget/CnTasksWidget.vue +175 -15
  345. package/src/components/CnToggleTableWidget/CnToggleTableWidget.vue +386 -0
  346. package/src/components/CnToggleTableWidget/index.js +26 -0
  347. package/src/components/CnWidgetGrid/registerDashboardWidgets.js +11 -0
  348. package/src/components/CnWidgetObjectTable/CnWidgetObjectTable.vue +7 -2
  349. package/src/components/CnWidgetObjectTable/dashboardRegistration.js +5 -0
  350. package/src/components/CnWorkspaceFilterWidget/CnWorkspaceFilterWidget.vue +493 -11
  351. package/src/components/index.js +19 -0
  352. package/src/composables/__tests__/useFormDraft.spec.js +69 -0
  353. package/src/composables/useFormDraft.js +139 -8
  354. package/src/composables/useListView.js +4 -4
  355. package/src/css/form-field.css +14 -0
  356. package/src/css/index-page.css +71 -0
  357. package/src/css/kpi-card.css +32 -0
  358. package/src/css/look-board-detail.css +113 -2
  359. package/src/css/look-board-index.css +90 -8
  360. package/src/css/look-board.css +109 -2
  361. package/src/css/table.css +19 -0
  362. package/src/index.js +19 -0
  363. package/src/integrations/builtin/field-inspection/CnFieldInspectionCard.vue +35 -20
  364. package/src/integrations/builtin/field-inspection.js +21 -0
  365. package/src/integrations/offline/checklistSubmission.js +137 -0
  366. package/src/integrations/offline/fieldCollectionHelpers.js +69 -4
  367. package/src/integrations/offline/index.js +3 -0
  368. package/src/integrations/offline/offlineDb.js +6 -1
  369. package/src/integrations/offline/syncReplayService.js +8 -2
  370. package/src/schemas/app-manifest-v2.schema.json +196 -13
  371. package/src/utils/contentHeaderLink.js +48 -0
  372. package/src/utils/detailActionModel.js +59 -2
  373. package/src/utils/facets.js +74 -2
  374. package/src/utils/fetchFilterCounts.js +39 -4
  375. package/src/utils/fillTemplate.js +116 -0
  376. package/src/utils/initials.js +29 -0
  377. package/src/utils/libraryWidgetKeys.js +11 -0
  378. package/src/utils/objectWrite.js +55 -0
  379. package/src/utils/pageControls.js +78 -0
  380. package/src/utils/personalLenses.js +39 -2
  381. package/src/utils/queryPresets.js +93 -0
  382. package/src/utils/resolveFilterTokens.js +14 -1
  383. package/src/utils/resolveManifestTokens.js +2 -0
  384. package/src/utils/schema.js +21 -0
  385. package/src/utils/sentinelTokens.js +22 -4
  386. package/src/utils/userGroupsPeek.js +87 -0
  387. package/src/utils/validateManifestV2.compiled.js +3 -3
  388. package/src/utils/visibleWhen.js +56 -4
  389. package/src/utils/widgetDispatch.js +7 -1
  390. package/src/utils/widgetVisibility.js +7 -56
@@ -50,7 +50,7 @@ import { resolveFilterValue, resolveFilterTokens } from './resolveFilterTokens.j
50
50
 
51
51
 
52
52
  /** Supported visibleWhen comparison operators. */
53
- const VISIBLE_WHEN_OPS = ['eq', 'neq', 'gt', 'gte', 'lt', 'lte', 'empty', 'notEmpty'];
53
+ const VISIBLE_WHEN_OPS = ['eq', 'neq', 'gt', 'gte', 'lt', 'lte', 'empty', 'notEmpty', 'in'];
54
54
 
55
55
  /**
56
56
  * Read a dot-path off an object (`'a.b.c'`); the object itself when no
@@ -94,6 +94,12 @@ function compareVisibleWhen(actual, op, expected, ctx) {
94
94
  // The shared @-token grammar, so a condition can name the READER (`@me`)
95
95
  // rather than a literal only the server knows.
96
96
  const right = resolveFilterValue(expected, ctx || {});
97
+ // `in` holds when the left-hand value is one of the listed values
98
+ // (screens-page-lenses: a widget shown under several chips).
99
+ if (operator === 'in') {
100
+ const list = Array.isArray(right) ? right : [right];
101
+ return list.some((entry) => entry === actual || String(entry) === String(actual))
102
+ }
97
103
  if (operator === 'eq' || operator === 'neq') {
98
104
  const equal = actual === right || String(actual) === String(right);
99
105
  return operator === 'eq' ? equal : !equal
@@ -115,17 +121,53 @@ function compareVisibleWhen(actual, op, expected, ctx) {
115
121
  return a <= b
116
122
  }
117
123
 
124
+ /**
125
+ * Whether a condition reads the page workspace context (`workspace: "<key>"`).
126
+ * Such a condition is answered synchronously from the reactive bag, so a
127
+ * widget appears and disappears the moment a page control writes its key
128
+ * (screens-page-lenses). A condition that also names an endpoint or a source
129
+ * is not a workspace condition.
130
+ *
131
+ * @param {object|null} cond The visibleWhen condition.
132
+ * @return {boolean} True for a workspace-mode condition.
133
+ * @spec openspec/changes/screens-page-lenses/specs/page-lenses/spec.md#requirement-a-widget-can-be-shown-by-a-workspace-value
134
+ */
135
+ function isWorkspaceCondition(cond) {
136
+ return Boolean(cond) && typeof cond === 'object' && typeof cond.workspace === 'string' && cond.workspace !== ''
137
+ && !cond.endpoint && !cond.source
138
+ }
139
+
140
+ /**
141
+ * Evaluate a workspace-mode condition against the workspace bag. No fetch.
142
+ * A key nobody wrote is unset, so only `empty` and `neq` hold for it.
143
+ *
144
+ * @param {{workspace: string, op?: string, value?: unknown}} cond The condition.
145
+ * @param {object} [workspace] The plain workspace bag.
146
+ * @return {boolean} Whether the guarded element shows.
147
+ * @spec openspec/changes/screens-page-lenses/specs/page-lenses/spec.md#requirement-a-widget-can-be-shown-by-a-workspace-value
148
+ */
149
+ function evaluateWorkspaceCondition(cond, workspace) {
150
+ const bag = workspace && typeof workspace === 'object' ? workspace : {};
151
+ return compareVisibleWhen(bag[cond.workspace], cond.op || 'eq', cond.value, { workspace: bag })
152
+ }
153
+
118
154
  /**
119
155
  * Resolve the condition's left-hand value from its endpoint / OpenRegister
120
156
  * source / local object context (see the module docblock for the three
121
157
  * modes). Throws on unusable conditions and failed fetches — callers that
122
158
  * want the fail-safe boolean use {@link evaluateVisibleWhen}.
123
159
  *
124
- * @param {{endpoint?: string, source?: {register: string, schema: string, filter?: object}, field?: string}} cond The visibleWhen condition.
160
+ * A `source` may carry `order` (`{ field: "asc" | "desc" }`), so "the first
161
+ * row" is the first of an ordered query. A caller that wants that row, not
162
+ * just the value, passes `sink`: the first result is written to `sink.row`.
163
+ *
164
+ * @param {{endpoint?: string, source?: {register: string, schema: string, filter?: object, order?: object}, field?: string}} cond The visibleWhen condition.
125
165
  * @param {{objectId?: (string|number), object?: object, workspace?: object, config?: object}} [ctx] The caller's token / object context.
166
+ * @param {{row?: object}} [sink] Receives the first result of a `source` query as `row`.
126
167
  * @return {Promise<unknown>} The value `field` points at.
168
+ * @spec openspec/changes/screens-start-here-banner/specs/start-here-banner/spec.md#requirement-a-banner-can-name-the-first-row-of-a-query
127
169
  */
128
- async function readVisibleWhenValue(cond, ctx) {
170
+ async function readVisibleWhenValue(cond, ctx, sink) {
129
171
  if (cond.endpoint) {
130
172
  const response = await fetch(prefixUrl(cond.endpoint), { headers: buildHeaders() });
131
173
  if (!response.ok) {
@@ -137,7 +179,11 @@ async function readVisibleWhenValue(cond, ctx) {
137
179
  const src = cond.source;
138
180
  if (src && src.register && src.schema) {
139
181
  const filter = resolveFilterTokens(src.filter || {}, ctx);
140
- const qs = buildQueryString({ ...filter, _limit: 1 });
182
+ const order = {};
183
+ for (const [field, dir] of Object.entries(src.order && typeof src.order === 'object' ? src.order : {})) {
184
+ order[`_order[${field}]`] = dir === 'desc' ? 'desc' : 'asc';
185
+ }
186
+ const qs = buildQueryString({ ...filter, ...order, _limit: 1 });
141
187
  const url = prefixUrl(`/apps/openregister/api/objects/${src.register}/${src.schema}${qs}`);
142
188
  const response = await fetch(url, { headers: buildHeaders() });
143
189
  if (!response.ok) {
@@ -148,6 +194,9 @@ async function readVisibleWhenValue(cond, ctx) {
148
194
  return data.total ?? (Array.isArray(data.results) ? data.results.length : 0)
149
195
  }
150
196
  const first = Array.isArray(data.results) ? data.results[0] : data;
197
+ if (sink && typeof sink === 'object') {
198
+ sink.row = first && typeof first === 'object' ? first : undefined;
199
+ }
151
200
  return readVisibleWhenPath(first, cond.field)
152
201
  }
153
202
  // Local mode (Wave 3): evaluate against the caller's object context.
@@ -186,6 +235,9 @@ async function evaluateVisibleWhen(cond, ctx) {
186
235
  return false
187
236
  }
188
237
  }
238
+ if (isWorkspaceCondition(cond)) {
239
+ return evaluateWorkspaceCondition(cond, ctx && ctx.workspace)
240
+ }
189
241
  try {
190
242
  // `appInstalled` is checked FIRST and on its own: it answers "is the app
191
243
  // that backs this action even here", which has to settle before any of
@@ -302,5 +354,5 @@ function isLocallyDecidableVisibleWhen(cond) {
302
354
  return !cond.endpoint && !cond.source
303
355
  }
304
356
 
305
- export { VISIBLE_WHEN_OPS, compareVisibleWhen, evaluateVisibleWhen, evaluateVisibleWhenLocal, isLocallyDecidableVisibleWhen, readVisibleWhenPath, readVisibleWhenValue };
357
+ export { VISIBLE_WHEN_OPS, compareVisibleWhen, evaluateVisibleWhen, evaluateVisibleWhenLocal, evaluateWorkspaceCondition, isLocallyDecidableVisibleWhen, isWorkspaceCondition, readVisibleWhenPath, readVisibleWhenValue };
306
358
  //# sourceMappingURL=visibleWhen.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"visibleWhen.js","sources":["../../../src/utils/visibleWhen.js"],"sourcesContent":["/**\n * SPDX-FileCopyrightText: 2026 Conduction B.V.\n * SPDX-License-Identifier: EUPL-1.2\n *\n * visibleWhen — the shared declarative visibility predicate (Wave 1 banner\n * shape, generalised in Wave 3 of nextcloud-vue#91 for manifest actions).\n *\n * A `visibleWhen` condition is\n * `{ appInstalled?, endpoint?, source?, field?, op?, value }`.\n *\n * `appInstalled` is a precondition rather than a mode: it names the Nextcloud\n * app that backs the guarded element, and it is checked before anything else.\n * On its own it IS the whole condition; combined with one of the modes below\n * it gates that mode. It exists because the menu's `visibleIf` already spoke\n * this word and `visibleWhen` did not, so the same manifest vocabulary meant\n * two different things in two places.\n *\n * The value itself comes from one of THREE evaluation modes (first match wins):\n *\n * 1. `endpoint` — GET a same-origin JSON endpoint; `field` is a dot-path\n * into the response body.\n * 2. `source` — `{ register, schema, filter? }`, an OpenRegister object\n * query (`filter` supports the shared @-token grammar). `field` is a\n * dot-path into the FIRST result; omit it — or use `@total` — to\n * compare the collection total.\n * 3. Neither — the LOCAL mode (Wave 3): `field` is a dot-path into the\n * caller's object context (`ctx.object`, e.g. the loaded detail-page\n * record) — no request is made. This is how detail header actions gate\n * on the current record's state (`{ field: \"lifecycleState\", op: \"eq\",\n * value: \"approved\" }`).\n *\n * `op` is `eq | neq | gt | gte | lt | lte` (default `eq`); `value` is the\n * literal right-hand side. Evaluation is FAIL-SAFE: any fetch / shape error\n * resolves `false` (hidden) — a broken predicate never breaks a page.\n *\n * manifest-form-logic adds `evaluateVisibleWhenLocal(cond, data)`, a SYNC\n * counterpart to `evaluateVisibleWhen()` for the LOCAL mode only, composed\n * from `readVisibleWhenPath` + `compareVisibleWhen` with no fetch / promise.\n * `CnFormPage` calls it on every form-data change so conditions gating one\n * field on another's live value resolve without flicker. `endpoint` /\n * `source` conditions on form fields still go through the async\n * `evaluateVisibleWhen()`, evaluated once at mount and cached.\n *\n * @module utils/visibleWhen\n */\n\nimport { isAppInstalled } from './appInstalled.js'\nimport { buildHeaders, buildQueryString, prefixUrl } from './headers.js'\nimport { resolveFilterTokens, resolveFilterValue } from './resolveFilterTokens.js'\n\n/** Supported visibleWhen comparison operators. */\nexport const VISIBLE_WHEN_OPS = ['eq', 'neq', 'gt', 'gte', 'lt', 'lte', 'empty', 'notEmpty']\n\n/**\n * Read a dot-path off an object (`'a.b.c'`); the object itself when no\n * field is given.\n *\n * @param {object} data The source object.\n * @param {string} [field] Dot-path into the object.\n * @return {unknown} The value at the path (undefined on a missing segment).\n */\nexport function readVisibleWhenPath(data, field) {\n\tif (!field) {\n\t\treturn data\n\t}\n\treturn String(field).split('.').reduce((obj, key) => (obj === null || obj === undefined ? obj : obj[key]), data)\n}\n\n/**\n * Apply a visibleWhen comparison operator. Ordering operators coerce both\n * sides to Number; equality compares loosely-normalized primitives\n * (`String(a) === String(b)` when types differ) so `\"3\" eq 3` holds for\n * JSON round-trips.\n *\n * @param {unknown} actual The resolved left-hand value.\n * @param {string} op The operator (`eq` when unknown).\n * @param {unknown} expected The declared right-hand value.\n * @param {{objectId?: (string|number), object?: object, workspace?: object, config?: object}} [ctx] Token-resolution\n * context for the right-hand side, so `@object.<field>` and `@workspace.<key>` resolve\n * as well as `@me`. Omitted, only the context-free tokens resolve.\n * @return {boolean} Whether the comparison holds.\n */\nexport function compareVisibleWhen(actual, op, expected, ctx) {\n\tconst operator = VISIBLE_WHEN_OPS.includes(op) ? op : 'eq'\n\t// `empty` takes no `value`. It is the one question eq cannot ask: an unset\n\t// field arrives as undefined, null or '' depending on the store and the\n\t// serialiser, and `String(null)` is the word \"null\" rather than blank.\n\tif (operator === 'empty' || operator === 'notEmpty') {\n\t\tconst blank = actual === undefined || actual === null || actual === ''\n\t\t\t|| (Array.isArray(actual) === true && actual.length === 0)\n\t\treturn operator === 'empty' ? blank : !blank\n\t}\n\t// The shared @-token grammar, so a condition can name the READER (`@me`)\n\t// rather than a literal only the server knows.\n\tconst right = resolveFilterValue(expected, ctx || {})\n\tif (operator === 'eq' || operator === 'neq') {\n\t\tconst equal = actual === right || String(actual) === String(right)\n\t\treturn operator === 'eq' ? equal : !equal\n\t}\n\tconst a = Number(actual)\n\tconst b = Number(right)\n\tif (!Number.isFinite(a) || !Number.isFinite(b)) {\n\t\treturn false\n\t}\n\tif (operator === 'gt') {\n\t\treturn a > b\n\t}\n\tif (operator === 'gte') {\n\t\treturn a >= b\n\t}\n\tif (operator === 'lt') {\n\t\treturn a < b\n\t}\n\treturn a <= b\n}\n\n/**\n * Resolve the condition's left-hand value from its endpoint / OpenRegister\n * source / local object context (see the module docblock for the three\n * modes). Throws on unusable conditions and failed fetches — callers that\n * want the fail-safe boolean use {@link evaluateVisibleWhen}.\n *\n * @param {{endpoint?: string, source?: {register: string, schema: string, filter?: object}, field?: string}} cond The visibleWhen condition.\n * @param {{objectId?: (string|number), object?: object, workspace?: object, config?: object}} [ctx] The caller's token / object context.\n * @return {Promise<unknown>} The value `field` points at.\n */\nexport async function readVisibleWhenValue(cond, ctx) {\n\tif (cond.endpoint) {\n\t\tconst response = await fetch(prefixUrl(cond.endpoint), { headers: buildHeaders() })\n\t\tif (!response.ok) {\n\t\t\tthrow new Error(`endpoint returned ${response.status}`)\n\t\t}\n\t\tconst data = await response.json()\n\t\treturn readVisibleWhenPath(data, cond.field)\n\t}\n\tconst src = cond.source\n\tif (src && src.register && src.schema) {\n\t\tconst filter = resolveFilterTokens(src.filter || {}, ctx)\n\t\tconst qs = buildQueryString({ ...filter, _limit: 1 })\n\t\tconst url = prefixUrl(`/apps/openregister/api/objects/${src.register}/${src.schema}${qs}`)\n\t\tconst response = await fetch(url, { headers: buildHeaders() })\n\t\tif (!response.ok) {\n\t\t\tthrow new Error(`source returned ${response.status}`)\n\t\t}\n\t\tconst data = await response.json()\n\t\tif (!cond.field || cond.field === '@total') {\n\t\t\treturn data.total ?? (Array.isArray(data.results) ? data.results.length : 0)\n\t\t}\n\t\tconst first = Array.isArray(data.results) ? data.results[0] : data\n\t\treturn readVisibleWhenPath(first, cond.field)\n\t}\n\t// Local mode (Wave 3): evaluate against the caller's object context.\n\tif (cond.field && ctx && ctx.object && typeof ctx.object === 'object') {\n\t\treturn readVisibleWhenPath(ctx.object, cond.field)\n\t}\n\tthrow new Error('visibleWhen needs an endpoint, a source, or a field on the object context')\n}\n\n/**\n * Evaluate a visibleWhen condition to a boolean, FAIL-SAFE: any error\n * (fetch failure, unusable condition, missing context) resolves `false`.\n * A `null` / `undefined` condition resolves `true` (no condition = always\n * visible) so callers can pass the raw config value straight through.\n *\n * @param {{endpoint?: string, source?: object, field?: string, op?: string, value?: unknown}|null} cond The condition (or null).\n * @param {{objectId?: (string|number), object?: object, workspace?: object, config?: object}} [ctx] The caller's token / object context.\n * @return {Promise<boolean>} Whether the guarded element should show.\n */\nexport async function evaluateVisibleWhen(cond, ctx) {\n\tif (!cond) {\n\t\treturn true\n\t}\n\t// `all` / `any` compose conditions, so a gate can be more than one fact.\n\t// Without it a claim button could say \"not closed\" OR \"nobody holds it\",\n\t// never both, and the weaker of the two is the one that ships.\n\tif (Array.isArray(cond.all) === true || Array.isArray(cond.any) === true) {\n\t\ttry {\n\t\t\t// Read the key that IS an array: a malformed `{ all: {}, any: [] }`\n\t\t\t// enters this branch on `any`, and `cond.all ?? cond.any` would hand\n\t\t\t// the object to `.map`.\n\t\t\tconst parts = Array.isArray(cond.all) === true ? cond.all : cond.any\n\t\t\tconst results = await Promise.all(parts.map((part) => evaluateVisibleWhen(part, ctx)))\n\t\t\treturn Array.isArray(cond.all) === true ? results.every(Boolean) : results.some(Boolean)\n\t\t} catch {\n\t\t\treturn false\n\t\t}\n\t}\n\ttry {\n\t\t// `appInstalled` is checked FIRST and on its own: it answers \"is the app\n\t\t// that backs this action even here\", which has to settle before any of\n\t\t// the other modes are worth evaluating. The menu's `visibleIf` already\n\t\t// spoke this word, and `visibleWhen` did not, so a manifest author who\n\t\t// wrote `{ appInstalled: \"humaniq\" }` here got a condition with no\n\t\t// `field` — which the local mode rejects as malformed and hides. The\n\t\t// button then never appeared, and nothing said why.\n\t\tif (typeof cond.appInstalled === 'string' && cond.appInstalled !== '') {\n\t\t\tif (!isAppInstalled(cond.appInstalled)) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\t// `appInstalled` on its own IS the whole condition. Combined with a\n\t\t\t// field/endpoint/source it acts as a precondition, and evaluation\n\t\t\t// falls through to that.\n\t\t\tif (!cond.field && !cond.endpoint && !cond.source) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t}\n\t\tconst actual = await readVisibleWhenValue(cond, ctx)\n\t\treturn compareVisibleWhen(actual, cond.op || 'eq', cond.value, ctx)\n\t} catch (error) {\n\t\t// Still false; `ctx.onError` lets a caller (a journey run) record why.\n\t\tif (ctx && typeof ctx.onError === 'function') {\n\t\t\tctx.onError(error, cond)\n\t\t}\n\t\treturn false\n\t}\n}\n\n/**\n * Evaluate a LOCAL-mode visibleWhen condition synchronously against a\n * plain data object (`CnFormPage`'s live `formData`). No fetch, no\n * promise — pure composition of {@link readVisibleWhenPath} and\n * {@link compareVisibleWhen}, so it is safe to call on every keystroke.\n *\n * A nullish condition resolves `true` (no condition = always visible),\n * mirroring {@link evaluateVisibleWhen}'s fail-safe posture. A malformed\n * condition — not a plain object, missing `field`, or declaring\n * `endpoint` / `source` (those are NOT local-mode conditions) — resolves\n * `false` (hidden).\n *\n * @param {{field?: string, op?: string, value?: unknown}|null} cond The LOCAL visibleWhen condition (or null).\n * @param {object} data The live data object `field` dot-paths into (e.g. formData).\n * @return {boolean} Whether the guarded element should show.\n */\nexport function evaluateVisibleWhenLocal(cond, data) {\n\tif (cond === null || cond === undefined) {\n\t\treturn true\n\t}\n\tif (typeof cond !== 'object' || Array.isArray(cond)) {\n\t\treturn false\n\t}\n\tif (Array.isArray(cond.all) === true || Array.isArray(cond.any) === true) {\n\t\ttry {\n\t\t\tconst parts = Array.isArray(cond.all) === true ? cond.all : cond.any\n\t\t\tconst results = parts.map((part) => evaluateVisibleWhenLocal(part, data))\n\t\t\treturn Array.isArray(cond.all) === true ? results.every(Boolean) : results.some(Boolean)\n\t\t} catch {\n\t\t\t// Same posture as the async twin: a malformed composition hides the\n\t\t\t// one element, rather than throwing out of the computed that calls it\n\t\t\t// and taking the render with it.\n\t\t\treturn false\n\t\t}\n\t}\n\tif (cond.endpoint || cond.source) {\n\t\treturn false\n\t}\n\tif (typeof cond.appInstalled === 'string' && cond.appInstalled !== '') {\n\t\tif (!isAppInstalled(cond.appInstalled)) {\n\t\t\treturn false\n\t\t}\n\t\tif (!cond.field) {\n\t\t\treturn true\n\t\t}\n\t}\n\tif (typeof cond.field !== 'string' || cond.field.length === 0) {\n\t\treturn false\n\t}\n\ttry {\n\t\tconst actual = readVisibleWhenPath(data, cond.field)\n\t\t// The row / form record IS the object context here, so `@object.<field>`\n\t\t// on the right-hand side compares one field against another instead of\n\t\t// against the literal token string.\n\t\treturn compareVisibleWhen(actual, cond.op || 'eq', cond.value, { object: data })\n\t} catch {\n\t\treturn false\n\t}\n}\n\n/**\n * Whether {@link evaluateVisibleWhenLocal} can actually DECIDE a condition.\n *\n * It answers `false` to anything naming an `endpoint` or a `source`, because it\n * cannot fetch. That is right for a form field, where an undecidable gate should\n * hide — and wrong for a surface that had no gate at all before, which would\n * simply lose the element. Callers in the second group check this first and skip\n * the gate when it returns `false`.\n *\n * @param {object|null} cond The condition (or null).\n * @return {boolean} True when every leaf is a local `field` / `appInstalled` check.\n */\nexport function isLocallyDecidableVisibleWhen(cond) {\n\tif (cond === null || cond === undefined) {\n\t\treturn true\n\t}\n\tif (typeof cond !== 'object' || Array.isArray(cond)) {\n\t\treturn false\n\t}\n\tif (Array.isArray(cond.all) === true || Array.isArray(cond.any) === true) {\n\t\tconst parts = Array.isArray(cond.all) === true ? cond.all : cond.any\n\t\treturn parts.every((part) => isLocallyDecidableVisibleWhen(part))\n\t}\n\treturn !cond.endpoint && !cond.source\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"visibleWhen.js","sources":["../../../src/utils/visibleWhen.js"],"sourcesContent":["/**\n * SPDX-FileCopyrightText: 2026 Conduction B.V.\n * SPDX-License-Identifier: EUPL-1.2\n *\n * visibleWhen — the shared declarative visibility predicate (Wave 1 banner\n * shape, generalised in Wave 3 of nextcloud-vue#91 for manifest actions).\n *\n * A `visibleWhen` condition is\n * `{ appInstalled?, endpoint?, source?, field?, op?, value }`.\n *\n * `appInstalled` is a precondition rather than a mode: it names the Nextcloud\n * app that backs the guarded element, and it is checked before anything else.\n * On its own it IS the whole condition; combined with one of the modes below\n * it gates that mode. It exists because the menu's `visibleIf` already spoke\n * this word and `visibleWhen` did not, so the same manifest vocabulary meant\n * two different things in two places.\n *\n * The value itself comes from one of THREE evaluation modes (first match wins):\n *\n * 1. `endpoint` — GET a same-origin JSON endpoint; `field` is a dot-path\n * into the response body.\n * 2. `source` — `{ register, schema, filter? }`, an OpenRegister object\n * query (`filter` supports the shared @-token grammar). `field` is a\n * dot-path into the FIRST result; omit it — or use `@total` — to\n * compare the collection total.\n * 3. Neither — the LOCAL mode (Wave 3): `field` is a dot-path into the\n * caller's object context (`ctx.object`, e.g. the loaded detail-page\n * record) — no request is made. This is how detail header actions gate\n * on the current record's state (`{ field: \"lifecycleState\", op: \"eq\",\n * value: \"approved\" }`).\n *\n * `op` is `eq | neq | gt | gte | lt | lte` (default `eq`); `value` is the\n * literal right-hand side. Evaluation is FAIL-SAFE: any fetch / shape error\n * resolves `false` (hidden) — a broken predicate never breaks a page.\n *\n * manifest-form-logic adds `evaluateVisibleWhenLocal(cond, data)`, a SYNC\n * counterpart to `evaluateVisibleWhen()` for the LOCAL mode only, composed\n * from `readVisibleWhenPath` + `compareVisibleWhen` with no fetch / promise.\n * `CnFormPage` calls it on every form-data change so conditions gating one\n * field on another's live value resolve without flicker. `endpoint` /\n * `source` conditions on form fields still go through the async\n * `evaluateVisibleWhen()`, evaluated once at mount and cached.\n *\n * @module utils/visibleWhen\n */\n\nimport { isAppInstalled } from './appInstalled.js'\nimport { buildHeaders, buildQueryString, prefixUrl } from './headers.js'\nimport { resolveFilterTokens, resolveFilterValue } from './resolveFilterTokens.js'\n\n/** Supported visibleWhen comparison operators. */\nexport const VISIBLE_WHEN_OPS = ['eq', 'neq', 'gt', 'gte', 'lt', 'lte', 'empty', 'notEmpty', 'in']\n\n/**\n * Read a dot-path off an object (`'a.b.c'`); the object itself when no\n * field is given.\n *\n * @param {object} data The source object.\n * @param {string} [field] Dot-path into the object.\n * @return {unknown} The value at the path (undefined on a missing segment).\n */\nexport function readVisibleWhenPath(data, field) {\n\tif (!field) {\n\t\treturn data\n\t}\n\treturn String(field).split('.').reduce((obj, key) => (obj === null || obj === undefined ? obj : obj[key]), data)\n}\n\n/**\n * Apply a visibleWhen comparison operator. Ordering operators coerce both\n * sides to Number; equality compares loosely-normalized primitives\n * (`String(a) === String(b)` when types differ) so `\"3\" eq 3` holds for\n * JSON round-trips.\n *\n * @param {unknown} actual The resolved left-hand value.\n * @param {string} op The operator (`eq` when unknown).\n * @param {unknown} expected The declared right-hand value.\n * @param {{objectId?: (string|number), object?: object, workspace?: object, config?: object}} [ctx] Token-resolution\n * context for the right-hand side, so `@object.<field>` and `@workspace.<key>` resolve\n * as well as `@me`. Omitted, only the context-free tokens resolve.\n * @return {boolean} Whether the comparison holds.\n */\nexport function compareVisibleWhen(actual, op, expected, ctx) {\n\tconst operator = VISIBLE_WHEN_OPS.includes(op) ? op : 'eq'\n\t// `empty` takes no `value`. It is the one question eq cannot ask: an unset\n\t// field arrives as undefined, null or '' depending on the store and the\n\t// serialiser, and `String(null)` is the word \"null\" rather than blank.\n\tif (operator === 'empty' || operator === 'notEmpty') {\n\t\tconst blank = actual === undefined || actual === null || actual === ''\n\t\t\t|| (Array.isArray(actual) === true && actual.length === 0)\n\t\treturn operator === 'empty' ? blank : !blank\n\t}\n\t// The shared @-token grammar, so a condition can name the READER (`@me`)\n\t// rather than a literal only the server knows.\n\tconst right = resolveFilterValue(expected, ctx || {})\n\t// `in` holds when the left-hand value is one of the listed values\n\t// (screens-page-lenses: a widget shown under several chips).\n\tif (operator === 'in') {\n\t\tconst list = Array.isArray(right) ? right : [right]\n\t\treturn list.some((entry) => entry === actual || String(entry) === String(actual))\n\t}\n\tif (operator === 'eq' || operator === 'neq') {\n\t\tconst equal = actual === right || String(actual) === String(right)\n\t\treturn operator === 'eq' ? equal : !equal\n\t}\n\tconst a = Number(actual)\n\tconst b = Number(right)\n\tif (!Number.isFinite(a) || !Number.isFinite(b)) {\n\t\treturn false\n\t}\n\tif (operator === 'gt') {\n\t\treturn a > b\n\t}\n\tif (operator === 'gte') {\n\t\treturn a >= b\n\t}\n\tif (operator === 'lt') {\n\t\treturn a < b\n\t}\n\treturn a <= b\n}\n\n/**\n * Whether a condition reads the page workspace context (`workspace: \"<key>\"`).\n * Such a condition is answered synchronously from the reactive bag, so a\n * widget appears and disappears the moment a page control writes its key\n * (screens-page-lenses). A condition that also names an endpoint or a source\n * is not a workspace condition.\n *\n * @param {object|null} cond The visibleWhen condition.\n * @return {boolean} True for a workspace-mode condition.\n * @spec openspec/changes/screens-page-lenses/specs/page-lenses/spec.md#requirement-a-widget-can-be-shown-by-a-workspace-value\n */\nexport function isWorkspaceCondition(cond) {\n\treturn Boolean(cond) && typeof cond === 'object' && typeof cond.workspace === 'string' && cond.workspace !== ''\n\t\t&& !cond.endpoint && !cond.source\n}\n\n/**\n * Evaluate a workspace-mode condition against the workspace bag. No fetch.\n * A key nobody wrote is unset, so only `empty` and `neq` hold for it.\n *\n * @param {{workspace: string, op?: string, value?: unknown}} cond The condition.\n * @param {object} [workspace] The plain workspace bag.\n * @return {boolean} Whether the guarded element shows.\n * @spec openspec/changes/screens-page-lenses/specs/page-lenses/spec.md#requirement-a-widget-can-be-shown-by-a-workspace-value\n */\nexport function evaluateWorkspaceCondition(cond, workspace) {\n\tconst bag = workspace && typeof workspace === 'object' ? workspace : {}\n\treturn compareVisibleWhen(bag[cond.workspace], cond.op || 'eq', cond.value, { workspace: bag })\n}\n\n/**\n * Resolve the condition's left-hand value from its endpoint / OpenRegister\n * source / local object context (see the module docblock for the three\n * modes). Throws on unusable conditions and failed fetches — callers that\n * want the fail-safe boolean use {@link evaluateVisibleWhen}.\n *\n * A `source` may carry `order` (`{ field: \"asc\" | \"desc\" }`), so \"the first\n * row\" is the first of an ordered query. A caller that wants that row, not\n * just the value, passes `sink`: the first result is written to `sink.row`.\n *\n * @param {{endpoint?: string, source?: {register: string, schema: string, filter?: object, order?: object}, field?: string}} cond The visibleWhen condition.\n * @param {{objectId?: (string|number), object?: object, workspace?: object, config?: object}} [ctx] The caller's token / object context.\n * @param {{row?: object}} [sink] Receives the first result of a `source` query as `row`.\n * @return {Promise<unknown>} The value `field` points at.\n * @spec openspec/changes/screens-start-here-banner/specs/start-here-banner/spec.md#requirement-a-banner-can-name-the-first-row-of-a-query\n */\nexport async function readVisibleWhenValue(cond, ctx, sink) {\n\tif (cond.endpoint) {\n\t\tconst response = await fetch(prefixUrl(cond.endpoint), { headers: buildHeaders() })\n\t\tif (!response.ok) {\n\t\t\tthrow new Error(`endpoint returned ${response.status}`)\n\t\t}\n\t\tconst data = await response.json()\n\t\treturn readVisibleWhenPath(data, cond.field)\n\t}\n\tconst src = cond.source\n\tif (src && src.register && src.schema) {\n\t\tconst filter = resolveFilterTokens(src.filter || {}, ctx)\n\t\tconst order = {}\n\t\tfor (const [field, dir] of Object.entries(src.order && typeof src.order === 'object' ? src.order : {})) {\n\t\t\torder[`_order[${field}]`] = dir === 'desc' ? 'desc' : 'asc'\n\t\t}\n\t\tconst qs = buildQueryString({ ...filter, ...order, _limit: 1 })\n\t\tconst url = prefixUrl(`/apps/openregister/api/objects/${src.register}/${src.schema}${qs}`)\n\t\tconst response = await fetch(url, { headers: buildHeaders() })\n\t\tif (!response.ok) {\n\t\t\tthrow new Error(`source returned ${response.status}`)\n\t\t}\n\t\tconst data = await response.json()\n\t\tif (!cond.field || cond.field === '@total') {\n\t\t\treturn data.total ?? (Array.isArray(data.results) ? data.results.length : 0)\n\t\t}\n\t\tconst first = Array.isArray(data.results) ? data.results[0] : data\n\t\tif (sink && typeof sink === 'object') {\n\t\t\tsink.row = first && typeof first === 'object' ? first : undefined\n\t\t}\n\t\treturn readVisibleWhenPath(first, cond.field)\n\t}\n\t// Local mode (Wave 3): evaluate against the caller's object context.\n\tif (cond.field && ctx && ctx.object && typeof ctx.object === 'object') {\n\t\treturn readVisibleWhenPath(ctx.object, cond.field)\n\t}\n\tthrow new Error('visibleWhen needs an endpoint, a source, or a field on the object context')\n}\n\n/**\n * Evaluate a visibleWhen condition to a boolean, FAIL-SAFE: any error\n * (fetch failure, unusable condition, missing context) resolves `false`.\n * A `null` / `undefined` condition resolves `true` (no condition = always\n * visible) so callers can pass the raw config value straight through.\n *\n * @param {{endpoint?: string, source?: object, field?: string, op?: string, value?: unknown}|null} cond The condition (or null).\n * @param {{objectId?: (string|number), object?: object, workspace?: object, config?: object}} [ctx] The caller's token / object context.\n * @return {Promise<boolean>} Whether the guarded element should show.\n */\nexport async function evaluateVisibleWhen(cond, ctx) {\n\tif (!cond) {\n\t\treturn true\n\t}\n\t// `all` / `any` compose conditions, so a gate can be more than one fact.\n\t// Without it a claim button could say \"not closed\" OR \"nobody holds it\",\n\t// never both, and the weaker of the two is the one that ships.\n\tif (Array.isArray(cond.all) === true || Array.isArray(cond.any) === true) {\n\t\ttry {\n\t\t\t// Read the key that IS an array: a malformed `{ all: {}, any: [] }`\n\t\t\t// enters this branch on `any`, and `cond.all ?? cond.any` would hand\n\t\t\t// the object to `.map`.\n\t\t\tconst parts = Array.isArray(cond.all) === true ? cond.all : cond.any\n\t\t\tconst results = await Promise.all(parts.map((part) => evaluateVisibleWhen(part, ctx)))\n\t\t\treturn Array.isArray(cond.all) === true ? results.every(Boolean) : results.some(Boolean)\n\t\t} catch {\n\t\t\treturn false\n\t\t}\n\t}\n\tif (isWorkspaceCondition(cond)) {\n\t\treturn evaluateWorkspaceCondition(cond, ctx && ctx.workspace)\n\t}\n\ttry {\n\t\t// `appInstalled` is checked FIRST and on its own: it answers \"is the app\n\t\t// that backs this action even here\", which has to settle before any of\n\t\t// the other modes are worth evaluating. The menu's `visibleIf` already\n\t\t// spoke this word, and `visibleWhen` did not, so a manifest author who\n\t\t// wrote `{ appInstalled: \"humaniq\" }` here got a condition with no\n\t\t// `field` — which the local mode rejects as malformed and hides. The\n\t\t// button then never appeared, and nothing said why.\n\t\tif (typeof cond.appInstalled === 'string' && cond.appInstalled !== '') {\n\t\t\tif (!isAppInstalled(cond.appInstalled)) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\t// `appInstalled` on its own IS the whole condition. Combined with a\n\t\t\t// field/endpoint/source it acts as a precondition, and evaluation\n\t\t\t// falls through to that.\n\t\t\tif (!cond.field && !cond.endpoint && !cond.source) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t}\n\t\tconst actual = await readVisibleWhenValue(cond, ctx)\n\t\treturn compareVisibleWhen(actual, cond.op || 'eq', cond.value, ctx)\n\t} catch (error) {\n\t\t// Still false; `ctx.onError` lets a caller (a journey run) record why.\n\t\tif (ctx && typeof ctx.onError === 'function') {\n\t\t\tctx.onError(error, cond)\n\t\t}\n\t\treturn false\n\t}\n}\n\n/**\n * Evaluate a LOCAL-mode visibleWhen condition synchronously against a\n * plain data object (`CnFormPage`'s live `formData`). No fetch, no\n * promise — pure composition of {@link readVisibleWhenPath} and\n * {@link compareVisibleWhen}, so it is safe to call on every keystroke.\n *\n * A nullish condition resolves `true` (no condition = always visible),\n * mirroring {@link evaluateVisibleWhen}'s fail-safe posture. A malformed\n * condition — not a plain object, missing `field`, or declaring\n * `endpoint` / `source` (those are NOT local-mode conditions) — resolves\n * `false` (hidden).\n *\n * @param {{field?: string, op?: string, value?: unknown}|null} cond The LOCAL visibleWhen condition (or null).\n * @param {object} data The live data object `field` dot-paths into (e.g. formData).\n * @return {boolean} Whether the guarded element should show.\n */\nexport function evaluateVisibleWhenLocal(cond, data) {\n\tif (cond === null || cond === undefined) {\n\t\treturn true\n\t}\n\tif (typeof cond !== 'object' || Array.isArray(cond)) {\n\t\treturn false\n\t}\n\tif (Array.isArray(cond.all) === true || Array.isArray(cond.any) === true) {\n\t\ttry {\n\t\t\tconst parts = Array.isArray(cond.all) === true ? cond.all : cond.any\n\t\t\tconst results = parts.map((part) => evaluateVisibleWhenLocal(part, data))\n\t\t\treturn Array.isArray(cond.all) === true ? results.every(Boolean) : results.some(Boolean)\n\t\t} catch {\n\t\t\t// Same posture as the async twin: a malformed composition hides the\n\t\t\t// one element, rather than throwing out of the computed that calls it\n\t\t\t// and taking the render with it.\n\t\t\treturn false\n\t\t}\n\t}\n\tif (cond.endpoint || cond.source) {\n\t\treturn false\n\t}\n\tif (typeof cond.appInstalled === 'string' && cond.appInstalled !== '') {\n\t\tif (!isAppInstalled(cond.appInstalled)) {\n\t\t\treturn false\n\t\t}\n\t\tif (!cond.field) {\n\t\t\treturn true\n\t\t}\n\t}\n\tif (typeof cond.field !== 'string' || cond.field.length === 0) {\n\t\treturn false\n\t}\n\ttry {\n\t\tconst actual = readVisibleWhenPath(data, cond.field)\n\t\t// The row / form record IS the object context here, so `@object.<field>`\n\t\t// on the right-hand side compares one field against another instead of\n\t\t// against the literal token string.\n\t\treturn compareVisibleWhen(actual, cond.op || 'eq', cond.value, { object: data })\n\t} catch {\n\t\treturn false\n\t}\n}\n\n/**\n * Whether {@link evaluateVisibleWhenLocal} can actually DECIDE a condition.\n *\n * It answers `false` to anything naming an `endpoint` or a `source`, because it\n * cannot fetch. That is right for a form field, where an undecidable gate should\n * hide — and wrong for a surface that had no gate at all before, which would\n * simply lose the element. Callers in the second group check this first and skip\n * the gate when it returns `false`.\n *\n * @param {object|null} cond The condition (or null).\n * @return {boolean} True when every leaf is a local `field` / `appInstalled` check.\n */\nexport function isLocallyDecidableVisibleWhen(cond) {\n\tif (cond === null || cond === undefined) {\n\t\treturn true\n\t}\n\tif (typeof cond !== 'object' || Array.isArray(cond)) {\n\t\treturn false\n\t}\n\tif (Array.isArray(cond.all) === true || Array.isArray(cond.any) === true) {\n\t\tconst parts = Array.isArray(cond.all) === true ? cond.all : cond.any\n\t\treturn parts.every((part) => isLocallyDecidableVisibleWhen(part))\n\t}\n\treturn !cond.endpoint && !cond.source\n}\n"],"names":[],"mappings":"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"}
@@ -40,10 +40,16 @@ import { canonicalWidgetType } from './widgetTypeAliases.js';
40
40
  * because a run is started by a flow, never by a person clicking Add.
41
41
  * `tasks` follows for the same two reasons: a bare row list, and a task is
42
42
  * created by a flow, never by a person clicking Add.
43
+ * `facts` is a bare list of label/value rows about one object: on a side
44
+ * card it needs the same titled wrapper, and there is nothing to Add.
45
+ * `field-list` draws rows of one object field and carries its own add form,
46
+ * so it takes the titled wrapper and not the catalog Add action.
47
+ * `record-list` draws bare rows of another schema's objects; the card and its
48
+ * header (link, note) come from the host, and it has no Add.
43
49
  *
44
50
  * @type {string[]}
45
51
  */
46
- const CONTENT_ONLY_TYPES = Object.freeze(['object-list', 'table', 'files', 'flow-runs', 'tasks']);
52
+ const CONTENT_ONLY_TYPES = Object.freeze(['object-list', 'table', 'files', 'flow-runs', 'tasks', 'facts', 'field-list', 'record-list', 'settings-form', 'switch-rows', 'radio-cards', 'chips-field', 'toggle-table', 'choice-picker']);
47
53
 
48
54
  /**
49
55
  * The stored content/config blob for a widget definition.
@@ -1 +1 @@
1
- {"version":3,"file":"widgetDispatch.js","sources":["../../../src/utils/widgetDispatch.js"],"sourcesContent":["/**\n * SPDX-FileCopyrightText: 2026 Conduction B.V.\n * SPDX-License-Identifier: EUPL-1.2\n *\n * widgetDispatch — how a detail-page widget definition picks its renderer.\n *\n * These predicates used to live as methods on `CnDetailPage`, each one calling\n * `findWidget(item)` first. That was fine while the detail grid was the only\n * surface rendering a widget definition. `CnTabsWidget` is a second one: it\n * renders the SAME definitions with no card chrome, because the tab strip owns\n * the title and the Actions menu instead.\n *\n * Two copies of \"is this a card widget?\" is exactly the kind of thing that\n * drifts. One copy grows a type, the other does not, and the symptom is a\n * widget that renders correctly on the page and blank inside a tab, with\n * nothing in the console either way. So the decisions live here as pure\n * functions over a widget DEFINITION, and both surfaces import them.\n *\n * The functions take the resolved definition, not a layout item. Resolving an\n * item to a definition needs the surface's own widget list, which is the one\n * part that genuinely differs between the two.\n *\n * @module utils/widgetDispatch\n */\n\nimport { BUILT_IN_WIDGETS } from '../components/CnWidgetGrid/builtInWidgets.js'\nimport { getWidgetTypeEntry } from '../components/CnWidgetGrid/dashboardWidgetRegistry.js'\nimport { canonicalWidgetType } from './widgetTypeAliases.js'\n\n/**\n * Content-only catalog widgets: bare renderers with no chrome of their own.\n * On a card surface they need the titled wrapper; inside a tab panel the strip\n * already supplies the title, so they render bare.\n *\n * `flow-runs` belongs here for the same reason the lists do: it renders a bare\n * row list, so without the wrapper it appeared on the detail page as loose text\n * with no title and no card, which ADR-062 rule 5 forbids (\"every body widget\n * has card chrome and its manifest title\"). It is NOT in the Add-action list,\n * because a run is started by a flow, never by a person clicking Add.\n * `tasks` follows for the same two reasons: a bare row list, and a task is\n * created by a flow, never by a person clicking Add.\n *\n * @type {string[]}\n */\nexport const CONTENT_ONLY_TYPES = Object.freeze(['object-list', 'table', 'files', 'flow-runs', 'tasks'])\n\n/**\n * The stored content/config blob for a widget definition.\n *\n * @param {object} def The widget definition.\n * @return {object} The definition's `content`, or an empty object.\n */\nexport function widgetContentOf(def) {\n\treturn (def && def.content && typeof def.content === 'object') ? def.content : {}\n}\n\n/**\n * Whether the definition is the schema-driven `data` widget.\n *\n * @param {object} def The widget definition.\n * @return {boolean} true for `type: 'data'`.\n */\nexport function isDataWidgetDef(def) {\n\treturn Boolean(def) && def.type === 'data'\n}\n\n/**\n * Whether the definition is the schema-driven `related` widget.\n *\n * @param {object} def The widget definition.\n * @return {boolean} true for `type: 'related'`.\n */\nexport function isRelatedWidgetDef(def) {\n\treturn Boolean(def) && def.type === 'related'\n}\n\n/**\n * Whether the definition is the `object-geo` widget.\n *\n * @param {object} def The widget definition.\n * @return {boolean} true for `type: 'object-geo'`.\n */\nexport function isGeoWidgetDef(def) {\n\treturn Boolean(def) && def.type === 'object-geo'\n}\n\n/**\n * Whether the definition names a registered integration leaf.\n *\n * @param {object} def The widget definition.\n * @return {boolean} true for `type: 'integration'` with an `integrationId`.\n */\nexport function isIntegrationWidgetDef(def) {\n\treturn Boolean(def) && def.type === 'integration' && typeof def.integrationId === 'string'\n}\n\n/**\n * Whether the definition is a content-only catalog widget.\n *\n * @param {object} def The widget definition.\n * @return {boolean} true when the type is in {@link CONTENT_ONLY_TYPES}.\n */\nexport function isContentOnlyWidgetDef(def) {\n\treturn Boolean(def) && CONTENT_ONLY_TYPES.includes(def.type)\n}\n\n/**\n * Whether the definition is a registry \"card\" widget: a self-contained KPI,\n * gauge or delta tile that headlines itself (registry entry `card: true`).\n *\n * @param {object} def The widget definition.\n * @return {boolean} true when the registry entry declares `card`.\n */\nexport function isCardWidgetDef(def) {\n\tif (!def || !def.type) {\n\t\treturn false\n\t}\n\tconst entry = getWidgetTypeEntry(def.type)\n\treturn Boolean(entry && entry.card === true)\n}\n\n/**\n * Resolve the registered RENDERER for a content-driven catalog widget type.\n *\n * Integration widgets resolve separately, and `data` needs object context the\n * caller supplies, so both are excluded from this generic fallback.\n *\n * Resolution order is consumer registry, then the dashboard catalog, then\n * `BUILT_IN_WIDGETS`. Those last two were near-disjoint vocabularies until they\n * were unified here: the dashboard catalog held chart / map / object-list /\n * related / stats-block / table, `BUILT_IN_WIDGETS` held audit-trail / banner /\n * card-grid / data / divider / form-renderer / header / integration /\n * map-viewer / metadata / nav-card-grid / object-geo / related / text, and only\n * `related` was in both. A widget authored against one was invisible to the\n * other, and the surface rendered nothing while saying nothing about why. On\n * hrmq that was 101 of 236 detail widgets.\n *\n * @param {object} def The widget definition.\n * @param {object} [cnRegistry] The consumer's component registry, if any.\n * @return {object|null} The renderer component, or null.\n */\nexport function resolveRegistryRenderer(def, cnRegistry = {}) {\n\tif (!def || !def.type || def.type === 'integration' || def.type === 'data') {\n\t\treturn null\n\t}\n\t// Consumer registry FIRST — the order REQ-MVR-005 mandates (\"Custom widget\n\t// overrides built-in\"), and the order CnWidgetGrid already uses.\n\tconst consumer = (cnRegistry || {})[def.type]\n\tif (consumer) {\n\t\treturn consumer.component ?? consumer\n\t}\n\tconst entry = getWidgetTypeEntry(canonicalWidgetType(def.type))\n\tif (entry && entry.renderer) {\n\t\treturn entry.renderer\n\t}\n\treturn BUILT_IN_WIDGETS[canonicalWidgetType(def.type)] || BUILT_IN_WIDGETS[def.type] || null\n}\n\n/**\n * The effective title for a widget definition.\n *\n * A title-owning type (registry `ownsTitle`, e.g. `related`) keeps its editable\n * title in `content.title`, and that MUST win over the chrome `def.title`.\n * Otherwise a non-empty seed title permanently shadows the user's edit and the\n * title can never be changed. Without a `content.title` it falls back to\n * `def.title`. Every other type reads `def.title` first.\n *\n * @param {object} def The widget definition.\n * @return {string|undefined} The title, or undefined to let the widget default.\n */\nexport function widgetTitleOf(def) {\n\tif (!def) {\n\t\treturn undefined\n\t}\n\tconst content = widgetContentOf(def)\n\tconst entry = getWidgetTypeEntry(def.type)\n\tif (entry && entry.ownsTitle) {\n\t\t// A manifest that never set content.title keeps its def.title.\n\t\tif (typeof content.title !== 'string') {\n\t\t\treturn def.title || undefined\n\t\t}\n\t\treturn content.title || undefined\n\t}\n\treturn def.title || content.title || undefined\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"widgetDispatch.js","sources":["../../../src/utils/widgetDispatch.js"],"sourcesContent":["/**\n * SPDX-FileCopyrightText: 2026 Conduction B.V.\n * SPDX-License-Identifier: EUPL-1.2\n *\n * widgetDispatch — how a detail-page widget definition picks its renderer.\n *\n * These predicates used to live as methods on `CnDetailPage`, each one calling\n * `findWidget(item)` first. That was fine while the detail grid was the only\n * surface rendering a widget definition. `CnTabsWidget` is a second one: it\n * renders the SAME definitions with no card chrome, because the tab strip owns\n * the title and the Actions menu instead.\n *\n * Two copies of \"is this a card widget?\" is exactly the kind of thing that\n * drifts. One copy grows a type, the other does not, and the symptom is a\n * widget that renders correctly on the page and blank inside a tab, with\n * nothing in the console either way. So the decisions live here as pure\n * functions over a widget DEFINITION, and both surfaces import them.\n *\n * The functions take the resolved definition, not a layout item. Resolving an\n * item to a definition needs the surface's own widget list, which is the one\n * part that genuinely differs between the two.\n *\n * @module utils/widgetDispatch\n */\n\nimport { BUILT_IN_WIDGETS } from '../components/CnWidgetGrid/builtInWidgets.js'\nimport { getWidgetTypeEntry } from '../components/CnWidgetGrid/dashboardWidgetRegistry.js'\nimport { canonicalWidgetType } from './widgetTypeAliases.js'\n\n/**\n * Content-only catalog widgets: bare renderers with no chrome of their own.\n * On a card surface they need the titled wrapper; inside a tab panel the strip\n * already supplies the title, so they render bare.\n *\n * `flow-runs` belongs here for the same reason the lists do: it renders a bare\n * row list, so without the wrapper it appeared on the detail page as loose text\n * with no title and no card, which ADR-062 rule 5 forbids (\"every body widget\n * has card chrome and its manifest title\"). It is NOT in the Add-action list,\n * because a run is started by a flow, never by a person clicking Add.\n * `tasks` follows for the same two reasons: a bare row list, and a task is\n * created by a flow, never by a person clicking Add.\n * `facts` is a bare list of label/value rows about one object: on a side\n * card it needs the same titled wrapper, and there is nothing to Add.\n * `field-list` draws rows of one object field and carries its own add form,\n * so it takes the titled wrapper and not the catalog Add action.\n * `record-list` draws bare rows of another schema's objects; the card and its\n * header (link, note) come from the host, and it has no Add.\n *\n * @type {string[]}\n */\nexport const CONTENT_ONLY_TYPES = Object.freeze(['object-list', 'table', 'files', 'flow-runs', 'tasks', 'facts', 'field-list', 'record-list', 'settings-form', 'switch-rows', 'radio-cards', 'chips-field', 'toggle-table', 'choice-picker'])\n\n/**\n * The stored content/config blob for a widget definition.\n *\n * @param {object} def The widget definition.\n * @return {object} The definition's `content`, or an empty object.\n */\nexport function widgetContentOf(def) {\n\treturn (def && def.content && typeof def.content === 'object') ? def.content : {}\n}\n\n/**\n * Whether the definition is the schema-driven `data` widget.\n *\n * @param {object} def The widget definition.\n * @return {boolean} true for `type: 'data'`.\n */\nexport function isDataWidgetDef(def) {\n\treturn Boolean(def) && def.type === 'data'\n}\n\n/**\n * Whether the definition is the schema-driven `related` widget.\n *\n * @param {object} def The widget definition.\n * @return {boolean} true for `type: 'related'`.\n */\nexport function isRelatedWidgetDef(def) {\n\treturn Boolean(def) && def.type === 'related'\n}\n\n/**\n * Whether the definition is the `object-geo` widget.\n *\n * @param {object} def The widget definition.\n * @return {boolean} true for `type: 'object-geo'`.\n */\nexport function isGeoWidgetDef(def) {\n\treturn Boolean(def) && def.type === 'object-geo'\n}\n\n/**\n * Whether the definition names a registered integration leaf.\n *\n * @param {object} def The widget definition.\n * @return {boolean} true for `type: 'integration'` with an `integrationId`.\n */\nexport function isIntegrationWidgetDef(def) {\n\treturn Boolean(def) && def.type === 'integration' && typeof def.integrationId === 'string'\n}\n\n/**\n * Whether the definition is a content-only catalog widget.\n *\n * @param {object} def The widget definition.\n * @return {boolean} true when the type is in {@link CONTENT_ONLY_TYPES}.\n */\nexport function isContentOnlyWidgetDef(def) {\n\treturn Boolean(def) && CONTENT_ONLY_TYPES.includes(def.type)\n}\n\n/**\n * Whether the definition is a registry \"card\" widget: a self-contained KPI,\n * gauge or delta tile that headlines itself (registry entry `card: true`).\n *\n * @param {object} def The widget definition.\n * @return {boolean} true when the registry entry declares `card`.\n */\nexport function isCardWidgetDef(def) {\n\tif (!def || !def.type) {\n\t\treturn false\n\t}\n\tconst entry = getWidgetTypeEntry(def.type)\n\treturn Boolean(entry && entry.card === true)\n}\n\n/**\n * Resolve the registered RENDERER for a content-driven catalog widget type.\n *\n * Integration widgets resolve separately, and `data` needs object context the\n * caller supplies, so both are excluded from this generic fallback.\n *\n * Resolution order is consumer registry, then the dashboard catalog, then\n * `BUILT_IN_WIDGETS`. Those last two were near-disjoint vocabularies until they\n * were unified here: the dashboard catalog held chart / map / object-list /\n * related / stats-block / table, `BUILT_IN_WIDGETS` held audit-trail / banner /\n * card-grid / data / divider / form-renderer / header / integration /\n * map-viewer / metadata / nav-card-grid / object-geo / related / text, and only\n * `related` was in both. A widget authored against one was invisible to the\n * other, and the surface rendered nothing while saying nothing about why. On\n * hrmq that was 101 of 236 detail widgets.\n *\n * @param {object} def The widget definition.\n * @param {object} [cnRegistry] The consumer's component registry, if any.\n * @return {object|null} The renderer component, or null.\n */\nexport function resolveRegistryRenderer(def, cnRegistry = {}) {\n\tif (!def || !def.type || def.type === 'integration' || def.type === 'data') {\n\t\treturn null\n\t}\n\t// Consumer registry FIRST — the order REQ-MVR-005 mandates (\"Custom widget\n\t// overrides built-in\"), and the order CnWidgetGrid already uses.\n\tconst consumer = (cnRegistry || {})[def.type]\n\tif (consumer) {\n\t\treturn consumer.component ?? consumer\n\t}\n\tconst entry = getWidgetTypeEntry(canonicalWidgetType(def.type))\n\tif (entry && entry.renderer) {\n\t\treturn entry.renderer\n\t}\n\treturn BUILT_IN_WIDGETS[canonicalWidgetType(def.type)] || BUILT_IN_WIDGETS[def.type] || null\n}\n\n/**\n * The effective title for a widget definition.\n *\n * A title-owning type (registry `ownsTitle`, e.g. `related`) keeps its editable\n * title in `content.title`, and that MUST win over the chrome `def.title`.\n * Otherwise a non-empty seed title permanently shadows the user's edit and the\n * title can never be changed. Without a `content.title` it falls back to\n * `def.title`. Every other type reads `def.title` first.\n *\n * @param {object} def The widget definition.\n * @return {string|undefined} The title, or undefined to let the widget default.\n */\nexport function widgetTitleOf(def) {\n\tif (!def) {\n\t\treturn undefined\n\t}\n\tconst content = widgetContentOf(def)\n\tconst entry = getWidgetTypeEntry(def.type)\n\tif (entry && entry.ownsTitle) {\n\t\t// A manifest that never set content.title keeps its def.title.\n\t\tif (typeof content.title !== 'string') {\n\t\t\treturn def.title || undefined\n\t\t}\n\t\treturn content.title || undefined\n\t}\n\treturn def.title || content.title || undefined\n}\n"],"names":[],"mappings":"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"}
@@ -1,6 +1,7 @@
1
1
  import axios__default from '@nextcloud/axios';
2
2
  import { generateOcsUrl } from '@nextcloud/router';
3
- import { reactive } from 'vue';
3
+ import { getCurrentUserId, resetGroupsPeek } from './userGroupsPeek.js';
4
+ export { peekCurrentUserGroups } from './userGroupsPeek.js';
4
5
 
5
6
  /**
6
7
  * Cached user groups — fetched once per session and reused.
@@ -13,29 +14,6 @@ const _cache = {
13
14
  promise: null,
14
15
  };
15
16
 
16
- /**
17
- * Reactive mirror of the group cache, keyed by user id, for synchronous
18
- * readers ({@link peekCurrentUserGroups}). A computed that reads a missing key
19
- * tracks it, so it re-runs when the groups arrive.
20
- *
21
- * @type {{ byUser: Record<string, string[]> }}
22
- */
23
- const _peek = reactive({ byUser: {} });
24
-
25
- /** User ids whose groups a peek already asked for (not reactive on purpose). */
26
- const _peekRequested = new Set();
27
-
28
- /**
29
- * Get the current Nextcloud user ID from OC.currentUser.
30
- *
31
- * @return {string|null} The current user ID, or null if not logged in
32
- */
33
- function getCurrentUserId() {
34
- return window.OC?.currentUser?.uid
35
- || window.OC?.currentUser
36
- || null
37
- }
38
-
39
17
  /**
40
18
  * Fetch the current user's Nextcloud groups. Results are cached so the
41
19
  * OCS API is only called once per page load.
@@ -72,34 +50,6 @@ async function getCurrentUserGroups() {
72
50
  return _cache.groups
73
51
  }
74
52
 
75
- /**
76
- * Synchronous, reactive read of the current user's group ids, for code that
77
- * cannot await (the `@myGroups` filter token). Returns the ids once they are
78
- * loaded, `null` while the first request is in flight (and starts that
79
- * request on first use), and `[]` when nobody is signed in. Read inside a
80
- * computed, the computed re-runs when the groups arrive.
81
- *
82
- * @spec openspec/changes/nextcloud-group-surfaces/specs/schema-utilities/spec.md#requirement-mygroups-resolves-to-the-current-users-group-ids
83
- * @return {string[]|null} The group ids, or null while loading.
84
- */
85
- function peekCurrentUserGroups() {
86
- const userId = getCurrentUserId();
87
- if (!userId) {
88
- return []
89
- }
90
- const known = _peek.byUser[userId];
91
- if (Array.isArray(known)) {
92
- return known
93
- }
94
- if (!_peekRequested.has(userId)) {
95
- _peekRequested.add(userId);
96
- getCurrentUserGroups().then((groups) => {
97
- _peek.byUser[userId] = Array.isArray(groups) ? [...groups] : [];
98
- });
99
- }
100
- return null
101
- }
102
-
103
53
  /**
104
54
  * Internal: fetch groups from OCS API.
105
55
  *
@@ -202,11 +152,8 @@ function resetVisibilityCache() {
202
152
  _cache.userId = null;
203
153
  _cache.groups = null;
204
154
  _cache.promise = null;
205
- _peekRequested.clear();
206
- for (const key of Object.keys(_peek.byUser)) {
207
- delete _peek.byUser[key];
208
- }
155
+ resetGroupsPeek();
209
156
  }
210
157
 
211
- export { filterWidgetsByVisibility, getCurrentUserGroups, getCurrentUserId, isWidgetVisible, peekCurrentUserGroups, resetVisibilityCache };
158
+ export { filterWidgetsByVisibility, getCurrentUserGroups, getCurrentUserId, isWidgetVisible, resetVisibilityCache };
212
159
  //# sourceMappingURL=widgetVisibility.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"widgetVisibility.js","sources":["../../../src/utils/widgetVisibility.js"],"sourcesContent":["import axios from '@nextcloud/axios'\nimport { generateOcsUrl } from '@nextcloud/router'\nimport { reactive } from 'vue'\n\n/**\n * Cached user groups — fetched once per session and reused.\n *\n * @type {{ userId: string|null, groups: string[]|null, promise: Promise|null }}\n */\nconst _cache = {\n\tuserId: null,\n\tgroups: null,\n\tpromise: null,\n}\n\n/**\n * Reactive mirror of the group cache, keyed by user id, for synchronous\n * readers ({@link peekCurrentUserGroups}). A computed that reads a missing key\n * tracks it, so it re-runs when the groups arrive.\n *\n * @type {{ byUser: Record<string, string[]> }}\n */\nconst _peek = reactive({ byUser: {} })\n\n/** User ids whose groups a peek already asked for (not reactive on purpose). */\nconst _peekRequested = new Set()\n\n/**\n * Get the current Nextcloud user ID from OC.currentUser.\n *\n * @return {string|null} The current user ID, or null if not logged in\n */\nexport function getCurrentUserId() {\n\treturn window.OC?.currentUser?.uid\n\t\t|| window.OC?.currentUser\n\t\t|| null\n}\n\n/**\n * Fetch the current user's Nextcloud groups. Results are cached so the\n * OCS API is only called once per page load.\n *\n * @return {Promise<string[]>} Array of group IDs the current user belongs to\n */\nexport async function getCurrentUserGroups() {\n\tconst userId = getCurrentUserId()\n\tif (!userId) {\n\t\treturn []\n\t}\n\n\t// Return cached result if we already fetched for this user\n\tif (_cache.userId === userId && _cache.groups !== null) {\n\t\treturn _cache.groups\n\t}\n\n\t// If a fetch is already in progress for this user, await it\n\tif (_cache.userId === userId && _cache.promise) {\n\t\treturn _cache.promise\n\t}\n\n\t_cache.userId = userId\n\t_cache.promise = _fetchGroups(userId)\n\n\ttry {\n\t\t_cache.groups = await _cache.promise\n\t} catch {\n\t\t_cache.groups = []\n\t} finally {\n\t\t_cache.promise = null\n\t}\n\n\treturn _cache.groups\n}\n\n/**\n * Synchronous, reactive read of the current user's group ids, for code that\n * cannot await (the `@myGroups` filter token). Returns the ids once they are\n * loaded, `null` while the first request is in flight (and starts that\n * request on first use), and `[]` when nobody is signed in. Read inside a\n * computed, the computed re-runs when the groups arrive.\n *\n * @spec openspec/changes/nextcloud-group-surfaces/specs/schema-utilities/spec.md#requirement-mygroups-resolves-to-the-current-users-group-ids\n * @return {string[]|null} The group ids, or null while loading.\n */\nexport function peekCurrentUserGroups() {\n\tconst userId = getCurrentUserId()\n\tif (!userId) {\n\t\treturn []\n\t}\n\tconst known = _peek.byUser[userId]\n\tif (Array.isArray(known)) {\n\t\treturn known\n\t}\n\tif (!_peekRequested.has(userId)) {\n\t\t_peekRequested.add(userId)\n\t\tgetCurrentUserGroups().then((groups) => {\n\t\t\t_peek.byUser[userId] = Array.isArray(groups) ? [...groups] : []\n\t\t})\n\t}\n\treturn null\n}\n\n/**\n * Internal: fetch groups from OCS API.\n *\n * @param {string} userId The user ID to look up\n * @return {Promise<string[]>} Array of group IDs\n */\nasync function _fetchGroups(userId) {\n\ttry {\n\t\tconst url = generateOcsUrl('/cloud/users/{userId}/groups', { userId })\n\t\tconst response = await axios.get(url)\n\t\tconst groups = response.data?.ocs?.data?.groups || []\n\t\treturn groups\n\t} catch (error) {\n\t\t// eslint-disable-next-line no-console -- diagnostic for a failure this code already degrades from\n\t\tconsole.error('[widgetVisibility] Failed to fetch user groups:', error)\n\t\treturn []\n\t}\n}\n\n/**\n * Check whether a single widget is visible to the current user based on\n * its `visibility` configuration.\n *\n * Visibility rules:\n * - No `visibility` property -> visible to everyone\n * - `visibility.users` contains the current user ID -> visible\n * - `visibility.groups` overlaps with the user's groups -> visible\n * - Both `users` and `groups` are specified -> either match grants access (OR logic)\n * - Both are empty arrays -> visible to everyone\n *\n * @param {object} widget Widget definition object\n * @param {object} [widget.visibility] Optional visibility configuration\n * @param {string[]} [widget.visibility.users] User IDs who can see this widget\n * @param {string[]} [widget.visibility.groups] Group names who can see this widget\n * @param {string|null} userId Current user ID\n * @param {string[]} userGroups Current user's group memberships\n * @return {boolean} Whether the widget should be visible\n */\nexport function isWidgetVisible(widget, userId, userGroups) {\n\tconst visibility = widget?.visibility\n\tif (!visibility) {\n\t\treturn true\n\t}\n\n\tconst allowedUsers = visibility.users || []\n\tconst allowedGroups = visibility.groups || []\n\n\t// If both are empty, visible to everyone\n\tif (allowedUsers.length === 0 && allowedGroups.length === 0) {\n\t\treturn true\n\t}\n\n\t// Check user match\n\tif (allowedUsers.length > 0 && userId && allowedUsers.includes(userId)) {\n\t\treturn true\n\t}\n\n\t// Check group match\n\tif (allowedGroups.length > 0 && userGroups.length > 0) {\n\t\tconst hasGroupMatch = allowedGroups.some((group) => userGroups.includes(group))\n\t\tif (hasGroupMatch) {\n\t\t\treturn true\n\t\t}\n\t}\n\n\treturn false\n}\n\n/**\n * Filter an array of widget definitions by visibility for the current user.\n *\n * This is an async function because it may need to fetch the user's groups\n * from the OCS API (cached after first call).\n *\n * @param {Array} widgets Array of widget definition objects\n * @return {Promise<Array>} Filtered array of visible widgets\n */\nexport async function filterWidgetsByVisibility(widgets) {\n\tif (!widgets || widgets.length === 0) {\n\t\treturn []\n\t}\n\n\t// Quick path: if no widgets have visibility config, return all\n\tconst hasVisibilityConfig = widgets.some((w) => w.visibility)\n\tif (!hasVisibilityConfig) {\n\t\treturn widgets\n\t}\n\n\tconst userId = getCurrentUserId()\n\tconst userGroups = await getCurrentUserGroups()\n\n\treturn widgets.filter((widget) => isWidgetVisible(widget, userId, userGroups))\n}\n\n/**\n * Reset the internal groups cache. Useful for testing or when user\n * context changes.\n */\nexport function resetVisibilityCache() {\n\t_cache.userId = null\n\t_cache.groups = null\n\t_cache.promise = null\n\t_peekRequested.clear()\n\tfor (const key of Object.keys(_peek.byUser)) {\n\t\tdelete _peek.byUser[key]\n\t}\n}\n"],"names":["axios"],"mappings":";;;;AAIA;AACA;AACA;AACA;AACA;AACA,MAAM,MAAM,GAAG;AACf,CAAC,MAAM,EAAE,IAAI;AACb,CAAC,MAAM,EAAE,IAAI;AACb,CAAC,OAAO,EAAE,IAAI;AACd,EAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM,KAAK,GAAG,QAAQ,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,EAAC;AACtC;AACA;AACA,MAAM,cAAc,GAAG,IAAI,GAAG,GAAE;AAChC;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,gBAAgB,GAAG;AACnC,CAAC,OAAO,MAAM,CAAC,EAAE,EAAE,WAAW,EAAE,GAAG;AACnC,KAAK,MAAM,CAAC,EAAE,EAAE,WAAW;AAC3B,KAAK,IAAI;AACT,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACO,eAAe,oBAAoB,GAAG;AAC7C,CAAC,MAAM,MAAM,GAAG,gBAAgB,GAAE;AAClC,CAAC,IAAI,CAAC,MAAM,EAAE;AACd,EAAE,OAAO,EAAE;AACX,EAAE;AACF;AACA;AACA,CAAC,IAAI,MAAM,CAAC,MAAM,KAAK,MAAM,IAAI,MAAM,CAAC,MAAM,KAAK,IAAI,EAAE;AACzD,EAAE,OAAO,MAAM,CAAC,MAAM;AACtB,EAAE;AACF;AACA;AACA,CAAC,IAAI,MAAM,CAAC,MAAM,KAAK,MAAM,IAAI,MAAM,CAAC,OAAO,EAAE;AACjD,EAAE,OAAO,MAAM,CAAC,OAAO;AACvB,EAAE;AACF;AACA,CAAC,MAAM,CAAC,MAAM,GAAG,OAAM;AACvB,CAAC,MAAM,CAAC,OAAO,GAAG,YAAY,CAAC,MAAM,EAAC;AACtC;AACA,CAAC,IAAI;AACL,EAAE,MAAM,CAAC,MAAM,GAAG,MAAM,MAAM,CAAC,QAAO;AACtC,EAAE,CAAC,MAAM;AACT,EAAE,MAAM,CAAC,MAAM,GAAG,GAAE;AACpB,EAAE,SAAS;AACX,EAAE,MAAM,CAAC,OAAO,GAAG,KAAI;AACvB,EAAE;AACF;AACA,CAAC,OAAO,MAAM,CAAC,MAAM;AACrB,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,qBAAqB,GAAG;AACxC,CAAC,MAAM,MAAM,GAAG,gBAAgB,GAAE;AAClC,CAAC,IAAI,CAAC,MAAM,EAAE;AACd,EAAE,OAAO,EAAE;AACX,EAAE;AACF,CAAC,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,MAAM,EAAC;AACnC,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE;AAC3B,EAAE,OAAO,KAAK;AACd,EAAE;AACF,CAAC,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE;AAClC,EAAE,cAAc,CAAC,GAAG,CAAC,MAAM,EAAC;AAC5B,EAAE,oBAAoB,EAAE,CAAC,IAAI,CAAC,CAAC,MAAM,KAAK;AAC1C,GAAG,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,GAAG,GAAE;AAClE,GAAG,EAAC;AACJ,EAAE;AACF,CAAC,OAAO,IAAI;AACZ,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA,eAAe,YAAY,CAAC,MAAM,EAAE;AACpC,CAAC,IAAI;AACL,EAAE,MAAM,GAAG,GAAG,cAAc,CAAC,8BAA8B,EAAE,EAAE,MAAM,EAAE,EAAC;AACxE,EAAE,MAAM,QAAQ,GAAG,MAAMA,cAAK,CAAC,GAAG,CAAC,GAAG,EAAC;AACvC,EAAE,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,IAAI,GAAE;AACvD,EAAE,OAAO,MAAM;AACf,EAAE,CAAC,OAAO,KAAK,EAAE;AACjB;AACA,EAAE,OAAO,CAAC,KAAK,CAAC,iDAAiD,EAAE,KAAK,EAAC;AACzE,EAAE,OAAO,EAAE;AACX,EAAE;AACF,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE;AAC5D,CAAC,MAAM,UAAU,GAAG,MAAM,EAAE,WAAU;AACtC,CAAC,IAAI,CAAC,UAAU,EAAE;AAClB,EAAE,OAAO,IAAI;AACb,EAAE;AACF;AACA,CAAC,MAAM,YAAY,GAAG,UAAU,CAAC,KAAK,IAAI,GAAE;AAC5C,CAAC,MAAM,aAAa,GAAG,UAAU,CAAC,MAAM,IAAI,GAAE;AAC9C;AACA;AACA,CAAC,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE;AAC9D,EAAE,OAAO,IAAI;AACb,EAAE;AACF;AACA;AACA,CAAC,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,IAAI,MAAM,IAAI,YAAY,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE;AACzE,EAAE,OAAO,IAAI;AACb,EAAE;AACF;AACA;AACA,CAAC,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE;AACxD,EAAE,MAAM,aAAa,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC,KAAK,KAAK,UAAU,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAC;AACjF,EAAE,IAAI,aAAa,EAAE;AACrB,GAAG,OAAO,IAAI;AACd,GAAG;AACH,EAAE;AACF;AACA,CAAC,OAAO,KAAK;AACb,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,eAAe,yBAAyB,CAAC,OAAO,EAAE;AACzD,CAAC,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE;AACvC,EAAE,OAAO,EAAE;AACX,EAAE;AACF;AACA;AACA,CAAC,MAAM,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,UAAU,EAAC;AAC9D,CAAC,IAAI,CAAC,mBAAmB,EAAE;AAC3B,EAAE,OAAO,OAAO;AAChB,EAAE;AACF;AACA,CAAC,MAAM,MAAM,GAAG,gBAAgB,GAAE;AAClC,CAAC,MAAM,UAAU,GAAG,MAAM,oBAAoB,GAAE;AAChD;AACA,CAAC,OAAO,OAAO,CAAC,MAAM,CAAC,CAAC,MAAM,KAAK,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,CAAC,CAAC;AAC/E,CAAC;AACD;AACA;AACA;AACA;AACA;AACO,SAAS,oBAAoB,GAAG;AACvC,CAAC,MAAM,CAAC,MAAM,GAAG,KAAI;AACrB,CAAC,MAAM,CAAC,MAAM,GAAG,KAAI;AACrB,CAAC,MAAM,CAAC,OAAO,GAAG,KAAI;AACtB,CAAC,cAAc,CAAC,KAAK,GAAE;AACvB,CAAC,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE;AAC9C,EAAE,OAAO,KAAK,CAAC,MAAM,CAAC,GAAG,EAAC;AAC1B,EAAE;AACF;;;;"}
1
+ {"version":3,"file":"widgetVisibility.js","sources":["../../../src/utils/widgetVisibility.js"],"sourcesContent":["import axios from '@nextcloud/axios'\nimport { generateOcsUrl } from '@nextcloud/router'\nimport { getCurrentUserId, peekCurrentUserGroups, resetGroupsPeek } from './userGroupsPeek.js'\n\n// The pure peek and user-id read live in userGroupsPeek.js so the filter-token\n// resolver can use them without importing axios; re-exported here so the public\n// API is unchanged.\nexport { getCurrentUserId, peekCurrentUserGroups }\n\n/**\n * Cached user groups — fetched once per session and reused.\n *\n * @type {{ userId: string|null, groups: string[]|null, promise: Promise|null }}\n */\nconst _cache = {\n\tuserId: null,\n\tgroups: null,\n\tpromise: null,\n}\n\n/**\n * Fetch the current user's Nextcloud groups. Results are cached so the\n * OCS API is only called once per page load.\n *\n * @return {Promise<string[]>} Array of group IDs the current user belongs to\n */\nexport async function getCurrentUserGroups() {\n\tconst userId = getCurrentUserId()\n\tif (!userId) {\n\t\treturn []\n\t}\n\n\t// Return cached result if we already fetched for this user\n\tif (_cache.userId === userId && _cache.groups !== null) {\n\t\treturn _cache.groups\n\t}\n\n\t// If a fetch is already in progress for this user, await it\n\tif (_cache.userId === userId && _cache.promise) {\n\t\treturn _cache.promise\n\t}\n\n\t_cache.userId = userId\n\t_cache.promise = _fetchGroups(userId)\n\n\ttry {\n\t\t_cache.groups = await _cache.promise\n\t} catch {\n\t\t_cache.groups = []\n\t} finally {\n\t\t_cache.promise = null\n\t}\n\n\treturn _cache.groups\n}\n\n/**\n * Internal: fetch groups from OCS API.\n *\n * @param {string} userId The user ID to look up\n * @return {Promise<string[]>} Array of group IDs\n */\nasync function _fetchGroups(userId) {\n\ttry {\n\t\tconst url = generateOcsUrl('/cloud/users/{userId}/groups', { userId })\n\t\tconst response = await axios.get(url)\n\t\tconst groups = response.data?.ocs?.data?.groups || []\n\t\treturn groups\n\t} catch (error) {\n\t\t// eslint-disable-next-line no-console -- diagnostic for a failure this code already degrades from\n\t\tconsole.error('[widgetVisibility] Failed to fetch user groups:', error)\n\t\treturn []\n\t}\n}\n\n/**\n * Check whether a single widget is visible to the current user based on\n * its `visibility` configuration.\n *\n * Visibility rules:\n * - No `visibility` property -> visible to everyone\n * - `visibility.users` contains the current user ID -> visible\n * - `visibility.groups` overlaps with the user's groups -> visible\n * - Both `users` and `groups` are specified -> either match grants access (OR logic)\n * - Both are empty arrays -> visible to everyone\n *\n * @param {object} widget Widget definition object\n * @param {object} [widget.visibility] Optional visibility configuration\n * @param {string[]} [widget.visibility.users] User IDs who can see this widget\n * @param {string[]} [widget.visibility.groups] Group names who can see this widget\n * @param {string|null} userId Current user ID\n * @param {string[]} userGroups Current user's group memberships\n * @return {boolean} Whether the widget should be visible\n */\nexport function isWidgetVisible(widget, userId, userGroups) {\n\tconst visibility = widget?.visibility\n\tif (!visibility) {\n\t\treturn true\n\t}\n\n\tconst allowedUsers = visibility.users || []\n\tconst allowedGroups = visibility.groups || []\n\n\t// If both are empty, visible to everyone\n\tif (allowedUsers.length === 0 && allowedGroups.length === 0) {\n\t\treturn true\n\t}\n\n\t// Check user match\n\tif (allowedUsers.length > 0 && userId && allowedUsers.includes(userId)) {\n\t\treturn true\n\t}\n\n\t// Check group match\n\tif (allowedGroups.length > 0 && userGroups.length > 0) {\n\t\tconst hasGroupMatch = allowedGroups.some((group) => userGroups.includes(group))\n\t\tif (hasGroupMatch) {\n\t\t\treturn true\n\t\t}\n\t}\n\n\treturn false\n}\n\n/**\n * Filter an array of widget definitions by visibility for the current user.\n *\n * This is an async function because it may need to fetch the user's groups\n * from the OCS API (cached after first call).\n *\n * @param {Array} widgets Array of widget definition objects\n * @return {Promise<Array>} Filtered array of visible widgets\n */\nexport async function filterWidgetsByVisibility(widgets) {\n\tif (!widgets || widgets.length === 0) {\n\t\treturn []\n\t}\n\n\t// Quick path: if no widgets have visibility config, return all\n\tconst hasVisibilityConfig = widgets.some((w) => w.visibility)\n\tif (!hasVisibilityConfig) {\n\t\treturn widgets\n\t}\n\n\tconst userId = getCurrentUserId()\n\tconst userGroups = await getCurrentUserGroups()\n\n\treturn widgets.filter((widget) => isWidgetVisible(widget, userId, userGroups))\n}\n\n/**\n * Reset the internal groups cache. Useful for testing or when user\n * context changes.\n */\nexport function resetVisibilityCache() {\n\t_cache.userId = null\n\t_cache.groups = null\n\t_cache.promise = null\n\tresetGroupsPeek()\n}\n"],"names":["axios"],"mappings":"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"}