@conduction/nextcloud-vue 2.141.0 → 2.142.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 (74) hide show
  1. package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue.js +1 -1
  2. package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue2.js +13 -0
  3. package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue2.js.map +1 -1
  4. package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue3.js +3 -3
  5. package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue3.js.map +1 -1
  6. package/dist/esm/components/CnDataTable/CnDataTable.vue2.js +21 -0
  7. package/dist/esm/components/CnDataTable/CnDataTable.vue2.js.map +1 -1
  8. package/dist/esm/components/CnDataTable/CnDataTable.vue3.js +1 -1
  9. package/dist/esm/components/CnDataTable/CnDataTable.vue3.js.map +1 -1
  10. package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue.js +1 -1
  11. package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue2.js +34 -3
  12. package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue2.js.map +1 -1
  13. package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue3.js.map +1 -1
  14. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue.js +1 -1
  15. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js +43 -3
  16. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js.map +1 -1
  17. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js +1 -1
  18. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js.map +1 -1
  19. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +21 -1
  20. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
  21. package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js +2 -1
  22. package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
  23. package/dist/esm/components/CnIndexPage/useSelfFetchList.js +14 -0
  24. package/dist/esm/components/CnIndexPage/useSelfFetchList.js.map +1 -1
  25. package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue.js +1 -1
  26. package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue2.js +3 -1
  27. package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue2.js.map +1 -1
  28. package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue3.js +2 -1
  29. package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue3.js.map +1 -1
  30. package/dist/esm/components/CnPartyPicker/CnPartyPicker.vue.js +1 -1
  31. package/dist/esm/components/CnPartyPicker/CnPartyPicker.vue2.js +31 -1
  32. package/dist/esm/components/CnPartyPicker/CnPartyPicker.vue2.js.map +1 -1
  33. package/dist/esm/components/CnPartyPicker/CnPartyPicker.vue3.js.map +1 -1
  34. package/dist/esm/integrations/builtin/contacts/CnContactsTab.vue.js +1 -1
  35. package/dist/esm/integrations/builtin/contacts/CnContactsTab.vue2.js +52 -1
  36. package/dist/esm/integrations/builtin/contacts/CnContactsTab.vue2.js.map +1 -1
  37. package/dist/esm/integrations/builtin/contacts/CnContactsTab.vue3.js +119 -65
  38. package/dist/esm/integrations/builtin/contacts/CnContactsTab.vue3.js.map +1 -1
  39. package/dist/esm/integrations/builtin/deck/CnDeckCard.vue.js +1 -1
  40. package/dist/esm/integrations/builtin/deck/CnDeckCard.vue2.js +86 -4
  41. package/dist/esm/integrations/builtin/deck/CnDeckCard.vue2.js.map +1 -1
  42. package/dist/esm/integrations/builtin/deck/CnDeckCard.vue3.js +67 -5
  43. package/dist/esm/integrations/builtin/deck/CnDeckCard.vue3.js.map +1 -1
  44. package/dist/esm/l10n/en.json.js +10 -1
  45. package/dist/esm/l10n/en.json.js.map +1 -1
  46. package/dist/esm/l10n/nl.json.js +11 -2
  47. package/dist/esm/l10n/nl.json.js.map +1 -1
  48. package/dist/esm/library-style.js +1 -1
  49. package/dist/esm/nextcloud-vue.css +527 -358
  50. package/dist/esm/utils/buildViewTree.js +23 -8
  51. package/dist/esm/utils/buildViewTree.js.map +1 -1
  52. package/dist/nextcloud-vue.cjs.js +1064 -616
  53. package/dist/nextcloud-vue.cjs.js.map +2 -2
  54. package/dist/nextcloud-vue.css +527 -358
  55. package/l10n/en.json +10 -1
  56. package/l10n/nl.json +11 -2
  57. package/package.json +1 -1
  58. package/src/components/CnCellRenderer/CnCellRenderer.vue +15 -1
  59. package/src/components/CnDataTable/CnDataTable.md +1 -0
  60. package/src/components/CnDataTable/CnDataTable.vue +22 -1
  61. package/src/components/CnFactsWidget/CnFactsWidget.vue +34 -3
  62. package/src/components/CnFilesBrowser/CnFilesBrowser.vue +44 -4
  63. package/src/components/CnIndexPage/CnIndexPage.vue +22 -1
  64. package/src/components/CnIndexPage/useSelfFetchList.js +14 -0
  65. package/src/components/CnObjectSidebar/CnFilesTab.vue +4 -1
  66. package/src/components/CnPartyPicker/CnPartyPicker.vue +31 -1
  67. package/src/css/look-board-detail.css +95 -0
  68. package/src/css/look-board-index.css +53 -0
  69. package/src/css/look-board.css +17 -0
  70. package/src/integrations/builtin/contacts/CnContactsTab.vue +101 -26
  71. package/src/integrations/builtin/contacts/__tests__/CnContactsTabBoardRows.spec.js +67 -0
  72. package/src/integrations/builtin/deck/CnDeckCard.vue +121 -2
  73. package/src/integrations/builtin/deck/__tests__/CnDeckCardHeaderActions.spec.js +68 -0
  74. package/src/utils/buildViewTree.js +23 -8
@@ -164,15 +164,15 @@ function buildViewTree({ views = [], labelFilter = '', maxDepth = 3 } = {}) {
164
164
  }
165
165
  }
166
166
 
167
- // Seeded roots first, then the reader's own, each alphabetically. A
168
- // dropdown whose order changes between two openings is a dropdown nobody
169
- // can build a habit with.
167
+ // Seeded roots first, in the order the app declares them, then the
168
+ // reader's own in the order they were saved (DqFilterBeheren). Both are
169
+ // stable between two openings, so a person can build a habit with them.
170
170
  const seededRoots = roots.filter(({ view }) => view?.seeded === true);
171
171
  const ownRoots = roots.filter(({ view }) => view?.seeded !== true);
172
- for (const { view, orphaned } of sortRootsByName(seededRoots)) {
172
+ for (const { view, orphaned } of seededRoots) {
173
173
  emit(view, 0, orphaned);
174
174
  }
175
- for (const { view, orphaned } of sortRootsByName(ownRoots)) {
175
+ for (const { view, orphaned } of sortRootsBySaved(ownRoots)) {
176
176
  emit(view, 0, orphaned);
177
177
  }
178
178
 
@@ -228,13 +228,28 @@ function sortByName(views) {
228
228
  }
229
229
 
230
230
  /**
231
- * Root entries by the name of the view they carry.
231
+ * Root entries in the order their views were saved (`created`, oldest
232
+ * first); views without a saved time follow, by name.
232
233
  *
233
234
  * @param {Array<object>} roots - The root entries.
234
235
  * @return {Array<object>} The same entries, sorted.
235
236
  */
236
- function sortRootsByName(roots) {
237
- return [...roots].sort((left, right) => String(left.view?.name ?? '').localeCompare(String(right.view?.name ?? '')))
237
+ function sortRootsBySaved(roots) {
238
+ const savedAt = (entry) => (typeof entry.view?.created === 'string' ? entry.view.created : '');
239
+ return [...roots].sort((left, right) => {
240
+ const a = savedAt(left);
241
+ const b = savedAt(right);
242
+ if (a !== b) {
243
+ if (a === '') {
244
+ return 1
245
+ }
246
+ if (b === '') {
247
+ return -1
248
+ }
249
+ return a < b ? -1 : 1
250
+ }
251
+ return String(left.view?.name ?? '').localeCompare(String(right.view?.name ?? ''))
252
+ })
238
253
  }
239
254
 
240
255
  export { VIEW_GROUPS, buildViewTree, labelsInUse, labelsOf };
@@ -1 +1 @@
1
- {"version":3,"file":"buildViewTree.js","sources":["../../../src/utils/buildViewTree.js"],"sourcesContent":["/**\n * SPDX-FileCopyrightText: 2026 Conduction B.V. <info@conduction.nl>\n * SPDX-License-Identifier: EUPL-1.2\n *\n * The order two hundred saved views go on screen in.\n *\n * A flat dropdown of two hundred views is the problem the tree exists to\n * solve, so the ordering is the feature and not a detail. It is a pure\n * function for the same reason `resolveViewInheritance` is: the control should\n * render a list somebody else decided, and the decision should be testable\n * without mounting anything.\n *\n * 🔴 A CHILD WHOSE PARENT IS NOT IN THE LIST RENDERS AT THE ROOT. Its parent\n * may be shared with a group this reader is not in, or may have been deleted\n * while the dropdown was open. Dropping the child would take a person's own\n * view off their own screen because of somebody else's permissions; nesting it\n * under nothing would lose it just as thoroughly. It comes back at depth zero,\n * flagged, so the control can say where the gap is.\n *\n * 🔴 A CYCLE DOES NOT HANG THE DROPDOWN, AND DOES NOT SWALLOW ITS MEMBERS.\n * `resolveViewInheritance` refuses a cycle when a view is saved, but a control\n * renders whatever the store hands it, including rows written before that rule\n * existed. A pure cycle has no root, so walking from the roots alone would\n * emit neither of its members: two views a person saved would vanish from\n * their own dropdown with nothing on screen saying so. Every view is emitted\n * exactly once, and anything the walk did not reach comes back at the root.\n *\n * Pure: no store, no fetch, no Vue.\n */\n\n/**\n * The group a view belongs to.\n *\n * Seeded views ship with the app and render above the user's own. The\n * separation is not cosmetic: a user may copy a seeded view but not delete it,\n * so the control has to be able to tell them apart without asking the server\n * a second time.\n *\n * @type {object}\n */\nexport const VIEW_GROUPS = Object.freeze({\n\tSEEDED: 'seeded',\n\tOWN: 'own',\n})\n\n/**\n * Every label in use, in the order the control should offer them.\n *\n * Labels already in use come before the option to type a new one, because a\n * label set that grows one typo at a time stops being a filter. Sorted so two\n * readers of the same views see the same order.\n *\n * @param {Array<object>} views - The views.\n * @return {Array<string>} The labels, without duplicates.\n */\nexport function labelsInUse(views = []) {\n\tconst seen = new Set()\n\tfor (const view of views) {\n\t\tfor (const label of labelsOf(view)) {\n\t\t\tseen.add(label)\n\t\t}\n\t}\n\n\treturn [...seen].sort((left, right) => left.localeCompare(right))\n}\n\n/**\n * The labels one view carries.\n *\n * Accepts `labels` as an array and `label` as a single string, because the\n * manifest declares one per seeded view and OpenRegister stores a list. A\n * reader should not have to know which shape a given view came from.\n *\n * @param {object} view - The view.\n * @return {Array<string>} Its labels, trimmed, without blanks.\n */\nexport function labelsOf(view) {\n\tconst raw = []\n\tif (Array.isArray(view?.labels)) {\n\t\traw.push(...view.labels)\n\t}\n\tif (typeof view?.label === 'string') {\n\t\traw.push(view.label)\n\t}\n\n\treturn raw\n\t\t.map((label) => String(label ?? '').trim())\n\t\t.filter((label) => label !== '')\n}\n\n/**\n * The views as a flat list in tree order, each carrying its depth.\n *\n * Flat rather than nested on purpose: the control renders `NcActionButton`\n * rows, which cannot nest, so a nested structure would have to be flattened\n * again at render time and the indentation would be decided in the template.\n * Here it is decided once and asserted once.\n *\n * @param {object} options - The call.\n * @param {Array<object>} options.views - Every view the reader can see.\n * @param {string} [options.labelFilter] - Show only views carrying this label.\n * @param {number} [options.maxDepth] - How deep to indent before flattening.\n *\n * @return {Array<object>} Rows of `{ view, depth, group, orphaned }`, seeded first.\n */\nexport function buildViewTree({ views = [], labelFilter = '', maxDepth = 3 } = {}) {\n\tconst visible = filterByLabel(views, labelFilter)\n\tconst bySlug = new Map()\n\tfor (const view of visible) {\n\t\tconst slug = slugOf(view)\n\t\tif (slug !== '') {\n\t\t\tbySlug.set(slug, view)\n\t\t}\n\t}\n\n\tconst childrenOf = new Map()\n\tconst roots = []\n\tfor (const view of visible) {\n\t\tconst parent = String(view?.parent ?? '').trim()\n\t\t// A parent outside the VISIBLE set, whether because it is invisible to\n\t\t// this reader or because a label filter just hid it. Either way the\n\t\t// child is still the reader's, so it comes back at the root.\n\t\tif (parent === '' || bySlug.has(parent) === false) {\n\t\t\troots.push({ view, orphaned: parent !== '' })\n\t\t\tcontinue\n\t\t}\n\t\tif (childrenOf.has(parent) === false) {\n\t\t\tchildrenOf.set(parent, [])\n\t\t}\n\t\tchildrenOf.get(parent).push(view)\n\t}\n\n\tconst rows = []\n\tconst emitted = new Set()\n\n\t/**\n\t * Emit one view and everything under it.\n\t *\n\t * @param {object} view - The view.\n\t * @param {number} depth - Its indent level.\n\t * @param {boolean} orphaned - Whether its parent is not in the list.\n\t * @return {void}\n\t */\n\tfunction emit(view, depth, orphaned) {\n\t\tconst slug = slugOf(view)\n\t\t// Exactly once, whatever the data says. A cycle written before the\n\t\t// save-time refusal existed must not hang a dropdown.\n\t\tif (slug !== '' && emitted.has(slug) === true) {\n\t\t\treturn\n\t\t}\n\t\tif (slug !== '') {\n\t\t\temitted.add(slug)\n\t\t}\n\n\t\trows.push({\n\t\t\tview,\n\t\t\tdepth: Math.min(depth, maxDepth),\n\t\t\tgroup: view?.seeded === true ? VIEW_GROUPS.SEEDED : VIEW_GROUPS.OWN,\n\t\t\torphaned,\n\t\t})\n\n\t\tfor (const child of sortByName(childrenOf.get(slug) || [])) {\n\t\t\temit(child, depth + 1, false)\n\t\t}\n\t}\n\n\t// Seeded roots first, then the reader's own, each alphabetically. A\n\t// dropdown whose order changes between two openings is a dropdown nobody\n\t// can build a habit with.\n\tconst seededRoots = roots.filter(({ view }) => view?.seeded === true)\n\tconst ownRoots = roots.filter(({ view }) => view?.seeded !== true)\n\tfor (const { view, orphaned } of sortRootsByName(seededRoots)) {\n\t\temit(view, 0, orphaned)\n\t}\n\tfor (const { view, orphaned } of sortRootsByName(ownRoots)) {\n\t\temit(view, 0, orphaned)\n\t}\n\n\t// 🔴 ANYTHING THE WALK DID NOT REACH, AT THE ROOT. A pure cycle has no\n\t// root, so walking from the roots alone emits neither of its members and\n\t// two views a person saved disappear from their own dropdown with nothing\n\t// on screen saying so. Every view arrives exactly once or the control is\n\t// lying about what exists.\n\tfor (const view of sortByName(visible)) {\n\t\temit(view, 0, true)\n\t}\n\n\treturn rows\n}\n\n/**\n * Only the views carrying a label, when one is asked for.\n *\n * A view with no label stays reachable when no filter is active, which is the\n * half that keeps the filter optional rather than a labelling regime.\n *\n * @param {Array<object>} views - The views.\n * @param {string} labelFilter - The label, or the empty string for all.\n * @return {Array<object>} The views to render.\n */\nfunction filterByLabel(views, labelFilter) {\n\tconst wanted = String(labelFilter ?? '').trim()\n\tif (wanted === '') {\n\t\treturn [...views]\n\t}\n\n\treturn views.filter((view) => labelsOf(view).includes(wanted))\n}\n\n/**\n * A view's stable name, whatever the store called the field.\n *\n * @param {object} view - The view.\n * @return {string} Its slug, or the empty string.\n */\nfunction slugOf(view) {\n\treturn String(view?.slug ?? view?.id ?? '').trim()\n}\n\n/**\n * Views by name, so the order is the same on two screens.\n *\n * @param {Array<object>} views - The views.\n * @return {Array<object>} The same views, sorted.\n */\nfunction sortByName(views) {\n\treturn [...views].sort((left, right) => String(left?.name ?? '').localeCompare(String(right?.name ?? '')))\n}\n\n/**\n * Root entries by the name of the view they carry.\n *\n * @param {Array<object>} roots - The root entries.\n * @return {Array<object>} The same entries, sorted.\n */\nfunction sortRootsByName(roots) {\n\treturn [...roots].sort((left, right) => String(left.view?.name ?? '').localeCompare(String(right.view?.name ?? '')))\n}\n"],"names":[],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACY,MAAC,WAAW,GAAG,MAAM,CAAC,MAAM,CAAC;AACzC,CAAC,MAAM,EAAE,QAAQ;AACjB,CAAC,GAAG,EAAE,KAAK;AACX,CAAC,EAAC;AACF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,WAAW,CAAC,KAAK,GAAG,EAAE,EAAE;AACxC,CAAC,MAAM,IAAI,GAAG,IAAI,GAAG,GAAE;AACvB,CAAC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE;AAC3B,EAAE,KAAK,MAAM,KAAK,IAAI,QAAQ,CAAC,IAAI,CAAC,EAAE;AACtC,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,EAAC;AAClB,GAAG;AACH,EAAE;AACF;AACA,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,KAAK,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;AAClE,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,QAAQ,CAAC,IAAI,EAAE;AAC/B,CAAC,MAAM,GAAG,GAAG,GAAE;AACf,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE;AAClC,EAAE,GAAG,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,MAAM,EAAC;AAC1B,EAAE;AACF,CAAC,IAAI,OAAO,IAAI,EAAE,KAAK,KAAK,QAAQ,EAAE;AACtC,EAAE,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,EAAC;AACtB,EAAE;AACF;AACA,CAAC,OAAO,GAAG;AACX,GAAG,GAAG,CAAC,CAAC,KAAK,KAAK,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;AAC7C,GAAG,MAAM,CAAC,CAAC,KAAK,KAAK,KAAK,KAAK,EAAE,CAAC;AAClC,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,aAAa,CAAC,EAAE,KAAK,GAAG,EAAE,EAAE,WAAW,GAAG,EAAE,EAAE,QAAQ,GAAG,CAAC,EAAE,GAAG,EAAE,EAAE;AACnF,CAAC,MAAM,OAAO,GAAG,aAAa,CAAC,KAAK,EAAE,WAAW,EAAC;AAClD,CAAC,MAAM,MAAM,GAAG,IAAI,GAAG,GAAE;AACzB,CAAC,KAAK,MAAM,IAAI,IAAI,OAAO,EAAE;AAC7B,EAAE,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,EAAC;AAC3B,EAAE,IAAI,IAAI,KAAK,EAAE,EAAE;AACnB,GAAG,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,EAAC;AACzB,GAAG;AACH,EAAE;AACF;AACA,CAAC,MAAM,UAAU,GAAG,IAAI,GAAG,GAAE;AAC7B,CAAC,MAAM,KAAK,GAAG,GAAE;AACjB,CAAC,KAAK,MAAM,IAAI,IAAI,OAAO,EAAE;AAC7B,EAAE,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,EAAE,MAAM,IAAI,EAAE,CAAC,CAAC,IAAI,GAAE;AAClD;AACA;AACA;AACA,EAAE,IAAI,MAAM,KAAK,EAAE,IAAI,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,KAAK,EAAE;AACrD,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,KAAK,EAAE,EAAE,EAAC;AAChD,GAAG,QAAQ;AACX,GAAG;AACH,EAAE,IAAI,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,KAAK,EAAE;AACxC,GAAG,UAAU,CAAC,GAAG,CAAC,MAAM,EAAE,EAAE,EAAC;AAC7B,GAAG;AACH,EAAE,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,EAAC;AACnC,EAAE;AACF;AACA,CAAC,MAAM,IAAI,GAAG,GAAE;AAChB,CAAC,MAAM,OAAO,GAAG,IAAI,GAAG,GAAE;AAC1B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC,SAAS,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE;AACtC,EAAE,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,EAAC;AAC3B;AACA;AACA,EAAE,IAAI,IAAI,KAAK,EAAE,IAAI,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE;AACjD,GAAG,MAAM;AACT,GAAG;AACH,EAAE,IAAI,IAAI,KAAK,EAAE,EAAE;AACnB,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,EAAC;AACpB,GAAG;AACH;AACA,EAAE,IAAI,CAAC,IAAI,CAAC;AACZ,GAAG,IAAI;AACP,GAAG,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,QAAQ,CAAC;AACnC,GAAG,KAAK,EAAE,IAAI,EAAE,MAAM,KAAK,IAAI,GAAG,WAAW,CAAC,MAAM,GAAG,WAAW,CAAC,GAAG;AACtE,GAAG,QAAQ;AACX,GAAG,EAAC;AACJ;AACA,EAAE,KAAK,MAAM,KAAK,IAAI,UAAU,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,EAAE;AAC9D,GAAG,IAAI,CAAC,KAAK,EAAE,KAAK,GAAG,CAAC,EAAE,KAAK,EAAC;AAChC,GAAG;AACH,EAAE;AACF;AACA;AACA;AACA;AACA,CAAC,MAAM,WAAW,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,IAAI,EAAE,MAAM,KAAK,IAAI,EAAC;AACtE,CAAC,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,IAAI,EAAE,MAAM,KAAK,IAAI,EAAC;AACnE,CAAC,KAAK,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,eAAe,CAAC,WAAW,CAAC,EAAE;AAChE,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,EAAE,QAAQ,EAAC;AACzB,EAAE;AACF,CAAC,KAAK,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,eAAe,CAAC,QAAQ,CAAC,EAAE;AAC7D,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,EAAE,QAAQ,EAAC;AACzB,EAAE;AACF;AACA;AACA;AACA;AACA;AACA;AACA,CAAC,KAAK,MAAM,IAAI,IAAI,UAAU,CAAC,OAAO,CAAC,EAAE;AACzC,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,EAAE,IAAI,EAAC;AACrB,EAAE;AACF;AACA,CAAC,OAAO,IAAI;AACZ,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS,aAAa,CAAC,KAAK,EAAE,WAAW,EAAE;AAC3C,CAAC,MAAM,MAAM,GAAG,MAAM,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC,IAAI,GAAE;AAChD,CAAC,IAAI,MAAM,KAAK,EAAE,EAAE;AACpB,EAAE,OAAO,CAAC,GAAG,KAAK,CAAC;AACnB,EAAE;AACF;AACA,CAAC,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;AAC/D,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS,MAAM,CAAC,IAAI,EAAE;AACtB,CAAC,OAAO,MAAM,CAAC,IAAI,EAAE,IAAI,IAAI,IAAI,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE;AACnD,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS,UAAU,CAAC,KAAK,EAAE;AAC3B,CAAC,OAAO,CAAC,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,KAAK,MAAM,CAAC,IAAI,EAAE,IAAI,IAAI,EAAE,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,KAAK,EAAE,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC;AAC3G,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS,eAAe,CAAC,KAAK,EAAE;AAChC,CAAC,OAAO,CAAC,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,KAAK,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,IAAI,EAAE,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC;AACrH;;;;"}
1
+ {"version":3,"file":"buildViewTree.js","sources":["../../../src/utils/buildViewTree.js"],"sourcesContent":["/**\n * SPDX-FileCopyrightText: 2026 Conduction B.V. <info@conduction.nl>\n * SPDX-License-Identifier: EUPL-1.2\n *\n * The order two hundred saved views go on screen in.\n *\n * A flat dropdown of two hundred views is the problem the tree exists to\n * solve, so the ordering is the feature and not a detail. It is a pure\n * function for the same reason `resolveViewInheritance` is: the control should\n * render a list somebody else decided, and the decision should be testable\n * without mounting anything.\n *\n * 🔴 A CHILD WHOSE PARENT IS NOT IN THE LIST RENDERS AT THE ROOT. Its parent\n * may be shared with a group this reader is not in, or may have been deleted\n * while the dropdown was open. Dropping the child would take a person's own\n * view off their own screen because of somebody else's permissions; nesting it\n * under nothing would lose it just as thoroughly. It comes back at depth zero,\n * flagged, so the control can say where the gap is.\n *\n * 🔴 A CYCLE DOES NOT HANG THE DROPDOWN, AND DOES NOT SWALLOW ITS MEMBERS.\n * `resolveViewInheritance` refuses a cycle when a view is saved, but a control\n * renders whatever the store hands it, including rows written before that rule\n * existed. A pure cycle has no root, so walking from the roots alone would\n * emit neither of its members: two views a person saved would vanish from\n * their own dropdown with nothing on screen saying so. Every view is emitted\n * exactly once, and anything the walk did not reach comes back at the root.\n *\n * Pure: no store, no fetch, no Vue.\n */\n\n/**\n * The group a view belongs to.\n *\n * Seeded views ship with the app and render above the user's own. The\n * separation is not cosmetic: a user may copy a seeded view but not delete it,\n * so the control has to be able to tell them apart without asking the server\n * a second time.\n *\n * @type {object}\n */\nexport const VIEW_GROUPS = Object.freeze({\n\tSEEDED: 'seeded',\n\tOWN: 'own',\n})\n\n/**\n * Every label in use, in the order the control should offer them.\n *\n * Labels already in use come before the option to type a new one, because a\n * label set that grows one typo at a time stops being a filter. Sorted so two\n * readers of the same views see the same order.\n *\n * @param {Array<object>} views - The views.\n * @return {Array<string>} The labels, without duplicates.\n */\nexport function labelsInUse(views = []) {\n\tconst seen = new Set()\n\tfor (const view of views) {\n\t\tfor (const label of labelsOf(view)) {\n\t\t\tseen.add(label)\n\t\t}\n\t}\n\n\treturn [...seen].sort((left, right) => left.localeCompare(right))\n}\n\n/**\n * The labels one view carries.\n *\n * Accepts `labels` as an array and `label` as a single string, because the\n * manifest declares one per seeded view and OpenRegister stores a list. A\n * reader should not have to know which shape a given view came from.\n *\n * @param {object} view - The view.\n * @return {Array<string>} Its labels, trimmed, without blanks.\n */\nexport function labelsOf(view) {\n\tconst raw = []\n\tif (Array.isArray(view?.labels)) {\n\t\traw.push(...view.labels)\n\t}\n\tif (typeof view?.label === 'string') {\n\t\traw.push(view.label)\n\t}\n\n\treturn raw\n\t\t.map((label) => String(label ?? '').trim())\n\t\t.filter((label) => label !== '')\n}\n\n/**\n * The views as a flat list in tree order, each carrying its depth.\n *\n * Flat rather than nested on purpose: the control renders `NcActionButton`\n * rows, which cannot nest, so a nested structure would have to be flattened\n * again at render time and the indentation would be decided in the template.\n * Here it is decided once and asserted once.\n *\n * @param {object} options - The call.\n * @param {Array<object>} options.views - Every view the reader can see.\n * @param {string} [options.labelFilter] - Show only views carrying this label.\n * @param {number} [options.maxDepth] - How deep to indent before flattening.\n *\n * @return {Array<object>} Rows of `{ view, depth, group, orphaned }`, seeded first.\n */\nexport function buildViewTree({ views = [], labelFilter = '', maxDepth = 3 } = {}) {\n\tconst visible = filterByLabel(views, labelFilter)\n\tconst bySlug = new Map()\n\tfor (const view of visible) {\n\t\tconst slug = slugOf(view)\n\t\tif (slug !== '') {\n\t\t\tbySlug.set(slug, view)\n\t\t}\n\t}\n\n\tconst childrenOf = new Map()\n\tconst roots = []\n\tfor (const view of visible) {\n\t\tconst parent = String(view?.parent ?? '').trim()\n\t\t// A parent outside the VISIBLE set, whether because it is invisible to\n\t\t// this reader or because a label filter just hid it. Either way the\n\t\t// child is still the reader's, so it comes back at the root.\n\t\tif (parent === '' || bySlug.has(parent) === false) {\n\t\t\troots.push({ view, orphaned: parent !== '' })\n\t\t\tcontinue\n\t\t}\n\t\tif (childrenOf.has(parent) === false) {\n\t\t\tchildrenOf.set(parent, [])\n\t\t}\n\t\tchildrenOf.get(parent).push(view)\n\t}\n\n\tconst rows = []\n\tconst emitted = new Set()\n\n\t/**\n\t * Emit one view and everything under it.\n\t *\n\t * @param {object} view - The view.\n\t * @param {number} depth - Its indent level.\n\t * @param {boolean} orphaned - Whether its parent is not in the list.\n\t * @return {void}\n\t */\n\tfunction emit(view, depth, orphaned) {\n\t\tconst slug = slugOf(view)\n\t\t// Exactly once, whatever the data says. A cycle written before the\n\t\t// save-time refusal existed must not hang a dropdown.\n\t\tif (slug !== '' && emitted.has(slug) === true) {\n\t\t\treturn\n\t\t}\n\t\tif (slug !== '') {\n\t\t\temitted.add(slug)\n\t\t}\n\n\t\trows.push({\n\t\t\tview,\n\t\t\tdepth: Math.min(depth, maxDepth),\n\t\t\tgroup: view?.seeded === true ? VIEW_GROUPS.SEEDED : VIEW_GROUPS.OWN,\n\t\t\torphaned,\n\t\t})\n\n\t\tfor (const child of sortByName(childrenOf.get(slug) || [])) {\n\t\t\temit(child, depth + 1, false)\n\t\t}\n\t}\n\n\t// Seeded roots first, in the order the app declares them, then the\n\t// reader's own in the order they were saved (DqFilterBeheren). Both are\n\t// stable between two openings, so a person can build a habit with them.\n\tconst seededRoots = roots.filter(({ view }) => view?.seeded === true)\n\tconst ownRoots = roots.filter(({ view }) => view?.seeded !== true)\n\tfor (const { view, orphaned } of seededRoots) {\n\t\temit(view, 0, orphaned)\n\t}\n\tfor (const { view, orphaned } of sortRootsBySaved(ownRoots)) {\n\t\temit(view, 0, orphaned)\n\t}\n\n\t// 🔴 ANYTHING THE WALK DID NOT REACH, AT THE ROOT. A pure cycle has no\n\t// root, so walking from the roots alone emits neither of its members and\n\t// two views a person saved disappear from their own dropdown with nothing\n\t// on screen saying so. Every view arrives exactly once or the control is\n\t// lying about what exists.\n\tfor (const view of sortByName(visible)) {\n\t\temit(view, 0, true)\n\t}\n\n\treturn rows\n}\n\n/**\n * Only the views carrying a label, when one is asked for.\n *\n * A view with no label stays reachable when no filter is active, which is the\n * half that keeps the filter optional rather than a labelling regime.\n *\n * @param {Array<object>} views - The views.\n * @param {string} labelFilter - The label, or the empty string for all.\n * @return {Array<object>} The views to render.\n */\nfunction filterByLabel(views, labelFilter) {\n\tconst wanted = String(labelFilter ?? '').trim()\n\tif (wanted === '') {\n\t\treturn [...views]\n\t}\n\n\treturn views.filter((view) => labelsOf(view).includes(wanted))\n}\n\n/**\n * A view's stable name, whatever the store called the field.\n *\n * @param {object} view - The view.\n * @return {string} Its slug, or the empty string.\n */\nfunction slugOf(view) {\n\treturn String(view?.slug ?? view?.id ?? '').trim()\n}\n\n/**\n * Views by name, so the order is the same on two screens.\n *\n * @param {Array<object>} views - The views.\n * @return {Array<object>} The same views, sorted.\n */\nfunction sortByName(views) {\n\treturn [...views].sort((left, right) => String(left?.name ?? '').localeCompare(String(right?.name ?? '')))\n}\n\n/**\n * Root entries in the order their views were saved (`created`, oldest\n * first); views without a saved time follow, by name.\n *\n * @param {Array<object>} roots - The root entries.\n * @return {Array<object>} The same entries, sorted.\n */\nfunction sortRootsBySaved(roots) {\n\tconst savedAt = (entry) => (typeof entry.view?.created === 'string' ? entry.view.created : '')\n\treturn [...roots].sort((left, right) => {\n\t\tconst a = savedAt(left)\n\t\tconst b = savedAt(right)\n\t\tif (a !== b) {\n\t\t\tif (a === '') {\n\t\t\t\treturn 1\n\t\t\t}\n\t\t\tif (b === '') {\n\t\t\t\treturn -1\n\t\t\t}\n\t\t\treturn a < b ? -1 : 1\n\t\t}\n\t\treturn String(left.view?.name ?? '').localeCompare(String(right.view?.name ?? ''))\n\t})\n}\n"],"names":[],"mappings":"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"}