@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
@@ -0,0 +1,652 @@
1
+ <!--
2
+ - SPDX-FileCopyrightText: 2026 Conduction B.V.
3
+ - SPDX-License-Identifier: EUPL-1.2
4
+ -->
5
+
6
+ <template>
7
+ <div
8
+ class="cn-record-list"
9
+ :class="`cn-record-list--${presentation}`"
10
+ data-testid="cn-record-list">
11
+ <p v-if="error" class="cn-record-list__error" data-testid="cn-record-list-error">
12
+ {{ errorLabel }}
13
+ </p>
14
+ <div v-else-if="loading && rows.length === 0" class="cn-record-list__loading">
15
+ <NcLoadingIcon :size="20" :name="loadingLabel" />
16
+ </div>
17
+ <p v-else-if="rows.length === 0" class="cn-record-list__empty" data-testid="cn-record-list-empty">
18
+ {{ emptyLabel }}
19
+ </p>
20
+ <ul v-else class="cn-record-list__list">
21
+ <li
22
+ v-for="item in items"
23
+ :key="item.key"
24
+ class="cn-record-list__item"
25
+ data-testid="cn-record-list-item">
26
+ <!-- rows: title and meta, then the pill, the date and a chevron. -->
27
+ <component
28
+ :is="item.tag"
29
+ v-if="presentation === 'rows'"
30
+ class="cn-record-list__row"
31
+ :class="{ 'cn-record-list__row--link': item.tag !== 'div' }"
32
+ v-bind="item.attrs">
33
+ <span v-if="item.initials"
34
+ class="cn-record-list__avatar"
35
+ aria-hidden="true"
36
+ data-testid="cn-record-list-avatar">{{ item.initials }}</span>
37
+ <span class="cn-record-list__main">
38
+ <span v-if="item.title" class="cn-record-list__title">{{ item.title }}</span>
39
+ <span v-if="item.meta" class="cn-record-list__meta">{{ item.meta }}</span>
40
+ </span>
41
+ <span v-if="item.pill || item.trailing" class="cn-record-list__aside">
42
+ <CnStatusBadge
43
+ v-if="item.pill"
44
+ :label="item.pill.label"
45
+ :variant="item.pill.variant"
46
+ size="small" />
47
+ <span v-if="item.trailing" class="cn-record-list__trailing">{{ item.trailing }}</span>
48
+ </span>
49
+ <ChevronRight
50
+ v-if="item.tag !== 'div'"
51
+ class="cn-record-list__chevron"
52
+ :size="18"
53
+ aria-hidden="true" />
54
+ </component>
55
+
56
+ <!-- feed: a round icon, a meta line and the text. -->
57
+ <div v-else-if="presentation === 'feed'" class="cn-record-list__feed-row">
58
+ <span class="cn-record-list__feed-icon" aria-hidden="true">
59
+ <CnIcon :name="item.icon" :size="18" />
60
+ </span>
61
+ <component :is="item.tag" class="cn-record-list__main" v-bind="item.attrs">
62
+ <span v-if="item.meta" class="cn-record-list__meta">{{ item.meta }}</span>
63
+ <span v-if="item.text" class="cn-record-list__text">{{ item.text }}</span>
64
+ </component>
65
+ </div>
66
+
67
+ <!-- inline: a label and the title, the title a link. -->
68
+ <div v-else class="cn-record-list__inline-row">
69
+ <span v-if="item.label" class="cn-record-list__label">{{ item.label }}</span>
70
+ <component :is="item.tag" class="cn-record-list__inline-title" v-bind="item.attrs">
71
+ {{ item.title }}
72
+ </component>
73
+ </div>
74
+ </li>
75
+ </ul>
76
+ </div>
77
+ </template>
78
+
79
+ <script>
80
+ import { subscribe, unsubscribe } from '@nextcloud/event-bus'
81
+ import { translate as t } from '@nextcloud/l10n'
82
+ import { NcLoadingIcon } from '@nextcloud/vue'
83
+ import ChevronRight from 'vue-material-design-icons/ChevronRight.vue'
84
+ import CnIcon from '../CnIcon/CnIcon.vue'
85
+ import CnStatusBadge from '../CnStatusBadge/CnStatusBadge.vue'
86
+ import { isBadgeVariant } from '../../utils/badgeVariants.js'
87
+ import { fillTemplate, firstFilled } from '../../utils/fillTemplate.js'
88
+ import { initialsOf } from '../../utils/initials.js'
89
+ import { pageFilter, pageSort } from '../../utils/pageControls.js'
90
+ import { readPath } from '../../utils/readPath.js'
91
+ import { dropOptionalUnresolved, hasUnresolvedTokens, resolveFilterTokens } from '../../utils/resolveFilterTokens.js'
92
+
93
+ const PAGE_REFRESH_CHANNEL = 'cn:page:refresh'
94
+ const PRESENTATIONS = ['rows', 'feed', 'inline']
95
+
96
+ /**
97
+ * Unwrap a value that may be a ref.
98
+ *
99
+ * @param {unknown} value The value.
100
+ * @return {unknown} The plain value.
101
+ */
102
+ function unwrap(value) {
103
+ return value && typeof value === 'object' && 'value' in value ? value.value : value
104
+ }
105
+
106
+ /**
107
+ * CnRecordListWidget — the objects of another schema that point at this
108
+ * record, drawn as the boards draw them (screens-relation-pages).
109
+ *
110
+ * A person page lists its open cases ("Verlichting fietspad Lindelaan,
111
+ * 2026-0082 · Woo-verzoek, In behandeling, Termijn 1 nov"), its latest contact
112
+ * moments (an icon by channel, a meta line, the summary) and its relations
113
+ * ("Secretaris van Buurtvereniging Oost"). Each is a list of another schema's
114
+ * objects filtered on a reference to this record. The source keys are those of
115
+ * `object-list` (`register`, `schema`, `filter` with the `@objectId` /
116
+ * `@object.<field>` / `@workspace.<key>` tokens, `sort`, `limit`, `extend`,
117
+ * `rowRoute`, `pageControls`); `avatar` puts a circle with the initials of a name
118
+ * template before the title; what differs is the drawing: `presentation` is `rows`, `feed`
119
+ * or `inline`, and each line is a template (`"{identifier} · {caseTypeName}"`,
120
+ * `"Termijn {deadline|date}"`).
121
+ *
122
+ * A content-only catalog type: on a card surface the detail host draws the
123
+ * titled card. The widget emits `header` with `{ link, note }` (the
124
+ * `headerLink` and `headerNote` with `{total}` filled in) for that card's
125
+ * header.
126
+ */
127
+ export default {
128
+ name: 'CnRecordListWidget',
129
+
130
+ components: { ChevronRight, CnIcon, CnStatusBadge, NcLoadingIcon },
131
+
132
+ inject: {
133
+ /** Detail-page object context (`{ objectId, object, register, schema }`). */
134
+ cnObjectContext: { default: null },
135
+ /** Page workspace bag, for `@workspace.<key>` tokens. */
136
+ cnWorkspaceContext: { default: null },
137
+ /** The host app's translate function. */
138
+ cnTranslate: { default: () => (key) => key },
139
+ },
140
+
141
+ props: {
142
+ /**
143
+ * The list config: `{ register, schema, filter?, sort?, limit?, extend?,
144
+ * presentation?, title?, meta?, text?, label?, pill?, trailing?, icon?,
145
+ * rowRoute?, rowIdField?, headerLink?, headerNote?, emptyText?, errorText? }`.
146
+ *
147
+ * @type {object}
148
+ */
149
+ content: {
150
+ type: Object,
151
+ default: () => ({}),
152
+ },
153
+
154
+ /** The current record's id, for the `@objectId` token. */
155
+ objectId: {
156
+ type: [String, Number],
157
+ default: null,
158
+ },
159
+
160
+ /** The current record, for `@object.<field>` tokens. */
161
+ objectData: {
162
+ type: Object,
163
+ default: null,
164
+ },
165
+ },
166
+
167
+ emits: ['header'],
168
+
169
+ data() {
170
+ return {
171
+ rows: [],
172
+ total: 0,
173
+ loading: false,
174
+ error: false,
175
+ }
176
+ },
177
+
178
+ computed: {
179
+ /** @return {string} `rows`, `feed` or `inline`. */
180
+ presentation() {
181
+ const value = this.content?.presentation
182
+ return PRESENTATIONS.includes(value) ? value : 'rows'
183
+ },
184
+
185
+ /** @return {object} The token context: record, id and workspace. */
186
+ tokenCtx() {
187
+ const injected = unwrap(this.cnObjectContext) || {}
188
+ return {
189
+ ...injected,
190
+ objectId: this.objectId ?? injected.objectId ?? this.objectData?.id ?? null,
191
+ object: this.objectData || injected.object || null,
192
+ workspace: unwrap(this.cnWorkspaceContext) || {},
193
+ }
194
+ },
195
+
196
+ /** @return {object} The filter with its tokens resolved. */
197
+ resolvedFilter() {
198
+ const filter = pageFilter(this.content?.pageControls, this.tokenCtx.workspace, this.content?.filter)
199
+ return dropOptionalUnresolved(resolveFilterTokens(filter, this.tokenCtx))
200
+ },
201
+
202
+ /** @return {boolean} A required token (the record id, say) has no value yet. */
203
+ waiting() {
204
+ return hasUnresolvedTokens(this.resolvedFilter)
205
+ },
206
+
207
+ /** @return {object|null} The sort: the page's sort control when the widget listens to one, else its own. */
208
+ effectiveSort() {
209
+ return pageSort(this.content?.pageControls, this.tokenCtx.workspace, this.content?.sort)
210
+ },
211
+
212
+ /** @return {number} The fetch cap. */
213
+ limit() {
214
+ const value = Number(this.content?.limit)
215
+ return Number.isFinite(value) && value > 0 ? Math.floor(value) : 5
216
+ },
217
+
218
+ /** @return {string} What a fetch depends on; a change fetches again. */
219
+ requestKey() {
220
+ const c = this.content || {}
221
+ return JSON.stringify([c.register, c.schema, this.resolvedFilter, this.effectiveSort, this.limit, c.extend, this.waiting])
222
+ },
223
+
224
+ /** @return {Array<object>} The rows ready to draw. */
225
+ items() {
226
+ const c = this.content || {}
227
+ return this.rows.slice(0, this.limit).map((row, index) => {
228
+ const link = this.rowLink(row)
229
+ return {
230
+ key: (row && (row.id || row['@self']?.id)) || `row-${index}`,
231
+ tag: link ? 'router-link' : 'div',
232
+ attrs: link ? { to: link } : {},
233
+ initials: this.initialsFor(row),
234
+ title: this.fill(c.title, row),
235
+ meta: this.fill(c.meta, row),
236
+ text: this.fill(c.text, row),
237
+ label: this.fill(c.label, row),
238
+ trailing: c.trailing ? firstFilled(c.trailing, row, this.translate) : '',
239
+ pill: this.pillOf(row),
240
+ icon: this.iconOf(row),
241
+ }
242
+ })
243
+ },
244
+
245
+ /** @return {object|null} The header link with `{total}` filled and tokens resolved. */
246
+ headerLink() {
247
+ const link = this.content?.headerLink
248
+ if (!link || typeof link !== 'object' || typeof link.label !== 'string' || link.label === '') {
249
+ return null
250
+ }
251
+ const resolved = { label: this.withTotal(link.label) }
252
+ if (link.route) {
253
+ resolved.route = link.route
254
+ if (link.params && typeof link.params === 'object') {
255
+ resolved.params = resolveFilterTokens(link.params, this.tokenCtx)
256
+ }
257
+ if (link.query && typeof link.query === 'object') {
258
+ resolved.query = resolveFilterTokens(link.query, this.tokenCtx)
259
+ }
260
+ } else if (typeof link.href === 'string') {
261
+ resolved.href = link.href
262
+ }
263
+ return resolved
264
+ },
265
+
266
+ /** @return {string} The header note with `{total}` filled. */
267
+ headerNote() {
268
+ const note = this.content?.headerNote
269
+ return typeof note === 'string' && note !== '' ? this.withTotal(note) : ''
270
+ },
271
+
272
+ /** @return {string} The empty line. */
273
+ emptyLabel() {
274
+ return this.content?.emptyText ? this.translate(this.content.emptyText) : t('nextcloud-vue', 'Nothing here yet')
275
+ },
276
+
277
+ /** @return {string} The error line. */
278
+ errorLabel() {
279
+ return this.content?.errorText ? this.translate(this.content.errorText) : t('nextcloud-vue', 'This list could not be loaded.')
280
+ },
281
+
282
+ /** @return {string} The spinner's accessible name. */
283
+ loadingLabel() {
284
+ return t('nextcloud-vue', 'Loading …')
285
+ },
286
+ },
287
+
288
+ watch: {
289
+ requestKey() {
290
+ this.fetchRows()
291
+ },
292
+ },
293
+
294
+ mounted() {
295
+ this.onRefresh = () => this.fetchRows()
296
+ subscribe(PAGE_REFRESH_CHANNEL, this.onRefresh)
297
+ this.fetchRows()
298
+ },
299
+
300
+ beforeUnmount() {
301
+ unsubscribe(PAGE_REFRESH_CHANNEL, this.onRefresh)
302
+ },
303
+
304
+ methods: {
305
+ /**
306
+ * Translate a manifest string through the host app.
307
+ *
308
+ * @param {string} text The text.
309
+ * @return {string} The translation.
310
+ */
311
+ translate(text) {
312
+ return typeof this.cnTranslate === 'function' ? this.cnTranslate(text) : text
313
+ },
314
+
315
+ /**
316
+ * The initials of the row's avatar (`avatar`: a name template such as
317
+ * `"{client.name}"`, or `{ text }`), or '' without one.
318
+ *
319
+ * @param {object} row The row.
320
+ * @return {string} One or two letters.
321
+ * @spec openspec/changes/screens-record-list-avatar/specs/record-list-avatar/spec.md#requirement-a-record-list-row-can-carry-an-avatar
322
+ */
323
+ initialsFor(row) {
324
+ const avatar = this.content?.avatar
325
+ const template = typeof avatar === 'string' ? avatar : (avatar && typeof avatar === 'object' ? avatar.text : '')
326
+ return initialsOf(this.fill(template, row))
327
+ },
328
+
329
+ /**
330
+ * Fill a template from a row, after translating it.
331
+ *
332
+ * @param {string} template The template.
333
+ * @param {object} row The row.
334
+ * @return {string} The text, '' when a token is empty.
335
+ */
336
+ fill(template, row) {
337
+ return typeof template === 'string' && template !== '' ? fillTemplate(this.translate(template), row) : ''
338
+ },
339
+
340
+ /**
341
+ * Replace `{total}` in a translated label.
342
+ *
343
+ * @param {string} label The label.
344
+ * @return {string} The text.
345
+ */
346
+ withTotal(label) {
347
+ return this.translate(label).replace(/\{total\}/g, String(this.total))
348
+ },
349
+
350
+ /**
351
+ * The route a row opens: `rowRoute` with the id at `rowIdField`.
352
+ *
353
+ * @param {object} row The row.
354
+ * @return {object|null} The router location, or null.
355
+ */
356
+ rowLink(row) {
357
+ const route = this.content?.rowRoute
358
+ if (!route || !this.$router || !row) {
359
+ return null
360
+ }
361
+ const field = this.content?.rowIdField
362
+ const id = field ? readPath(row, field) : (row.id || row['@self']?.id)
363
+ if (id === null || id === undefined || id === '' || typeof id === 'object') {
364
+ return null
365
+ }
366
+ return { name: route, params: { id: String(id) } }
367
+ },
368
+
369
+ /**
370
+ * The row's pill: `{ field, labels?, colorMap?, variant? }`.
371
+ *
372
+ * @param {object} row The row.
373
+ * @return {{label: string, variant: string}|null} The pill, or null.
374
+ */
375
+ pillOf(row) {
376
+ const pill = this.content?.pill
377
+ if (!pill || typeof pill !== 'object' || !pill.field) {
378
+ return null
379
+ }
380
+ const raw = readPath(row, pill.field)
381
+ if (raw === null || raw === undefined || raw === '' || typeof raw === 'object') {
382
+ return null
383
+ }
384
+ const key = String(raw)
385
+ const labels = pill.labels && typeof pill.labels === 'object' ? pill.labels : {}
386
+ const map = pill.colorMap && typeof pill.colorMap === 'object' ? pill.colorMap : {}
387
+ const found = Object.keys(map).find((k) => k.toLowerCase() === key.toLowerCase())
388
+ const variant = found ? map[found] : pill.variant
389
+ return {
390
+ label: labels[key] ? this.translate(labels[key]) : key,
391
+ variant: isBadgeVariant(variant) ? variant : 'default',
392
+ }
393
+ },
394
+
395
+ /**
396
+ * The feed icon: an icon name, or `{ field, map, default }`.
397
+ *
398
+ * @param {object} row The row.
399
+ * @return {string} The MDI icon name.
400
+ */
401
+ iconOf(row) {
402
+ const icon = this.content?.icon
403
+ if (typeof icon === 'string' && icon !== '') {
404
+ return icon
405
+ }
406
+ if (icon && typeof icon === 'object') {
407
+ const raw = icon.field ? readPath(row, icon.field) : undefined
408
+ const map = icon.map && typeof icon.map === 'object' ? icon.map : {}
409
+ if (raw !== null && raw !== undefined && map[String(raw)]) {
410
+ return map[String(raw)]
411
+ }
412
+ if (typeof icon.default === 'string' && icon.default !== '') {
413
+ return icon.default
414
+ }
415
+ }
416
+ return 'CircleSmall'
417
+ },
418
+
419
+ /** Tell the card around this list what its header shows. */
420
+ emitHeader() {
421
+ /**
422
+ * @event header Emitted after every read with the card header's parts.
423
+ * @type {{link: (object|null), note: string}} The header link (resolved, with `{total}` filled) and the note.
424
+ */
425
+ this.$emit('header', { link: this.headerLink, note: this.headerNote })
426
+ },
427
+
428
+ /**
429
+ * Fetch the list. Sends nothing while a required token is unresolved
430
+ * or the source is incomplete.
431
+ *
432
+ * @return {Promise<void>}
433
+ */
434
+ async fetchRows() {
435
+ const c = this.content || {}
436
+ if (!c.register || !c.schema || this.waiting) {
437
+ this.rows = []
438
+ this.total = 0
439
+ this.error = false
440
+ this.emitHeader()
441
+ return
442
+ }
443
+ this.loading = true
444
+ this.error = false
445
+ try {
446
+ const [{ default: axios }, { generateUrl }] = await Promise.all([
447
+ import('@nextcloud/axios'),
448
+ import('@nextcloud/router'),
449
+ ])
450
+ const url = generateUrl('/apps/openregister/api/objects/{register}/{schema}', { register: c.register, schema: c.schema })
451
+ const params = { _limit: this.limit }
452
+ const sort = this.effectiveSort
453
+ if (sort && typeof sort === 'object' && sort.field) {
454
+ params[`_order[${sort.field}]`] = sort.dir === 'desc' ? 'desc' : 'asc'
455
+ }
456
+ if (Array.isArray(c.extend)) {
457
+ const extend = c.extend.filter((e) => typeof e === 'string' && e !== '')
458
+ if (extend.length > 0) {
459
+ params._extend = extend
460
+ }
461
+ }
462
+ for (const [key, value] of Object.entries(this.resolvedFilter)) {
463
+ if (value && typeof value === 'object' && !Array.isArray(value)) {
464
+ for (const [op, operand] of Object.entries(value)) {
465
+ params[`${key}[${op}]`] = operand
466
+ }
467
+ } else if (value !== '' && value !== null && value !== undefined) {
468
+ params[key] = value
469
+ }
470
+ }
471
+ const response = await axios.get(url, { params })
472
+ const data = response && response.data ? response.data : {}
473
+ this.rows = Array.isArray(data.results) ? data.results : []
474
+ this.total = typeof data.total === 'number' ? data.total : this.rows.length
475
+ } catch (e) {
476
+ // eslint-disable-next-line no-console
477
+ console.warn('[CnRecordListWidget] failed to load objects:', e)
478
+ this.rows = []
479
+ this.total = 0
480
+ this.error = true
481
+ } finally {
482
+ this.loading = false
483
+ this.emitHeader()
484
+ }
485
+ },
486
+ },
487
+ }
488
+ </script>
489
+
490
+ <style scoped>
491
+ .cn-record-list__list {
492
+ list-style: none;
493
+ margin: 0;
494
+ padding: 0;
495
+ }
496
+
497
+ .cn-record-list__empty,
498
+ .cn-record-list__error {
499
+ color: var(--color-text-maxcontrast);
500
+ margin: 0;
501
+ }
502
+
503
+ .cn-record-list__loading {
504
+ display: flex;
505
+ justify-content: center;
506
+ padding: 8px 0;
507
+ }
508
+
509
+ /* rows */
510
+ .cn-record-list--rows .cn-record-list__item + .cn-record-list__item {
511
+ border-top: 1px solid var(--color-border);
512
+ }
513
+
514
+ .cn-record-list__row {
515
+ align-items: center;
516
+ color: var(--color-main-text);
517
+ display: flex;
518
+ gap: 16px;
519
+ padding: 12px 0;
520
+ text-decoration: none;
521
+ }
522
+
523
+ .cn-record-list__row--link:hover .cn-record-list__title,
524
+ .cn-record-list__row--link:focus-visible .cn-record-list__title {
525
+ text-decoration: underline;
526
+ }
527
+
528
+ .cn-record-list__avatar {
529
+ align-items: center;
530
+ background: var(--color-background-hover);
531
+ border-radius: 50%;
532
+ color: var(--color-main-text);
533
+ display: flex;
534
+ flex: none;
535
+ font-size: 12px;
536
+ font-weight: 700;
537
+ height: 36px;
538
+ justify-content: center;
539
+ width: 36px;
540
+ }
541
+
542
+ .cn-record-list__main {
543
+ display: flex;
544
+ flex: 1 1 auto;
545
+ flex-direction: column;
546
+ gap: 2px;
547
+ min-width: 0;
548
+ }
549
+
550
+ .cn-record-list__title {
551
+ font-size: 15px;
552
+ font-weight: 700;
553
+ }
554
+
555
+ .cn-record-list__meta {
556
+ color: var(--color-text-maxcontrast);
557
+ font-size: 13px;
558
+ }
559
+
560
+ .cn-record-list__aside {
561
+ align-items: center;
562
+ display: flex;
563
+ flex: none;
564
+ gap: 16px;
565
+ }
566
+
567
+ .cn-record-list__trailing {
568
+ font-size: 14px;
569
+ white-space: nowrap;
570
+ }
571
+
572
+ .cn-record-list__chevron {
573
+ color: var(--color-text-maxcontrast);
574
+ flex: none;
575
+ }
576
+
577
+ /* feed */
578
+ .cn-record-list--feed .cn-record-list__item + .cn-record-list__item {
579
+ border-top: 1px solid var(--color-border);
580
+ }
581
+
582
+ .cn-record-list__feed-row {
583
+ align-items: flex-start;
584
+ display: flex;
585
+ gap: 14px;
586
+ padding: 12px 0;
587
+ }
588
+
589
+ .cn-record-list__feed-icon {
590
+ align-items: center;
591
+ background: var(--color-primary-element-light);
592
+ border-radius: 50%;
593
+ color: var(--color-primary-element-light-text, var(--color-primary-element));
594
+ display: flex;
595
+ flex: none;
596
+ height: 36px;
597
+ justify-content: center;
598
+ width: 36px;
599
+ }
600
+
601
+ .cn-record-list__text {
602
+ font-size: 15px;
603
+ }
604
+
605
+ .cn-record-list--feed .cn-record-list__main {
606
+ color: var(--color-main-text);
607
+ text-decoration: none;
608
+ }
609
+
610
+ /* inline */
611
+ .cn-record-list__inline-row {
612
+ padding: 4px 0;
613
+ }
614
+
615
+ .cn-record-list__label {
616
+ margin-inline-end: 4px;
617
+ }
618
+
619
+ .cn-record-list__inline-title {
620
+ color: var(--color-main-text);
621
+ }
622
+
623
+ a.cn-record-list__inline-title {
624
+ color: var(--color-primary-element);
625
+ text-decoration: underline;
626
+ }
627
+ </style>
628
+
629
+ <style>
630
+ /* In a narrow side column a row stacks: title, meta, then pill and date. */
631
+ .cn-detail-page__side .cn-record-list__row {
632
+ align-items: flex-start;
633
+ flex-direction: column;
634
+ gap: 6px;
635
+ }
636
+
637
+ .cn-detail-page__side .cn-record-list__row .cn-record-list__title {
638
+ color: var(--color-primary-element);
639
+ text-decoration: underline;
640
+ }
641
+
642
+ .cn-detail-page__side .cn-record-list__chevron {
643
+ display: none;
644
+ }
645
+
646
+ /* A row is a touch target of at least 44px on a phone. */
647
+ @media (max-width: 640px) {
648
+ .cn-record-list__row {
649
+ min-height: 44px;
650
+ }
651
+ }
652
+ </style>
@@ -0,0 +1,30 @@
1
+ /**
2
+ * SPDX-FileCopyrightText: 2026 Conduction B.V.
3
+ * SPDX-License-Identifier: EUPL-1.2
4
+ *
5
+ * CnRecordListWidget — self-registers the `record-list` widget type (the
6
+ * objects of another schema that point at this record, as board rows, a feed
7
+ * or inline links) into the shared dashboardWidgetRegistry at module load.
8
+ * Renderer only: the list is declared in the manifest.
9
+ */
10
+
11
+ import CnRecordListWidget from './CnRecordListWidget.vue'
12
+ import { registerDashboardWidget } from '../CnWidgetGrid/dashboardWidgetRegistry.js'
13
+
14
+ registerDashboardWidget('record-list', {
15
+ renderer: CnRecordListWidget,
16
+ form: null,
17
+ defaultContent: {
18
+ register: '',
19
+ schema: '',
20
+ filter: {},
21
+ presentation: 'rows',
22
+ limit: 5,
23
+ },
24
+ displayName: 'Record list',
25
+ icon: 'FormatListBulleted',
26
+ surfaces: ['detail-page', 'app-dashboard'],
27
+ })
28
+
29
+ export { CnRecordListWidget }
30
+ export default CnRecordListWidget