@conduction/nextcloud-vue 2.75.0 → 2.77.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 (158) hide show
  1. package/dist/esm/components/CnAppNav/CnAppNav.vue2.js +18 -3
  2. package/dist/esm/components/CnAppNav/CnAppNav.vue2.js.map +1 -1
  3. package/dist/esm/components/CnAppNav/CnAppNav.vue3.js +49 -3
  4. package/dist/esm/components/CnAppNav/CnAppNav.vue3.js.map +1 -1
  5. package/dist/esm/components/CnCardGrid/CnCardGrid.vue2.js +6 -0
  6. package/dist/esm/components/CnCardGrid/CnCardGrid.vue2.js.map +1 -1
  7. package/dist/esm/components/CnCardGrid/CnCardGrid.vue3.js +3 -2
  8. package/dist/esm/components/CnCardGrid/CnCardGrid.vue3.js.map +1 -1
  9. package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue2.js +42 -1
  10. package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue2.js.map +1 -1
  11. package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue3.js +228 -203
  12. package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue3.js.map +1 -1
  13. package/dist/esm/components/CnCellRenderer/CnGroupNameCell.vue.js +9 -0
  14. package/dist/esm/components/CnCellRenderer/CnGroupNameCell.vue.js.map +1 -0
  15. package/dist/esm/components/CnCellRenderer/CnGroupNameCell.vue2.js +50 -0
  16. package/dist/esm/components/CnCellRenderer/CnGroupNameCell.vue2.js.map +1 -0
  17. package/dist/esm/components/CnCellRenderer/CnGroupNameCell.vue3.js +13 -0
  18. package/dist/esm/components/CnCellRenderer/CnGroupNameCell.vue3.js.map +1 -0
  19. package/dist/esm/components/CnCredentials/CnCredentials.vue2.js +11 -10
  20. package/dist/esm/components/CnCredentials/CnCredentials.vue2.js.map +1 -1
  21. package/dist/esm/components/CnCredentials/CnCredentials.vue3.js.map +1 -1
  22. package/dist/esm/components/CnDataTable/CnDataTable.vue2.js +41 -4
  23. package/dist/esm/components/CnDataTable/CnDataTable.vue2.js.map +1 -1
  24. package/dist/esm/components/CnDataTable/CnDataTable.vue3.js +90 -51
  25. package/dist/esm/components/CnDataTable/CnDataTable.vue3.js.map +1 -1
  26. package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js +24 -33
  27. package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js.map +1 -1
  28. package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js +12 -24
  29. package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js.map +1 -1
  30. package/dist/esm/components/CnFavouriteToggle/CnFavouriteToggle.vue2.js +7 -2
  31. package/dist/esm/components/CnFavouriteToggle/CnFavouriteToggle.vue2.js.map +1 -1
  32. package/dist/esm/components/CnFavouriteToggle/CnFavouriteToggle.vue3.js.map +1 -1
  33. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js +114 -1
  34. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js.map +1 -1
  35. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js +115 -62
  36. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js.map +1 -1
  37. package/dist/esm/components/CnFollowToggle/CnFollowToggle.vue2.js +89 -7
  38. package/dist/esm/components/CnFollowToggle/CnFollowToggle.vue2.js.map +1 -1
  39. package/dist/esm/components/CnFollowToggle/CnFollowToggle.vue3.js +62 -30
  40. package/dist/esm/components/CnFollowToggle/CnFollowToggle.vue3.js.map +1 -1
  41. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +242 -19
  42. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
  43. package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js +25 -20
  44. package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
  45. package/dist/esm/components/CnIndexPage/selfModeActions.js +90 -14
  46. package/dist/esm/components/CnIndexPage/selfModeActions.js.map +1 -1
  47. package/dist/esm/components/CnIndexPage/useSelfFetchList.js +15 -3
  48. package/dist/esm/components/CnIndexPage/useSelfFetchList.js.map +1 -1
  49. package/dist/esm/components/CnObjectCard/CnObjectCard.vue2.js +26 -0
  50. package/dist/esm/components/CnObjectCard/CnObjectCard.vue2.js.map +1 -1
  51. package/dist/esm/components/CnObjectCard/CnObjectCard.vue3.js +26 -9
  52. package/dist/esm/components/CnObjectCard/CnObjectCard.vue3.js.map +1 -1
  53. package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue2.js +199 -7
  54. package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue2.js.map +1 -1
  55. package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue3.js +155 -119
  56. package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue3.js.map +1 -1
  57. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js +19 -3
  58. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js.map +1 -1
  59. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue3.js.map +1 -1
  60. package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue2.js +6 -0
  61. package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue2.js.map +1 -1
  62. package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue3.js +4 -1
  63. package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue3.js.map +1 -1
  64. package/dist/esm/components/CnRelatedObjectsWidget/CnRelatedObjectsWidget.vue2.js +153 -38
  65. package/dist/esm/components/CnRelatedObjectsWidget/CnRelatedObjectsWidget.vue2.js.map +1 -1
  66. package/dist/esm/components/CnRelatedObjectsWidget/CnRelatedObjectsWidget.vue3.js +74 -56
  67. package/dist/esm/components/CnRelatedObjectsWidget/CnRelatedObjectsWidget.vue3.js.map +1 -1
  68. package/dist/esm/components/CnWidgetObjectTable/CnWidgetObjectTable.vue2.js +13 -0
  69. package/dist/esm/components/CnWidgetObjectTable/CnWidgetObjectTable.vue2.js.map +1 -1
  70. package/dist/esm/components/CnWidgetObjectTable/CnWidgetObjectTable.vue3.js.map +1 -1
  71. package/dist/esm/composables/useListView.js +4 -0
  72. package/dist/esm/composables/useListView.js.map +1 -1
  73. package/dist/esm/composables/useObjectLock.js +41 -10
  74. package/dist/esm/composables/useObjectLock.js.map +1 -1
  75. package/dist/esm/index.js +3 -1
  76. package/dist/esm/index.js.map +1 -1
  77. package/dist/esm/l10n/en.json.js +31 -1
  78. package/dist/esm/l10n/en.json.js.map +1 -1
  79. package/dist/esm/l10n/nl.json.js +32 -2
  80. package/dist/esm/l10n/nl.json.js.map +1 -1
  81. package/dist/esm/nextcloud-vue.css +376 -75
  82. package/dist/esm/store/plugins/interactions.js +20 -10
  83. package/dist/esm/store/plugins/interactions.js.map +1 -1
  84. package/dist/esm/store/useObjectStore.js +54 -9
  85. package/dist/esm/store/useObjectStore.js.map +1 -1
  86. package/dist/esm/utils/builtInFormatters.js +15 -7
  87. package/dist/esm/utils/builtInFormatters.js.map +1 -1
  88. package/dist/esm/utils/groupAutocomplete.js +63 -1
  89. package/dist/esm/utils/groupAutocomplete.js.map +1 -1
  90. package/dist/esm/utils/lensAvailability.js +90 -0
  91. package/dist/esm/utils/lensAvailability.js.map +1 -0
  92. package/dist/esm/utils/objectSignals.js +44 -0
  93. package/dist/esm/utils/objectSignals.js.map +1 -0
  94. package/dist/esm/utils/personalLenses.js +13 -6
  95. package/dist/esm/utils/personalLenses.js.map +1 -1
  96. package/dist/esm/utils/recordInteractions.js +31 -13
  97. package/dist/esm/utils/recordInteractions.js.map +1 -1
  98. package/dist/esm/utils/resolveFilterTokens.js +46 -3
  99. package/dist/esm/utils/resolveFilterTokens.js.map +1 -1
  100. package/dist/esm/utils/schema.js +1 -1
  101. package/dist/esm/utils/schema.js.map +1 -1
  102. package/dist/esm/utils/sentinelTokens.js +4 -4
  103. package/dist/esm/utils/sentinelTokens.js.map +1 -1
  104. package/dist/esm/utils/validateManifestV2.compiled.js +2 -2
  105. package/dist/esm/utils/validateManifestV2.compiled.js.map +1 -1
  106. package/dist/esm/utils/widgetVisibility.js +46 -1
  107. package/dist/esm/utils/widgetVisibility.js.map +1 -1
  108. package/dist/nextcloud-vue.cjs.js +4732 -2990
  109. package/dist/nextcloud-vue.cjs.js.map +2 -2
  110. package/dist/nextcloud-vue.css +376 -75
  111. package/l10n/en.json +31 -1
  112. package/l10n/nl.json +32 -2
  113. package/package.json +1 -1
  114. package/src/components/CnAppNav/CnAppNav.vue +44 -5
  115. package/src/components/CnCardGrid/CnCardGrid.md +1 -0
  116. package/src/components/CnCardGrid/CnCardGrid.vue +7 -0
  117. package/src/components/CnCellRenderer/CnCellRenderer.vue +56 -1
  118. package/src/components/CnCellRenderer/CnGroupNameCell.vue +61 -0
  119. package/src/components/CnCredentials/CnCredentials.vue +17 -16
  120. package/src/components/CnDataTable/CnDataTable.md +9 -0
  121. package/src/components/CnDataTable/CnDataTable.vue +80 -20
  122. package/src/components/CnDetailPage/CnDetailPage.vue +18 -32
  123. package/src/components/CnFavouriteToggle/CnFavouriteToggle.vue +7 -2
  124. package/src/components/CnFilesBrowser/CnFilesBrowser.vue +204 -5
  125. package/src/components/CnFollowToggle/CnFollowToggle.vue +118 -13
  126. package/src/components/CnIndexPage/CnIndexPage.md +51 -0
  127. package/src/components/CnIndexPage/CnIndexPage.vue +261 -35
  128. package/src/components/CnIndexPage/selfModeActions.js +89 -13
  129. package/src/components/CnIndexPage/useSelfFetchList.js +15 -3
  130. package/src/components/CnObjectCard/CnObjectCard.md +1 -0
  131. package/src/components/CnObjectCard/CnObjectCard.vue +89 -1
  132. package/src/components/CnObjectDataWidget/CnObjectDataWidget.vue +226 -2
  133. package/src/components/CnObjectListWidget/CnObjectListWidget.vue +19 -3
  134. package/src/components/CnObjectSidebar/CnFilesTab.vue +9 -0
  135. package/src/components/CnRelatedObjectsWidget/CnRelatedObjectsWidget.vue +181 -38
  136. package/src/components/CnWidgetObjectTable/CnWidgetObjectTable.vue +13 -0
  137. package/src/composables/__tests__/useObjectLock.endpoints.spec.js +83 -0
  138. package/src/composables/useListView.js +4 -0
  139. package/src/composables/useObjectLock.js +41 -10
  140. package/src/css/look-board-detail.css +40 -2
  141. package/src/css/look-board-index.css +35 -1
  142. package/src/css/table.css +82 -17
  143. package/src/index.js +3 -1
  144. package/src/schemas/app-manifest-v2.schema.json +11 -7
  145. package/src/store/plugins/interactions.js +20 -10
  146. package/src/store/useObjectStore.js +54 -9
  147. package/src/utils/builtInFormatters.js +15 -7
  148. package/src/utils/groupAutocomplete.js +75 -0
  149. package/src/utils/index.js +2 -1
  150. package/src/utils/lensAvailability.js +86 -0
  151. package/src/utils/objectSignals.js +41 -0
  152. package/src/utils/personalLenses.js +13 -6
  153. package/src/utils/recordInteractions.js +31 -13
  154. package/src/utils/resolveFilterTokens.js +45 -2
  155. package/src/utils/schema.js +1 -1
  156. package/src/utils/sentinelTokens.js +4 -4
  157. package/src/utils/validateManifestV2.compiled.js +2 -2
  158. package/src/utils/widgetVisibility.js +45 -0
@@ -15,7 +15,7 @@ import __sfc_main$v from '../../dialogs/CnConfirmDialog.vue.js';
15
15
  import __sfc_main$w from '../../dialogs/CnQuickEditDialog.vue.js';
16
16
  import __sfc_main from '../CnBuildiqEditButton/CnBuildiqEditButton.vue.js';
17
17
  import __sfc_main$2 from '../CnEmptyContent/CnEmptyContent.vue.js';
18
- import __sfc_main$1 from '../CnFavouriteToggle/CnFavouriteToggle.vue.js';
18
+ import __sfc_main$1 from '../CnFollowToggle/CnFollowToggle.vue.js';
19
19
  import { useLook } from '../../composables/useLook.js';
20
20
  import { copyKindsOf } from '../../composables/useObjectCopy.js';
21
21
  import { createRefLabelResolver } from '../../composables/useRefLabels.js';
@@ -27,10 +27,12 @@ import { resolveRegisteredHandler, buildOnSuccessRoute } from '../../utils/actio
27
27
  import { reportBindingProblems } from '../../utils/diagnostics.js';
28
28
  import { fetchFilterCounts } from '../../utils/fetchFilterCounts.js';
29
29
  import { buildExportUrl } from '../../utils/indexExportHelpers.js';
30
+ import { lensUnavailableText } from '../../utils/lensAvailability.js';
30
31
  import { openRowTarget } from '../../utils/linkNavigation.js';
31
32
  import { resolveClaimedTeams, splitViewsIntoTabs, viewAsTab, resolveClaimTokens, viewIdOf } from '../../utils/listLenses.js';
32
33
  import { LIST_SHORTCUTS, listPaletteCommands, shortcutFor } from '../../utils/listShortcuts.js';
33
34
  import { multiKeySort } from '../../utils/multiKeySort.js';
35
+ import { OBJECTS_CHANGED_EVENT } from '../../utils/objectSignals.js';
34
36
  import { withPersonalLenses } from '../../utils/personalLenses.js';
35
37
  import { resolveDeepTokens, resolveFilterValue } from '../../utils/resolveFilterTokens.js';
36
38
  import { resolveRowActions } from '../../utils/resolveRowActions.js';
@@ -79,7 +81,7 @@ import { buildDefaultActions } from './defaultActions.js';
79
81
  import { dispatchAction } from './manifestActionDispatch.js';
80
82
  import { applyManualOrder, manualOrderKey, moveInOrder, visibleIdsOf, dropInOrder } from './manualOrder.js';
81
83
  import { reconcilePersonalColumns, orderColumns, personalColumnsKey } from './personalColumns.js';
82
- import { createSelfModeActions } from './selfModeActions.js';
84
+ import { createSelfModeActions, resolveRowTarget } from './selfModeActions.js';
83
85
  import { applyRowPatches, splitLayoutFor, normalisePaneWidth, rowIdOf } from './splitView.js';
84
86
  import { useNamedSource } from './useNamedSource.js';
85
87
  import { useSelfFetchList } from './useSelfFetchList.js';
@@ -99,8 +101,8 @@ const CALENDAR_PAGE_SIZE = 200;
99
101
  */
100
102
  const RANGE_SEPARATOR = '..';
101
103
 
102
- /** Key of the synthetic star column (`showFavouriteColumn`). */
103
- const FAVOURITE_COLUMN_KEY = '__favourite';
104
+ /** Key of the synthetic follow column (`showFollowColumn`). */
105
+ const FOLLOW_COLUMN_KEY = '__follow';
104
106
 
105
107
  /**
106
108
  * Whether a schema property wants a from/to pair rather than a value list.
@@ -302,7 +304,7 @@ var script = {
302
304
 
303
305
  components: {
304
306
  CnBuildiqEditButton: __sfc_main,
305
- CnFavouriteToggle: __sfc_main$1,
307
+ CnFollowToggle: __sfc_main$1,
306
308
  NcLoadingIcon,
307
309
  CnEmptyContent: __sfc_main$2,
308
310
  NcActions,
@@ -539,6 +541,17 @@ var script = {
539
541
  default: null,
540
542
  },
541
543
 
544
+ /**
545
+ * Gives each card in the card view a status accent: a colored start
546
+ * border and icon. See CnObjectCard `accent`.
547
+ *
548
+ * @type {((object: object) => ({variant: string, icon: string, label: string}|null))|null}
549
+ */
550
+ cardAccent: {
551
+ type: Function,
552
+ default: null,
553
+ },
554
+
542
555
  /**
543
556
  * Board look: free text after the footer's count ("8 of 48 · click a
544
557
  * column header to sort"). Manifest key `config.footerNote`.
@@ -627,9 +640,10 @@ var script = {
627
640
  },
628
641
 
629
642
  /**
630
- * Personal lenses appended to the quick filters: any of `favourite`
631
- * (`_favourite`), `recent` (`_recent`), `watching` (`_watching`) and
632
- * `unread` (`_unread`).
643
+ * Personal lenses appended to the quick filters: any of `watching`
644
+ * (`_watching`, labelled Following), `recent` (`_recent`) and `unread`
645
+ * (`_unread`). `favourite` is a deprecated alias of `watching`: a
646
+ * favourite is a follow now, and asking for both gives one tab.
633
647
  * They combine with every other filter. While Recent is active column
634
648
  * sorting is off, because the lens owns the order. Manifest
635
649
  * `config.personalLenses`.
@@ -642,9 +656,20 @@ var script = {
642
656
  },
643
657
 
644
658
  /**
645
- * Add a first column with a star per row (`CnFavouriteToggle`), bound to
646
- * each row's `@self.favourite`. Clicking it does not open the row.
647
- * Manifest `config.showFavouriteColumn`.
659
+ * Add a first column with a follow toggle per row (`CnFollowToggle`,
660
+ * compact), bound to each row's `@self.watching`. Clicking it does not
661
+ * open the row. Manifest `config.showFollowColumn`.
662
+ */
663
+ showFollowColumn: {
664
+ type: Boolean,
665
+ default: false,
666
+ },
667
+
668
+ /**
669
+ * Deprecated alias of `showFollowColumn`: the star column became the
670
+ * follow column (OpenRegister `merge-follow-and-favourites`).
671
+ *
672
+ * @deprecated Use `showFollowColumn`.
648
673
  */
649
674
  showFavouriteColumn: {
650
675
  type: Boolean,
@@ -710,6 +735,21 @@ var script = {
710
735
  default: () => [],
711
736
  },
712
737
 
738
+ /**
739
+ * Self-fetch only: list from this endpoint instead of
740
+ * `/api/objects/{register}/{schema}`, e.g. an app endpoint that searches
741
+ * several register/schema pairs at once. `register` and `schema` stay the
742
+ * page's own pair (columns, create, export, import). Rows of another pair,
743
+ * read from their `@self.register` / `@self.schema`, are edited, copied and
744
+ * deleted against that pair, with its own form. The endpoint takes
745
+ * `_page`, `_limit`, `_search` and `_order[key]=dir` and answers
746
+ * `{ results, total, page, pages }`.
747
+ */
748
+ collectionUrl: {
749
+ type: String,
750
+ default: '',
751
+ },
752
+
713
753
  /**
714
754
  * Offer an "Also search inside files" switch beside the search box. On,
715
755
  * a search also matches words inside attached files (OpenRegister
@@ -1124,6 +1164,34 @@ var script = {
1124
1164
  default: 'No items found',
1125
1165
  },
1126
1166
 
1167
+ /**
1168
+ * Personal-lens report of the list on screen, for a host that fetches
1169
+ * itself: the response's `@self.lenses` (`{ recent: { available,
1170
+ * reason } }`). In self-fetch mode the page reads it from the store
1171
+ * and this prop is ignored. When a lens reports `available: false`
1172
+ * the empty state explains why instead of showing `emptyText`.
1173
+ *
1174
+ * @type {object|null}
1175
+ * @spec openspec/changes/lens-says-why-it-is-empty/specs/personal-lens-availability/spec.md#requirement-an-unavailable-lens-explains-its-empty-page
1176
+ */
1177
+ lenses: {
1178
+ type: Object,
1179
+ default: null,
1180
+ },
1181
+
1182
+ /**
1183
+ * App wording for an unavailable lens, keyed `<lens>.<reason>`
1184
+ * (`recent.audit-trail-disabled`) or `<reason>`; the specific key
1185
+ * wins, and both win over the library's object-neutral text.
1186
+ *
1187
+ * @type {{[key: string]: string}|null}
1188
+ * @spec openspec/changes/lens-says-why-it-is-empty/specs/personal-lens-availability/spec.md#requirement-an-unavailable-lens-explains-its-empty-page
1189
+ */
1190
+ lensReasonTexts: {
1191
+ type: Object,
1192
+ default: null,
1193
+ },
1194
+
1127
1195
  /** Accessible label for the loading spinner (NcLoadingIcon aria-label) */
1128
1196
  loadingText: {
1129
1197
  type: String,
@@ -2217,6 +2285,8 @@ var script = {
2217
2285
  */
2218
2286
  persistedFilterKeys: [...(this.initialQueryFilterKeys || [])],
2219
2287
  internalSelectedIds: [...this.selectedIds],
2288
+ // Rows seen in a collectionUrl list, so a selection kept across pages still resolves its own pair.
2289
+ collectionRowsById: markRaw(new Map()),
2220
2290
  // Folder-sidebar state: selected folder id + the register-fetched list.
2221
2291
  selectedFolderId: null,
2222
2292
  /**
@@ -2254,6 +2324,9 @@ var script = {
2254
2324
  // Dialog targets
2255
2325
  actionTargetItem: null,
2256
2326
  editItem: null,
2327
+ // The pair and schema of a row edited outside the page's own pair (collectionUrl).
2328
+ rowFormTarget: null,
2329
+ rowFormSchema: null,
2257
2330
  // Drives the Actions-menu Refresh spinner during a self-fetch
2258
2331
  // refresh, where the host has no promise to bind `:refreshing` to.
2259
2332
  internalRefreshing: false,
@@ -2310,6 +2383,40 @@ var script = {
2310
2383
  return this.emptyText ? fn(this.emptyText) : this.emptyText
2311
2384
  },
2312
2385
 
2386
+ /**
2387
+ * The personal-lens reports of the list on screen: the store's copy
2388
+ * of the latest response in self-fetch mode, else the `lenses` prop.
2389
+ *
2390
+ * @return {object}
2391
+ * @spec openspec/changes/lens-says-why-it-is-empty/specs/personal-lens-availability/spec.md#requirement-a-list-response-carries-the-report-of-the-lenses-it-was-asked-for
2392
+ */
2393
+ effectiveLenses() {
2394
+ if (this.isNamedSource) {
2395
+ return {}
2396
+ }
2397
+ if (this.isSelfFetchMode) {
2398
+ return (this.list.lenses && this.list.lenses.value) || {}
2399
+ }
2400
+ return this.lenses || {}
2401
+ },
2402
+
2403
+ /**
2404
+ * Why the list is empty when a personal lens could not answer (the
2405
+ * audit trail is off, nobody is logged in, the history could not be
2406
+ * read), or `''` to keep the generic empty text.
2407
+ *
2408
+ * @return {string}
2409
+ * @spec openspec/changes/lens-says-why-it-is-empty/specs/personal-lens-availability/spec.md#requirement-an-unavailable-lens-explains-its-empty-page
2410
+ */
2411
+ lensReasonText() {
2412
+ const text = lensUnavailableText(this.effectiveLenses, this.lensReasonTexts);
2413
+ if (!text) {
2414
+ return ''
2415
+ }
2416
+ const fn = typeof this.cnTranslate === 'function' ? this.cnTranslate : (k) => k;
2417
+ return fn(text)
2418
+ },
2419
+
2313
2420
  /**
2314
2421
  * Whether the host manifest editor is in edit mode (unwraps the injected
2315
2422
  * `cnEditingBody`, which may be a Vue ref or a plain boolean). Drives the
@@ -3203,12 +3310,22 @@ var script = {
3203
3310
  if (this.recentLensActive) {
3204
3311
  cols = cols.map((col) => (col && typeof col === 'object' ? { ...col, sortable: false } : col));
3205
3312
  }
3206
- if (this.showFavouriteColumn && this.favouriteSchemaSlug !== '') {
3207
- cols = [{ key: FAVOURITE_COLUMN_KEY, label: '', sortable: false, width: '48px' }, ...cols];
3313
+ if (this.followColumnOn && this.favouriteSchemaSlug !== '') {
3314
+ cols = [{ key: FOLLOW_COLUMN_KEY, label: '', sortable: false, width: '48px' }, ...cols];
3208
3315
  }
3209
3316
  return cols
3210
3317
  },
3211
3318
 
3319
+ /**
3320
+ * Whether the follow column renders (`showFollowColumn`, or the deprecated `showFavouriteColumn`).
3321
+ *
3322
+ * @return {boolean}
3323
+ * @spec openspec/changes/one-follow-control/specs/record-follow/spec.md#requirement-index-pages-offer-one-following-lens-and-a-follow-column
3324
+ */
3325
+ followColumnOn() {
3326
+ return this.showFollowColumn || this.showFavouriteColumn
3327
+ },
3328
+
3212
3329
  /**
3213
3330
  * Whether the active quick filter is the Recent lens.
3214
3331
  *
@@ -3223,7 +3340,7 @@ var script = {
3223
3340
  },
3224
3341
 
3225
3342
  /**
3226
- * Schema slug the star column calls with: the page's own slug in self-fetch
3343
+ * Schema slug the follow column calls with: the page's own slug in self-fetch
3227
3344
  * mode, else the schema object's `slug`. Empty when neither is known.
3228
3345
  *
3229
3346
  * @return {string}
@@ -3535,6 +3652,16 @@ var script = {
3535
3652
  return (this.schema && typeof this.schema === 'object') ? this.schema : null
3536
3653
  },
3537
3654
 
3655
+ /** The form dialog's schema: the edited row's own when it is of another pair. */
3656
+ formSchema() {
3657
+ return this.rowFormTarget ? this.rowFormSchema : this.effectiveSchema
3658
+ },
3659
+
3660
+ /** The form dialog's register, following `formSchema`. */
3661
+ formRegister() {
3662
+ return this.rowFormTarget ? this.rowFormTarget.register : this.register
3663
+ },
3664
+
3538
3665
  /**
3539
3666
  * Schema slug for the export-leaf URL — the `schema` prop directly
3540
3667
  * when it's a string (self-fetch mode's precondition), else the
@@ -3921,8 +4048,7 @@ var script = {
3921
4048
  this.$emit('edit-open', row);
3922
4049
  return
3923
4050
  }
3924
- this.editItem = row;
3925
- this.showFormDialogVisible = true;
4051
+ this.openFormFor(row);
3926
4052
  },
3927
4053
  onCopy: (row) => {
3928
4054
  this.actionTargetItem = row;
@@ -4431,6 +4557,21 @@ var script = {
4431
4557
  },
4432
4558
 
4433
4559
  watch: {
4560
+ effectiveObjects: {
4561
+ immediate: true,
4562
+ handler(rows) {
4563
+ if (!this.collectionUrl || !this.isSelfFetchMode || !Array.isArray(rows)) {
4564
+ return
4565
+ }
4566
+ for (const row of rows) {
4567
+ const id = row?.id ?? row?.['@self']?.id;
4568
+ if (id !== undefined && id !== null) {
4569
+ this.collectionRowsById.set(id, row);
4570
+ }
4571
+ }
4572
+ },
4573
+ },
4574
+
4434
4575
  // A column or form field bound to a property the schema lacks is told to the host once.
4435
4576
  effectiveSchema: {
4436
4577
  immediate: true,
@@ -4623,6 +4764,9 @@ var script = {
4623
4764
  if (this.splitViewEnabled && typeof window !== 'undefined') {
4624
4765
  window.addEventListener('resize', this.measureSplitViewport);
4625
4766
  }
4767
+ if (typeof window !== 'undefined') {
4768
+ window.addEventListener(OBJECTS_CHANGED_EVENT, this.onObjectsChanged);
4769
+ }
4626
4770
  this.loadManualOrder();
4627
4771
  this.loadPersonalColumns();
4628
4772
  this.publishHoistedSidebar();
@@ -4647,6 +4791,8 @@ var script = {
4647
4791
  this.selfActions = createSelfModeActions({
4648
4792
  isSelfFetchMode: () => this.isSelfFetchMode,
4649
4793
  selfObjectStore: () => this.selfObjectStore,
4794
+ rowTarget: (row) => this.rowTypeTarget(row),
4795
+ knownRow: (id) => this.collectionRowsById.get(id),
4650
4796
  selfObjectType: () => this.selfObjectType,
4651
4797
  list: () => this.list,
4652
4798
  selectedIds: () => this.internalSelectedIds,
@@ -4672,13 +4818,14 @@ var script = {
4672
4818
  },
4673
4819
 
4674
4820
  /**
4675
- * Drop the resize listener and the hoisted sidebar.
4821
+ * Drop the window listeners and the hoisted sidebar.
4676
4822
  *
4677
4823
  * @spec openspec/changes/case-page-and-list-as-a-place/specs/index-page/spec.md
4678
4824
  */
4679
4825
  beforeUnmount() {
4680
4826
  if (typeof window !== 'undefined') {
4681
4827
  window.removeEventListener('resize', this.measureSplitViewport);
4828
+ window.removeEventListener(OBJECTS_CHANGED_EVENT, this.onObjectsChanged);
4682
4829
  }
4683
4830
  // Clear the holder so the hoisted sidebar disappears when
4684
4831
  // the user navigates away from the index page.
@@ -6140,6 +6287,33 @@ var script = {
6140
6287
  }
6141
6288
  },
6142
6289
 
6290
+ /**
6291
+ * Refresh the list when `dispatchObjectsChanged` names this page's
6292
+ * register and schema, by slug or id. A part missing on either side matches.
6293
+ *
6294
+ * @param {CustomEvent} event The objects-changed event.
6295
+ * @return {void}
6296
+ */
6297
+ onObjectsChanged(event) {
6298
+ // A collection list can hold rows of any pair, so any change may show in it.
6299
+ if (this.isSelfFetchMode && this.collectionUrl) {
6300
+ this.onRefreshEvent();
6301
+ return
6302
+ }
6303
+ const detail = (event && event.detail) || {};
6304
+ const schema = this.effectiveSchema;
6305
+ const schemaIds = [this.schema, schema && schema.id, schema && schema.slug]
6306
+ .filter((v) => v !== undefined && v !== null && v !== '' && typeof v !== 'object')
6307
+ .map(String);
6308
+ if (detail.register && this.register && detail.register !== String(this.register)) {
6309
+ return
6310
+ }
6311
+ if (detail.schema && schemaIds.length > 0 && !schemaIds.includes(detail.schema)) {
6312
+ return
6313
+ }
6314
+ this.onRefreshEvent();
6315
+ },
6316
+
6143
6317
  /** @return {Promise<void>} */
6144
6318
  async onRefreshEvent() {
6145
6319
  this.$emit('refresh');
@@ -7282,6 +7456,8 @@ var script = {
7282
7456
  closeFormDialog() {
7283
7457
  this.showFormDialogVisible = false;
7284
7458
  this.editItem = null;
7459
+ this.rowFormTarget = null;
7460
+ this.rowFormSchema = null;
7285
7461
  },
7286
7462
 
7287
7463
  /**
@@ -7342,8 +7518,55 @@ var script = {
7342
7518
  * @public
7343
7519
  */
7344
7520
  openFormDialog(item = null) {
7345
- this.editItem = item;
7346
- this.showFormDialogVisible = true;
7521
+ return this.openFormFor(item)
7522
+ },
7523
+
7524
+ /**
7525
+ * Open the form dialog for an item. A row of another pair (collectionUrl)
7526
+ * opens with its own schema; everything else opens at once, as before.
7527
+ *
7528
+ * @param {object|null} item The row to edit, or null to create.
7529
+ * @return {Promise<void>|void}
7530
+ */
7531
+ openFormFor(item) {
7532
+ const target = item ? this.rowTypeTarget(item) : null;
7533
+ if (!target) {
7534
+ this.rowFormTarget = null;
7535
+ this.rowFormSchema = null;
7536
+ this.editItem = item;
7537
+ this.showFormDialogVisible = true;
7538
+ return
7539
+ }
7540
+ const store = this.selfObjectStore;
7541
+ return Promise.resolve(store.getSchema?.(target.type) || store.fetchSchema?.(target.type))
7542
+ .catch(() => null)
7543
+ .then((schema) => {
7544
+ if (!schema) {
7545
+ this.toastSavedView('error', translate('nextcloud-vue', 'Could not load the form for this item.'));
7546
+ return
7547
+ }
7548
+ this.rowFormTarget = target;
7549
+ this.rowFormSchema = schema;
7550
+ this.editItem = item;
7551
+ this.showFormDialogVisible = true;
7552
+ })
7553
+ },
7554
+
7555
+ /**
7556
+ * The row's own pair when it differs from the page's in a collectionUrl list.
7557
+ *
7558
+ * @param {object} row The row.
7559
+ * @return {{register: string, schema: string, type: string}|null} The pair, or null.
7560
+ */
7561
+ rowTypeTarget(row) {
7562
+ return resolveRowTarget({
7563
+ collectionUrl: this.isSelfFetchMode ? this.collectionUrl : '',
7564
+ register: this.register,
7565
+ schema: this.schema,
7566
+ primarySchema: this.effectiveSchema,
7567
+ primaryRegister: this.selfObjectStore?.getRegister?.(this.selfObjectType) || null,
7568
+ store: this.selfObjectStore,
7569
+ }, row)
7347
7570
  },
7348
7571
 
7349
7572
  /**