@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
@@ -216,6 +216,24 @@ export { CnFlowStepOutcomes } from './CnFlowStepOutcomes/index.js'
216
216
  export { CnFlowRunsWidgetForm } from './CnFlowRunsWidgetForm/index.js'
217
217
  export { CnTasksWidget } from './CnTasksWidget/index.js'
218
218
  export { CnTasksWidgetForm } from './CnTasksWidgetForm/index.js'
219
+ export { CnSectionsWidget } from './CnSectionsWidget/index.js'
220
+ export { CnFactsWidget } from './CnFactsWidget/index.js'
221
+ export { CnFieldListWidget } from './CnFieldListWidget/index.js'
222
+ export { CnSettingsFormWidget } from './CnSettingsFormWidget/index.js'
223
+ export { CnSwitchRowsWidget } from './CnSwitchRowsWidget/index.js'
224
+ export { CnRadioCardsWidget } from './CnRadioCardsWidget/index.js'
225
+ export { CnChipsFieldWidget } from './CnChipsFieldWidget/index.js'
226
+ export { CnToggleTableWidget } from './CnToggleTableWidget/index.js'
227
+ export { CnChoicePickerWidget } from './CnChoicePickerWidget/index.js'
228
+ export { CnRecordListWidget } from './CnRecordListWidget/index.js'
229
+ export { CnBannerWidget } from './CnBannerWidget/index.js'
230
+ export { default as CnConversationWidget } from './CnConversationThread/CnConversationWidget.vue'
231
+ export { default as CnDocumentReviewWidget } from './CnDocumentReviewList/CnDocumentReviewWidget.vue'
232
+ export { default as CnNextStepWidget } from './CnNextStepCard/CnNextStepWidget.vue'
233
+ export { default as CnAuditTrailWidget } from './CnAuditTrailWidget/CnAuditTrailWidget.vue'
234
+ export { CnKbSearchWidget } from './CnKbSearchWidget/index.js'
235
+ export { CnInteractionFormWidget } from './CnInteractionFormWidget/index.js'
236
+ export { CnWorkspaceFilterWidget } from './CnWorkspaceFilterWidget/index.js'
219
237
  export { CnFilePreview } from './CnFilePreview/index.js'
220
238
  export { CnTaskFormDialog } from './CnTaskFormDialog/index.js'
221
239
  export { CnChildRecordsField } from './CnChildRecordsField/index.js'
@@ -224,6 +242,7 @@ export { CnMarkdownWidget } from './CnMarkdownWidget/index.js'
224
242
  export { CnMarkdownWidgetForm } from './CnMarkdownWidgetForm/index.js'
225
243
  export { CnObjectListWidget } from './CnObjectListWidget/index.js'
226
244
  export { CnObjectListWidgetForm } from './CnObjectListWidgetForm/index.js'
245
+ export { CnSavedViewsWidget } from './CnSavedViewsWidget/index.js'
227
246
  export { CnSavedViewWidget } from './CnSavedViewWidget/index.js'
228
247
  export { CnSavedViewWidgetForm } from './CnSavedViewWidgetForm/index.js'
229
248
  export { CnChartWidgetForm } from './CnChartWidgetForm/index.js'
@@ -17,11 +17,21 @@
17
17
  * one, and it would be this library's fault in somebody else's app.
18
18
  */
19
19
 
20
+ jest.mock('@nextcloud/auth', () => ({
21
+ ...jest.requireActual('@nextcloud/auth'),
22
+ getCurrentUser: jest.fn(() => null),
23
+ }))
24
+
25
+ import { getCurrentUser } from '@nextcloud/auth'
20
26
  import {
27
+ clearAnonymousDrafts,
21
28
  clearDraft,
22
29
  DRAFT_MAX_AGE_MS,
23
30
  draftKey,
31
+ hasDraftChanges,
24
32
  readDraft,
33
+ resolveDraftUserId,
34
+ sameDraftValue,
25
35
  writeDraft,
26
36
  } from '../useFormDraft.js'
27
37
 
@@ -170,3 +180,62 @@ describe('when storage is not available', () => {
170
180
  expect(() => clearDraft('cn-form-draft:a:s:new:u')).not.toThrow()
171
181
  })
172
182
  })
183
+
184
+ // @spec openspec/changes/form-draft-on-change-and-help-text-spacing/specs/form-draft-on-change-and-help-text-spacing/spec.md#requirement-a-draft-belongs-to-the-signed-in-user
185
+ describe('resolveDraftUserId', () => {
186
+ afterEach(() => getCurrentUser.mockReturnValue(null))
187
+
188
+ it('prefers the id the host passed', () => {
189
+ getCurrentUser.mockReturnValue({ uid: 'cluade' })
190
+ expect(resolveDraftUserId('anne')).toBe('anne')
191
+ })
192
+
193
+ it('falls back to the signed-in user', () => {
194
+ getCurrentUser.mockReturnValue({ uid: 'cluade' })
195
+ expect(resolveDraftUserId('')).toBe('cluade')
196
+ })
197
+
198
+ it('is empty when nobody is signed in, and when the lookup throws', () => {
199
+ expect(resolveDraftUserId()).toBe('')
200
+ getCurrentUser.mockImplementationOnce(() => {
201
+ throw new Error('no head')
202
+ })
203
+ expect(resolveDraftUserId()).toBe('')
204
+ })
205
+ })
206
+
207
+ describe('clearAnonymousDrafts', () => {
208
+ beforeEach(() => window.localStorage.clear())
209
+
210
+ it('removes only drafts stored under anonymous', () => {
211
+ const anon = draftKey({ appId: 'pipelinq', schema: 'crmTask', objectId: 't1' })
212
+ const anne = draftKey({ appId: 'pipelinq', schema: 'crmTask', objectId: 't1', userId: 'anne' })
213
+ writeDraft(anon, { title: 'x' })
214
+ writeDraft(anne, { title: 'y' })
215
+ window.localStorage.setItem('unrelated:anonymous', 'keep')
216
+
217
+ expect(clearAnonymousDrafts()).toBe(1)
218
+ expect(window.localStorage.getItem(anon)).toBeNull()
219
+ expect(window.localStorage.getItem(anne)).not.toBeNull()
220
+ expect(window.localStorage.getItem('unrelated:anonymous')).toBe('keep')
221
+ })
222
+ })
223
+
224
+ // @spec openspec/changes/form-draft-on-change-and-help-text-spacing/specs/form-draft-on-change-and-help-text-spacing/spec.md#requirement-a-draft-is-written-only-after-a-person-changes-a-field
225
+ describe('hasDraftChanges', () => {
226
+ it('treats empty values as equal', () => {
227
+ expect(sameDraftValue(null, '')).toBe(true)
228
+ expect(sameDraftValue(undefined, [])).toBe(true)
229
+ expect(sameDraftValue('a', 'b')).toBe(false)
230
+ expect(sameDraftValue({ a: 1 }, { a: 1 })).toBe(true)
231
+ })
232
+
233
+ it('counts only fields a person edited', () => {
234
+ const baseline = { title: 'Call back', notes: '' }
235
+ // The form changed `notes` by itself; nobody edited it.
236
+ expect(hasDraftChanges({ title: 'Call back', notes: 'filled in' }, baseline, [])).toBe(false)
237
+ // Edited, but back to what it was.
238
+ expect(hasDraftChanges({ title: 'Call back' }, baseline, ['title'])).toBe(false)
239
+ expect(hasDraftChanges({ title: 'Call back tomorrow' }, baseline, ['title'])).toBe(true)
240
+ })
241
+ })
@@ -23,6 +23,7 @@
23
23
  * value, and the audit trail is read by people answering "who changed this".
24
24
  */
25
25
 
26
+ import { getCurrentUser } from '@nextcloud/auth'
26
27
  import { translate as t } from '@nextcloud/l10n'
27
28
 
28
29
  /** How long a draft stays interesting, in milliseconds (7 days). */
@@ -34,6 +35,9 @@ export const DRAFT_DEBOUNCE_MS = 500
34
35
  /** The prefix every draft key carries, so a sweep can find them. */
35
36
  export const DRAFT_KEY_PREFIX = 'cn-form-draft'
36
37
 
38
+ /** The user part of a draft key when nobody is signed in. */
39
+ export const DRAFT_ANONYMOUS_USER = 'anonymous'
40
+
37
41
  /**
38
42
  * The storage key one form's draft lives under.
39
43
  *
@@ -54,10 +58,124 @@ export function draftKey({ appId = '', schema = '', objectId = '', userId = '' }
54
58
  String(appId || 'app'),
55
59
  String(schema || 'schema'),
56
60
  String(objectId || 'new'),
57
- String(userId || 'anonymous'),
61
+ String(userId || DRAFT_ANONYMOUS_USER),
58
62
  ].join(':')
59
63
  }
60
64
 
65
+ /**
66
+ * Who a draft belongs to: the id the host passed, else the signed-in
67
+ * Nextcloud user, else '' (which {@link draftKey} stores as `anonymous`).
68
+ *
69
+ * 🔴 A HOST THAT PASSES NOTHING STILL GETS PER-USER DRAFTS. Leaving the user
70
+ * to every host meant no host passed it, and every draft on a shared device
71
+ * was keyed `anonymous`: the next person at the counter was offered what the
72
+ * last one typed.
73
+ *
74
+ * @param {string} [explicit] The id the host passed (`draftUserId`).
75
+ * @return {string} The user id, or '' when nobody is signed in.
76
+ * @spec openspec/changes/form-draft-on-change-and-help-text-spacing/specs/form-draft-on-change-and-help-text-spacing/spec.md#requirement-a-draft-belongs-to-the-signed-in-user
77
+ */
78
+ export function resolveDraftUserId(explicit = '') {
79
+ if (explicit) {
80
+ return String(explicit)
81
+ }
82
+ try {
83
+ const uid = getCurrentUser()?.uid
84
+ return uid ? String(uid) : ''
85
+ } catch {
86
+ // No Nextcloud page around us (a test, an embed): nobody is signed in.
87
+ return ''
88
+ }
89
+ }
90
+
91
+ /**
92
+ * Remove every draft stored under the anonymous user.
93
+ *
94
+ * Called once a signed-in user is known. Such a draft was written by a page
95
+ * that did not know who was typing, so it may be somebody else's, and it is
96
+ * deleted rather than moved: moving it would hand it to whoever opened the
97
+ * form next.
98
+ *
99
+ * @return {number} How many drafts were removed.
100
+ * @spec openspec/changes/form-draft-on-change-and-help-text-spacing/specs/form-draft-on-change-and-help-text-spacing/spec.md#requirement-a-draft-belongs-to-the-signed-in-user
101
+ */
102
+ export function clearAnonymousDrafts() {
103
+ let removed = 0
104
+ try {
105
+ const storage = window.localStorage
106
+ const suffix = ':' + DRAFT_ANONYMOUS_USER
107
+ const doomed = []
108
+ for (let i = 0; i < storage.length; i++) {
109
+ const key = storage.key(i)
110
+ if (key && key.startsWith(DRAFT_KEY_PREFIX + ':') && key.endsWith(suffix)) {
111
+ doomed.push(key)
112
+ }
113
+ }
114
+ for (const key of doomed) {
115
+ storage.removeItem(key)
116
+ removed++
117
+ }
118
+ } catch {
119
+ // Blocked storage holds no drafts to leak.
120
+ }
121
+ return removed
122
+ }
123
+
124
+ /**
125
+ * Whether a value counts as empty for a draft: null, undefined, '' and [].
126
+ *
127
+ * @param {unknown} value The value.
128
+ * @return {boolean} True when empty.
129
+ */
130
+ function isEmptyDraftValue(value) {
131
+ return value === null || value === undefined || value === '' || (Array.isArray(value) && value.length === 0)
132
+ }
133
+
134
+ /**
135
+ * Whether two field values are the same for the purpose of a draft.
136
+ *
137
+ * Empty values are equal to each other: an input reports a missing value back
138
+ * as '', and that is the control normalising, not a person typing.
139
+ *
140
+ * @param {unknown} a One value.
141
+ * @param {unknown} b The other.
142
+ * @return {boolean} True when they are the same.
143
+ */
144
+ export function sameDraftValue(a, b) {
145
+ if (isEmptyDraftValue(a) && isEmptyDraftValue(b)) {
146
+ return true
147
+ }
148
+ if (a === b) {
149
+ return true
150
+ }
151
+ try {
152
+ return JSON.stringify(a) === JSON.stringify(b)
153
+ } catch {
154
+ return false
155
+ }
156
+ }
157
+
158
+ /**
159
+ * Whether a person changed the form: one of the fields they edited holds a
160
+ * value different from the one the form opened with.
161
+ *
162
+ * 🔴 ONLY EDITED FIELDS COUNT. A form fills in values by itself after it
163
+ * opens (defaults, normalised dates, the active organisation, options that
164
+ * arrive later). Counting those wrote a draft and said "Saved just now" on a
165
+ * dialog nobody had touched.
166
+ *
167
+ * @param {object} values The current values.
168
+ * @param {object} baseline The values the form opened with.
169
+ * @param {string[]} editedKeys The fields a person edited.
170
+ * @return {boolean} True when there is something worth keeping.
171
+ * @spec openspec/changes/form-draft-on-change-and-help-text-spacing/specs/form-draft-on-change-and-help-text-spacing/spec.md#requirement-a-draft-is-written-only-after-a-person-changes-a-field
172
+ */
173
+ export function hasDraftChanges(values, baseline, editedKeys) {
174
+ const now = values || {}
175
+ const base = baseline || {}
176
+ return (editedKeys || []).some((key) => !sameDraftValue(now[key], base[key]))
177
+ }
178
+
61
179
  /**
62
180
  * Read one draft back, or null when there is nothing usable.
63
181
  *
@@ -218,13 +336,6 @@ export function formDraftMixin() {
218
336
  draftSavedAt: 0,
219
337
  /** Non-reactive handle for the debounce. */
220
338
  draftTimeout: null,
221
- /**
222
- * Whether the form's own initial population has happened.
223
- *
224
- * The first change to the values is the component building
225
- * them, not a person typing. See the watcher that reads this.
226
- */
227
- draftSeeded: false,
228
339
  }
229
340
  },
230
341
 
@@ -265,6 +376,26 @@ export function formDraftMixin() {
265
376
  }, DRAFT_DEBOUNCE_MS)
266
377
  },
267
378
 
379
+ /**
380
+ * The form is back to what it opened with: cancel a pending write,
381
+ * remove a draft written earlier and stop announcing anything.
382
+ *
383
+ * @param {string} key The storage key.
384
+ * @return {void}
385
+ * @spec openspec/changes/form-draft-on-change-and-help-text-spacing/specs/form-draft-on-change-and-help-text-spacing/spec.md#requirement-a-draft-is-written-only-after-a-person-changes-a-field
386
+ */
387
+ settleUnchangedDraft(key) {
388
+ if (this.draftTimeout) {
389
+ clearTimeout(this.draftTimeout)
390
+ this.draftTimeout = null
391
+ }
392
+ if (this.draftState !== 'idle') {
393
+ clearDraft(key)
394
+ this.draftState = 'idle'
395
+ this.draftSavedAt = 0
396
+ }
397
+ },
398
+
268
399
  /**
269
400
  * Drop the draft and stop announcing anything about it.
270
401
  *
@@ -1,5 +1,6 @@
1
1
  import { computed, isRef, onBeforeUnmount, onMounted, ref, watch } from 'vue'
2
2
  import { useObjectStore } from '../store/index.js'
3
+ import { facetFilterParams } from '../utils/facets.js'
3
4
 
4
5
  /**
5
6
  * Composable for managing list view state with full objectStore integration.
@@ -163,10 +164,9 @@ export function useListView(objectTypeOrOptions, options) {
163
164
  }
164
165
 
165
166
  for (const [key, values] of Object.entries(activeFilters.value)) {
166
- if (values && values.length > 0) {
167
- // Single-value arrays are unwrapped to scalar params
168
- params[key] = values.length === 1 ? values[0] : values
169
- }
167
+ // Single-value arrays are unwrapped to scalar params; the
168
+ // missing-value option becomes `<key>_isnull=true`.
169
+ Object.assign(params, facetFilterParams(key, values))
170
170
  }
171
171
 
172
172
  // Fixed filters (e.g. a route-param-scoped `pages[].config.filter`) are
@@ -82,6 +82,20 @@
82
82
  min-height: var(--cn-field-height);
83
83
  }
84
84
 
85
+ /* NcTextField draws its input inside `.input-field__main-wrapper`, which has a
86
+ FIXED height (`--default-clickable-area`, 34px on Nextcloud 34) and a 2px
87
+ padding ring for the focus outline. The min-height above makes the input
88
+ 40px, so without this the input overflowed its wrapper by 6px and the help
89
+ line under it, which starts at the wrapper's bottom edge, sat behind the
90
+ input's lower border. NcSelect grows with its content, which is why only
91
+ plain inputs showed it. The wrapper now takes the field height plus its
92
+ padding ring, so the input fits and the help line starts below it.
93
+ @spec openspec/changes/form-draft-on-change-and-help-text-spacing/specs/form-draft-on-change-and-help-text-spacing/spec.md#requirement-help-text-starts-below-every-input */
94
+ .cn-look-board .cn-form-dialog__field .input-field__main-wrapper,
95
+ .cn-look-board .cn-form-page__field .input-field__main-wrapper {
96
+ height: calc(var(--cn-field-height) + 2 * var(--border-width-input-focused, 2px));
97
+ }
98
+
85
99
  .cn-look-board .cn-form-dialog__field textarea,
86
100
  .cn-look-board .cn-form-page__field textarea {
87
101
  padding: 10px 12px;
@@ -240,3 +240,74 @@
240
240
  color: var(--color-text-maxcontrast);
241
241
  font-size: 0.9em;
242
242
  }
243
+
244
+ /* An index page with cards beside its list (`sidePanel`,
245
+ screens-index-stat-row): the header rows span the page, the toolbar and the
246
+ list take the first column and the side panel the second (300px, 20px
247
+ apart), spanning both. Every other child (dialogs, the inline sidebar) sits
248
+ in a zero-height area after them. The list row is the flexible one, so a
249
+ side panel taller than the toolbar never opens a gap under the toolbar.
250
+ Below 1024px the panel moves above the toolbar. */
251
+ .cn-index-page--with-side-panel {
252
+ display: grid;
253
+ grid-template-columns: minmax(0, 1fr) var(--cn-index-side-panel-width, 300px);
254
+ grid-template-rows: auto auto auto auto minmax(0, 1fr) auto;
255
+ grid-template-areas:
256
+ "head head"
257
+ "below below"
258
+ "stats stats"
259
+ "bar side"
260
+ "body side"
261
+ "extra extra";
262
+ column-gap: 20px;
263
+ align-content: start;
264
+ }
265
+
266
+ .cn-index-page--with-side-panel > * {
267
+ grid-area: extra;
268
+ min-width: 0;
269
+ }
270
+
271
+ .cn-index-page--with-side-panel > :first-child {
272
+ grid-area: head;
273
+ }
274
+
275
+ .cn-index-page--with-side-panel > .cn-index-page__below-header {
276
+ grid-area: below;
277
+ }
278
+
279
+ .cn-index-page--with-side-panel > .cn-index-page__stat-row {
280
+ grid-area: stats;
281
+ }
282
+
283
+ .cn-index-page--with-side-panel > .cn-actions-bar {
284
+ grid-area: bar;
285
+ }
286
+
287
+ .cn-index-page--with-side-panel > .cn-index-page__body {
288
+ grid-area: body;
289
+ }
290
+
291
+ .cn-index-page--with-side-panel > .cn-index-page__side-panel {
292
+ grid-area: side;
293
+ align-self: start;
294
+ }
295
+
296
+ @media (max-width: 1024px) {
297
+ .cn-index-page--with-side-panel {
298
+ grid-template-columns: minmax(0, 1fr);
299
+ grid-template-areas:
300
+ "head"
301
+ "below"
302
+ "stats"
303
+ "side"
304
+ "bar"
305
+ "body"
306
+ "extra";
307
+ grid-template-rows: auto auto auto auto auto minmax(0, 1fr) auto;
308
+ }
309
+
310
+ .cn-index-page--with-side-panel > .cn-index-page__side-panel {
311
+ margin-bottom: 20px;
312
+ }
313
+ }
@@ -450,6 +450,38 @@ a.cn-kpi-card--stacked:focus-visible {
450
450
  font-weight: 400;
451
451
  }
452
452
 
453
+ /* A caption on a line of its own wraps, up to two lines (DqDashboard: "haalden
454
+ hun termijn, naar doorlooptijd" runs over two lines in a narrow tile). The
455
+ one-line rule of `.cn-kpi-card__label` is for a caption BESIDE the number,
456
+ where a second line would push the tile taller; this line has the width of
457
+ the tile to itself. The clamp is safe here because the element is a plain
458
+ span, not a flex row (compare the title note above).
459
+ @spec openspec/changes/dashboard-tile-text-fits/specs/dashboard-tile-text-fits/spec.md#requirement-a-kpi-tiles-caption-and-board-label-wrap-to-two-lines */
460
+ .cn-kpi-card--stacked .cn-kpi-card__caption-line {
461
+ display: -webkit-box;
462
+ -webkit-box-orient: vertical;
463
+ -webkit-line-clamp: 2;
464
+ line-clamp: 2;
465
+ white-space: normal;
466
+ overflow-wrap: break-word;
467
+ }
468
+
469
+ /* Board look: the label wraps too, up to two lines, beside its icon badge
470
+ ("Afgehandeld deze maand"). The clamp sits on the label's own span
471
+ (`cn-kpi-card__title-text`), not on the title row, which stays the flex row
472
+ that carries the badge or the range select. */
473
+ .cn-kpi-card--board .cn-kpi-card__title-text {
474
+ flex: 1 1 auto;
475
+ min-width: 0;
476
+ display: -webkit-box;
477
+ -webkit-box-orient: vertical;
478
+ -webkit-line-clamp: 2;
479
+ line-clamp: 2;
480
+ overflow: hidden;
481
+ white-space: normal;
482
+ overflow-wrap: break-word;
483
+ }
484
+
453
485
  /* The 18px glyph before the label, drawn only on a link tile. */
454
486
  .cn-kpi-card--board .cn-kpi-card__title {
455
487
  display: flex;
@@ -87,6 +87,61 @@
87
87
  margin-bottom: 0;
88
88
  }
89
89
 
90
+ /* The breadcrumb is a line of 14px text between the pills and the meta, as
91
+ the boards draw it (screens-detail-header-row-parity). NcBreadcrumbs grows to
92
+ the full row and draws each crumb as a 34px tertiary button, which pushed the
93
+ pills above it and the meta under it. The doubled class outranks its scoped
94
+ rules. */
95
+ .cn-look-board .cn-detail-page__header-row2 .cn-detail-page__breadcrumbs.cn-detail-page__breadcrumbs {
96
+ flex: 0 1 auto;
97
+ height: auto;
98
+ min-height: 0;
99
+ min-width: 0;
100
+ width: auto;
101
+ }
102
+
103
+ .cn-look-board .cn-detail-page__header-row2 .cn-detail-page__breadcrumbs .breadcrumb__crumbs {
104
+ gap: 8px;
105
+ margin: 0;
106
+ min-height: 0;
107
+ padding: 0;
108
+ vertical-align: middle;
109
+ }
110
+
111
+ .cn-look-board .cn-detail-page__header-row2 .cn-detail-page__breadcrumbs .vue-crumb.vue-crumb {
112
+ gap: 8px;
113
+ height: auto;
114
+ min-height: 0;
115
+ min-width: 0;
116
+ }
117
+
118
+ .cn-look-board .cn-detail-page__header-row2 .cn-detail-page__breadcrumbs .vue-crumb .button-vue.button-vue {
119
+ background: transparent;
120
+ border: 0;
121
+ font-size: 14px;
122
+ font-weight: 400;
123
+ height: auto;
124
+ min-height: 0;
125
+ min-width: 0;
126
+ padding: 0;
127
+ }
128
+
129
+ .cn-look-board .cn-detail-page__header-row2 .cn-detail-page__breadcrumbs .vue-crumb .button-vue__text {
130
+ font-weight: inherit;
131
+ line-height: 20px;
132
+ padding: 0;
133
+ }
134
+
135
+ /* The list is the link; the record's own crumb is plain muted text. */
136
+ .cn-look-board .cn-detail-page__header-row2 .cn-detail-page__breadcrumbs .vue-crumb .button-vue[aria-current='page'] {
137
+ color: var(--color-text-maxcontrast);
138
+ cursor: default;
139
+ }
140
+
141
+ .cn-look-board .cn-detail-page__header-row2 .cn-detail-page__breadcrumbs .vue-crumb__separator {
142
+ margin: 0;
143
+ }
144
+
90
145
  .cn-look-board .cn-detail-page__header-dot,
91
146
  .cn-look-board .cn-detail-page__header-meta {
92
147
  color: var(--color-text-maxcontrast);
@@ -147,6 +202,15 @@
147
202
  gap: 4px;
148
203
  }
149
204
 
205
+ /* No inner scroller: tabs that do not fit the width wrap onto a second row
206
+ instead of scrolling sideways (the library's default strip), so the strip
207
+ has no scrollbar, no clipped tab and no fade or chevron to find the rest. */
208
+ .cn-look-board .cn-tabs--board .cn-tabs__nav {
209
+ flex-wrap: wrap;
210
+ overflow: visible;
211
+ row-gap: 4px;
212
+ }
213
+
150
214
  .cn-look-board .cn-tabs--board .cn-tabs__nav-item {
151
215
  background-color: var(--color-background-dark);
152
216
  border: 1px solid var(--color-border-dark);
@@ -229,6 +293,22 @@
229
293
  border-radius: 0;
230
294
  }
231
295
 
296
+ /* A tab that holds a stack (`widgetIds`, screens-relation-pages): the panel
297
+ draws no frame and no padding; each widget is its own card. The first card
298
+ joins the open tab (the first-card rule above), the next ones stand 20px
299
+ apart, as the Overzicht of DqContact and PqOrganisatie draws them. */
300
+ .cn-look-board .cn-tabs--board.cn-tabs-widget__tabs .cn-tabs__content:has(> .cn-tab:not([hidden]) > .cn-tabs-widget__stack) {
301
+ background: transparent;
302
+ border: 0;
303
+ border-radius: 0;
304
+ padding: 0;
305
+ }
306
+
307
+ /* The stack's next cards are whole cards, not joined to the strip. */
308
+ .cn-look-board .cn-tabs--board .cn-tabs__content .cn-tab .cn-tabs-widget__stack-item .cn-widget-wrapper {
309
+ border-radius: var(--cn-board-card-radius);
310
+ }
311
+
232
312
  /* ---- Body cards and side cards ----------------------------------------- */
233
313
 
234
314
  .cn-look-board .cn-detail-page .cn-widget-wrapper,
@@ -276,12 +356,28 @@
276
356
  padding: 0 0 10px;
277
357
  }
278
358
 
279
- .cn-look-board .cn-object-data-widget__label {
280
- color: var(--color-text-maxcontrast);
359
+ /* Outranks the component's own `.cn-object-data-widget__label[data-v-...]`
360
+ (weight 500, 0.85em, which has the same specificity as the look's rule and
361
+ wins on source order wherever a bundle, such as a companion app's, loads
362
+ after this stylesheet), through the grid the labels sit in. Measured live:
363
+ the labels read bold and dark where the boards (DqContact, PqKlant, ShKlant)
364
+ draw them 13px, regular weight and light grey.
365
+
366
+ The colour carries `!important`: a theme (nldesign's element overrides) sets
367
+ the ink of every `div` outside the header with a selector that has an id in
368
+ its `:not()`, which no class rule outranks. */
369
+ .cn-look-board .cn-object-data-widget__grid .cn-object-data-widget__label {
370
+ color: var(--color-text-maxcontrast) !important;
281
371
  font-size: 13px;
282
372
  font-weight: 400;
283
373
  }
284
374
 
375
+ /* The facts card's labels: the same light grey, regular weight. */
376
+ .cn-look-board .cn-facts-widget .cn-facts-widget__label {
377
+ color: var(--color-text-maxcontrast);
378
+ font-weight: 400;
379
+ }
380
+
285
381
  .cn-look-board .cn-object-data-widget__value {
286
382
  font-weight: 500;
287
383
  }
@@ -308,6 +404,12 @@
308
404
  display: none;
309
405
  }
310
406
 
407
+ /* A side card whose widget reports a header action (screens-relation-pages:
408
+ the "+ Toevoegen" of Contactkanalen and Relaties) keeps that one button. */
409
+ .cn-look-board .cn-detail-page__side .cn-widget-wrapper__actions:has(.cn-detail-page__catalog-action) {
410
+ display: flex;
411
+ }
412
+
311
413
  /* The notice at the top of the side column: radius 12, padding 14px 16px. */
312
414
  .cn-look-board .cn-detail-page__side-item--notice .cn-widget-wrapper,
313
415
  .cn-look-board .cn-detail-page__side-item--notice .cn-banner-widget,
@@ -533,3 +635,12 @@
533
635
  font-size: 13px;
534
636
  margin: 2px 0 0;
535
637
  }
638
+
639
+ /* The sidebar's own open toggle (NcAppSidebar's `.app-sidebar__toggle`, drawn
640
+ when the sidebar is closed) is positioned over the content's top-right
641
+ corner, which in this look is the header's last button: a stray square icon
642
+ on "More". The board draws none, so it is hidden on a detail page and the
643
+ header menu offers "Open sidebar" instead. */
644
+ .cn-look-board:has(.cn-detail-page) > .app-sidebar__toggle {
645
+ display: none;
646
+ }