@conduction/nextcloud-vue 2.138.0 → 2.140.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.
- package/dist/esm/components/CnAppRoot/CnAppRoot.vue2.js +9 -2
- package/dist/esm/components/CnAppRoot/CnAppRoot.vue2.js.map +1 -1
- package/dist/esm/components/CnAppRoot/CnAppRoot.vue3.js.map +1 -1
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue.js +1 -1
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue2.js +17 -1
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue2.js.map +1 -1
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue3.js +2 -2
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue3.js.map +1 -1
- package/dist/esm/components/CnChartWidget/CnChartWidget.vue.js +1 -1
- package/dist/esm/components/CnChartWidget/CnChartWidget.vue2.js +52 -1
- package/dist/esm/components/CnChartWidget/CnChartWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnChartWidget/CnChartWidget.vue3.js +23 -1
- package/dist/esm/components/CnChartWidget/CnChartWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnConversationThread/CnConversationWidget.vue.js +1 -1
- package/dist/esm/components/CnConversationThread/CnConversationWidget.vue2.js +106 -0
- package/dist/esm/components/CnConversationThread/CnConversationWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnConversationThread/CnConversationWidget.vue3.js +30 -7
- package/dist/esm/components/CnConversationThread/CnConversationWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue.js +1 -1
- package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue2.js +59 -3
- package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue3.js +44 -34
- package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue.js +1 -1
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js +28 -1
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js.map +1 -1
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js.map +1 -1
- package/dist/esm/components/CnFilesBrowser/filesBrowser.js +7 -1
- package/dist/esm/components/CnFilesBrowser/filesBrowser.js.map +1 -1
- package/dist/esm/components/CnFilesBrowser/filesBrowserColumns.js +5 -0
- package/dist/esm/components/CnFilesBrowser/filesBrowserColumns.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +129 -6
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js +2 -2
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
- package/dist/esm/components/CnIndexSidebar/CnIndexSidebar.vue2.js +2 -0
- package/dist/esm/components/CnIndexSidebar/CnIndexSidebar.vue2.js.map +1 -1
- package/dist/esm/components/CnIndexSidebar/CnIndexSidebar.vue3.js +13 -2
- package/dist/esm/components/CnIndexSidebar/CnIndexSidebar.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue.js +1 -1
- package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue2.js +28 -3
- package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue.js +1 -1
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js +1 -1
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordNoteRows.vue.js +1 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordNoteRows.vue2.js +10 -0
- package/dist/esm/components/CnRecordListWidget/CnRecordNoteRows.vue2.js.map +1 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordNoteRows.vue3.js.map +1 -1
- package/dist/esm/components/CnStackedBarWidget/CnStackedBarWidget.vue.js +1 -1
- package/dist/esm/components/CnStackedBarWidget/CnStackedBarWidget.vue2.js +12 -1
- package/dist/esm/components/CnStackedBarWidget/CnStackedBarWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnStackedBarWidget/CnStackedBarWidget.vue3.js +1 -1
- package/dist/esm/components/CnStackedBarWidget/CnStackedBarWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnTransitionInputFields/CnTransitionInputFields.vue.js +1 -1
- package/dist/esm/components/CnTransitionInputFields/CnTransitionInputFields.vue2.js +23 -1
- package/dist/esm/components/CnTransitionInputFields/CnTransitionInputFields.vue2.js.map +1 -1
- package/dist/esm/components/CnTransitionInputFields/CnTransitionInputFields.vue3.js +43 -13
- package/dist/esm/components/CnTransitionInputFields/CnTransitionInputFields.vue3.js.map +1 -1
- package/dist/esm/composables/indexSources.js +48 -6
- package/dist/esm/composables/indexSources.js.map +1 -1
- package/dist/esm/composables/useTaskInboxStore.js +4 -3
- package/dist/esm/composables/useTaskInboxStore.js.map +1 -1
- package/dist/esm/l10n/en.json.js +4 -1
- package/dist/esm/l10n/en.json.js.map +1 -1
- package/dist/esm/l10n/nl.json.js +7 -1
- package/dist/esm/l10n/nl.json.js.map +1 -1
- package/dist/esm/library-style.js +1 -1
- package/dist/esm/nextcloud-vue.css +604 -407
- package/dist/esm/utils/builtInFormatters.js +23 -1
- package/dist/esm/utils/builtInFormatters.js.map +1 -1
- package/dist/esm/utils/fillTemplate.js +7 -1
- package/dist/esm/utils/fillTemplate.js.map +1 -1
- package/dist/esm/utils/myTeam.js +24 -4
- package/dist/esm/utils/myTeam.js.map +1 -1
- package/dist/esm/utils/resolveFilterTokens.js +5 -4
- package/dist/esm/utils/resolveFilterTokens.js.map +1 -1
- package/dist/esm/utils/transitionInputs.js +43 -2
- package/dist/esm/utils/transitionInputs.js.map +1 -1
- package/dist/nextcloud-vue.cjs.js +932 -236
- package/dist/nextcloud-vue.cjs.js.map +2 -2
- package/dist/nextcloud-vue.css +604 -407
- package/l10n/en.json +4 -1
- package/l10n/nl.json +7 -1
- package/package.json +1 -1
- package/src/components/CnAppRoot/CnAppRoot.vue +9 -2
- package/src/components/CnCellRenderer/CnCellRenderer.vue +19 -3
- package/src/components/CnChartWidget/CnChartWidget.md +1 -0
- package/src/components/CnChartWidget/CnChartWidget.vue +76 -1
- package/src/components/CnConversationThread/CnConversationWidget.vue +126 -1
- package/src/components/CnFactsWidget/CnFactsWidget.vue +78 -9
- package/src/components/CnFilesBrowser/CnFilesBrowser.vue +39 -1
- package/src/components/CnFilesBrowser/filesBrowser.js +7 -1
- package/src/components/CnFilesBrowser/filesBrowserColumns.js +5 -0
- package/src/components/CnIndexPage/CnIndexPage.vue +131 -8
- package/src/components/CnIndexSidebar/CnIndexSidebar.vue +10 -2
- package/src/components/CnObjectDataWidget/CnObjectDataWidget.vue +28 -3
- package/src/components/CnObjectListWidget/CnObjectListWidget.vue +1 -1
- package/src/components/CnRecordListWidget/CnRecordNoteRows.vue +10 -0
- package/src/components/CnStackedBarWidget/CnStackedBarWidget.vue +68 -2
- package/src/components/CnTransitionInputFields/CnTransitionInputFields.vue +43 -1
- package/src/composables/indexSources.js +48 -6
- package/src/composables/useTaskInboxStore.js +4 -3
- package/src/css/dialog.css +18 -0
- package/src/css/look-board-detail.css +24 -0
- package/src/css/look-board-index.css +21 -0
- package/src/css/look-board.css +31 -2
- package/src/css/table.css +13 -0
- package/src/utils/builtInFormatters.js +22 -0
- package/src/utils/fillTemplate.js +7 -1
- package/src/utils/myTeam.js +24 -4
- package/src/utils/resolveFilterTokens.js +5 -4
- package/src/utils/transitionInputs.js +42 -1
|
@@ -263,13 +263,19 @@ function indexRowData(data, { path = '', key = 'fileId' } = {}) {
|
|
|
263
263
|
* `visibleIf.extension` lists file extensions (no case, a leading dot is
|
|
264
264
|
* allowed); `visibleIf.mime` lists mime types, where one ending in `/` or
|
|
265
265
|
* `/*` names the whole family. Every condition named must hold. An action
|
|
266
|
-
* without `visibleIf` is offered on every file, as before.
|
|
266
|
+
* without `visibleIf` is offered on every file, as before. An action with
|
|
267
|
+
* `when` is offered only while `when` is `true`.
|
|
267
268
|
*
|
|
268
269
|
* @param {object} action The declared action.
|
|
269
270
|
* @param {object} node The file (`basename`, `mime`).
|
|
270
271
|
* @return {boolean} True when the action belongs on this file.
|
|
271
272
|
*/
|
|
272
273
|
function hostActionApplies(action, node) {
|
|
274
|
+
// `when`: the action applies only while it is true (a case type flag).
|
|
275
|
+
// @spec openspec/changes/files-review-row-when/specs/files-review-row-when/spec.md#requirement-a-files-browser-entry-can-apply-only-when-a-condition-holds
|
|
276
|
+
if (action && typeof action === 'object' && 'when' in action && action.when !== true) {
|
|
277
|
+
return false
|
|
278
|
+
}
|
|
273
279
|
const condition = action && action.visibleIf;
|
|
274
280
|
if (!condition || typeof condition !== 'object') {
|
|
275
281
|
return true
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"filesBrowser.js","sources":["../../../../src/components/CnFilesBrowser/filesBrowser.js"],"sourcesContent":["/**\n * SPDX-FileCopyrightText: 2026 Conduction B.V.\n * SPDX-License-Identifier: EUPL-1.2\n *\n * The pure half of CnFilesBrowser: paths, crumbs and the folder lookup.\n *\n * Kept out of the component so a test can pin them without a DAV server:\n * a wrong path here sends every listing to the wrong folder, silently.\n */\nimport axios from '@nextcloud/axios'\nimport { generateUrl } from '@nextcloud/router'\n\n/**\n * Actions the Files app registers that cannot run on a page without the Files\n * app's own list: the details action opens the Files sidebar, which on\n * Nextcloud 34 is a store bound to the Files router and node list; the\n * folder-navigation actions route through that list; and rename turns the\n * list's own name cell into an input, which is not here. Verified on a case\n * page: Rename ran and nothing happened. The browser offers its own rename\n * instead, a dialog over a DAV move.\n *\n * @type {string[]}\n */\nexport const ACTIONS_NEEDING_THE_FILES_PAGE = ['details', 'sidebar', 'open-folder', 'view-in-folder', 'rename']\n\n/**\n * A DAV href for a node under the user's files root, as a path relative to\n * that root: `/remote.php/dav/files/admin/Open%20Registers/x/` becomes\n * `/Open Registers/x`.\n *\n * @param {string} href The href as the DAV server returned it.\n * @param {string} uid The current user's id.\n * @return {string} The user-relative path without a trailing slash, `/` at least.\n */\nexport function userRelativePathFromHref(href, uid) {\n\tlet decoded\n\ttry {\n\t\tdecoded = decodeURIComponent(String(href || ''))\n\t} catch {\n\t\tdecoded = String(href || '')\n\t}\n\tconst marker = `/dav/files/${uid}`\n\tconst at = decoded.indexOf(marker)\n\tconst rest = at === -1 ? decoded : decoded.slice(at + marker.length)\n\tconst trimmed = rest.replace(/\\/+$/, '')\n\treturn trimmed === '' ? '/' : trimmed\n}\n\n/**\n * Join a directory and a name into a path, with exactly one slash between.\n *\n * @param {string} dir The directory path.\n * @param {string} name The child name.\n * @return {string} The child's path.\n */\nexport function joinPath(dir, name) {\n\treturn `${String(dir || '').replace(/\\/+$/, '')}/${String(name || '').replace(/^\\/+/, '')}`\n}\n\n/**\n * The breadcrumb trail: every folder from the user's files root down to the\n * open folder, the way the Files app draws it.\n *\n * The folders ABOVE the browser's root are part of the trail too (a reader\n * wants to see where this folder lives), but the browser never navigates\n * above its root, so those crumbs carry `aboveRoot: true` and the component\n * links them into the Files app instead. The root reads `rootLabel` when the\n * caller gave one and its own basename otherwise; every other crumb is the\n * folder's basename.\n *\n * @param {string} rootPath The browser's root, user-relative.\n * @param {string} currentPath The open folder, user-relative, at or below the root.\n * @param {string|null} [rootLabel] What the root crumb reads; null for its basename.\n * @return {Array<{name: string, path: string, aboveRoot: boolean}>} The crumbs, outermost first.\n */\nexport function crumbsFor(rootPath, currentPath, rootLabel = null) {\n\tconst root = String(rootPath || '/').replace(/\\/+$/, '') || '/'\n\tconst current = String(currentPath || root).replace(/\\/+$/, '') || '/'\n\tconst crumbs = []\n\tlet path = ''\n\tfor (const segment of root.split('/').filter(Boolean)) {\n\t\tpath = joinPath(path, segment)\n\t\tcrumbs.push({ name: segment, path, aboveRoot: path !== root })\n\t}\n\tif (root === '/') {\n\t\tcrumbs.push({ name: rootLabel || '/', path: '/', aboveRoot: false })\n\t} else if (rootLabel) {\n\t\tcrumbs[crumbs.length - 1].name = rootLabel\n\t}\n\tif (current === root || !current.startsWith(root === '/' ? '/' : `${root}/`)) {\n\t\treturn crumbs\n\t}\n\tconst below = root === '/' ? current.slice(1) : current.slice(root.length + 1)\n\tpath = root\n\tfor (const segment of below.split('/').filter(Boolean)) {\n\t\tpath = joinPath(path, segment)\n\t\tcrumbs.push({ name: segment, path, aboveRoot: false })\n\t}\n\treturn crumbs\n}\n\n/**\n * The DAV SEARCH body that finds one node by its file id under the user's root.\n *\n * @param {number|string} fileId The Nextcloud file id.\n * @param {string} uid The current user's id.\n * @return {string} The request body.\n */\nexport function fileIdSearchBody(fileId, uid) {\n\tconst id = String(fileId).replace(/[^0-9]/g, '')\n\tconst scope = `/files/${uid}`.replace(/[<>&]/g, '')\n\treturn '<?xml version=\"1.0\"?>'\n\t\t+ '<d:searchrequest xmlns:d=\"DAV:\" xmlns:oc=\"http://owncloud.org/ns\"><d:basicsearch>'\n\t\t+ '<d:select><d:prop><oc:fileid/></d:prop></d:select>'\n\t\t+ `<d:from><d:scope><d:href>${scope}</d:href><d:depth>infinity</d:depth></d:scope></d:from>`\n\t\t+ `<d:where><d:eq><d:prop><oc:fileid/></d:prop><d:literal>${id}</d:literal></d:eq></d:where>`\n\t\t+ '</d:basicsearch></d:searchrequest>'\n}\n\n/**\n * The first `d:href` in a DAV multistatus body, or null.\n *\n * @param {string} xml The response body.\n * @return {string|null} The href.\n */\nexport function firstHrefIn(xml) {\n\ttry {\n\t\tconst doc = new DOMParser().parseFromString(String(xml || ''), 'application/xml')\n\t\tconst href = doc.getElementsByTagNameNS('DAV:', 'href')[0]\n\t\treturn href ? href.textContent : null\n\t} catch {\n\t\treturn null\n\t}\n}\n\n/**\n * Where an OpenRegister object keeps its files, as a user-relative path.\n *\n * The object carries the folder's file id in `@self.folder`; a DAV search\n * by that id turns it into a path the DAV client can list. Null when the\n * object has no folder, or the search cannot see it (a user the folder is\n * not shared with), in which case the caller falls back to the object's\n * files endpoint.\n *\n * @param {object} options The lookup.\n * @param {string} options.apiBase OpenRegister's API base, `/apps/openregister/api`.\n * @param {string} options.register The register slug.\n * @param {string} options.schema The schema slug.\n * @param {string} options.objectId The object's uuid.\n * @param {string} options.uid The current user's id.\n * @param {string} options.remoteUrl The DAV remote url, `…/remote.php/dav`.\n * @return {Promise<string|null>} The user-relative folder path, or null.\n */\nexport async function resolveObjectFolder(options) {\n\tconst info = await resolveObjectFolderInfo(options)\n\treturn info === null ? null : info.path\n}\n\n/**\n * The object's display name: `@self.name`, else `title`, else `name`. A\n * value equal to the object's uuid is no name (the folder already reads so).\n *\n * @param {object|null} object The object as OpenRegister returns it.\n * @param {string} objectId The object's uuid.\n * @return {string|null} The name, or null.\n * @spec openspec/changes/dutch-library-strings-and-files-crumb/specs/dutch-library-strings-and-files-crumb/spec.md#requirement-the-files-browser-names-the-object-in-its-root-crumb\n */\nexport function objectDisplayName(object, objectId) {\n\tconst candidates = [object?.['@self']?.name, object?.title, object?.name]\n\tfor (const candidate of candidates) {\n\t\tif (typeof candidate === 'string' && candidate.trim() !== '' && candidate.trim() !== String(objectId)) {\n\t\t\treturn candidate.trim()\n\t\t}\n\t}\n\treturn null\n}\n\n/**\n * `resolveObjectFolder`, plus the object's display name from the same read,\n * so the browser can name the root crumb after the object instead of the\n * uuid its folder is called on disk.\n *\n * @param {object} options The lookup, as for `resolveObjectFolder`.\n * @param {string} options.apiBase OpenRegister's API base, `/apps/openregister/api`.\n * @param {string} options.register The register slug.\n * @param {string} options.schema The schema slug.\n * @param {string} options.objectId The object's uuid.\n * @param {string} options.uid The current user's id.\n * @param {string} options.remoteUrl The DAV remote url, `…/remote.php/dav`.\n * @return {Promise<{path: string, name: (string|null)}|null>} The folder and the object's name, or null.\n * @spec openspec/changes/dutch-library-strings-and-files-crumb/specs/dutch-library-strings-and-files-crumb/spec.md#requirement-the-files-browser-names-the-object-in-its-root-crumb\n */\nexport async function resolveObjectFolderInfo({ apiBase, register, schema, objectId, uid, remoteUrl }) {\n\tif (!register || !schema || !objectId || !uid) {\n\t\treturn null\n\t}\n\tlet folderId\n\tlet name\n\ttry {\n\t\tconst { data } = await axios.get(generateUrl(`${apiBase}/objects/{register}/{schema}/{objectId}`, { register, schema, objectId }))\n\t\tfolderId = data?.['@self']?.folder ?? null\n\t\tname = objectDisplayName(data, objectId)\n\t} catch {\n\t\treturn null\n\t}\n\tif (folderId === null || folderId === '' || Number.isNaN(Number(folderId))) {\n\t\treturn null\n\t}\n\ttry {\n\t\tconst response = await axios.request({\n\t\t\tmethod: 'SEARCH',\n\t\t\turl: `${remoteUrl.replace(/\\/+$/, '')}/`,\n\t\t\theaders: { 'Content-Type': 'application/xml' },\n\t\t\tdata: fileIdSearchBody(folderId, uid),\n\t\t\tresponseType: 'text',\n\t\t})\n\t\tconst href = firstHrefIn(response.data)\n\t\treturn href === null ? null : { path: userRelativePathFromHref(href, uid), name }\n\t} catch {\n\t\treturn null\n\t}\n}\n\n/**\n * Read a dotted path off a value without throwing on a missing segment.\n *\n * @param {(Array|object|string|number|boolean|null|undefined)} value The value.\n * @param {string} path A dotted path; empty answers the value itself.\n * @return {(Array|object|string|number|boolean|null|undefined)} What sits at the path, or undefined.\n */\nfunction readPath(value, path) {\n\tif (typeof path !== 'string' || path === '') {\n\t\treturn value\n\t}\n\treturn path.split('.').reduce((acc, key) => (acc === null || acc === undefined ? undefined : acc[key]), value)\n}\n\n/**\n * Turn a host endpoint's answer into the browser's `rowData`: the host's own\n * record for each file, keyed by file id.\n *\n * The answer may be a list of records (directly, at `path`, or under `items`\n * or `results`), each naming its file in `key` (`fileId` unless the host says\n * otherwise); a record without one is skipped. An object that is not a list\n * and holds neither is taken as already keyed by file id. Anything else is\n * an empty map: the extra columns stay empty, the files still list.\n *\n * @param {(Array|object|string|number|boolean|null|undefined)} data The endpoint answer.\n * @param {object} [options] Where to look.\n * @param {string} [options.path] A dotted path to the list in the answer.\n * @param {string} [options.key] The record field that holds the file id.\n * @return {object} The records by file id.\n */\nexport function indexRowData(data, { path = '', key = 'fileId' } = {}) {\n\tlet picked = readPath(data, path)\n\tif (picked && typeof picked === 'object' && !Array.isArray(picked)) {\n\t\tif (Array.isArray(picked.items)) {\n\t\t\tpicked = picked.items\n\t\t} else if (Array.isArray(picked.results)) {\n\t\t\tpicked = picked.results\n\t\t} else {\n\t\t\treturn { ...picked }\n\t\t}\n\t}\n\tif (!Array.isArray(picked)) {\n\t\treturn {}\n\t}\n\tconst byId = {}\n\tpicked.forEach((record) => {\n\t\tif (!record || typeof record !== 'object') {\n\t\t\treturn\n\t\t}\n\t\tconst id = record[key]\n\t\tif (id === null || id === undefined || id === '') {\n\t\t\treturn\n\t\t}\n\t\tbyId[String(id)] = record\n\t})\n\treturn byId\n}\n\n/**\n * Whether a host row action is offered on a file, by its `visibleIf`.\n *\n * `visibleIf.extension` lists file extensions (no case, a leading dot is\n * allowed); `visibleIf.mime` lists mime types, where one ending in `/` or\n * `/*` names the whole family. Every condition named must hold. An action\n * without `visibleIf` is offered on every file, as before.\n *\n * @param {object} action The declared action.\n * @param {object} node The file (`basename`, `mime`).\n * @return {boolean} True when the action belongs on this file.\n */\nexport function hostActionApplies(action, node) {\n\tconst condition = action && action.visibleIf\n\tif (!condition || typeof condition !== 'object') {\n\t\treturn true\n\t}\n\tif (Array.isArray(condition.extension)) {\n\t\tconst name = String((node && node.basename) || '')\n\t\tconst dot = name.lastIndexOf('.')\n\t\tconst extension = dot > 0 ? name.slice(dot + 1).toLowerCase() : ''\n\t\tconst wanted = condition.extension.map((entry) => String(entry).replace(/^\\./, '').toLowerCase())\n\t\tif (extension === '' || !wanted.includes(extension)) {\n\t\t\treturn false\n\t\t}\n\t}\n\tif (Array.isArray(condition.mime)) {\n\t\tconst mime = String((node && node.mime) || '').toLowerCase()\n\t\tconst matches = condition.mime.some((entry) => {\n\t\t\tconst wanted = String(entry).toLowerCase()\n\t\t\tif (wanted.endsWith('/*') || wanted.endsWith('/')) {\n\t\t\t\treturn mime.startsWith(wanted.replace(/\\*$/, ''))\n\t\t\t}\n\t\t\treturn mime === wanted\n\t\t})\n\t\tif (!matches) {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n"],"names":["axios"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"filesBrowser.js","sources":["../../../../src/components/CnFilesBrowser/filesBrowser.js"],"sourcesContent":["/**\n * SPDX-FileCopyrightText: 2026 Conduction B.V.\n * SPDX-License-Identifier: EUPL-1.2\n *\n * The pure half of CnFilesBrowser: paths, crumbs and the folder lookup.\n *\n * Kept out of the component so a test can pin them without a DAV server:\n * a wrong path here sends every listing to the wrong folder, silently.\n */\nimport axios from '@nextcloud/axios'\nimport { generateUrl } from '@nextcloud/router'\n\n/**\n * Actions the Files app registers that cannot run on a page without the Files\n * app's own list: the details action opens the Files sidebar, which on\n * Nextcloud 34 is a store bound to the Files router and node list; the\n * folder-navigation actions route through that list; and rename turns the\n * list's own name cell into an input, which is not here. Verified on a case\n * page: Rename ran and nothing happened. The browser offers its own rename\n * instead, a dialog over a DAV move.\n *\n * @type {string[]}\n */\nexport const ACTIONS_NEEDING_THE_FILES_PAGE = ['details', 'sidebar', 'open-folder', 'view-in-folder', 'rename']\n\n/**\n * A DAV href for a node under the user's files root, as a path relative to\n * that root: `/remote.php/dav/files/admin/Open%20Registers/x/` becomes\n * `/Open Registers/x`.\n *\n * @param {string} href The href as the DAV server returned it.\n * @param {string} uid The current user's id.\n * @return {string} The user-relative path without a trailing slash, `/` at least.\n */\nexport function userRelativePathFromHref(href, uid) {\n\tlet decoded\n\ttry {\n\t\tdecoded = decodeURIComponent(String(href || ''))\n\t} catch {\n\t\tdecoded = String(href || '')\n\t}\n\tconst marker = `/dav/files/${uid}`\n\tconst at = decoded.indexOf(marker)\n\tconst rest = at === -1 ? decoded : decoded.slice(at + marker.length)\n\tconst trimmed = rest.replace(/\\/+$/, '')\n\treturn trimmed === '' ? '/' : trimmed\n}\n\n/**\n * Join a directory and a name into a path, with exactly one slash between.\n *\n * @param {string} dir The directory path.\n * @param {string} name The child name.\n * @return {string} The child's path.\n */\nexport function joinPath(dir, name) {\n\treturn `${String(dir || '').replace(/\\/+$/, '')}/${String(name || '').replace(/^\\/+/, '')}`\n}\n\n/**\n * The breadcrumb trail: every folder from the user's files root down to the\n * open folder, the way the Files app draws it.\n *\n * The folders ABOVE the browser's root are part of the trail too (a reader\n * wants to see where this folder lives), but the browser never navigates\n * above its root, so those crumbs carry `aboveRoot: true` and the component\n * links them into the Files app instead. The root reads `rootLabel` when the\n * caller gave one and its own basename otherwise; every other crumb is the\n * folder's basename.\n *\n * @param {string} rootPath The browser's root, user-relative.\n * @param {string} currentPath The open folder, user-relative, at or below the root.\n * @param {string|null} [rootLabel] What the root crumb reads; null for its basename.\n * @return {Array<{name: string, path: string, aboveRoot: boolean}>} The crumbs, outermost first.\n */\nexport function crumbsFor(rootPath, currentPath, rootLabel = null) {\n\tconst root = String(rootPath || '/').replace(/\\/+$/, '') || '/'\n\tconst current = String(currentPath || root).replace(/\\/+$/, '') || '/'\n\tconst crumbs = []\n\tlet path = ''\n\tfor (const segment of root.split('/').filter(Boolean)) {\n\t\tpath = joinPath(path, segment)\n\t\tcrumbs.push({ name: segment, path, aboveRoot: path !== root })\n\t}\n\tif (root === '/') {\n\t\tcrumbs.push({ name: rootLabel || '/', path: '/', aboveRoot: false })\n\t} else if (rootLabel) {\n\t\tcrumbs[crumbs.length - 1].name = rootLabel\n\t}\n\tif (current === root || !current.startsWith(root === '/' ? '/' : `${root}/`)) {\n\t\treturn crumbs\n\t}\n\tconst below = root === '/' ? current.slice(1) : current.slice(root.length + 1)\n\tpath = root\n\tfor (const segment of below.split('/').filter(Boolean)) {\n\t\tpath = joinPath(path, segment)\n\t\tcrumbs.push({ name: segment, path, aboveRoot: false })\n\t}\n\treturn crumbs\n}\n\n/**\n * The DAV SEARCH body that finds one node by its file id under the user's root.\n *\n * @param {number|string} fileId The Nextcloud file id.\n * @param {string} uid The current user's id.\n * @return {string} The request body.\n */\nexport function fileIdSearchBody(fileId, uid) {\n\tconst id = String(fileId).replace(/[^0-9]/g, '')\n\tconst scope = `/files/${uid}`.replace(/[<>&]/g, '')\n\treturn '<?xml version=\"1.0\"?>'\n\t\t+ '<d:searchrequest xmlns:d=\"DAV:\" xmlns:oc=\"http://owncloud.org/ns\"><d:basicsearch>'\n\t\t+ '<d:select><d:prop><oc:fileid/></d:prop></d:select>'\n\t\t+ `<d:from><d:scope><d:href>${scope}</d:href><d:depth>infinity</d:depth></d:scope></d:from>`\n\t\t+ `<d:where><d:eq><d:prop><oc:fileid/></d:prop><d:literal>${id}</d:literal></d:eq></d:where>`\n\t\t+ '</d:basicsearch></d:searchrequest>'\n}\n\n/**\n * The first `d:href` in a DAV multistatus body, or null.\n *\n * @param {string} xml The response body.\n * @return {string|null} The href.\n */\nexport function firstHrefIn(xml) {\n\ttry {\n\t\tconst doc = new DOMParser().parseFromString(String(xml || ''), 'application/xml')\n\t\tconst href = doc.getElementsByTagNameNS('DAV:', 'href')[0]\n\t\treturn href ? href.textContent : null\n\t} catch {\n\t\treturn null\n\t}\n}\n\n/**\n * Where an OpenRegister object keeps its files, as a user-relative path.\n *\n * The object carries the folder's file id in `@self.folder`; a DAV search\n * by that id turns it into a path the DAV client can list. Null when the\n * object has no folder, or the search cannot see it (a user the folder is\n * not shared with), in which case the caller falls back to the object's\n * files endpoint.\n *\n * @param {object} options The lookup.\n * @param {string} options.apiBase OpenRegister's API base, `/apps/openregister/api`.\n * @param {string} options.register The register slug.\n * @param {string} options.schema The schema slug.\n * @param {string} options.objectId The object's uuid.\n * @param {string} options.uid The current user's id.\n * @param {string} options.remoteUrl The DAV remote url, `…/remote.php/dav`.\n * @return {Promise<string|null>} The user-relative folder path, or null.\n */\nexport async function resolveObjectFolder(options) {\n\tconst info = await resolveObjectFolderInfo(options)\n\treturn info === null ? null : info.path\n}\n\n/**\n * The object's display name: `@self.name`, else `title`, else `name`. A\n * value equal to the object's uuid is no name (the folder already reads so).\n *\n * @param {object|null} object The object as OpenRegister returns it.\n * @param {string} objectId The object's uuid.\n * @return {string|null} The name, or null.\n * @spec openspec/changes/dutch-library-strings-and-files-crumb/specs/dutch-library-strings-and-files-crumb/spec.md#requirement-the-files-browser-names-the-object-in-its-root-crumb\n */\nexport function objectDisplayName(object, objectId) {\n\tconst candidates = [object?.['@self']?.name, object?.title, object?.name]\n\tfor (const candidate of candidates) {\n\t\tif (typeof candidate === 'string' && candidate.trim() !== '' && candidate.trim() !== String(objectId)) {\n\t\t\treturn candidate.trim()\n\t\t}\n\t}\n\treturn null\n}\n\n/**\n * `resolveObjectFolder`, plus the object's display name from the same read,\n * so the browser can name the root crumb after the object instead of the\n * uuid its folder is called on disk.\n *\n * @param {object} options The lookup, as for `resolveObjectFolder`.\n * @param {string} options.apiBase OpenRegister's API base, `/apps/openregister/api`.\n * @param {string} options.register The register slug.\n * @param {string} options.schema The schema slug.\n * @param {string} options.objectId The object's uuid.\n * @param {string} options.uid The current user's id.\n * @param {string} options.remoteUrl The DAV remote url, `…/remote.php/dav`.\n * @return {Promise<{path: string, name: (string|null)}|null>} The folder and the object's name, or null.\n * @spec openspec/changes/dutch-library-strings-and-files-crumb/specs/dutch-library-strings-and-files-crumb/spec.md#requirement-the-files-browser-names-the-object-in-its-root-crumb\n */\nexport async function resolveObjectFolderInfo({ apiBase, register, schema, objectId, uid, remoteUrl }) {\n\tif (!register || !schema || !objectId || !uid) {\n\t\treturn null\n\t}\n\tlet folderId\n\tlet name\n\ttry {\n\t\tconst { data } = await axios.get(generateUrl(`${apiBase}/objects/{register}/{schema}/{objectId}`, { register, schema, objectId }))\n\t\tfolderId = data?.['@self']?.folder ?? null\n\t\tname = objectDisplayName(data, objectId)\n\t} catch {\n\t\treturn null\n\t}\n\tif (folderId === null || folderId === '' || Number.isNaN(Number(folderId))) {\n\t\treturn null\n\t}\n\ttry {\n\t\tconst response = await axios.request({\n\t\t\tmethod: 'SEARCH',\n\t\t\turl: `${remoteUrl.replace(/\\/+$/, '')}/`,\n\t\t\theaders: { 'Content-Type': 'application/xml' },\n\t\t\tdata: fileIdSearchBody(folderId, uid),\n\t\t\tresponseType: 'text',\n\t\t})\n\t\tconst href = firstHrefIn(response.data)\n\t\treturn href === null ? null : { path: userRelativePathFromHref(href, uid), name }\n\t} catch {\n\t\treturn null\n\t}\n}\n\n/**\n * Read a dotted path off a value without throwing on a missing segment.\n *\n * @param {(Array|object|string|number|boolean|null|undefined)} value The value.\n * @param {string} path A dotted path; empty answers the value itself.\n * @return {(Array|object|string|number|boolean|null|undefined)} What sits at the path, or undefined.\n */\nfunction readPath(value, path) {\n\tif (typeof path !== 'string' || path === '') {\n\t\treturn value\n\t}\n\treturn path.split('.').reduce((acc, key) => (acc === null || acc === undefined ? undefined : acc[key]), value)\n}\n\n/**\n * Turn a host endpoint's answer into the browser's `rowData`: the host's own\n * record for each file, keyed by file id.\n *\n * The answer may be a list of records (directly, at `path`, or under `items`\n * or `results`), each naming its file in `key` (`fileId` unless the host says\n * otherwise); a record without one is skipped. An object that is not a list\n * and holds neither is taken as already keyed by file id. Anything else is\n * an empty map: the extra columns stay empty, the files still list.\n *\n * @param {(Array|object|string|number|boolean|null|undefined)} data The endpoint answer.\n * @param {object} [options] Where to look.\n * @param {string} [options.path] A dotted path to the list in the answer.\n * @param {string} [options.key] The record field that holds the file id.\n * @return {object} The records by file id.\n */\nexport function indexRowData(data, { path = '', key = 'fileId' } = {}) {\n\tlet picked = readPath(data, path)\n\tif (picked && typeof picked === 'object' && !Array.isArray(picked)) {\n\t\tif (Array.isArray(picked.items)) {\n\t\t\tpicked = picked.items\n\t\t} else if (Array.isArray(picked.results)) {\n\t\t\tpicked = picked.results\n\t\t} else {\n\t\t\treturn { ...picked }\n\t\t}\n\t}\n\tif (!Array.isArray(picked)) {\n\t\treturn {}\n\t}\n\tconst byId = {}\n\tpicked.forEach((record) => {\n\t\tif (!record || typeof record !== 'object') {\n\t\t\treturn\n\t\t}\n\t\tconst id = record[key]\n\t\tif (id === null || id === undefined || id === '') {\n\t\t\treturn\n\t\t}\n\t\tbyId[String(id)] = record\n\t})\n\treturn byId\n}\n\n/**\n * Whether a host row action is offered on a file, by its `visibleIf`.\n *\n * `visibleIf.extension` lists file extensions (no case, a leading dot is\n * allowed); `visibleIf.mime` lists mime types, where one ending in `/` or\n * `/*` names the whole family. Every condition named must hold. An action\n * without `visibleIf` is offered on every file, as before. An action with\n * `when` is offered only while `when` is `true`.\n *\n * @param {object} action The declared action.\n * @param {object} node The file (`basename`, `mime`).\n * @return {boolean} True when the action belongs on this file.\n */\nexport function hostActionApplies(action, node) {\n\t// `when`: the action applies only while it is true (a case type flag).\n\t// @spec openspec/changes/files-review-row-when/specs/files-review-row-when/spec.md#requirement-a-files-browser-entry-can-apply-only-when-a-condition-holds\n\tif (action && typeof action === 'object' && 'when' in action && action.when !== true) {\n\t\treturn false\n\t}\n\tconst condition = action && action.visibleIf\n\tif (!condition || typeof condition !== 'object') {\n\t\treturn true\n\t}\n\tif (Array.isArray(condition.extension)) {\n\t\tconst name = String((node && node.basename) || '')\n\t\tconst dot = name.lastIndexOf('.')\n\t\tconst extension = dot > 0 ? name.slice(dot + 1).toLowerCase() : ''\n\t\tconst wanted = condition.extension.map((entry) => String(entry).replace(/^\\./, '').toLowerCase())\n\t\tif (extension === '' || !wanted.includes(extension)) {\n\t\t\treturn false\n\t\t}\n\t}\n\tif (Array.isArray(condition.mime)) {\n\t\tconst mime = String((node && node.mime) || '').toLowerCase()\n\t\tconst matches = condition.mime.some((entry) => {\n\t\t\tconst wanted = String(entry).toLowerCase()\n\t\t\tif (wanted.endsWith('/*') || wanted.endsWith('/')) {\n\t\t\t\treturn mime.startsWith(wanted.replace(/\\*$/, ''))\n\t\t\t}\n\t\t\treturn mime === wanted\n\t\t})\n\t\tif (!matches) {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n"],"names":["axios"],"mappings":"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"}
|
|
@@ -78,6 +78,11 @@ function normaliseFileColumns(columns) {
|
|
|
78
78
|
if (!entry || typeof entry !== 'object' || typeof entry.key !== 'string' || entry.key === '') {
|
|
79
79
|
return
|
|
80
80
|
}
|
|
81
|
+
// `when`: the column applies only while it is true (a case type flag).
|
|
82
|
+
// @spec openspec/changes/files-review-row-when/specs/files-review-row-when/spec.md#requirement-a-files-browser-entry-can-apply-only-when-a-condition-holds
|
|
83
|
+
if ('when' in entry && entry.when !== true) {
|
|
84
|
+
return
|
|
85
|
+
}
|
|
81
86
|
if (isBuiltInFileColumn(entry.key) && entry.source === undefined) {
|
|
82
87
|
out.push({ ...BUILT_IN_FILE_COLUMNS[entry.key], ...entry, builtIn: true });
|
|
83
88
|
return
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"filesBrowserColumns.js","sources":["../../../../src/components/CnFilesBrowser/filesBrowserColumns.js"],"sourcesContent":["/**\n * SPDX-FileCopyrightText: 2026 Conduction B.V. <info@conduction.nl>\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\n/**\n * The built-in columns a host may name by string, and what each one reads.\n *\n * `nodeKey` is the property on the @nextcloud/files node. `sortKey` is what\n * `sortNodes` understands, so a built-in sorts the way the Files app sorts;\n * a built-in with no `sortKey` sorts client-side like a declared column.\n *\n * @type {object}\n */\nexport const BUILT_IN_FILE_COLUMNS = {\n\tname: { key: 'name', source: 'node', nodeKey: 'basename', sortKey: 'basename', sortable: true },\n\tsize: { key: 'size', source: 'node', nodeKey: 'size', sortKey: 'size', sortable: true },\n\tmodified: { key: 'modified', source: 'node', nodeKey: 'mtime', sortKey: 'mtime', sortable: true },\n\towner: { key: 'owner', source: 'node', nodeKey: 'owner', sortable: true },\n\ttype: { key: 'type', source: 'node', nodeKey: 'mime', sortable: true },\n\ttags: { key: 'tags', source: 'node', nodeKey: 'attributes.system-tags', sortable: false },\n}\n\n/**\n * The columns a browser shows when its host declares none: what the table has\n * always shown, in the order it has always shown it.\n *\n * @type {string[]}\n */\nexport const DEFAULT_FILE_COLUMNS = ['name', 'size', 'modified']\n\n/**\n * Read a dotted path off a node without throwing on a missing segment.\n *\n * @param {object} node The node.\n * @param {string} path A dotted path.\n * @return {(Array|object|string|number|boolean|undefined)} The value.\n */\nfunction atPath(node, path) {\n\tif (!node || typeof path !== 'string' || path === '') {\n\t\treturn undefined\n\t}\n\treturn path.split('.').reduce((acc, key) => (acc === null || acc === undefined ? undefined : acc[key]), node)\n}\n\n/**\n * Whether a string names a built-in column.\n *\n * @param {string} name The candidate name.\n * @return {boolean} True when it is a built-in.\n */\nexport function isBuiltInFileColumn(name) {\n\treturn typeof name === 'string' && Object.hasOwn(BUILT_IN_FILE_COLUMNS, name)\n}\n\n/**\n * Resolve a host's `columns` declaration into column objects.\n *\n * A string names a built-in. An object declares its own: `key`, `label`,\n * `source` (`node`, `attribute` or `row`), `attribute`, `formatter` and\n * `sortable`. An entry naming an unknown built-in is dropped here and refused\n * by the manifest validator, so an author hears about it at authoring time\n * rather than finding a column missing at runtime.\n *\n * @param {(Array|null|undefined)} columns The declaration, or nothing.\n * @return {Array<object>} The resolved columns, in the declared order.\n */\nexport function normaliseFileColumns(columns) {\n\tconst declared = Array.isArray(columns) && columns.length > 0 ? columns : DEFAULT_FILE_COLUMNS\n\tconst out = []\n\tdeclared.forEach((entry) => {\n\t\tif (typeof entry === 'string') {\n\t\t\tif (isBuiltInFileColumn(entry)) {\n\t\t\t\tout.push({ ...BUILT_IN_FILE_COLUMNS[entry], builtIn: true })\n\t\t\t}\n\t\t\treturn\n\t\t}\n\t\tif (!entry || typeof entry !== 'object' || typeof entry.key !== 'string' || entry.key === '') {\n\t\t\treturn\n\t\t}\n\t\tif (isBuiltInFileColumn(entry.key) && entry.source === undefined) {\n\t\t\tout.push({ ...BUILT_IN_FILE_COLUMNS[entry.key], ...entry, builtIn: true })\n\t\t\treturn\n\t\t}\n\t\tout.push({\n\t\t\tsource: 'node',\n\t\t\tsortable: false,\n\t\t\t...entry,\n\t\t\tbuiltIn: false,\n\t\t})\n\t})\n\treturn out\n}\n\n/**\n * The columns a browser renders: the host's declaration, narrowed by what this\n * user chose to see.\n *\n * Which side wins on what:\n *\n * - The HOST decides MEMBERSHIP. The result is built by walking the\n * declaration, so a column exists only because the host declared it, in the\n * order the host declared it.\n * - The USER decides VISIBILITY, and only downward. A stored preference can\n * hide a declared column; it can never add one. A key in the stored list\n * that the host no longer declares is passed over, so unticking a column\n * last month cannot bring it back once the host removed it, and neither can\n * a preference written while a different column set was declared.\n *\n * A stored value of `null` is a user who has never chosen, which shows\n * every declared column but the ones the host declared `hidden: true`. An\n * empty list is a user who hid everything, which is a choice and is honoured.\n *\n * @param {Array<object>} declared The resolved declared columns.\n * @param {(string[]|null|undefined)} visibleKeys The user's stored visible keys.\n * @return {Array<object>} The columns to render.\n */\nexport function visibleFileColumns(declared, visibleKeys) {\n\tconst columns = Array.isArray(declared) ? declared : []\n\tif (!Array.isArray(visibleKeys)) {\n\t\treturn columns.filter((column) => column.hidden !== true)\n\t}\n\tconst wanted = new Set(visibleKeys)\n\treturn columns.filter((column) => wanted.has(column.key))\n}\n\n/**\n * The DAV properties a declaration needs in the PROPFIND, so an `attribute`\n * column's value is there when the folder lists rather than one request later.\n *\n * @param {Array<object>} columns The resolved columns.\n * @return {string[]} The property names, deduplicated, in declaration order.\n */\nexport function attributePropertiesFor(columns) {\n\tconst out = []\n\t;(Array.isArray(columns) ? columns : []).forEach((column) => {\n\t\tif (column && column.source === 'attribute' && typeof column.attribute === 'string' && column.attribute !== '') {\n\t\t\tif (!out.includes(column.attribute)) {\n\t\t\t\tout.push(column.attribute)\n\t\t\t}\n\t\t}\n\t})\n\treturn out\n}\n\n/**\n * The value one column shows for one node. A `row` column's key may be a\n * dotted path into the host's record.\n *\n * @param {object} column A resolved column.\n * @param {object} node The node.\n * @param {object} [rowData] The host's per-file data, keyed by file id.\n * @return {(Array|object|string|number|boolean|undefined)} The cell value.\n */\nexport function fileColumnValue(column, node, rowData = null) {\n\tif (!column || !node) {\n\t\treturn undefined\n\t}\n\tif (column.source === 'attribute') {\n\t\t// Read the key directly, NOT through the dotted-path reader: a DAV\n\t\t// property name is `{http://owncloud.org/ns}av-status`, and splitting\n\t\t// that on dots looks for a property called `org/ns}av-status` inside\n\t\t// one called `owncloud`, which is undefined every time.\n\t\tconst attributes = node.attributes\n\t\treturn attributes && typeof attributes === 'object' ? attributes[column.attribute] : undefined\n\t}\n\tif (column.source === 'row') {\n\t\tconst byId = rowData && typeof rowData === 'object' ? rowData : null\n\t\tif (!byId) {\n\t\t\treturn undefined\n\t\t}\n\t\tconst entry = byId[node.fileid] ?? byId[String(node.fileid)]\n\t\tif (!entry) {\n\t\t\treturn undefined\n\t\t}\n\t\t// A key the record holds as written wins; otherwise a dotted key reads\n\t\t// a nested field (`scanVerdict.state`, `integrity.value`).\n\t\treturn Object.hasOwn(entry, column.key) ? entry[column.key] : atPath(entry, column.key)\n\t}\n\treturn atPath(node, column.nodeKey || column.key)\n}\n\n/**\n * Sort nodes on a declared column's resolved value, within the listed folder.\n *\n * Folders stay first, the way the Files app lists them and the way the\n * built-in sorts already do, so switching to a declared column does not\n * reshuffle the folders into the files.\n *\n * @param {Array<object>} nodes The nodes.\n * @param {object} column The resolved column.\n * @param {boolean} ascending Sort direction.\n * @param {object} [rowData] The host's per-file data.\n * @param {(node: object) => boolean} [isFolder] Whether a node is a folder.\n * @return {Array<object>} A new, sorted array.\n */\nexport function sortNodesByColumn(nodes, column, ascending, rowData = null, isFolder = () => false) {\n\tconst list = Array.isArray(nodes) ? [...nodes] : []\n\tif (!column) {\n\t\treturn list\n\t}\n\tconst direction = ascending ? 1 : -1\n\treturn list.sort((a, b) => {\n\t\tconst folderA = isFolder(a)\n\t\tconst folderB = isFolder(b)\n\t\tif (folderA !== folderB) {\n\t\t\treturn folderA ? -1 : 1\n\t\t}\n\t\tconst left = fileColumnValue(column, a, rowData)\n\t\tconst right = fileColumnValue(column, b, rowData)\n\t\tconst leftMissing = left === undefined || left === null || left === ''\n\t\tconst rightMissing = right === undefined || right === null || right === ''\n\t\t// A value nobody filled in sorts last in BOTH directions. Letting it\n\t\t// ride to the top on a descending sort hides the rows that do carry\n\t\t// one, which is the opposite of what sorting was asked for.\n\t\tif (leftMissing !== rightMissing) {\n\t\t\treturn leftMissing ? 1 : -1\n\t\t}\n\t\tif (leftMissing && rightMissing) {\n\t\t\treturn 0\n\t\t}\n\t\tif (typeof left === 'number' && typeof right === 'number') {\n\t\t\treturn (left - right) * direction\n\t\t}\n\t\treturn String(left).localeCompare(String(right)) * direction\n\t})\n}\n\n/**\n * Whether a cell value counts as filled in.\n *\n * @param {(Array|object|string|number|boolean|null|undefined)} value The value.\n * @return {boolean} False for nothing, an empty string or an empty list.\n */\nfunction isFilled(value) {\n\tif (value === null || value === undefined || value === '') {\n\t\treturn false\n\t}\n\treturn !(Array.isArray(value) && value.length === 0)\n}\n\n/**\n * The single value a node is grouped under, as a string key: a list groups\n * under its first entry, an object under its label, title, name or id.\n *\n * @param {(Array|object|string|number|boolean|null|undefined)} value The cell value.\n * @return {(string|null)} The group key, or null when nothing is filled in.\n */\nfunction groupKeyOf(value) {\n\tconst first = Array.isArray(value) ? value[0] : value\n\tif (!isFilled(first)) {\n\t\treturn null\n\t}\n\tif (typeof first === 'object') {\n\t\tconst label = first.label ?? first.title ?? first.name ?? first.id\n\t\treturn isFilled(label) ? String(label) : null\n\t}\n\treturn String(first)\n}\n\n/**\n * The values a node carries in a column, as strings, for counting and\n * filtering: every entry of a list, the one value otherwise.\n *\n * @param {object} column A resolved column.\n * @param {object} node The node.\n * @param {object} [rowData] The host's per-file data.\n * @return {string[]} The values, deduplicated.\n */\nfunction facetValuesOf(column, node, rowData) {\n\tconst value = fileColumnValue(column, node, rowData)\n\tconst entries = Array.isArray(value) ? value : [value]\n\tconst out = []\n\tentries.forEach((entry) => {\n\t\tconst key = groupKeyOf(entry)\n\t\tif (key !== null && !out.includes(key)) {\n\t\t\tout.push(key)\n\t\t}\n\t})\n\treturn out\n}\n\n/**\n * Group nodes on a column's value, in the order each value is first met.\n * Nodes with no value come last, in one group whose value is null.\n *\n * @param {Array<object>} nodes The nodes, already in display order.\n * @param {object} column The resolved column.\n * @param {object} [rowData] The host's per-file data.\n * @return {Array<{value: (string|null), nodes: Array<object>}>} The groups.\n */\nexport function groupNodes(nodes, column, rowData = null) {\n\tconst groups = []\n\tconst byKey = new Map()\n\tconst empty = { value: null, nodes: [] }\n\t;(Array.isArray(nodes) ? nodes : []).forEach((node) => {\n\t\tconst key = column ? groupKeyOf(fileColumnValue(column, node, rowData)) : null\n\t\tif (key === null) {\n\t\t\tempty.nodes.push(node)\n\t\t\treturn\n\t\t}\n\t\tif (!byKey.has(key)) {\n\t\t\tconst group = { value: key, nodes: [] }\n\t\t\tbyKey.set(key, group)\n\t\t\tgroups.push(group)\n\t\t}\n\t\tbyKey.get(key).nodes.push(node)\n\t})\n\tif (empty.nodes.length > 0) {\n\t\tgroups.push(empty)\n\t}\n\treturn groups\n}\n\n/**\n * The values in use in a column across the nodes, with how many nodes carry\n * each; a list counts once per entry. Most used first, then in first-seen\n * order.\n *\n * @param {Array<object>} nodes The nodes.\n * @param {object} column The resolved column.\n * @param {object} [rowData] The host's per-file data.\n * @return {Array<{value: string, count: number}>} The values and counts.\n */\nexport function facetCounts(nodes, column, rowData = null) {\n\tconst counts = []\n\tconst byValue = new Map()\n\t;(Array.isArray(nodes) ? nodes : []).forEach((node) => {\n\t\tfacetValuesOf(column, node, rowData).forEach((value) => {\n\t\t\tif (!byValue.has(value)) {\n\t\t\t\tconst entry = { value, count: 0 }\n\t\t\t\tbyValue.set(value, entry)\n\t\t\t\tcounts.push(entry)\n\t\t\t}\n\t\t\tbyValue.get(value).count += 1\n\t\t})\n\t})\n\treturn counts\n\t\t.map((entry, index) => ({ entry, index }))\n\t\t.sort((a, b) => (b.entry.count - a.entry.count) || (a.index - b.index))\n\t\t.map(({ entry }) => entry)\n}\n\n/**\n * Whether a node passes the chosen facet values: within one facet any chosen\n * value will do, and every facet with a choice must pass. A facet with\n * nothing chosen does not filter.\n *\n * @param {object} node The node.\n * @param {object} selections Chosen values by column key.\n * @param {object} columnsByKey Resolved columns by key.\n * @param {object} [rowData] The host's per-file data.\n * @return {boolean} True when the node stays in the list.\n */\nexport function nodeMatchesFacets(node, selections, columnsByKey, rowData = null) {\n\treturn Object.entries(selections || {}).every(([key, chosen]) => {\n\t\tif (!Array.isArray(chosen) || chosen.length === 0) {\n\t\t\treturn true\n\t\t}\n\t\tconst column = columnsByKey && columnsByKey[key]\n\t\tif (!column) {\n\t\t\treturn true\n\t\t}\n\t\tconst values = facetValuesOf(column, node, rowData)\n\t\treturn chosen.some((value) => values.includes(value))\n\t})\n}\n"],"names":[],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACY,MAAC,qBAAqB,GAAG;AACrC,CAAC,IAAI,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,IAAI,EAAE;AAChG,CAAC,IAAI,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE;AACxF,CAAC,QAAQ,EAAE,EAAE,GAAG,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE;AAClG,CAAC,KAAK,EAAE,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE;AAC1E,CAAC,IAAI,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE;AACvE,CAAC,IAAI,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,wBAAwB,EAAE,QAAQ,EAAE,KAAK,EAAE;AAC1F,EAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACY,MAAC,oBAAoB,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAC;AAChE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE;AAC5B,CAAC,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,EAAE,EAAE;AACvD,EAAE,OAAO,SAAS;AAClB,EAAE;AACF,CAAC,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,GAAG,MAAM,GAAG,KAAK,IAAI,IAAI,GAAG,KAAK,SAAS,GAAG,SAAS,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC;AAC9G,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,mBAAmB,CAAC,IAAI,EAAE;AAC1C,CAAC,OAAO,OAAO,IAAI,KAAK,QAAQ,IAAI,MAAM,CAAC,MAAM,CAAC,qBAAqB,EAAE,IAAI,CAAC;AAC9E,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,oBAAoB,CAAC,OAAO,EAAE;AAC9C,CAAC,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,GAAG,OAAO,GAAG,qBAAoB;AAC/F,CAAC,MAAM,GAAG,GAAG,GAAE;AACf,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,KAAK,KAAK;AAC7B,EAAE,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE;AACjC,GAAG,IAAI,mBAAmB,CAAC,KAAK,CAAC,EAAE;AACnC,IAAI,GAAG,CAAC,IAAI,CAAC,EAAE,GAAG,qBAAqB,CAAC,KAAK,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,EAAC;AAChE,IAAI;AACJ,GAAG,MAAM;AACT,GAAG;AACH,EAAE,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,OAAO,KAAK,CAAC,GAAG,KAAK,QAAQ,IAAI,KAAK,CAAC,GAAG,KAAK,EAAE,EAAE;AAChG,GAAG,MAAM;AACT,GAAG;AACH,EAAE,IAAI,mBAAmB,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,MAAM,KAAK,SAAS,EAAE;AACpE,GAAG,GAAG,CAAC,IAAI,CAAC,EAAE,GAAG,qBAAqB,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,GAAG,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,EAAC;AAC7E,GAAG,MAAM;AACT,GAAG;AACH,EAAE,GAAG,CAAC,IAAI,CAAC;AACX,GAAG,MAAM,EAAE,MAAM;AACjB,GAAG,QAAQ,EAAE,KAAK;AAClB,GAAG,GAAG,KAAK;AACX,GAAG,OAAO,EAAE,KAAK;AACjB,GAAG,EAAC;AACJ,EAAE,EAAC;AACH,CAAC,OAAO,GAAG;AACX,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,kBAAkB,CAAC,QAAQ,EAAE,WAAW,EAAE;AAC1D,CAAC,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,QAAQ,GAAG,GAAE;AACxD,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE;AAClC,EAAE,OAAO,OAAO,CAAC,MAAM,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,MAAM,KAAK,IAAI,CAAC;AAC3D,EAAE;AACF,CAAC,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,WAAW,EAAC;AACpC,CAAC,OAAO,OAAO,CAAC,MAAM,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;AAC1D,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,sBAAsB,CAAC,OAAO,EAAE;AAChD,CAAC,MAAM,GAAG,GAAG,EAAE;AACf,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,GAAG,EAAE,EAAE,OAAO,CAAC,CAAC,MAAM,KAAK;AAC9D,EAAE,IAAI,MAAM,IAAI,MAAM,CAAC,MAAM,KAAK,WAAW,IAAI,OAAO,MAAM,CAAC,SAAS,KAAK,QAAQ,IAAI,MAAM,CAAC,SAAS,KAAK,EAAE,EAAE;AAClH,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE;AACxC,IAAI,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAC;AAC9B,IAAI;AACJ,GAAG;AACH,EAAE,EAAC;AACH,CAAC,OAAO,GAAG;AACX,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,eAAe,CAAC,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,IAAI,EAAE;AAC9D,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE;AACvB,EAAE,OAAO,SAAS;AAClB,EAAE;AACF,CAAC,IAAI,MAAM,CAAC,MAAM,KAAK,WAAW,EAAE;AACpC;AACA;AACA;AACA;AACA,EAAE,MAAM,UAAU,GAAG,IAAI,CAAC,WAAU;AACpC,EAAE,OAAO,UAAU,IAAI,OAAO,UAAU,KAAK,QAAQ,GAAG,UAAU,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,SAAS;AAChG,EAAE;AACF,CAAC,IAAI,MAAM,CAAC,MAAM,KAAK,KAAK,EAAE;AAC9B,EAAE,MAAM,IAAI,GAAG,OAAO,IAAI,OAAO,OAAO,KAAK,QAAQ,GAAG,OAAO,GAAG,KAAI;AACtE,EAAE,IAAI,CAAC,IAAI,EAAE;AACb,GAAG,OAAO,SAAS;AACnB,GAAG;AACH,EAAE,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,EAAC;AAC9D,EAAE,IAAI,CAAC,KAAK,EAAE;AACd,GAAG,OAAO,SAAS;AACnB,GAAG;AACH;AACA;AACA,EAAE,OAAO,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC;AACzF,EAAE;AACF,CAAC,OAAO,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,OAAO,IAAI,MAAM,CAAC,GAAG,CAAC;AAClD,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,GAAG,IAAI,EAAE,QAAQ,GAAG,MAAM,KAAK,EAAE;AACpG,CAAC,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,GAAG,GAAE;AACpD,CAAC,IAAI,CAAC,MAAM,EAAE;AACd,EAAE,OAAO,IAAI;AACb,EAAE;AACF,CAAC,MAAM,SAAS,GAAG,SAAS,GAAG,CAAC,GAAG,CAAC,EAAC;AACrC,CAAC,OAAO,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK;AAC5B,EAAE,MAAM,OAAO,GAAG,QAAQ,CAAC,CAAC,EAAC;AAC7B,EAAE,MAAM,OAAO,GAAG,QAAQ,CAAC,CAAC,EAAC;AAC7B,EAAE,IAAI,OAAO,KAAK,OAAO,EAAE;AAC3B,GAAG,OAAO,OAAO,GAAG,CAAC,CAAC,GAAG,CAAC;AAC1B,GAAG;AACH,EAAE,MAAM,IAAI,GAAG,eAAe,CAAC,MAAM,EAAE,CAAC,EAAE,OAAO,EAAC;AAClD,EAAE,MAAM,KAAK,GAAG,eAAe,CAAC,MAAM,EAAE,CAAC,EAAE,OAAO,EAAC;AACnD,EAAE,MAAM,WAAW,GAAG,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,GAAE;AACxE,EAAE,MAAM,YAAY,GAAG,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,GAAE;AAC5E;AACA;AACA;AACA,EAAE,IAAI,WAAW,KAAK,YAAY,EAAE;AACpC,GAAG,OAAO,WAAW,GAAG,CAAC,GAAG,CAAC,CAAC;AAC9B,GAAG;AACH,EAAE,IAAI,WAAW,IAAI,YAAY,EAAE;AACnC,GAAG,OAAO,CAAC;AACX,GAAG;AACH,EAAE,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE;AAC7D,GAAG,OAAO,CAAC,IAAI,GAAG,KAAK,IAAI,SAAS;AACpC,GAAG;AACH,EAAE,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,GAAG,SAAS;AAC9D,EAAE,CAAC;AACH,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS,QAAQ,CAAC,KAAK,EAAE;AACzB,CAAC,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,EAAE,EAAE;AAC5D,EAAE,OAAO,KAAK;AACd,EAAE;AACF,CAAC,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC;AACrD,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS,UAAU,CAAC,KAAK,EAAE;AAC3B,CAAC,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,GAAG,MAAK;AACtD,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE;AACvB,EAAE,OAAO,IAAI;AACb,EAAE;AACF,CAAC,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE;AAChC,EAAE,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC,GAAE;AACpE,EAAE,OAAO,QAAQ,CAAC,KAAK,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI;AAC/C,EAAE;AACF,CAAC,OAAO,MAAM,CAAC,KAAK,CAAC;AACrB,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS,aAAa,CAAC,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE;AAC9C,CAAC,MAAM,KAAK,GAAG,eAAe,CAAC,MAAM,EAAE,IAAI,EAAE,OAAO,EAAC;AACrD,CAAC,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,KAAK,GAAG,CAAC,KAAK,EAAC;AACvD,CAAC,MAAM,GAAG,GAAG,GAAE;AACf,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,KAAK,KAAK;AAC5B,EAAE,MAAM,GAAG,GAAG,UAAU,CAAC,KAAK,EAAC;AAC/B,EAAE,IAAI,GAAG,KAAK,IAAI,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE;AAC1C,GAAG,GAAG,CAAC,IAAI,CAAC,GAAG,EAAC;AAChB,GAAG;AACH,EAAE,EAAC;AACH,CAAC,OAAO,GAAG;AACX,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,GAAG,IAAI,EAAE;AAC1D,CAAC,MAAM,MAAM,GAAG,GAAE;AAClB,CAAC,MAAM,KAAK,GAAG,IAAI,GAAG,GAAE;AACxB,CAAC,MAAM,KAAK,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE;AACzC,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,KAAK,GAAG,EAAE,EAAE,OAAO,CAAC,CAAC,IAAI,KAAK;AACxD,EAAE,MAAM,GAAG,GAAG,MAAM,GAAG,UAAU,CAAC,eAAe,CAAC,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC,GAAG,KAAI;AAChF,EAAE,IAAI,GAAG,KAAK,IAAI,EAAE;AACpB,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,EAAC;AACzB,GAAG,MAAM;AACT,GAAG;AACH,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE;AACvB,GAAG,MAAM,KAAK,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE,GAAE;AAC1C,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,EAAC;AACxB,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,EAAC;AACrB,GAAG;AACH,EAAE,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,EAAC;AACjC,EAAE,EAAC;AACH,CAAC,IAAI,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE;AAC7B,EAAE,MAAM,CAAC,IAAI,CAAC,KAAK,EAAC;AACpB,EAAE;AACF,CAAC,OAAO,MAAM;AACd,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,GAAG,IAAI,EAAE;AAC3D,CAAC,MAAM,MAAM,GAAG,GAAE;AAClB,CAAC,MAAM,OAAO,GAAG,IAAI,GAAG,EAAE;AAC1B,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,KAAK,GAAG,EAAE,EAAE,OAAO,CAAC,CAAC,IAAI,KAAK;AACxD,EAAE,aAAa,CAAC,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,KAAK;AAC1D,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE;AAC5B,IAAI,MAAM,KAAK,GAAG,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,GAAE;AACrC,IAAI,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,EAAC;AAC7B,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,EAAC;AACtB,IAAI;AACJ,GAAG,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,KAAK,IAAI,EAAC;AAChC,GAAG,EAAC;AACJ,EAAE,EAAC;AACH,CAAC,OAAO,MAAM;AACd,GAAG,GAAG,CAAC,CAAC,KAAK,EAAE,KAAK,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;AAC5C,GAAG,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,KAAK,MAAM,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC;AACzE,GAAG,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,KAAK,CAAC;AAC5B,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,iBAAiB,CAAC,IAAI,EAAE,UAAU,EAAE,YAAY,EAAE,OAAO,GAAG,IAAI,EAAE;AAClF,CAAC,OAAO,MAAM,CAAC,OAAO,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,EAAE,MAAM,CAAC,KAAK;AAClE,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE;AACrD,GAAG,OAAO,IAAI;AACd,GAAG;AACH,EAAE,MAAM,MAAM,GAAG,YAAY,IAAI,YAAY,CAAC,GAAG,EAAC;AAClD,EAAE,IAAI,CAAC,MAAM,EAAE;AACf,GAAG,OAAO,IAAI;AACd,GAAG;AACH,EAAE,MAAM,MAAM,GAAG,aAAa,CAAC,MAAM,EAAE,IAAI,EAAE,OAAO,EAAC;AACrD,EAAE,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,KAAK,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AACvD,EAAE,CAAC;AACH;;;;"}
|
|
1
|
+
{"version":3,"file":"filesBrowserColumns.js","sources":["../../../../src/components/CnFilesBrowser/filesBrowserColumns.js"],"sourcesContent":["/**\n * SPDX-FileCopyrightText: 2026 Conduction B.V. <info@conduction.nl>\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\n/**\n * The built-in columns a host may name by string, and what each one reads.\n *\n * `nodeKey` is the property on the @nextcloud/files node. `sortKey` is what\n * `sortNodes` understands, so a built-in sorts the way the Files app sorts;\n * a built-in with no `sortKey` sorts client-side like a declared column.\n *\n * @type {object}\n */\nexport const BUILT_IN_FILE_COLUMNS = {\n\tname: { key: 'name', source: 'node', nodeKey: 'basename', sortKey: 'basename', sortable: true },\n\tsize: { key: 'size', source: 'node', nodeKey: 'size', sortKey: 'size', sortable: true },\n\tmodified: { key: 'modified', source: 'node', nodeKey: 'mtime', sortKey: 'mtime', sortable: true },\n\towner: { key: 'owner', source: 'node', nodeKey: 'owner', sortable: true },\n\ttype: { key: 'type', source: 'node', nodeKey: 'mime', sortable: true },\n\ttags: { key: 'tags', source: 'node', nodeKey: 'attributes.system-tags', sortable: false },\n}\n\n/**\n * The columns a browser shows when its host declares none: what the table has\n * always shown, in the order it has always shown it.\n *\n * @type {string[]}\n */\nexport const DEFAULT_FILE_COLUMNS = ['name', 'size', 'modified']\n\n/**\n * Read a dotted path off a node without throwing on a missing segment.\n *\n * @param {object} node The node.\n * @param {string} path A dotted path.\n * @return {(Array|object|string|number|boolean|undefined)} The value.\n */\nfunction atPath(node, path) {\n\tif (!node || typeof path !== 'string' || path === '') {\n\t\treturn undefined\n\t}\n\treturn path.split('.').reduce((acc, key) => (acc === null || acc === undefined ? undefined : acc[key]), node)\n}\n\n/**\n * Whether a string names a built-in column.\n *\n * @param {string} name The candidate name.\n * @return {boolean} True when it is a built-in.\n */\nexport function isBuiltInFileColumn(name) {\n\treturn typeof name === 'string' && Object.hasOwn(BUILT_IN_FILE_COLUMNS, name)\n}\n\n/**\n * Resolve a host's `columns` declaration into column objects.\n *\n * A string names a built-in. An object declares its own: `key`, `label`,\n * `source` (`node`, `attribute` or `row`), `attribute`, `formatter` and\n * `sortable`. An entry naming an unknown built-in is dropped here and refused\n * by the manifest validator, so an author hears about it at authoring time\n * rather than finding a column missing at runtime.\n *\n * @param {(Array|null|undefined)} columns The declaration, or nothing.\n * @return {Array<object>} The resolved columns, in the declared order.\n */\nexport function normaliseFileColumns(columns) {\n\tconst declared = Array.isArray(columns) && columns.length > 0 ? columns : DEFAULT_FILE_COLUMNS\n\tconst out = []\n\tdeclared.forEach((entry) => {\n\t\tif (typeof entry === 'string') {\n\t\t\tif (isBuiltInFileColumn(entry)) {\n\t\t\t\tout.push({ ...BUILT_IN_FILE_COLUMNS[entry], builtIn: true })\n\t\t\t}\n\t\t\treturn\n\t\t}\n\t\tif (!entry || typeof entry !== 'object' || typeof entry.key !== 'string' || entry.key === '') {\n\t\t\treturn\n\t\t}\n\t\t// `when`: the column applies only while it is true (a case type flag).\n\t\t// @spec openspec/changes/files-review-row-when/specs/files-review-row-when/spec.md#requirement-a-files-browser-entry-can-apply-only-when-a-condition-holds\n\t\tif ('when' in entry && entry.when !== true) {\n\t\t\treturn\n\t\t}\n\t\tif (isBuiltInFileColumn(entry.key) && entry.source === undefined) {\n\t\t\tout.push({ ...BUILT_IN_FILE_COLUMNS[entry.key], ...entry, builtIn: true })\n\t\t\treturn\n\t\t}\n\t\tout.push({\n\t\t\tsource: 'node',\n\t\t\tsortable: false,\n\t\t\t...entry,\n\t\t\tbuiltIn: false,\n\t\t})\n\t})\n\treturn out\n}\n\n/**\n * The columns a browser renders: the host's declaration, narrowed by what this\n * user chose to see.\n *\n * Which side wins on what:\n *\n * - The HOST decides MEMBERSHIP. The result is built by walking the\n * declaration, so a column exists only because the host declared it, in the\n * order the host declared it.\n * - The USER decides VISIBILITY, and only downward. A stored preference can\n * hide a declared column; it can never add one. A key in the stored list\n * that the host no longer declares is passed over, so unticking a column\n * last month cannot bring it back once the host removed it, and neither can\n * a preference written while a different column set was declared.\n *\n * A stored value of `null` is a user who has never chosen, which shows\n * every declared column but the ones the host declared `hidden: true`. An\n * empty list is a user who hid everything, which is a choice and is honoured.\n *\n * @param {Array<object>} declared The resolved declared columns.\n * @param {(string[]|null|undefined)} visibleKeys The user's stored visible keys.\n * @return {Array<object>} The columns to render.\n */\nexport function visibleFileColumns(declared, visibleKeys) {\n\tconst columns = Array.isArray(declared) ? declared : []\n\tif (!Array.isArray(visibleKeys)) {\n\t\treturn columns.filter((column) => column.hidden !== true)\n\t}\n\tconst wanted = new Set(visibleKeys)\n\treturn columns.filter((column) => wanted.has(column.key))\n}\n\n/**\n * The DAV properties a declaration needs in the PROPFIND, so an `attribute`\n * column's value is there when the folder lists rather than one request later.\n *\n * @param {Array<object>} columns The resolved columns.\n * @return {string[]} The property names, deduplicated, in declaration order.\n */\nexport function attributePropertiesFor(columns) {\n\tconst out = []\n\t;(Array.isArray(columns) ? columns : []).forEach((column) => {\n\t\tif (column && column.source === 'attribute' && typeof column.attribute === 'string' && column.attribute !== '') {\n\t\t\tif (!out.includes(column.attribute)) {\n\t\t\t\tout.push(column.attribute)\n\t\t\t}\n\t\t}\n\t})\n\treturn out\n}\n\n/**\n * The value one column shows for one node. A `row` column's key may be a\n * dotted path into the host's record.\n *\n * @param {object} column A resolved column.\n * @param {object} node The node.\n * @param {object} [rowData] The host's per-file data, keyed by file id.\n * @return {(Array|object|string|number|boolean|undefined)} The cell value.\n */\nexport function fileColumnValue(column, node, rowData = null) {\n\tif (!column || !node) {\n\t\treturn undefined\n\t}\n\tif (column.source === 'attribute') {\n\t\t// Read the key directly, NOT through the dotted-path reader: a DAV\n\t\t// property name is `{http://owncloud.org/ns}av-status`, and splitting\n\t\t// that on dots looks for a property called `org/ns}av-status` inside\n\t\t// one called `owncloud`, which is undefined every time.\n\t\tconst attributes = node.attributes\n\t\treturn attributes && typeof attributes === 'object' ? attributes[column.attribute] : undefined\n\t}\n\tif (column.source === 'row') {\n\t\tconst byId = rowData && typeof rowData === 'object' ? rowData : null\n\t\tif (!byId) {\n\t\t\treturn undefined\n\t\t}\n\t\tconst entry = byId[node.fileid] ?? byId[String(node.fileid)]\n\t\tif (!entry) {\n\t\t\treturn undefined\n\t\t}\n\t\t// A key the record holds as written wins; otherwise a dotted key reads\n\t\t// a nested field (`scanVerdict.state`, `integrity.value`).\n\t\treturn Object.hasOwn(entry, column.key) ? entry[column.key] : atPath(entry, column.key)\n\t}\n\treturn atPath(node, column.nodeKey || column.key)\n}\n\n/**\n * Sort nodes on a declared column's resolved value, within the listed folder.\n *\n * Folders stay first, the way the Files app lists them and the way the\n * built-in sorts already do, so switching to a declared column does not\n * reshuffle the folders into the files.\n *\n * @param {Array<object>} nodes The nodes.\n * @param {object} column The resolved column.\n * @param {boolean} ascending Sort direction.\n * @param {object} [rowData] The host's per-file data.\n * @param {(node: object) => boolean} [isFolder] Whether a node is a folder.\n * @return {Array<object>} A new, sorted array.\n */\nexport function sortNodesByColumn(nodes, column, ascending, rowData = null, isFolder = () => false) {\n\tconst list = Array.isArray(nodes) ? [...nodes] : []\n\tif (!column) {\n\t\treturn list\n\t}\n\tconst direction = ascending ? 1 : -1\n\treturn list.sort((a, b) => {\n\t\tconst folderA = isFolder(a)\n\t\tconst folderB = isFolder(b)\n\t\tif (folderA !== folderB) {\n\t\t\treturn folderA ? -1 : 1\n\t\t}\n\t\tconst left = fileColumnValue(column, a, rowData)\n\t\tconst right = fileColumnValue(column, b, rowData)\n\t\tconst leftMissing = left === undefined || left === null || left === ''\n\t\tconst rightMissing = right === undefined || right === null || right === ''\n\t\t// A value nobody filled in sorts last in BOTH directions. Letting it\n\t\t// ride to the top on a descending sort hides the rows that do carry\n\t\t// one, which is the opposite of what sorting was asked for.\n\t\tif (leftMissing !== rightMissing) {\n\t\t\treturn leftMissing ? 1 : -1\n\t\t}\n\t\tif (leftMissing && rightMissing) {\n\t\t\treturn 0\n\t\t}\n\t\tif (typeof left === 'number' && typeof right === 'number') {\n\t\t\treturn (left - right) * direction\n\t\t}\n\t\treturn String(left).localeCompare(String(right)) * direction\n\t})\n}\n\n/**\n * Whether a cell value counts as filled in.\n *\n * @param {(Array|object|string|number|boolean|null|undefined)} value The value.\n * @return {boolean} False for nothing, an empty string or an empty list.\n */\nfunction isFilled(value) {\n\tif (value === null || value === undefined || value === '') {\n\t\treturn false\n\t}\n\treturn !(Array.isArray(value) && value.length === 0)\n}\n\n/**\n * The single value a node is grouped under, as a string key: a list groups\n * under its first entry, an object under its label, title, name or id.\n *\n * @param {(Array|object|string|number|boolean|null|undefined)} value The cell value.\n * @return {(string|null)} The group key, or null when nothing is filled in.\n */\nfunction groupKeyOf(value) {\n\tconst first = Array.isArray(value) ? value[0] : value\n\tif (!isFilled(first)) {\n\t\treturn null\n\t}\n\tif (typeof first === 'object') {\n\t\tconst label = first.label ?? first.title ?? first.name ?? first.id\n\t\treturn isFilled(label) ? String(label) : null\n\t}\n\treturn String(first)\n}\n\n/**\n * The values a node carries in a column, as strings, for counting and\n * filtering: every entry of a list, the one value otherwise.\n *\n * @param {object} column A resolved column.\n * @param {object} node The node.\n * @param {object} [rowData] The host's per-file data.\n * @return {string[]} The values, deduplicated.\n */\nfunction facetValuesOf(column, node, rowData) {\n\tconst value = fileColumnValue(column, node, rowData)\n\tconst entries = Array.isArray(value) ? value : [value]\n\tconst out = []\n\tentries.forEach((entry) => {\n\t\tconst key = groupKeyOf(entry)\n\t\tif (key !== null && !out.includes(key)) {\n\t\t\tout.push(key)\n\t\t}\n\t})\n\treturn out\n}\n\n/**\n * Group nodes on a column's value, in the order each value is first met.\n * Nodes with no value come last, in one group whose value is null.\n *\n * @param {Array<object>} nodes The nodes, already in display order.\n * @param {object} column The resolved column.\n * @param {object} [rowData] The host's per-file data.\n * @return {Array<{value: (string|null), nodes: Array<object>}>} The groups.\n */\nexport function groupNodes(nodes, column, rowData = null) {\n\tconst groups = []\n\tconst byKey = new Map()\n\tconst empty = { value: null, nodes: [] }\n\t;(Array.isArray(nodes) ? nodes : []).forEach((node) => {\n\t\tconst key = column ? groupKeyOf(fileColumnValue(column, node, rowData)) : null\n\t\tif (key === null) {\n\t\t\tempty.nodes.push(node)\n\t\t\treturn\n\t\t}\n\t\tif (!byKey.has(key)) {\n\t\t\tconst group = { value: key, nodes: [] }\n\t\t\tbyKey.set(key, group)\n\t\t\tgroups.push(group)\n\t\t}\n\t\tbyKey.get(key).nodes.push(node)\n\t})\n\tif (empty.nodes.length > 0) {\n\t\tgroups.push(empty)\n\t}\n\treturn groups\n}\n\n/**\n * The values in use in a column across the nodes, with how many nodes carry\n * each; a list counts once per entry. Most used first, then in first-seen\n * order.\n *\n * @param {Array<object>} nodes The nodes.\n * @param {object} column The resolved column.\n * @param {object} [rowData] The host's per-file data.\n * @return {Array<{value: string, count: number}>} The values and counts.\n */\nexport function facetCounts(nodes, column, rowData = null) {\n\tconst counts = []\n\tconst byValue = new Map()\n\t;(Array.isArray(nodes) ? nodes : []).forEach((node) => {\n\t\tfacetValuesOf(column, node, rowData).forEach((value) => {\n\t\t\tif (!byValue.has(value)) {\n\t\t\t\tconst entry = { value, count: 0 }\n\t\t\t\tbyValue.set(value, entry)\n\t\t\t\tcounts.push(entry)\n\t\t\t}\n\t\t\tbyValue.get(value).count += 1\n\t\t})\n\t})\n\treturn counts\n\t\t.map((entry, index) => ({ entry, index }))\n\t\t.sort((a, b) => (b.entry.count - a.entry.count) || (a.index - b.index))\n\t\t.map(({ entry }) => entry)\n}\n\n/**\n * Whether a node passes the chosen facet values: within one facet any chosen\n * value will do, and every facet with a choice must pass. A facet with\n * nothing chosen does not filter.\n *\n * @param {object} node The node.\n * @param {object} selections Chosen values by column key.\n * @param {object} columnsByKey Resolved columns by key.\n * @param {object} [rowData] The host's per-file data.\n * @return {boolean} True when the node stays in the list.\n */\nexport function nodeMatchesFacets(node, selections, columnsByKey, rowData = null) {\n\treturn Object.entries(selections || {}).every(([key, chosen]) => {\n\t\tif (!Array.isArray(chosen) || chosen.length === 0) {\n\t\t\treturn true\n\t\t}\n\t\tconst column = columnsByKey && columnsByKey[key]\n\t\tif (!column) {\n\t\t\treturn true\n\t\t}\n\t\tconst values = facetValuesOf(column, node, rowData)\n\t\treturn chosen.some((value) => values.includes(value))\n\t})\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -822,6 +822,21 @@ var script = {
|
|
|
822
822
|
default: '',
|
|
823
823
|
},
|
|
824
824
|
|
|
825
|
+
/**
|
|
826
|
+
* Board look: the count line while a saved view is applied (manifest
|
|
827
|
+
* `config.savedViewCountText`), a template as `countText` that may name
|
|
828
|
+
* the view's conditions as `{view}`: its description, else its filters
|
|
829
|
+
* in words (DqFilterInMenu "3 van 48 lopende zaken · termijn binnen 7
|
|
830
|
+
* dagen, van mij · gesorteerd op termijn"). A view's own `countText`
|
|
831
|
+
* override and a scope's come first.
|
|
832
|
+
*
|
|
833
|
+
* @spec openspec/changes/applied-view-lights-its-lens/specs/applied-view-lights-its-lens/spec.md
|
|
834
|
+
*/
|
|
835
|
+
savedViewCountText: {
|
|
836
|
+
type: String,
|
|
837
|
+
default: '',
|
|
838
|
+
},
|
|
839
|
+
|
|
825
840
|
/**
|
|
826
841
|
* Board look: a count line per view (manifest `config.countTextByView`),
|
|
827
842
|
* `{ table?, cards?, list?, board?, map? }`, each a template as
|
|
@@ -3162,6 +3177,8 @@ var script = {
|
|
|
3162
3177
|
savedViewCounts: null,
|
|
3163
3178
|
// The id (or slug) of the saved view that is applied; its chip shows selected under the board look.
|
|
3164
3179
|
appliedSavedViewId: '',
|
|
3180
|
+
/** Whether the reader picked a lens chip after the applied view (then their chip shows). */
|
|
3181
|
+
lensChosenByHand: false,
|
|
3165
3182
|
// The sort option the applied view's `overrides.sortOption` selected, so leaving the view can undo it.
|
|
3166
3183
|
viewSortOption: '',
|
|
3167
3184
|
// The applied view's filters as one comparable key, so the address keeps naming the view until they change.
|
|
@@ -3235,6 +3252,8 @@ var script = {
|
|
|
3235
3252
|
savedViews: [],
|
|
3236
3253
|
savedViewsLoading: false,
|
|
3237
3254
|
showSaveViewDialog: false,
|
|
3255
|
+
/** Whether the reader changed the view since it was opened or saved. */
|
|
3256
|
+
viewChanged: false,
|
|
3238
3257
|
viewPendingDelete: null,
|
|
3239
3258
|
/** An `api-call` header action waiting on its confirmation, or null. */
|
|
3240
3259
|
headerApiCallPending: null,
|
|
@@ -5001,13 +5020,53 @@ var script = {
|
|
|
5001
5020
|
* @spec openspec/changes/working-list-row-actions/specs/index-page/spec.md
|
|
5002
5021
|
*/
|
|
5003
5022
|
/**
|
|
5004
|
-
* The chip
|
|
5005
|
-
*
|
|
5006
|
-
*
|
|
5023
|
+
* The lens chip an applied saved view narrows within: the non-default
|
|
5024
|
+
* tab whose every condition the view's own conditions (its filters
|
|
5025
|
+
* over its locked filters, tokens as written) hold, the most specific
|
|
5026
|
+
* first (DqFilterInMenu: "Termijn deze week" lit for the view of that
|
|
5027
|
+
* name). Null without an applied view or a fitting tab.
|
|
5028
|
+
*
|
|
5029
|
+
* @return {number|null} The tab index.
|
|
5030
|
+
* @spec openspec/changes/applied-view-lights-its-lens/specs/applied-view-lights-its-lens/spec.md
|
|
5031
|
+
*/
|
|
5032
|
+
appliedViewLensIndex() {
|
|
5033
|
+
const view = this.appliedSavedView;
|
|
5034
|
+
const tabs = Array.isArray(this.tabStripEntries) ? this.tabStripEntries : [];
|
|
5035
|
+
if (!view || tabs.length === 0) {
|
|
5036
|
+
return null
|
|
5037
|
+
}
|
|
5038
|
+
const query = view.query && typeof view.query === 'object' ? view.query : {};
|
|
5039
|
+
const locked = query.overrides && typeof query.overrides.lockedFilters === 'object' ? query.overrides.lockedFilters : {};
|
|
5040
|
+
const conditions = { ...(locked || {}), ...(query.filters || view.filters || {}) };
|
|
5041
|
+
const same = (a, b) => JSON.stringify(Array.isArray(a) ? a.map(String) : String(a)) === JSON.stringify(Array.isArray(b) ? b.map(String) : String(b));
|
|
5042
|
+
let best = null;
|
|
5043
|
+
let bestSize = 0;
|
|
5044
|
+
tabs.forEach((tab, index) => {
|
|
5045
|
+
const filter = tab && tab.filter && typeof tab.filter === 'object' ? tab.filter : {};
|
|
5046
|
+
const keys = Object.keys(filter);
|
|
5047
|
+
if (tab.default === true || keys.length === 0 || keys.length <= bestSize) {
|
|
5048
|
+
return
|
|
5049
|
+
}
|
|
5050
|
+
if (keys.every((key) => Object.hasOwn(conditions, key) && same(conditions[key], filter[key]))) {
|
|
5051
|
+
best = index;
|
|
5052
|
+
bestSize = keys.length;
|
|
5053
|
+
}
|
|
5054
|
+
});
|
|
5055
|
+
return best
|
|
5056
|
+
},
|
|
5057
|
+
|
|
5058
|
+
/**
|
|
5059
|
+
* The chip the strip lights: the lens an applied saved view narrows
|
|
5060
|
+
* within (until the reader picks a chip), else the active tab, else
|
|
5061
|
+
* the default tab of tabs that arrived after setup
|
|
5062
|
+
* (`quickFiltersFrom`), which is the one the fetch applies.
|
|
5007
5063
|
*
|
|
5008
5064
|
* @return {number|null} The tab index, or null without tabs.
|
|
5009
5065
|
*/
|
|
5010
5066
|
shownQuickFilterIndex() {
|
|
5067
|
+
if (!this.quickFilterMultiple && !this.lensChosenByHand && this.appliedViewLensIndex !== null) {
|
|
5068
|
+
return this.appliedViewLensIndex
|
|
5069
|
+
}
|
|
5011
5070
|
if (this.activeQuickFilterIndex !== null && this.activeQuickFilterIndex !== undefined) {
|
|
5012
5071
|
return this.activeQuickFilterIndex
|
|
5013
5072
|
}
|
|
@@ -7231,12 +7290,20 @@ var script = {
|
|
|
7231
7290
|
|
|
7232
7291
|
/**
|
|
7233
7292
|
* Whether the toolbar draws Save view: not when the page switches it
|
|
7234
|
-
* off (`savedViewSave: false`) or its header carries one
|
|
7293
|
+
* off (`savedViewSave: false`) or its header carries one, and in the
|
|
7294
|
+
* board look only once the view has changed.
|
|
7235
7295
|
*
|
|
7296
|
+
* @spec openspec/changes/board-save-view-only-when-changed/specs/saved-views/spec.md#requirement-the-board-look-offers-save-view-once-the-view-has-changed
|
|
7236
7297
|
* @return {boolean}
|
|
7237
7298
|
*/
|
|
7238
7299
|
toolbarSavesView() {
|
|
7239
|
-
|
|
7300
|
+
if (this.savedViewSave === false || this.headerSavesView) {
|
|
7301
|
+
return false
|
|
7302
|
+
}
|
|
7303
|
+
// The board look offers it once the view differs from the one
|
|
7304
|
+
// opened: changed by the reader, or, with no saved view open,
|
|
7305
|
+
// filtered by the address.
|
|
7306
|
+
return !this.isBoardLook || this.viewChanged || (!this.appliedSavedViewId && this.activeFilterChips.length > 0)
|
|
7240
7307
|
},
|
|
7241
7308
|
|
|
7242
7309
|
/**
|
|
@@ -7397,6 +7464,11 @@ var script = {
|
|
|
7397
7464
|
* @return {string}
|
|
7398
7465
|
*/
|
|
7399
7466
|
presentedCountText() {
|
|
7467
|
+
const viewLine = this.savedViewCountText;
|
|
7468
|
+
const view = this.appliedSavedView;
|
|
7469
|
+
if (view && typeof viewLine === 'string' && viewLine !== '' && this.activeScopePresentation.countText === undefined && !savedViewOverrides(view)?.countText) {
|
|
7470
|
+
return viewLine
|
|
7471
|
+
}
|
|
7400
7472
|
if (this.activeScopePresentation.countText === undefined) {
|
|
7401
7473
|
const byView = this.countTextByView;
|
|
7402
7474
|
const own = byView && typeof byView === 'object' ? byView[this.currentViewMode] : undefined;
|
|
@@ -7407,6 +7479,23 @@ var script = {
|
|
|
7407
7479
|
return this.presented('countText')
|
|
7408
7480
|
},
|
|
7409
7481
|
|
|
7482
|
+
/**
|
|
7483
|
+
* The applied saved view's conditions for the count line's `{view}`:
|
|
7484
|
+
* its description, else its filters in words, starting lower case.
|
|
7485
|
+
*
|
|
7486
|
+
* @return {string}
|
|
7487
|
+
* @spec openspec/changes/applied-view-lights-its-lens/specs/applied-view-lights-its-lens/spec.md
|
|
7488
|
+
*/
|
|
7489
|
+
appliedViewConditionsText() {
|
|
7490
|
+
const view = this.appliedSavedView;
|
|
7491
|
+
if (!view) {
|
|
7492
|
+
return ''
|
|
7493
|
+
}
|
|
7494
|
+
const own = typeof view.description === 'string' ? view.description.trim() : '';
|
|
7495
|
+
const text = own !== '' ? own : String(this.viewFilterSummary(view) || '');
|
|
7496
|
+
return text.charAt(0).toLowerCase() + text.slice(1)
|
|
7497
|
+
},
|
|
7498
|
+
|
|
7410
7499
|
headerDescriptionBase() {
|
|
7411
7500
|
const total = this.effectivePagination?.total;
|
|
7412
7501
|
// Board look: the count line is a template over the rows on this page
|
|
@@ -7430,6 +7519,7 @@ var script = {
|
|
|
7430
7519
|
.replace('{shown}', String(shown))
|
|
7431
7520
|
.replace('{total}', String(total))
|
|
7432
7521
|
.replace(/\{term\}/g, this.sourceTerm)
|
|
7522
|
+
.replace(/\{view\}/g, this.appliedViewConditionsText)
|
|
7433
7523
|
}
|
|
7434
7524
|
return this.countLine(this.countSubtitle, total, shown)
|
|
7435
7525
|
}
|
|
@@ -7495,6 +7585,17 @@ var script = {
|
|
|
7495
7585
|
return !!this.resolvedSidebar.enabled && this.resolvedSidebar.show !== false
|
|
7496
7586
|
},
|
|
7497
7587
|
|
|
7588
|
+
/**
|
|
7589
|
+
* Whether the page's side panel is open now; the board look then lays
|
|
7590
|
+
* the header out narrower (DqZakenSorteren).
|
|
7591
|
+
*
|
|
7592
|
+
* @spec openspec/changes/board-header-buttons-under-title-beside-side-panel/specs/board-header-buttons-under-title-beside-side-panel/spec.md#requirement-the-header-buttons-sit-under-the-title-while-the-side-panel-is-open
|
|
7593
|
+
* @return {boolean}
|
|
7594
|
+
*/
|
|
7595
|
+
sidebarPanelOpen() {
|
|
7596
|
+
return Boolean(this.sidebarOpen && this.hasSidebar)
|
|
7597
|
+
},
|
|
7598
|
+
|
|
7498
7599
|
/**
|
|
7499
7600
|
* Whether the board toolbar draws the Filter button as a menu: the
|
|
7500
7601
|
* board look, `filterMenu` on, something to filter by, and no filter
|
|
@@ -7537,7 +7638,9 @@ var script = {
|
|
|
7537
7638
|
|
|
7538
7639
|
/** Search props forwarded to the embedded CnIndexSidebar (defaults applied per CnIndexSidebar). */
|
|
7539
7640
|
sidebarSearchProps() {
|
|
7540
|
-
|
|
7641
|
+
// The page's own search hint, unless `sidebar.search` names one.
|
|
7642
|
+
const own = this.shownSearchPlaceholder ? { searchPlaceholder: this.shownSearchPlaceholder } : {};
|
|
7643
|
+
return { ...own, ...((this.sidebar && this.sidebar.search) || {}) }
|
|
7541
7644
|
},
|
|
7542
7645
|
|
|
7543
7646
|
/**
|
|
@@ -9338,6 +9441,7 @@ var script = {
|
|
|
9338
9441
|
* @return {void}
|
|
9339
9442
|
*/
|
|
9340
9443
|
onSearchEvent(value) {
|
|
9444
|
+
this.viewChanged = true;
|
|
9341
9445
|
if (this.namedSourceSearches) {
|
|
9342
9446
|
this.namedSearchTerm = value || '';
|
|
9343
9447
|
}
|
|
@@ -9357,9 +9461,11 @@ var script = {
|
|
|
9357
9461
|
* @return {void}
|
|
9358
9462
|
*/
|
|
9359
9463
|
onQuickFilterChange(index) {
|
|
9464
|
+
this.viewChanged = true;
|
|
9360
9465
|
// `activeQuickFilterIndex` is a setup-returned ref; the
|
|
9361
9466
|
// Vue 2 ref-unwrap proxy makes plain assignment work.
|
|
9362
9467
|
this.activeQuickFilterIndex = index;
|
|
9468
|
+
this.lensChosenByHand = true;
|
|
9363
9469
|
this.$emit('quick-filter-change', index);
|
|
9364
9470
|
},
|
|
9365
9471
|
|
|
@@ -9372,6 +9478,7 @@ var script = {
|
|
|
9372
9478
|
* @return {void}
|
|
9373
9479
|
*/
|
|
9374
9480
|
onQuickFilterMultiChange(indices) {
|
|
9481
|
+
this.viewChanged = true;
|
|
9375
9482
|
this.selectedQuickFilterIndices = Array.isArray(indices) ? indices : [];
|
|
9376
9483
|
this.$emit('quick-filter-change', this.selectedQuickFilterIndices);
|
|
9377
9484
|
},
|
|
@@ -9387,6 +9494,7 @@ var script = {
|
|
|
9387
9494
|
* @return {void}
|
|
9388
9495
|
*/
|
|
9389
9496
|
onSidebarSortChange(keys, value) {
|
|
9497
|
+
this.viewChanged = true;
|
|
9390
9498
|
if (value !== undefined && this.selectSortOption(value)) {
|
|
9391
9499
|
return
|
|
9392
9500
|
}
|
|
@@ -9466,6 +9574,7 @@ var script = {
|
|
|
9466
9574
|
* @return {void}
|
|
9467
9575
|
*/
|
|
9468
9576
|
onSortEvent(payload) {
|
|
9577
|
+
this.viewChanged = true;
|
|
9469
9578
|
// An order by keys (a column header, a field in the Sort section)
|
|
9470
9579
|
// leaves an endpoint-ranked order.
|
|
9471
9580
|
if (this.sortSource.value) {
|
|
@@ -9669,6 +9778,7 @@ var script = {
|
|
|
9669
9778
|
* @return {void}
|
|
9670
9779
|
*/
|
|
9671
9780
|
onClearFilters() {
|
|
9781
|
+
this.viewChanged = true;
|
|
9672
9782
|
// "Clear all" on the Active line also undoes the quick filters it
|
|
9673
9783
|
// listed (a tab without an `activeLabel` is not a filter there).
|
|
9674
9784
|
for (const chip of this.quickFilterActiveChips) {
|
|
@@ -9777,6 +9887,7 @@ var script = {
|
|
|
9777
9887
|
* @spec openspec/changes/screens-board-reference-columns/specs/board-view/spec.md#requirement-a-board-can-switch-the-field-its-columns-come-from
|
|
9778
9888
|
*/
|
|
9779
9889
|
onBoardColumnFieldChange(field) {
|
|
9890
|
+
this.viewChanged = true;
|
|
9780
9891
|
this.boardColumnFieldChoice = field;
|
|
9781
9892
|
/**
|
|
9782
9893
|
* @event board-column-field-change The board's column switch picked another field. Payload: the field name.
|
|
@@ -9792,6 +9903,7 @@ var script = {
|
|
|
9792
9903
|
* @return {void}
|
|
9793
9904
|
*/
|
|
9794
9905
|
onBoardNarrowChange(value) {
|
|
9906
|
+
this.viewChanged = true;
|
|
9795
9907
|
this.onFilterEvent({ key: this.boardNarrow.field, values: value === '' ? [] : [value] });
|
|
9796
9908
|
},
|
|
9797
9909
|
|
|
@@ -9854,6 +9966,7 @@ var script = {
|
|
|
9854
9966
|
* @return {void}
|
|
9855
9967
|
*/
|
|
9856
9968
|
onFilterEvent(payload) {
|
|
9969
|
+
this.viewChanged = true;
|
|
9857
9970
|
if (this.isSelfFetchMode && typeof this.list.onFilterChange === 'function') {
|
|
9858
9971
|
this.list.onFilterChange(payload.key, payload.values);
|
|
9859
9972
|
this.persistViewStateToRoute(this.currentViewState());
|
|
@@ -9876,6 +9989,7 @@ var script = {
|
|
|
9876
9989
|
* @spec openspec/changes/screens-index-list-parity/specs/index-list-board-look/spec.md#requirement-the-toolbar-sits-on-the-ground-in-two-rows
|
|
9877
9990
|
*/
|
|
9878
9991
|
onRemoveActiveFilter(chip) {
|
|
9992
|
+
this.viewChanged = true;
|
|
9879
9993
|
if (chip && chip.searchTerm === true) {
|
|
9880
9994
|
this.onSearchEvent('');
|
|
9881
9995
|
return
|
|
@@ -10844,6 +10958,7 @@ var script = {
|
|
|
10844
10958
|
* @return {void}
|
|
10845
10959
|
*/
|
|
10846
10960
|
onColumnsEvent(columns) {
|
|
10961
|
+
this.viewChanged = true;
|
|
10847
10962
|
if (this.isSelfFetchMode && this.list.visibleColumns) {
|
|
10848
10963
|
this.list.visibleColumns.value = columns;
|
|
10849
10964
|
}
|
|
@@ -10891,6 +11006,7 @@ var script = {
|
|
|
10891
11006
|
* @return {void}
|
|
10892
11007
|
*/
|
|
10893
11008
|
onColumnsReorder(columns) {
|
|
11009
|
+
this.viewChanged = true;
|
|
10894
11010
|
this.onColumnsEvent(columns);
|
|
10895
11011
|
},
|
|
10896
11012
|
|
|
@@ -10901,6 +11017,7 @@ var script = {
|
|
|
10901
11017
|
* @return {void}
|
|
10902
11018
|
*/
|
|
10903
11019
|
onPinChange(count) {
|
|
11020
|
+
this.viewChanged = true;
|
|
10904
11021
|
if (!this.personalColumns || Array.isArray(this.appliedViewColumns)) {
|
|
10905
11022
|
return
|
|
10906
11023
|
}
|
|
@@ -11795,6 +11912,7 @@ var script = {
|
|
|
11795
11912
|
*/
|
|
11796
11913
|
onApplySavedView(view, { keepSavedViewKey = false } = {}) {
|
|
11797
11914
|
this.appliedSavedViewId = view && (view.id || view.slug) ? String(view.id || view.slug) : '';
|
|
11915
|
+
this.lensChosenByHand = false;
|
|
11798
11916
|
const state = extractViewState(view);
|
|
11799
11917
|
// A view's filters may carry tokens (`@me`, `@myTeam`): resolved here,
|
|
11800
11918
|
// and an optional one that answers nothing (no team) is dropped. A
|
|
@@ -11803,6 +11921,10 @@ var script = {
|
|
|
11803
11921
|
loadMyTeam().then(() => this.onApplySavedView(view, { keepSavedViewKey }));
|
|
11804
11922
|
return
|
|
11805
11923
|
}
|
|
11924
|
+
// An opened view is unchanged until the reader changes it.
|
|
11925
|
+
this.$nextTick(() => {
|
|
11926
|
+
this.viewChanged = false;
|
|
11927
|
+
});
|
|
11806
11928
|
const ctx = typeof this.selfFetchTokenCtx === 'function' ? this.selfFetchTokenCtx() : {};
|
|
11807
11929
|
state.filters = dropOptionalUnresolved(resolveFilterTokens(state.filters, ctx));
|
|
11808
11930
|
this.appliedViewFiltersKey = this.viewFiltersKey(state.filters);
|
|
@@ -11928,6 +12050,7 @@ var script = {
|
|
|
11928
12050
|
}
|
|
11929
12051
|
this.savedViews = [...this.savedViews, view];
|
|
11930
12052
|
this.showSaveViewDialog = false;
|
|
12053
|
+
this.viewChanged = false;
|
|
11931
12054
|
this.sidebarActiveTab = 'filters-tab';
|
|
11932
12055
|
this.sidebarOpen = true;
|
|
11933
12056
|
this.toastSavedView('success', translate('nextcloud-vue', 'View "{name}" saved', { name }));
|