@conduction/nextcloud-vue 2.121.0 → 2.123.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 +1 -0
- 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/CnAttentionFlagWidget/CnAttentionFlagWidget.vue.js +1 -1
- package/dist/esm/components/CnAttentionFlagWidget/CnAttentionFlagWidget.vue2.js +18 -4
- package/dist/esm/components/CnAttentionFlagWidget/CnAttentionFlagWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnAttentionFlagWidget/CnAttentionFlagWidget.vue3.js +63 -32
- package/dist/esm/components/CnAttentionFlagWidget/CnAttentionFlagWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnChartWidget/CnChartWidget.vue.js +1 -1
- package/dist/esm/components/CnChartWidget/CnChartWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnChartWidget/CnChartWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js +35 -0
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js.map +1 -1
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js +11 -5
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js.map +1 -1
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue.js +1 -1
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue2.js +13 -0
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue2.js.map +1 -1
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue3.js +37 -5
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue3.js.map +1 -1
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue.js +1 -1
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js +40 -0
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js.map +1 -1
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js +71 -65
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js.map +1 -1
- package/dist/esm/components/CnFlowDetail/CnFlowDetail.vue.js +1 -1
- package/dist/esm/components/CnFlowDetail/CnFlowDetail.vue2.js +20 -0
- package/dist/esm/components/CnFlowDetail/CnFlowDetail.vue2.js.map +1 -1
- package/dist/esm/components/CnFlowDetail/CnFlowDetail.vue3.js +2 -1
- package/dist/esm/components/CnFlowDetail/CnFlowDetail.vue3.js.map +1 -1
- package/dist/esm/components/CnFlowsPage/CnFlowBoard.vue.js +1 -1
- package/dist/esm/components/CnFlowsPage/CnFlowBoard.vue2.js +2 -0
- package/dist/esm/components/CnFlowsPage/CnFlowBoard.vue2.js.map +1 -1
- package/dist/esm/components/CnFlowsPage/CnFlowBoard.vue3.js +49 -44
- package/dist/esm/components/CnFlowsPage/CnFlowBoard.vue3.js.map +1 -1
- package/dist/esm/components/CnFlowsPage/CnFlowEditorPage.vue2.js +10 -0
- package/dist/esm/components/CnFlowsPage/CnFlowEditorPage.vue2.js.map +1 -1
- package/dist/esm/components/CnFlowsPage/CnFlowEditorPage.vue3.js +2 -1
- package/dist/esm/components/CnFlowsPage/CnFlowEditorPage.vue3.js.map +1 -1
- package/dist/esm/components/CnGraphCanvas/CnGraphCanvas.vue2.js +31 -0
- package/dist/esm/components/CnGraphCanvas/CnGraphCanvas.vue2.js.map +1 -1
- package/dist/esm/components/CnGraphCanvas/CnGraphCanvas.vue3.js +4 -3
- package/dist/esm/components/CnGraphCanvas/CnGraphCanvas.vue3.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +34 -2
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
- package/dist/esm/components/CnIndexSidebar/CnIndexSidebar.vue2.js.map +1 -1
- package/dist/esm/components/CnIndexSidebar/CnIndexSidebar.vue3.js +1 -0
- package/dist/esm/components/CnIndexSidebar/CnIndexSidebar.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue.js +1 -1
- package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue2.js +2 -0
- package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue3.js +2 -1
- package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue3.js.map +1 -1
- package/dist/esm/components/CnSectionsWidget/CnSectionsWidget.vue.js +1 -1
- package/dist/esm/components/CnSectionsWidget/CnSectionsWidget.vue2.js +31 -1
- package/dist/esm/components/CnSectionsWidget/CnSectionsWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnSectionsWidget/CnSectionsWidget.vue3.js +14 -4
- package/dist/esm/components/CnSectionsWidget/CnSectionsWidget.vue3.js.map +1 -1
- package/dist/esm/composables/flowGraphLayout.js +36 -7
- package/dist/esm/composables/flowGraphLayout.js.map +1 -1
- package/dist/esm/composables/useFlowStore.js +7 -3
- package/dist/esm/composables/useFlowStore.js.map +1 -1
- package/dist/esm/l10n/en.json.js +3 -1
- package/dist/esm/l10n/en.json.js.map +1 -1
- package/dist/esm/l10n/nl.json.js +3 -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 +670 -316
- package/dist/esm/utils/manifestTranslate.js +12 -3
- package/dist/esm/utils/manifestTranslate.js.map +1 -1
- package/dist/esm/utils/routeFilters.js +3 -3
- package/dist/esm/utils/routeFilters.js.map +1 -1
- package/dist/nextcloud-vue.cjs.js +1218 -847
- package/dist/nextcloud-vue.cjs.js.map +2 -2
- package/dist/nextcloud-vue.css +670 -316
- package/l10n/en.json +3 -1
- package/l10n/nl.json +3 -1
- package/package.json +1 -1
- package/src/components/CnAppRoot/CnAppRoot.vue +1 -0
- package/src/components/CnAttentionFlagWidget/CnAttentionFlagWidget.vue +50 -5
- package/src/components/CnChartWidget/CnChartWidget.vue +10 -8
- package/src/components/CnDetailPage/CnDetailPage.md +10 -0
- package/src/components/CnDetailPage/CnDetailPage.vue +42 -1
- package/src/components/CnDetailWidgetHost/CnDetailWidgetHost.vue +39 -0
- package/src/components/CnFilesBrowser/CnFilesBrowser.vue +95 -37
- package/src/components/CnFlowDetail/CnFlowDetail.vue +21 -0
- package/src/components/CnFlowsPage/CnFlowBoard.vue +35 -18
- package/src/components/CnFlowsPage/CnFlowEditorPage.vue +11 -0
- package/src/components/CnGraphCanvas/CnGraphCanvas.vue +34 -2
- package/src/components/CnIndexPage/CnIndexPage.vue +34 -2
- package/src/components/CnIndexSidebar/CnIndexSidebar.vue +1 -0
- package/src/components/CnObjectSidebar/CnFilesTab.vue +3 -0
- package/src/components/CnSectionsWidget/CnSectionsWidget.vue +53 -2
- package/src/composables/flowGraphLayout.js +35 -6
- package/src/composables/useFlowStore.js +7 -3
- package/src/css/detail-page.css +6 -0
- package/src/css/look-board-detail.css +53 -6
- package/src/css/look-board-index.css +151 -12
- package/src/css/look-board.css +116 -4
- package/src/utils/manifestTranslate.js +12 -3
- package/src/utils/routeFilters.js +3 -3
|
@@ -12,7 +12,9 @@
|
|
|
12
12
|
* for the language, then for its base (`en_GB` falls back to `en`);
|
|
13
13
|
* 2. otherwise the host's `translate(text, vars)`, whose answer is the text
|
|
14
14
|
* itself when it has no translation;
|
|
15
|
-
* 3. the
|
|
15
|
+
* 3. the library's own catalog (`library`), for the strings a library
|
|
16
|
+
* component asks through `cnTranslate` and the app never translates;
|
|
17
|
+
* 4. the text as written.
|
|
16
18
|
*
|
|
17
19
|
* The fallback is per label, never per page. The manifest is read through a
|
|
18
20
|
* getter on every call, so an edit to the working copy shows at once.
|
|
@@ -52,9 +54,10 @@ function fill(text, vars) {
|
|
|
52
54
|
* @param {() => (object|null|undefined)} options.getManifest The live manifest (the editor's working copy while editing).
|
|
53
55
|
* @param {() => string} options.getLanguage The language to show.
|
|
54
56
|
* @param {(text: string, vars?: object) => string} [options.translate] The host's translate.
|
|
57
|
+
* @param {(text: string, vars?: object) => string} [options.library] The library's translate, asked when the host has no translation.
|
|
55
58
|
* @return {Function} `(text, vars) => string`, with `lookup`, `fellBack` and `sourceLanguage` attached.
|
|
56
59
|
*/
|
|
57
|
-
function createManifestTranslate({ getManifest, getLanguage, translate }) {
|
|
60
|
+
function createManifestTranslate({ getManifest, getLanguage, translate, library }) {
|
|
58
61
|
const host = typeof translate === 'function' ? translate : (text) => text;
|
|
59
62
|
|
|
60
63
|
const i18n = () => {
|
|
@@ -79,7 +82,13 @@ function createManifestTranslate({ getManifest, getLanguage, translate }) {
|
|
|
79
82
|
}
|
|
80
83
|
}
|
|
81
84
|
const answer = host(text, vars);
|
|
82
|
-
|
|
85
|
+
let shown = typeof answer === 'string' && answer !== '' ? answer : fill(text, vars);
|
|
86
|
+
if (shown === fill(text, vars) && typeof library === 'function') {
|
|
87
|
+
const own = library(text, vars);
|
|
88
|
+
if (typeof own === 'string' && own !== '') {
|
|
89
|
+
shown = own;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
83
92
|
return { text: shown, fellBack: !!block && !inSource && shown === fill(text, vars) }
|
|
84
93
|
};
|
|
85
94
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manifestTranslate.js","sources":["../../../src/utils/manifestTranslate.js"],"sourcesContent":["/**\n * SPDX-FileCopyrightText: 2026 Conduction B.V.\n * SPDX-License-Identifier: EUPL-1.2\n *\n * The label lookup of an app whose manifest carries translations.\n *\n * Labels are written once, in the manifest's `i18n.sourceLanguage`, and\n * `i18n.labels[<language>]` maps the text as written to its translation. The\n * lookup, per label:\n *\n * 1. when the language is not the source language: the manifest's translation\n * for the language, then for its base (`en_GB` falls back to `en`);\n * 2. otherwise the host's `translate(text, vars)`, whose answer is the text\n * itself when it has no translation;\n * 3. the text as written.\n *\n * The fallback is per label, never per page. The manifest is read through a\n * getter on every call, so an edit to the working copy shows at once.\n *\n * @module utils/manifestTranslate\n * @spec openspec/changes/manifest-i18n-labels/tasks.md#task-2\n */\n\n/**\n * The base of a language code: `en_GB` and `en-GB` give `en`.\n *\n * @param {string} language A Nextcloud language code.\n * @return {string} The part before the region.\n */\nexport function baseLanguage(language) {\n\treturn String(language || '').split(/[-_]/)[0]\n}\n\n/**\n * Fill `{name}` placeholders from `vars`, as Nextcloud's `t()` does.\n *\n * @param {string} text The text.\n * @param {object} [vars] Values by placeholder name.\n * @return {string} The text with the placeholders filled.\n */\nfunction fill(text, vars) {\n\tif (!vars || typeof vars !== 'object') {\n\t\treturn text\n\t}\n\treturn text.replace(/\\{(\\w+)\\}/g, (match, name) => (Object.hasOwn(vars, name) ? String(vars[name]) : match))\n}\n\n/**\n * Build the lookup the root provides as `cnTranslate`.\n *\n * @param {object} options Options.\n * @param {() => (object|null|undefined)} options.getManifest The live manifest (the editor's working copy while editing).\n * @param {() => string} options.getLanguage The language to show.\n * @param {(text: string, vars?: object) => string} [options.translate] The host's translate.\n * @return {Function} `(text, vars) => string`, with `lookup`, `fellBack` and `sourceLanguage` attached.\n */\nexport function createManifestTranslate({ getManifest, getLanguage, translate }) {\n\tconst host = typeof translate === 'function' ? translate : (text) => text\n\n\tconst i18n = () => {\n\t\tconst block = getManifest() && getManifest().i18n\n\t\treturn block && typeof block === 'object' ? block : null\n\t}\n\n\tconst lookup = (text, vars) => {\n\t\tif (typeof text !== 'string' || text === '') {\n\t\t\treturn { text, fellBack: false }\n\t\t}\n\t\tconst block = i18n()\n\t\tconst language = String(getLanguage() || '')\n\t\tconst source = block ? block.sourceLanguage : null\n\t\tconst inSource = !block || language === source || baseLanguage(language) === baseLanguage(source)\n\t\tif (block && !inSource && block.labels) {\n\t\t\tfor (const candidate of [language, baseLanguage(language)]) {\n\t\t\t\tconst table = block.labels[candidate]\n\t\t\t\tif (table && typeof table[text] === 'string' && table[text] !== '') {\n\t\t\t\t\treturn { text: fill(table[text], vars), fellBack: false }\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tconst answer = host(text, vars)\n\t\
|
|
1
|
+
{"version":3,"file":"manifestTranslate.js","sources":["../../../src/utils/manifestTranslate.js"],"sourcesContent":["/**\n * SPDX-FileCopyrightText: 2026 Conduction B.V.\n * SPDX-License-Identifier: EUPL-1.2\n *\n * The label lookup of an app whose manifest carries translations.\n *\n * Labels are written once, in the manifest's `i18n.sourceLanguage`, and\n * `i18n.labels[<language>]` maps the text as written to its translation. The\n * lookup, per label:\n *\n * 1. when the language is not the source language: the manifest's translation\n * for the language, then for its base (`en_GB` falls back to `en`);\n * 2. otherwise the host's `translate(text, vars)`, whose answer is the text\n * itself when it has no translation;\n * 3. the library's own catalog (`library`), for the strings a library\n * component asks through `cnTranslate` and the app never translates;\n * 4. the text as written.\n *\n * The fallback is per label, never per page. The manifest is read through a\n * getter on every call, so an edit to the working copy shows at once.\n *\n * @module utils/manifestTranslate\n * @spec openspec/changes/manifest-i18n-labels/tasks.md#task-2\n */\n\n/**\n * The base of a language code: `en_GB` and `en-GB` give `en`.\n *\n * @param {string} language A Nextcloud language code.\n * @return {string} The part before the region.\n */\nexport function baseLanguage(language) {\n\treturn String(language || '').split(/[-_]/)[0]\n}\n\n/**\n * Fill `{name}` placeholders from `vars`, as Nextcloud's `t()` does.\n *\n * @param {string} text The text.\n * @param {object} [vars] Values by placeholder name.\n * @return {string} The text with the placeholders filled.\n */\nfunction fill(text, vars) {\n\tif (!vars || typeof vars !== 'object') {\n\t\treturn text\n\t}\n\treturn text.replace(/\\{(\\w+)\\}/g, (match, name) => (Object.hasOwn(vars, name) ? String(vars[name]) : match))\n}\n\n/**\n * Build the lookup the root provides as `cnTranslate`.\n *\n * @param {object} options Options.\n * @param {() => (object|null|undefined)} options.getManifest The live manifest (the editor's working copy while editing).\n * @param {() => string} options.getLanguage The language to show.\n * @param {(text: string, vars?: object) => string} [options.translate] The host's translate.\n * @param {(text: string, vars?: object) => string} [options.library] The library's translate, asked when the host has no translation.\n * @return {Function} `(text, vars) => string`, with `lookup`, `fellBack` and `sourceLanguage` attached.\n */\nexport function createManifestTranslate({ getManifest, getLanguage, translate, library }) {\n\tconst host = typeof translate === 'function' ? translate : (text) => text\n\n\tconst i18n = () => {\n\t\tconst block = getManifest() && getManifest().i18n\n\t\treturn block && typeof block === 'object' ? block : null\n\t}\n\n\tconst lookup = (text, vars) => {\n\t\tif (typeof text !== 'string' || text === '') {\n\t\t\treturn { text, fellBack: false }\n\t\t}\n\t\tconst block = i18n()\n\t\tconst language = String(getLanguage() || '')\n\t\tconst source = block ? block.sourceLanguage : null\n\t\tconst inSource = !block || language === source || baseLanguage(language) === baseLanguage(source)\n\t\tif (block && !inSource && block.labels) {\n\t\t\tfor (const candidate of [language, baseLanguage(language)]) {\n\t\t\t\tconst table = block.labels[candidate]\n\t\t\t\tif (table && typeof table[text] === 'string' && table[text] !== '') {\n\t\t\t\t\treturn { text: fill(table[text], vars), fellBack: false }\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tconst answer = host(text, vars)\n\t\tlet shown = typeof answer === 'string' && answer !== '' ? answer : fill(text, vars)\n\t\tif (shown === fill(text, vars) && typeof library === 'function') {\n\t\t\tconst own = library(text, vars)\n\t\t\tif (typeof own === 'string' && own !== '') {\n\t\t\t\tshown = own\n\t\t\t}\n\t\t}\n\t\treturn { text: shown, fellBack: !!block && !inSource && shown === fill(text, vars) }\n\t}\n\n\tconst translateLabel = (text, vars) => lookup(text, vars).text\n\ttranslateLabel.lookup = lookup\n\ttranslateLabel.fellBack = (text, vars) => lookup(text, vars).fellBack\n\tObject.defineProperty(translateLabel, 'sourceLanguage', { get: () => (i18n() ? i18n().sourceLanguage : '') })\n\treturn translateLabel\n}\n\n/**\n * The `lang` attribute for a label: the manifest's source language when the\n * label fell back to its written text in another language, else null.\n *\n * @param {Function|null} translate The injected `cnTranslate`.\n * @param {string} text The label as written.\n * @return {string|null} The language code, or null.\n */\nexport function labelLang(translate, text) {\n\tif (translate && typeof translate.fellBack === 'function' && translate.fellBack(text)) {\n\t\treturn translate.sourceLanguage || null\n\t}\n\treturn null\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -123,9 +123,9 @@ function resolveQueryFilters(query, ctx) {
|
|
|
123
123
|
}
|
|
124
124
|
const out = {};
|
|
125
125
|
for (const [k, v] of Object.entries(query)) {
|
|
126
|
-
// `contentSearch` is the index page's own "search inside files" switch
|
|
127
|
-
//
|
|
128
|
-
if (k.startsWith('_') || k === 'contentSearch') {
|
|
126
|
+
// `contentSearch` is the index page's own "search inside files" switch
|
|
127
|
+
// and `savedView` names the applied saved view: neither filters the records.
|
|
128
|
+
if (k.startsWith('_') || k === 'contentSearch' || k === 'savedView') {
|
|
129
129
|
continue
|
|
130
130
|
}
|
|
131
131
|
if (v === undefined || v === null || v === '') {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routeFilters.js","sources":["../../../src/utils/routeFilters.js"],"sourcesContent":["import { dropOptionalUnresolved, resolveFilterTokens } from './resolveFilterTokens.js'\n\n/**\n * Resolve a page base/quick filter map at fetch time.\n *\n * Two grammars are applied, in order:\n * 1. Route-param interpolation — `@route.<name>` / `:<name>` string values are\n * replaced with the matching `$route.params` entry.\n * 2. The shared fetch-time `@`-token grammar (via `resolveFilterTokens`):\n * `@me` (current user), `@today`/`@today±Nd`, `@monthStart`/`@quarterStart`/\n * `@yearStart`, etc. — the same tokens widget/KPI filters use — so a page\n * base filter can scope to the signed-in user (e.g. `{ assignee: '@me' }`)\n * or a relative date window without a bespoke wrapper. `@workspace.<key>` /\n * `@config.<key>` tokens resolve too, against the `ctx` the caller supplies\n * (the page-level `cnWorkspaceContext`/`cnAppConfig` bags — see\n * `useSelfFetchList`) — the same grammar `CnObjectListWidget` uses. An\n * UNRESOLVED OPTIONAL token (`@workspace.<key>?`) is dropped from the\n * result (see `dropOptionalUnresolved`) so an unset selection shows all\n * rows instead of sending the literal token string to the API. Literals\n * and unknown strings pass through unchanged.\n *\n * @param {object} filterMap The configured filter map.\n * @param {object} params The current `$route.params`.\n * @param {{objectId?: (string|number), object?: object, workspace?: object, config?: object}} [ctx] Token-resolution\n * context for `@workspace.<key>` / `@config.<key>` / `@objectId` / `@object.<field>` tokens.\n * @return {object} The resolved filter map.\n */\nexport function resolveFilterMap(filterMap, params, ctx) {\n\tif (!filterMap || typeof filterMap !== 'object') {\n\t\treturn {}\n\t}\n\tconst out = {}\n\tfor (const [k, v] of Object.entries(filterMap)) {\n\t\tif (typeof v === 'string' && v.startsWith('@route.')) {\n\t\t\tout[k] = params[v.slice('@route.'.length)]\n\t\t} else if (typeof v === 'string' && v.startsWith(':')) {\n\t\t\tout[k] = params[v.slice(1)]\n\t\t} else {\n\t\t\tout[k] = v\n\t\t}\n\t}\n\treturn dropOptionalUnresolved(resolveFilterTokens(out, ctx))\n}\n\n/**\n * Parse the `_order` query value — the JSON-encoded ordered array that carries\n * a list's sort through the address, `[{ key, order }, …]`.\n *\n * This is the ONE parser for that value. It used to be three near-copies (here,\n * in `listNavigation`, and privately in `CnPageRenderer`), and a fourth\n * component wrote a different spelling entirely; that drift is what let a saved\n * view's sort be written in a format nothing read.\n *\n * Defensive by design — a hand-edited or truncated param must not break the\n * page, so anything that is not an array of `{ key }` entries yields an empty\n * list. Deliberately uncapped: CnDataTable caps shift+click at three keys as an\n * affordance, but a capped parser would silently drop the third key of a link\n * somebody sent.\n *\n * @param {unknown} raw The raw `_order` query value.\n * @return {Array<{key: string, order: 'asc'|'desc'}>} The sort, or an empty list.\n */\nexport function parseSortKeys(raw) {\n\tif (typeof raw !== 'string' || raw === '') {\n\t\treturn []\n\t}\n\tlet parsed\n\ttry {\n\t\tparsed = JSON.parse(raw)\n\t} catch {\n\t\treturn []\n\t}\n\tif (!Array.isArray(parsed)) {\n\t\treturn []\n\t}\n\treturn parsed\n\t\t.filter((k) => k && typeof k.key === 'string' && k.key !== '')\n\t\t.map((k) => ({ key: k.key, order: k.order === 'desc' ? 'desc' : 'asc' }))\n}\n\n/**\n * Read a persisted multi-column sort back out of `$route.query._order`, so a\n * reload or a shared link reproduces the sort it carried.\n *\n * Shared by CnIndexPage's `useSelfFetchList` and CnLogsPage: both feed the\n * result to `useListView`'s `defaultSortKeys`, and while this lived privately in\n * the former, a `?_order=` link was silently ignored on a logs page.\n *\n * Returns `null` rather than `[]` for nothing, because both callers fall through\n * to a configured default with `||` and an empty array would satisfy it.\n *\n * @param {object|null} route The current `$route` (or null when there is no router).\n * @return {Array<{key: string, order: 'asc'|'desc'}>|null} The restored sort, or null.\n */\nexport function parseSortKeysFromQuery(route) {\n\tconst keys = parseSortKeys(route && route.query && route.query._order)\n\treturn keys.length > 0 ? keys : null\n}\n\n/**\n * Extract deep-link filters from `$route.query`. Lets a widget/link navigate to\n * `/cases?caseType=X&status=Y` and land the list pre-filtered. Reserved\n * underscore-prefixed list params (`_search`, `_page`, `_limit`, `_order`) are\n * skipped; everything else is passed through to the fetch (scalars + arrays, so\n * `?status[]=a&status[]=b` becomes an IN match). Merged BELOW the page's\n * `config.filter` so a page's own scoping still wins on a key collision.\n *\n * The values go through the SAME `@`-token grammar a page's `config.filter`\n * gets (see `resolveFilterMap`), so `?assignee=@me` scopes to the signed-in\n * user and `?due=@today` to today. Without that, a `menu[].query` preset\n * carrying a token sent the LITERAL string `@me` to the API and the entry\n * silently listed nothing — which is exactly the shape ADR-097 Decision 5\n * asks apps to replace a duplicate index page with.\n *\n * @param {object} query The `$route.query` object.\n * @param {{objectId?: (string|number), object?: object, workspace?: object, config?: object}} [ctx] Token-resolution\n * context, the same bag `resolveFilterMap` takes.\n * @return {object} The query-derived filter map.\n */\nexport function resolveQueryFilters(query, ctx) {\n\tif (!query || typeof query !== 'object') {\n\t\treturn {}\n\t}\n\tconst out = {}\n\tfor (const [k, v] of Object.entries(query)) {\n\t\t// `contentSearch` is the index page's own \"search inside files\" switch
|
|
1
|
+
{"version":3,"file":"routeFilters.js","sources":["../../../src/utils/routeFilters.js"],"sourcesContent":["import { dropOptionalUnresolved, resolveFilterTokens } from './resolveFilterTokens.js'\n\n/**\n * Resolve a page base/quick filter map at fetch time.\n *\n * Two grammars are applied, in order:\n * 1. Route-param interpolation — `@route.<name>` / `:<name>` string values are\n * replaced with the matching `$route.params` entry.\n * 2. The shared fetch-time `@`-token grammar (via `resolveFilterTokens`):\n * `@me` (current user), `@today`/`@today±Nd`, `@monthStart`/`@quarterStart`/\n * `@yearStart`, etc. — the same tokens widget/KPI filters use — so a page\n * base filter can scope to the signed-in user (e.g. `{ assignee: '@me' }`)\n * or a relative date window without a bespoke wrapper. `@workspace.<key>` /\n * `@config.<key>` tokens resolve too, against the `ctx` the caller supplies\n * (the page-level `cnWorkspaceContext`/`cnAppConfig` bags — see\n * `useSelfFetchList`) — the same grammar `CnObjectListWidget` uses. An\n * UNRESOLVED OPTIONAL token (`@workspace.<key>?`) is dropped from the\n * result (see `dropOptionalUnresolved`) so an unset selection shows all\n * rows instead of sending the literal token string to the API. Literals\n * and unknown strings pass through unchanged.\n *\n * @param {object} filterMap The configured filter map.\n * @param {object} params The current `$route.params`.\n * @param {{objectId?: (string|number), object?: object, workspace?: object, config?: object}} [ctx] Token-resolution\n * context for `@workspace.<key>` / `@config.<key>` / `@objectId` / `@object.<field>` tokens.\n * @return {object} The resolved filter map.\n */\nexport function resolveFilterMap(filterMap, params, ctx) {\n\tif (!filterMap || typeof filterMap !== 'object') {\n\t\treturn {}\n\t}\n\tconst out = {}\n\tfor (const [k, v] of Object.entries(filterMap)) {\n\t\tif (typeof v === 'string' && v.startsWith('@route.')) {\n\t\t\tout[k] = params[v.slice('@route.'.length)]\n\t\t} else if (typeof v === 'string' && v.startsWith(':')) {\n\t\t\tout[k] = params[v.slice(1)]\n\t\t} else {\n\t\t\tout[k] = v\n\t\t}\n\t}\n\treturn dropOptionalUnresolved(resolveFilterTokens(out, ctx))\n}\n\n/**\n * Parse the `_order` query value — the JSON-encoded ordered array that carries\n * a list's sort through the address, `[{ key, order }, …]`.\n *\n * This is the ONE parser for that value. It used to be three near-copies (here,\n * in `listNavigation`, and privately in `CnPageRenderer`), and a fourth\n * component wrote a different spelling entirely; that drift is what let a saved\n * view's sort be written in a format nothing read.\n *\n * Defensive by design — a hand-edited or truncated param must not break the\n * page, so anything that is not an array of `{ key }` entries yields an empty\n * list. Deliberately uncapped: CnDataTable caps shift+click at three keys as an\n * affordance, but a capped parser would silently drop the third key of a link\n * somebody sent.\n *\n * @param {unknown} raw The raw `_order` query value.\n * @return {Array<{key: string, order: 'asc'|'desc'}>} The sort, or an empty list.\n */\nexport function parseSortKeys(raw) {\n\tif (typeof raw !== 'string' || raw === '') {\n\t\treturn []\n\t}\n\tlet parsed\n\ttry {\n\t\tparsed = JSON.parse(raw)\n\t} catch {\n\t\treturn []\n\t}\n\tif (!Array.isArray(parsed)) {\n\t\treturn []\n\t}\n\treturn parsed\n\t\t.filter((k) => k && typeof k.key === 'string' && k.key !== '')\n\t\t.map((k) => ({ key: k.key, order: k.order === 'desc' ? 'desc' : 'asc' }))\n}\n\n/**\n * Read a persisted multi-column sort back out of `$route.query._order`, so a\n * reload or a shared link reproduces the sort it carried.\n *\n * Shared by CnIndexPage's `useSelfFetchList` and CnLogsPage: both feed the\n * result to `useListView`'s `defaultSortKeys`, and while this lived privately in\n * the former, a `?_order=` link was silently ignored on a logs page.\n *\n * Returns `null` rather than `[]` for nothing, because both callers fall through\n * to a configured default with `||` and an empty array would satisfy it.\n *\n * @param {object|null} route The current `$route` (or null when there is no router).\n * @return {Array<{key: string, order: 'asc'|'desc'}>|null} The restored sort, or null.\n */\nexport function parseSortKeysFromQuery(route) {\n\tconst keys = parseSortKeys(route && route.query && route.query._order)\n\treturn keys.length > 0 ? keys : null\n}\n\n/**\n * Extract deep-link filters from `$route.query`. Lets a widget/link navigate to\n * `/cases?caseType=X&status=Y` and land the list pre-filtered. Reserved\n * underscore-prefixed list params (`_search`, `_page`, `_limit`, `_order`) are\n * skipped; everything else is passed through to the fetch (scalars + arrays, so\n * `?status[]=a&status[]=b` becomes an IN match). Merged BELOW the page's\n * `config.filter` so a page's own scoping still wins on a key collision.\n *\n * The values go through the SAME `@`-token grammar a page's `config.filter`\n * gets (see `resolveFilterMap`), so `?assignee=@me` scopes to the signed-in\n * user and `?due=@today` to today. Without that, a `menu[].query` preset\n * carrying a token sent the LITERAL string `@me` to the API and the entry\n * silently listed nothing — which is exactly the shape ADR-097 Decision 5\n * asks apps to replace a duplicate index page with.\n *\n * @param {object} query The `$route.query` object.\n * @param {{objectId?: (string|number), object?: object, workspace?: object, config?: object}} [ctx] Token-resolution\n * context, the same bag `resolveFilterMap` takes.\n * @return {object} The query-derived filter map.\n */\nexport function resolveQueryFilters(query, ctx) {\n\tif (!query || typeof query !== 'object') {\n\t\treturn {}\n\t}\n\tconst out = {}\n\tfor (const [k, v] of Object.entries(query)) {\n\t\t// `contentSearch` is the index page's own \"search inside files\" switch\n\t\t// and `savedView` names the applied saved view: neither filters the records.\n\t\tif (k.startsWith('_') || k === 'contentSearch' || k === 'savedView') {\n\t\t\tcontinue\n\t\t}\n\t\tif (v === undefined || v === null || v === '') {\n\t\t\tcontinue\n\t\t}\n\t\tout[k] = v\n\t}\n\treturn dropOptionalUnresolved(resolveFilterTokens(out, ctx))\n}\n"],"names":[],"mappings":"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"}
|