@conduction/nextcloud-vue 2.109.0 → 2.111.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/dist/esm/components/CnActionDialog/CnActionDialog.vue.js +1 -1
  2. package/dist/esm/components/CnActionDialog/CnActionDialog.vue2.js +115 -12
  3. package/dist/esm/components/CnActionDialog/CnActionDialog.vue2.js.map +1 -1
  4. package/dist/esm/components/CnActionDialog/CnActionDialog.vue3.js +36 -9
  5. package/dist/esm/components/CnActionDialog/CnActionDialog.vue3.js.map +1 -1
  6. package/dist/esm/components/CnAppRoot/CnAppRoot.vue2.js +2 -1
  7. package/dist/esm/components/CnAppRoot/CnAppRoot.vue2.js.map +1 -1
  8. package/dist/esm/components/CnAppRoot/CnAppRoot.vue3.js.map +1 -1
  9. package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js +20 -0
  10. package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js.map +1 -1
  11. package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js +68 -61
  12. package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js.map +1 -1
  13. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +37 -12
  14. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
  15. package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
  16. package/dist/esm/components/CnIndexSidebar/CnIndexSidebar.vue2.js.map +1 -1
  17. package/dist/esm/components/CnIndexSidebar/CnIndexSidebar.vue3.js +1 -1
  18. package/dist/esm/components/CnIndexSidebar/CnIndexSidebar.vue3.js.map +1 -1
  19. package/dist/esm/components/CnWorkQueue/CnWorkQueue.vue.js +1 -1
  20. package/dist/esm/components/CnWorkQueue/CnWorkQueue.vue2.js +8 -1
  21. package/dist/esm/components/CnWorkQueue/CnWorkQueue.vue2.js.map +1 -1
  22. package/dist/esm/components/CnWorkQueue/CnWorkQueue.vue3.js.map +1 -1
  23. package/dist/esm/library-style.js +1 -1
  24. package/dist/esm/nextcloud-vue.css +131 -64
  25. package/dist/esm/utils/actionsDispatcher.js +5 -2
  26. package/dist/esm/utils/actionsDispatcher.js.map +1 -1
  27. package/dist/esm/utils/savedViewHelpers.js +40 -3
  28. package/dist/esm/utils/savedViewHelpers.js.map +1 -1
  29. package/dist/nextcloud-vue.cjs.js +479 -251
  30. package/dist/nextcloud-vue.cjs.js.map +2 -2
  31. package/dist/nextcloud-vue.css +131 -64
  32. package/package.json +1 -1
  33. package/src/components/CnActionDialog/CnActionDialog.vue +134 -13
  34. package/src/components/CnAppRoot/CnAppRoot.vue +2 -1
  35. package/src/components/CnDetailPage/CnDetailPage.vue +35 -11
  36. package/src/components/CnIndexPage/CnIndexPage.md +1 -1
  37. package/src/components/CnIndexPage/CnIndexPage.vue +37 -12
  38. package/src/components/CnIndexSidebar/CnIndexSidebar.md +1 -1
  39. package/src/components/CnIndexSidebar/CnIndexSidebar.vue +2 -2
  40. package/src/components/CnWorkQueue/CnWorkQueue.vue +8 -1
  41. package/src/css/board.css +5 -2
  42. package/src/css/look-board-detail.css +19 -7
  43. package/src/css/look-board-index.css +14 -10
  44. package/src/css/look-board-reports.css +1 -1
  45. package/src/css/look-board.css +54 -9
  46. package/src/utils/actionsDispatcher.js +4 -1
  47. package/src/utils/savedViewHelpers.js +39 -2
@@ -1 +1 @@
1
- {"version":3,"file":"actionsDispatcher.js","sources":["../../../src/utils/actionsDispatcher.js"],"sourcesContent":["/**\n * SPDX-FileCopyrightText: 2024 Conduction B.V.\n * SPDX-License-Identifier: EUPL-1.2\n *\n * actionsDispatcher — unified action dispatcher for v2 manifest actions.\n *\n * Dispatches an action object against a context. All dispatch types are\n * handled without throwing — errors surface as console.warn calls.\n * Types: handler | open-modal | open-page | navigate | object-op (the\n * declarative OpenRegister mutation verb added by ADR-049 — dispatched\n * via the shared object store, intent-only, RBAC stays server-side) |\n * export (opens the shared CnMassExportDialog export launcher configured\n * via the action's `entities[]` / `formats[]` — Wave 1 of\n * nextcloud-vue#91; the host page provides `context.openExport`) |\n * open-form (Wave 3 — schema-driven create dialog; the rendering host\n * provides `context.openForm`) | refresh (Wave 3 — bumps the page-level\n * refresh signal on the `cn:page:refresh` event-bus channel) | api-call\n * (Wave 3 — POST/PUT a configured app endpoint with success/error toasts\n * and an automatic page refresh; any `confirm` on the action is INTENT\n * consumed by the rendering surface BEFORE dispatch, like object-op) |\n * agent (run a governed hermiq agent against the page object via\n * POST /apps/hermiq/api/agents/{agent}/run-on-object — hermiq#41; a\n * first-class companion to api-call that resolves the register/schema/\n * objectId context for the author and fail-closes when hermiq is absent) |\n * run-node (manifest-run-node-action — invoke ONE OpenRegister flow node\n * directly against a subject object via\n * POST /api/flows/{flowId}/nodes/{nodeId}/run; the rendering surface\n * provides context.openRunNode, mirroring open-form, and resolves the\n * node's own declared config form before opening a dialog — see or-flow-run-node).\n *\n * `api-call`'s request body prefers `payload` (DEEP @-token resolution at\n * any nesting depth — object/array, e.g. a Filinq-style\n * `{ dataRefs: [{ id: '@objectId' }] }` body) over the legacy `params`\n * (shallow, one-level filter-map resolution, kept for back-compat). Set\n * `download: true` to request a binary blob response and trigger a\n * browser file download instead of a JSON toast+refresh cycle (filename:\n * `Content-Disposition` header, else the token-resolved `filename`, else\n * `'download.pdf'`; no auto-refresh unless `refresh: true` is explicit).\n *\n * `toggle` (Wave 3) is deliberately NOT dispatchable: a toggle is a\n * stateful two-way control (GET state on mount, write on click) rendered\n * by the header-actions surface (CnActionButtons); dispatching it here\n * warns and no-ops.\n *\n * Spec: REQ-MVR-011 (manifest-v2-renderer) — unified actions dispatcher\n * / ADR-036 Decision 7 / ADR-049 Decision 2 / #91 Wave 3\n */\n\nimport { emit } from '@nextcloud/event-bus'\nimport { translate as t } from '@nextcloud/l10n'\nimport { parseDispositionFilename, triggerBlobDownload } from '../components/CnIndexPage/selfModeIO.js'\nimport { interpolateUrlTokens } from '../composables/useEndpointSource.js'\nimport { routeHref } from './actionLink.js'\nimport { resolveModalEntry } from './builtInModals.js'\nimport {\n\tdropOptionalUnresolved,\n\tdropOptionalUnresolvedDeep,\n\thasUnresolvedDeepTokens,\n\thasUnresolvedTokens,\n\tresolveDeepTokens,\n\tresolveFilterTokens,\n} from './resolveFilterTokens.js'\nimport { schemaRefSlug } from './schemaRefSlug.js'\n\n/** Event-bus channel the page-level Refresh signal broadcasts on (Wave 2). */\nconst PAGE_REFRESH_CHANNEL = 'cn:page:refresh'\n\n/**\n * Whether a `navigate` target leaves the app: it is `http(s)://`,\n * protocol-relative (`//`), or a `mailto:` / `tel:` link. Anything else is an\n * in-app path for the router.\n *\n * vue-router happily accepts an absolute URL as a PATH — `router.push` on\n * `https://youtu.be/x?v=1` matches no route and lands on the fallback with the\n * query carried over, which reads as the app ignoring the link.\n *\n * An allowlist, not a generic `<scheme>://` match: manifests are\n * admin-editable app-wide config, and an external target renders into an\n * anchor `href` and a dispatcher `window.open` — a generic scheme match would\n * accept `javascript://` too.\n *\n * @param {unknown} target The action target to test.\n * @return {boolean} True when the target is external.\n */\nexport function isExternalActionTarget(target) {\n\tif (typeof target !== 'string') {\n\t\treturn false\n\t}\n\treturn /^\\/\\//.test(target) || /^(https?|mailto|tel):/i.test(target)\n}\n\n/**\n * Resolve the object-store type slug for a widget `source` register/schema\n * pair. Reuses an already-registered type whose config matches (so an app's\n * own caches stay coherent); otherwise registers a deterministic\n * `<register>/<schema>` slug on the fly.\n *\n * `source.schema` is routed through {@link schemaRefSlug} before it ever\n * reaches the store or the objects API: a caller that passes a `$ref`\n * schema TITLE (`ReportPeriod`) rather than its slug (`report-period`)\n * would otherwise register — and fetch — a 404 (defect 7, learniq round\n * 1). Idempotent for a caller that already passes a correct slug.\n *\n * A caller that already holds the schema SLUG (not a `$ref` title) passes\n * `{ exactSchema: true }`: the slug is then used exactly as given. Kebab-casing\n * a real camelCase slug (`productCategory` -> `product-category`) asks the\n * objects API for a schema that does not exist and 404s (pipelinq review,\n * round two).\n *\n * @spec openspec/changes/review-round-two/specs/schema-utilities/spec.md\n *\n * A title is not always registered under its kebab form: learniq holds\n * `LearniqSettings` and `SubjectTeacherAssignment` as written. So a type\n * registered here for a value the kebab rule CHANGED also carries the value\n * as written as its `schemaFallback`, and the store retries with it once\n * when the kebab form answers 404 (keeping it from then on). The kebab form\n * is still tried first, so a schema registered under it costs nothing.\n *\n * @spec openspec/changes/zuiddrecht-pixel-gaps-2/specs/zuiddrecht-pixel-gaps-2/spec.md#requirement-a-schema-title-falls-back-to-its-written-form\n * @param {object} store The object store instance (useObjectStore shape).\n * @param {{register: (string|number), schema: (string|number)}} source The widget source.\n * @param {{exactSchema: (boolean|undefined)}} [options] `exactSchema: true` skips the title-to-slug step.\n * @return {string} The type slug to use for store CRUD calls.\n */\nexport function resolveObjectOpType(store, source, options = {}) {\n\tconst register = String(source.register)\n\tconst schema = options.exactSchema === true ? String(source.schema) : String(schemaRefSlug(source.schema))\n\tconst written = typeof source.schema === 'string'\n\t\t? source.schema.substring(source.schema.lastIndexOf('/') + 1)\n\t\t: ''\n\tconst registry = store.objectTypeRegistry || {}\n\tfor (const [slug, config] of Object.entries(registry)) {\n\t\tif (!config) {\n\t\t\tcontinue\n\t\t}\n\t\tif ((String(config.register) === register && String(config.schema) === schema)\n\t\t\t|| (config.registerSlug === register && config.schemaSlug === schema)) {\n\t\t\treturn slug\n\t\t}\n\t}\n\tconst slug = `${register}/${schema}`\n\tif (!registry[slug]) {\n\t\tstore.registerObjectType(slug, schema, register)\n\t\tif (written !== '' && written !== schema && typeof store.setSchemaFallback === 'function') {\n\t\t\tstore.setSchemaFallback(slug, written)\n\t\t}\n\t}\n\treturn slug\n}\n\n/**\n * Extract an OpenRegister object's id from a row (top-level `id` wins,\n * `@self.id` metadata fallback).\n *\n * @param {object} row The row object.\n * @return {string|number|null} The object id, or null when absent.\n */\nfunction rowObjectId(row) {\n\tif (!row || typeof row !== 'object') {\n\t\treturn null\n\t}\n\tif (row.id !== undefined && row.id !== null) {\n\t\treturn row.id\n\t}\n\tconst self = row['@self']\n\tif (self && typeof self === 'object' && self.id !== undefined && self.id !== null) {\n\t\treturn self.id\n\t}\n\treturn null\n}\n\n/**\n * Extract a saved OpenRegister object's id for a post-save deep-link:\n * top-level `id`, then `uuid`, then the `@self.id` metadata fallback.\n *\n * @param {object} saved The saved record returned by the object store.\n * @return {string|number|null} The object id, or null when absent.\n */\nexport function savedObjectId(saved) {\n\tif (!saved || typeof saved !== 'object') {\n\t\treturn null\n\t}\n\tif (saved.id !== undefined && saved.id !== null) {\n\t\treturn saved.id\n\t}\n\tif (saved.uuid !== undefined && saved.uuid !== null) {\n\t\treturn saved.uuid\n\t}\n\tconst self = saved['@self']\n\tif (self && typeof self === 'object' && self.id !== undefined && self.id !== null) {\n\t\treturn self.id\n\t}\n\treturn null\n}\n\n/**\n * Resolve a manifest-named FUNCTION out of the v2 registry, falling back to the\n * legacy customComponents map.\n *\n * A manifest names a behaviour the same way it names a component — by string —\n * so every surface that dispatches one (`actions[].handler`,\n * `bulkActions[].handler`, `headerActions[].handler`, `config.createOverride`)\n * has to agree on where that string is looked up and what counts as a match.\n * Recognised shapes, in order:\n * 1. a registry entry exposing the function as `.handler` / `.fn` (the\n * `kind: 'handler'` and `kind: 'create-override'` entries),\n * 2. a directly function-valued registry entry,\n * 3. a function-valued legacy `customComponents` entry.\n *\n * The legacy map stays last so an app that has not migrated is unchanged, and\n * so an app mid-migration can move its handlers over one at a time.\n *\n * @param {string} name The registered handler name.\n * @param {object} registry The v2 component registry.\n * @param {object} customComponents The legacy customComponents map.\n * @return {?((scope?: object) => unknown)} The handler, or null when nothing of that name is a function.\n */\nexport function resolveRegisteredHandler(name, registry, customComponents) {\n\tif (typeof name !== 'string' || name === '') {\n\t\treturn null\n\t}\n\tconst entry = (registry || {})[name]\n\tif (typeof entry === 'function') {\n\t\treturn entry\n\t}\n\tif (entry && typeof entry === 'object') {\n\t\tif (typeof entry.handler === 'function') {\n\t\t\treturn entry.handler\n\t\t}\n\t\tif (typeof entry.fn === 'function') {\n\t\t\treturn entry.fn\n\t\t}\n\t}\n\tconst legacy = (customComponents || {})[name]\n\treturn typeof legacy === 'function' ? legacy : null\n}\n\n/**\n * Resolve a named create-override handler out of the v2 registry (or the\n * legacy customComponents map) by value shape.\n *\n * A create-override is a plain async function that replaces the default\n * `objectStore.saveObject` persist path — needed whenever a schema requires a\n * field the create form cannot supply on its own (a server-minted foreign key,\n * say).\n *\n * Shared by CnPageRenderer (page-level `config.createOverride` → CnIndexPage's\n * prop) and CnActionButtons (per-action `createOverride` on an `open-form`), so\n * the two surfaces cannot drift on what counts as a valid handler.\n *\n * @param {string} name The registered handler name.\n * @param {object} registry The v2 component registry.\n * @param {object} customComponents The legacy customComponents map.\n * @return {?((props?: object) => Promise<unknown>)} The async create handler, or null when unresolved.\n */\nexport function resolveCreateOverrideHandler(name, registry, customComponents) {\n\treturn resolveRegisteredHandler(name, registry, customComponents)\n}\n\n/**\n * Build the vue-router push location for an `open-form` action's\n * `onSuccessRoute`, merging the saved object's id into the route params so\n * the post-save navigation can deep-link to the created object's detail page\n * (#91).\n *\n * `onSuccessRoute` may be:\n * - a STRING route NAME → `{ name, params: { id } }`. The saved id lands\n * under the default `id` param; a route without an `:id` segment simply\n * ignores the extra param, so a bare-name route keeps working unchanged\n * (backward compatible).\n * - an OBJECT `{ name, paramField?, objectParam? }` → the id is placed\n * under `paramField` (default `id`), and — when `objectParam` is set —\n * the whole saved object is passed under that param key too (so a\n * `props: true` detail route can render the record without a refetch).\n *\n * The id is read via {@link savedObjectId} (`saved.id` → `saved.uuid` →\n * `saved['@self'].id`). Returns `null` when no route name is resolvable, so\n * the caller can skip the navigation.\n *\n * @param {(string|{name: string, paramField?: string, objectParam?: string})} onSuccessRoute The action's onSuccessRoute config.\n * @param {object} saved The saved OpenRegister object.\n * @return {{name: string, params: object}|null} The router push location, or null.\n */\nexport function buildOnSuccessRoute(onSuccessRoute, saved) {\n\tconst spec = typeof onSuccessRoute === 'string'\n\t\t? { name: onSuccessRoute }\n\t\t: (onSuccessRoute && typeof onSuccessRoute === 'object' ? onSuccessRoute : null)\n\tif (!spec || typeof spec.name !== 'string' || spec.name === '') {\n\t\treturn null\n\t}\n\tconst params = {}\n\tconst id = savedObjectId(saved)\n\tif (id !== null && id !== undefined) {\n\t\tparams[spec.paramField || 'id'] = id\n\t}\n\tif (spec.objectParam && saved && typeof saved === 'object') {\n\t\tparams[spec.objectParam] = saved\n\t}\n\treturn { name: spec.name, params }\n}\n\n/**\n * Run a manifest-authored toast message through the host translate function.\n *\n * `successMessage` / `errorMessage` are English source strings authored in the\n * manifest (ADR-007), so they need the SAME translator the rest of the page\n * chrome uses — the consumer's bound `t()`, handed to the dispatcher by the\n * rendering surface as `context.translate` (which itself comes from the\n * `cnTranslate` CnAppRoot provides).\n *\n * A pure pass-through: with no translator, no message, or a catalogue that\n * lacks the key, the message is returned byte-identical. Server-supplied\n * messages are data and are never routed through here.\n *\n * @param {unknown} message The manifest-authored message (may be undefined).\n * @param {object} context The dispatch context (`context.translate` optional).\n * @return {unknown} The translated message, or the input unchanged.\n */\nfunction translateMessage(message, context) {\n\tconst fn = context && context.translate\n\tif (!message || typeof fn !== 'function') {\n\t\treturn message\n\t}\n\treturn fn(message)\n}\n\n/**\n * Interpolate the `api-call` URL/filename token grammar inside a string:\n * the `{objectId}` BRACE convention (a literal placeholder some manifests\n * use for path templates, matching the OpenRegister credential-broker path\n * style) as well as the full `@objectId` / `@object.<field>` /\n * `@workspace.<key>` / `@config.<key>` grammar {@link interpolateUrlTokens}\n * already understands. Unresolved `@`-tokens and an unresolved\n * `{objectId}` both collapse to an empty string (never leak a literal\n * placeholder into a request URL or a downloaded filename).\n *\n * @param {string} str The raw string (an action's `url` or `filename`).\n * @param {{objectId?: (string|number), object?: object, workspace?: object, config?: object}} ctx Token context.\n * @return {string} The interpolated string.\n */\nfunction interpolateActionString(str, ctx) {\n\tif (typeof str !== 'string') {\n\t\treturn str\n\t}\n\tconst braced = str.replace(/\\{objectId\\}/g, () => {\n\t\tconst id = ctx.objectId\n\t\treturn (id === undefined || id === null) ? '' : String(id)\n\t})\n\treturn interpolateUrlTokens(braced, ctx)\n}\n\n/**\n * Interpolate an action's `target` URL — the same grammar `url` runs.\n *\n * Exported because the rendering surface resolves a target BEFORE deciding\n * whether it is an external link, and that decision happens there rather than\n * in the dispatcher.\n *\n * @param {string} target The action's raw `target`.\n * @param {object} ctx Token context (`{ objectId?, object?, workspace?, config? }`).\n *\n * @return {string} The interpolated target.\n */\nexport function interpolateActionTarget(target, ctx) {\n\treturn interpolateActionString(target || '', ctx || {})\n}\n\n// The tokens interpolateActionString resolves; a bare `@` or `{` is not one.\nconst ACTION_TARGET_TOKEN = /@(?:objectId|object\\.|page\\.|workspace\\.|config\\.|range\\.)|\\{objectId\\}/\n\n/**\n * Whether an action target carries a token that interpolation would resolve,\n * so it can only be known once the page context is. A `mailto:` address or a\n * URL with an `@handle` in it has none.\n *\n * @param {string} target The action's raw `target`.\n * @return {boolean}\n */\nexport function hasActionTargetTokens(target) {\n\treturn typeof target === 'string' && ACTION_TARGET_TOKEN.test(target)\n}\n\n/**\n * The link an action renders as when its only job is to navigate to a target\n * known at render time: `navigate` (token-interpolated like the dispatcher)\n * and `open-page`. Anything else, a `confirm: true` action, or an in-app\n * target the router cannot resolve answers null and keeps dispatching.\n *\n * `to` is what a plain click hands the router (null for an external URL,\n * which the browser opens in a new tab like the dispatcher's `window.open`).\n *\n * @param {object} action The manifest action.\n * @param {{router?: object, tokenCtx?: object}} [context] The dispatch context.\n * @return {{href: string, to: (string|object|null), external: boolean}|null} The link, or null.\n */\nexport function actionLink(action, context = {}) {\n\tif (!action || typeof action !== 'object' || action.confirm) {\n\t\treturn null\n\t}\n\tif (action.type === 'navigate') {\n\t\tconst target = interpolateActionString(action.target || '', context.tokenCtx || {})\n\t\tif (!target) {\n\t\t\treturn null\n\t\t}\n\t\tif (isExternalActionTarget(target)) {\n\t\t\treturn { href: target, to: null, external: true }\n\t\t}\n\t\tconst href = routeHref(target, context.router)\n\t\treturn href ? { href, to: target, external: false } : null\n\t}\n\tif (action.type === 'open-page') {\n\t\tif (typeof action.target !== 'string' || action.target.length === 0) {\n\t\t\treturn null\n\t\t}\n\t\tconst to = { name: action.target }\n\t\tconst href = routeHref(to, context.router)\n\t\treturn href ? { href, to, external: false } : null\n\t}\n\treturn null\n}\n\n/**\n * Execute a Wave-3 `api-call` action: POST/PUT the configured app endpoint\n * (URL + body run the SAME @-token grammar endpoint sources use), toast the\n * outcome via @nextcloud/dialogs, then — unless `action.refresh` is `false`\n * (or, for a `download` action, unless `action.refresh` is explicitly\n * `true`) — bump the page-level refresh signal so every endpoint-bound\n * widget refetches. Confirm-gating is the RENDERING SURFACE's job (the\n * `confirm` field is intent, object-op precedent): this runs after any\n * confirmation already happened.\n *\n * The request body prefers `action.payload` (DEEP token resolution, any\n * nesting — {@link resolveDeepTokens}) over the legacy `action.params`\n * (shallow, one-level filter-map resolution — unchanged for back-compat).\n * A required token left unresolved anywhere in the body BLOCKS the call\n * (error toast) rather than sending a literal `@objectId` to the server.\n *\n * `action.download === true` requests the response as a binary blob\n * (`responseType: 'blob'`) and triggers a browser file download — the\n * filename comes from the response's `Content-Disposition` header, else\n * the token-resolved `action.filename`, else `'download.pdf'`.\n *\n * Never throws: a failed call resolves `{ ok: false, error }` after the\n * error toast (so a confirm dialog can await the outcome).\n *\n * @param {object} action The api-call action (`url`, `method?`, `payload?`,\n * `params?`, `download?`, `filename?`, `successMessage?`, `errorMessage?`,\n * `refresh?`).\n * @param {object} context Runtime context; `context.tokenCtx` is the token\n * context (`{ objectId?, object?, workspace?, config? }`) the URL/body\n * resolve against.\n * @return {Promise<{ok: boolean, data?: unknown, error?: unknown}>} The call outcome.\n */\nasync function executeApiCall(action, context) {\n\tconst tokenCtx = context.tokenCtx || {}\n\tconst url = interpolateActionString(action.url || '', tokenCtx)\n\n\tconst hasPayload = action.payload && typeof action.payload === 'object' && !Array.isArray(action.payload)\n\tconst body = hasPayload\n\t\t? dropOptionalUnresolvedDeep(resolveDeepTokens(action.payload, tokenCtx))\n\t\t: dropOptionalUnresolved(resolveFilterTokens(action.params || {}, tokenCtx))\n\tconst bodyBlocked = hasPayload ? hasUnresolvedDeepTokens(body) : hasUnresolvedTokens(body)\n\n\tif (!url || bodyBlocked) {\n\t\t// eslint-disable-next-line no-console\n\t\tconsole.warn('[dispatchAction] api-call is missing its url or a required token is unresolved — skipping.', action)\n\t\treturn { ok: false, error: new Error('api-call blocked') }\n\t}\n\tconst method = String(action.method || 'POST').toUpperCase() === 'PUT' ? 'put' : 'post'\n\tconst isDownload = action.download === true\n\tconst [{ default: axios }, { generateUrl }, dialogs] = await Promise.all([\n\t\timport('@nextcloud/axios'),\n\t\timport('@nextcloud/router'),\n\t\timport('@nextcloud/dialogs'),\n\t])\n\tconst target = /^https?:\\/\\//i.test(url) ? url : generateUrl(url)\n\ttry {\n\t\t// Only pass a third axios config arg for a download call — an\n\t\t// explicit `undefined` third argument would otherwise change the\n\t\t// call shape for every existing (non-download) api-call consumer/test.\n\t\tconst res = isDownload\n\t\t\t? await axios[method](target, body, { responseType: 'blob' })\n\t\t\t: await axios[method](target, body)\n\t\tif (isDownload) {\n\t\t\tconst filename = parseDispositionFilename(\n\t\t\t\tres && res.headers && res.headers['content-disposition'],\n\t\t\t\tinterpolateActionString(action.filename, tokenCtx) || 'download.pdf',\n\t\t\t)\n\t\t\ttriggerBlobDownload(res.data, filename)\n\t\t}\n\t\tif (typeof dialogs.showSuccess === 'function') {\n\t\t\tdialogs.showSuccess(translateMessage(action.successMessage, context) || t('nextcloud-vue', 'Action completed.'))\n\t\t}\n\t\tconst shouldRefresh = isDownload ? action.refresh === true : action.refresh !== false\n\t\tif (shouldRefresh) {\n\t\t\temit(PAGE_REFRESH_CHANNEL, {})\n\t\t}\n\t\treturn { ok: true, data: res && res.data }\n\t} catch (error) {\n\t\tconst serverMessage = error && error.response && error.response.data\n\t\t\t&& (error.response.data.error || error.response.data.message)\n\t\tif (typeof dialogs.showError === 'function') {\n\t\t\tdialogs.showError(translateMessage(action.errorMessage, context) || serverMessage || t('nextcloud-vue', 'Action failed.'))\n\t\t}\n\t\treturn { ok: false, error }\n\t}\n}\n\n/**\n * Resolve an agent-action object reference (`register` / `schema` / `objectId`):\n * an explicitly-declared action value WINS (it may itself be an @-token string,\n * interpolated against the token context), otherwise it falls back to the page\n * object context default (`tokenCtx.register` / `.schema` / `.objectId`). An\n * unresolved token collapses to an empty string (never leaks a literal `@objectId`\n * to the server); a `{ slug | id }` object (a schema holder) is flattened to its\n * slug/id.\n *\n * @param {unknown} actionVal The action's explicit value (may be undefined or an @-token).\n * @param {unknown} ctxDefault The page-context default (`tokenCtx.<field>`).\n * @param {object} tokenCtx The token context the @-tokens resolve against.\n * @return {string} The resolved reference, or '' when unresolved/absent.\n */\nfunction resolveAgentRef(actionVal, ctxDefault, tokenCtx) {\n\tlet v = actionVal\n\tif (v === undefined || v === null || v === '') {\n\t\tv = ctxDefault\n\t} else if (typeof v === 'string') {\n\t\tv = interpolateActionString(v, tokenCtx)\n\t}\n\tif (v && typeof v === 'object') {\n\t\treturn String(v.slug || v.id || '')\n\t}\n\tif (v === undefined || v === null) {\n\t\treturn ''\n\t}\n\treturn String(v)\n}\n\n/**\n * Execute an `agent` action: run a governed hermiq agent against the page's\n * OpenRegister object. Resolves the object context (`register` / `schema` /\n * `objectId` — explicit action fields override, else default to the page's\n * `@register` / `@schema` / `@objectId` context) and POSTs\n * `{ register, schema, objectId, resultField?, skill?, prompt? }` to hermiq's\n * object-RBAC-scoped run endpoint `/apps/hermiq/api/agents/{agent}/run-on-object`\n * (hermiq#41), which dispatches the governed `AgentRunRequestedEvent`.\n *\n * A first-class companion to `type:\"api-call\"` — the author declares \"run agent\n * here\" without hand-wiring the URL/body. `type:\"api-call\"` remains the escape\n * hatch for a bespoke body.\n *\n * Fail-closed. An unresolved REQUIRED `@objectId` (or a missing agent/register/\n * schema) BLOCKS the call (warn) rather than POSTing a literal token. On the\n * server's 202 it toasts `successMessage` (default 'Run queued') and — unless\n * `refresh: false` — bumps the page refresh signal. A 403 / 404 with a structured\n * error body fail-closes with that message; a 404 with NO structured body is read\n * as \"hermiq absent\" and toasts a graceful 'agent runtime unavailable' — the\n * dispatcher NEVER hard-requires hermiq to be installed. Never throws.\n *\n * @param {object} action The agent action (`agent`, `skill?`, `prompt?`,\n * `resultField?`, `register?`, `schema?`, `objectId?`, `successMessage?`,\n * `errorMessage?`, `refresh?`).\n * @param {object} context Runtime context; `context.tokenCtx` is the token\n * context (`{ objectId?, object?, register?, schema?, workspace?, config? }`).\n * @return {Promise<{ok: boolean, data?: unknown, error?: unknown}>} The call outcome.\n */\nasync function executeAgentAction(action, context) {\n\tconst tokenCtx = context.tokenCtx || {}\n\tconst agent = resolveAgentRef(action.agent, undefined, tokenCtx)\n\tconst register = resolveAgentRef(action.register, tokenCtx.register, tokenCtx)\n\tconst schema = resolveAgentRef(action.schema, tokenCtx.schema, tokenCtx)\n\tconst objectId = resolveAgentRef(action.objectId, tokenCtx.objectId, tokenCtx)\n\n\tif (!agent || !register || !schema || !objectId) {\n\t\t// eslint-disable-next-line no-console\n\t\tconsole.warn('[dispatchAction] agent action is missing its agent or a required object-context token (register/schema/objectId) is unresolved — skipping.', action)\n\t\treturn { ok: false, error: new Error('agent action blocked') }\n\t}\n\n\tconst body = { register, schema, objectId }\n\tconst resultField = resolveAgentRef(action.resultField, undefined, tokenCtx)\n\tif (resultField) {\n\t\tbody.resultField = resultField\n\t}\n\tconst skill = resolveAgentRef(action.skill, undefined, tokenCtx)\n\tif (skill) {\n\t\tbody.skill = skill\n\t}\n\tif (typeof action.prompt === 'string' && action.prompt !== '') {\n\t\tbody.prompt = interpolateActionString(action.prompt, tokenCtx)\n\t}\n\n\tconst [{ default: axios }, { generateUrl }, dialogs] = await Promise.all([\n\t\timport('@nextcloud/axios'),\n\t\timport('@nextcloud/router'),\n\t\timport('@nextcloud/dialogs'),\n\t])\n\tconst target = generateUrl(`/apps/hermiq/api/agents/${encodeURIComponent(agent)}/run-on-object`)\n\ttry {\n\t\tconst res = await axios.post(target, body)\n\t\tif (typeof dialogs.showSuccess === 'function') {\n\t\t\tdialogs.showSuccess(translateMessage(action.successMessage, context) || t('nextcloud-vue', 'Run queued'))\n\t\t}\n\t\tif (action.refresh !== false) {\n\t\t\temit(PAGE_REFRESH_CHANNEL, {})\n\t\t}\n\t\treturn { ok: true, data: res && res.data }\n\t} catch (error) {\n\t\tconst response = error && error.response\n\t\tconst status = response && response.status\n\t\tconst serverMessage = response && response.data\n\t\t\t&& (response.data.error || response.data.message)\n\t\t// A 404 with NO structured error body = hermiq is not installed (the app\n\t\t// route 404s at the NC level) — surface a graceful \"runtime unavailable\"\n\t\t// rather than a fail-closed authorization message.\n\t\tconst hermiqAbsent = status === 404 && !serverMessage\n\t\tif (typeof dialogs.showError === 'function') {\n\t\t\tconst msg = hermiqAbsent\n\t\t\t\t? t('nextcloud-vue', 'Agent runtime unavailable')\n\t\t\t\t: (translateMessage(action.errorMessage, context) || serverMessage || t('nextcloud-vue', 'Action failed.'))\n\t\t\tdialogs.showError(msg)\n\t\t}\n\t\treturn { ok: false, error }\n\t}\n}\n\n/**\n * POST the run-node call: `POST /apps/openregister/api/flows/{flowId}/nodes/{nodeId}/run`.\n *\n * This is the SECOND half of `run-node` (manifest-run-node-action / or-flow-run-node) —\n * the first half is `context.openRunNode` in the `dispatchAction` switch below, which\n * only OPENS the config dialog (or decides none is needed) and never itself waits for\n * the person. Once the rendering surface has a `config` object (from the dialog's\n * submit, or `{}` when the node's declared form was empty), it calls this directly —\n * it is not reached through `dispatchAction`'s switch, because by that point there is\n * no further \"type\" dispatch to do, only the call itself, same as `executeAgentAction`\n * is called directly by `case 'api-call'`'s sibling rather than re-entering the switch.\n *\n * Fail-closed exactly like `executeAgentAction`: an unresolved REQUIRED subject\n * (`action.subject`, defaulting to the page's `@objectId`) or a missing\n * `flowId`/`nodeId` BLOCKS the call (warn) rather than POSTing a literal token or an\n * incomplete subject reference. The subject sent is `{ uuid, register, schema }` —\n * OpenRegister's `FlowNodeRunController::resolveAuthorizedSubject()` needs all three\n * to resolve the object and evaluate the caller's object-RBAC permission on it; `register`\n * / `schema` default to the page's own `@register` / `@schema` context, the same\n * defaulting `agent` already uses.\n *\n * A 403 here means the caller holds no update permission on the subject\n * (OpenRegister's object-RBAC, evaluated server-side — RN-1(c)) — this function does not\n * special-case it beyond surfacing the server's message, the same fail-closed handling\n * `api-call` / `agent` already give a rejected call.\n *\n * @param {object} action The run-node action (`flowId`, `nodeId`, `subject?`,\n * `register?`, `schema?`, `successMessage?`, `errorMessage?`, `refresh?`).\n * @param {object} context Runtime context — needs `context.tokenCtx` and, for a\n * localised toast, `context.translate`.\n * @param {object} [config] The node's collected config (from its `configForm()`\n * dialog), or `{}` for a node with no declared fields.\n * @return {Promise<{ok: boolean, data?: object, error?: Error}>} The call outcome —\n * `data` is the created `FlowRun` on success.\n *\n * @spec openspec/changes/manifest-run-node-action/specs/manifest-run-node-action/spec.md#requirement-a-run-node-action-invokes-one-flow-node-against-the-page-object\n */\nexport async function postRunNode(action, context, config = {}) {\n\tconst tokenCtx = context.tokenCtx || {}\n\tconst flowId = resolveAgentRef(action.flowId, undefined, tokenCtx)\n\tconst nodeId = resolveAgentRef(action.nodeId, undefined, tokenCtx)\n\tconst uuid = resolveAgentRef(action.subject, tokenCtx.objectId, tokenCtx)\n\tconst register = resolveAgentRef(action.register, tokenCtx.register, tokenCtx)\n\tconst schema = resolveAgentRef(action.schema, tokenCtx.schema, tokenCtx)\n\n\tif (!flowId || !nodeId || !uuid || !register || !schema) {\n\t\t// eslint-disable-next-line no-console\n\t\tconsole.warn('[dispatchAction] run-node is missing flowId/nodeId or a required subject token (objectId/register/schema) is unresolved — skipping.', action)\n\t\treturn { ok: false, error: new Error('run-node blocked') }\n\t}\n\n\tconst [{ default: axios }, { generateUrl }, dialogs] = await Promise.all([\n\t\timport('@nextcloud/axios'),\n\t\timport('@nextcloud/router'),\n\t\timport('@nextcloud/dialogs'),\n\t])\n\tconst target = generateUrl(`/apps/openregister/api/flows/${encodeURIComponent(flowId)}/nodes/${encodeURIComponent(nodeId)}/run`)\n\ttry {\n\t\tconst res = await axios.post(target, { subject: { uuid, register, schema }, config: config || {} })\n\t\tif (typeof dialogs.showSuccess === 'function') {\n\t\t\tdialogs.showSuccess(translateMessage(action.successMessage, context) || t('nextcloud-vue', 'Run completed.'))\n\t\t}\n\t\tif (action.refresh !== false) {\n\t\t\temit(PAGE_REFRESH_CHANNEL, {})\n\t\t}\n\t\treturn { ok: true, data: res && res.data }\n\t} catch (error) {\n\t\tconst response = error && error.response\n\t\tconst serverMessage = response && response.data\n\t\t\t&& (response.data.error || response.data.message)\n\t\tif (typeof dialogs.showError === 'function') {\n\t\t\tdialogs.showError(translateMessage(action.errorMessage, context) || serverMessage || t('nextcloud-vue', 'Action failed.'))\n\t\t}\n\t\treturn { ok: false, error }\n\t}\n}\n\n/**\n * Dispatch a v2 manifest action.\n *\n * @param {object} action The action object from the manifest.\n * @param {string} [action.type] Dispatch type: \"handler\" | \"open-modal\" | \"open-page\" | \"navigate\" |\n * \"object-op\" | \"export\" | \"open-form\" | \"refresh\" | \"api-call\" | \"agent\".\n * When absent, treated as \"handler\" for v1 backward compatibility.\n * @param {string} [action.handler] Registry key for \"handler\" type. For \"export\": the optional\n * handler invoked by the host with the dialog's confirm payload (`{ format, entity }`).\n * @param {Array} [action.args] Arguments spread to the handler function.\n * @param {string} [action.target] Target for \"open-modal\", \"open-page\", and \"navigate\" types.\n * @param {object} [action.props] Props forwarded to modal for \"open-modal\" type.\n * @param {string} [action.op] \"object-op\" only: mutation verb — \"patch\" | \"delete\" | \"create\".\n * @param {object} [action.values] \"object-op\" only: the verb's payload — the partial object\n * merged over the row for \"patch\", the new object's properties for \"create\"; ignored for \"delete\".\n * @param {boolean} [action.confirm] \"object-op\" only: confirm-gating INTENT consumed by the\n * rendering host (CnWidgetObjectTable routes it through CnConfirmDialog) — the dispatcher\n * itself never gates; it is called after any confirmation already happened.\n * @param {Array<{id: string, label: string}>} [action.entities] \"export\" only: selectable\n * entity types offered by the export launcher (e.g. Leads / Requests). Optional — when\n * absent the dialog shows only the format picker.\n * @param {Array<string|{id: string, label: string}>} [action.formats] \"export\" only: the\n * offered export formats (bare ids like \"csv\" or full `{id, label}` entries). Optional —\n * the dialog's built-in Excel/CSV defaults apply when absent.\n * @param {string} [action.description] \"export\" only: pre-translated description shown\n * above the pickers.\n * @param {string} [action.url] \"api-call\" only: the app endpoint — app-relative (routed\n * through generateUrl) or absolute. May interpolate the shared URL tokens\n * (`@objectId`, `@object.<field>`, `@workspace.<key>`, `@config.<key>`, and the\n * `{objectId}` brace form).\n * @param {string} [action.method] \"api-call\" only: \"POST\" (default) | \"PUT\".\n * @param {object} [action.payload] \"api-call\" only: the JSON body — preferred over `params`.\n * Values resolve the shared `@`-token grammar RECURSIVELY at any nesting depth (objects\n * and arrays of objects, e.g. `{ dataRefs: [{ id: '@objectId' }] }`); optional (`…?`)\n * tokens drop when unresolved anywhere in the tree, an unresolved REQUIRED token blocks\n * the call. When set, `params` is ignored.\n * @param {object} [action.params] \"api-call\" only: legacy JSON body (ignored when `payload`\n * is set). Values pass the shared filter-token grammar ONE level deep; optional (`…?`)\n * tokens drop when unresolved, an unresolved REQUIRED token blocks the call.\n * @param {boolean} [action.download] \"api-call\" only: request the response as a binary blob\n * (`responseType: 'blob'`) and trigger a browser file download instead of a JSON\n * toast+refresh cycle. Default `false`.\n * @param {string} [action.filename] \"api-call\" `download: true` only: fallback filename when\n * the response carries no `Content-Disposition` header (falls back further to\n * `'download.pdf'`). Interpolates the same token grammar as `url`.\n * @param {string} [action.successMessage] \"api-call\" / \"open-form\": pre-translated success\n * toast text (a library default applies when absent).\n * @param {string} [action.errorMessage] \"api-call\" / \"open-form\": pre-translated error toast\n * text (falls back to the server's `error`/`message`, then a library default).\n * @param {boolean} [action.refresh] \"api-call\" / \"agent\" only: bump the `cn:page:refresh` signal\n * after a successful call. Default `true` — EXCEPT for a `download: true` api-call, whose\n * default is `false` (a file download normally shouldn't also force-refetch every widget); set\n * the flag explicitly either way to override.\n * @param {string} [action.agent] \"agent\" only (REQUIRED): the hermiq agent uuid to run against\n * the page object. POSTed to `/apps/hermiq/api/agents/{agent}/run-on-object` (hermiq#41).\n * @param {string} [action.skill] \"agent\" only: optional skill id folded into the governed run.\n * @param {string} [action.prompt] \"agent\" only: optional prompt (interpolates the shared `@`-token\n * grammar inline — `@objectId`, `@object.<field>`, `@workspace.<key>`, `@config.<key>`).\n * @param {string} [action.resultField] \"agent\" only: object field the agent's result is written to.\n * @param {string} [action.register] \"agent\" / \"open-form\": OpenRegister register slug (agent:\n * defaults to the page object context's `@register`).\n * @param {string} [action.schema] \"agent\" / \"open-form\": OpenRegister schema slug (agent: defaults\n * to the page object context's `@schema`).\n * @param {string} [action.objectId] \"agent\" only: the target object id (defaults to the page\n * object context's `@objectId`). An unresolved required token BLOCKS the call (fail-closed).\n *\n * @param {object} context Runtime context.\n * @param {object} [context.router] Vue Router instance. Required for \"open-page\" and \"navigate\".\n * @param {object} [context.registry] Component registry (Record<string, { kind, component }>).\n * Required for \"open-modal\" type.\n * @param {object} [context.handlers] Map of handler name → function. Required for \"handler\" type.\n * @param {(key: string, props?: object) => void} [context.openModal] Opens a modal.\n * Required for \"open-modal\" type.\n * @param {(action: object) => void} [context.openExport] Opens the shared\n * CnMassExportDialog configured from the action. Required for \"export\" type —\n * CnPageRenderer pre-binds it in the `cnDispatchAction` context.\n * @param {(action: object) => void} [context.openForm] Opens the schema-driven\n * create dialog. Required for \"open-form\" type — the rendering surface\n * (CnActionButtons) provides it, mirroring `openExport`. On a successful save the\n * surface navigates to `action.onSuccessRoute` (a route NAME string, or\n * `{name, paramField?, objectParam?}`) via {@link buildOnSuccessRoute}, which merges\n * the saved object's id into the route params so the navigation can deep-link to the\n * created object.\n * @param {(action: object) => void} [context.openRunNode] Opens the\n * node-config dialog (or runs immediately for an empty config form) and\n * POSTs to OpenRegister's direct-invoke endpoint on submit. Required for\n * \"run-node\" type — the rendering surface (CnActionButtons) provides it,\n * mirroring `openForm`.\n * @param {{objectId?: (string|number), object?: object, workspace?: object, config?: object}} [context.tokenCtx]\n * Token context \"api-call\" URLs/params resolve against (the same shape\n * `resolveFilterTokens` / `interpolateUrlTokens` take).\n * @param {(app: string, text: string, vars?: object) => string} [context.translate] The consumer's bound `t()`, the same\n * `cnTranslate` CnAppRoot provides to the page chrome. Applied to the\n * manifest-authored `successMessage` / `errorMessage` of \"api-call\" and\n * \"agent\" so their toasts follow the user's language. Omitted (or a\n * catalogue miss) leaves the message byte-identical.\n * @param {object} [context.objectStore] Object store instance (useObjectStore shape).\n * Required for \"object-op\" type. All mutations go through `saveObject` / `deleteObject`\n * so store caches (and their no-mutation-on-error semantics) apply.\n * @param {{register: (string|number), schema: (string|number)}} [context.source] The widget's\n * declarative source the mutation targets. Required for \"object-op\" type.\n * @param {object} [context.row] The row object a row-scoped \"object-op\" (patch/delete) mutates.\n *\n * @return {Promise<object|boolean|null>|undefined} For \"object-op\": the store call's promise —\n * the saved object (or `null` on a rejected write) for patch/create, `true`/`false` for\n * delete. The store only mutates its local caches on SUCCESS, so a backend (RBAC) rejection\n * surfaces via the store's `errors[type]` without any local state change. For \"api-call\":\n * a promise of `{ ok, data?, error? }` (toasts + refresh already handled). All other types\n * return undefined.\n */\nexport function dispatchAction(action, context = {}) {\n\tif (!action || typeof action !== 'object') {\n\t\t// eslint-disable-next-line no-console\n\t\tconsole.warn('[dispatchAction] Received invalid action:', action)\n\t\treturn\n\t}\n\n\t// Missing type is treated as \"handler\" for v1 backward compatibility\n\tconst type = action.type || 'handler'\n\n\tswitch (type) {\n\t\tcase 'handler': {\n\t\t\tconst handlerName = action.handler\n\t\t\tconst handlers = context.handlers || {}\n\n\t\t\tif (!handlerName || typeof handlers[handlerName] !== 'function') {\n\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.warn(`[dispatchAction] Handler \"${handlerName}\" not found in context.handlers.`)\n\t\t\t\treturn\n\t\t\t}\n\t\t\thandlers[handlerName](...(action.args ?? []))\n\t\t\tbreak\n\t\t}\n\n\t\tcase 'open-modal': {\n\t\t\tconst target = action.target\n\t\t\tconst entry = resolveModalEntry(context.registry, target)\n\n\t\t\tif (!entry) {\n\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.warn(`[dispatchAction] open-modal target \"${target}\" not found in registry.`)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tif (entry.kind !== 'modal') {\n\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.warn(`[dispatchAction] open-modal target \"${target}\" has kind \"${entry.kind}\" (expected \"modal\").`)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tif (typeof context.openModal !== 'function') {\n\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.warn('[dispatchAction] open-modal requires context.openModal to be a function.')\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tcontext.openModal(target, action.props ?? {})\n\t\t\tbreak\n\t\t}\n\n\t\tcase 'open-page': {\n\t\t\tif (!context.router) {\n\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.warn('[dispatchAction] open-page requires context.router to be a Vue Router instance.')\n\t\t\t\treturn\n\t\t\t}\n\t\t\tcontext.router.push({ name: action.target })\n\t\t\tbreak\n\t\t}\n\n\t\tcase 'navigate': {\n\t\t\t// A target is a URL exactly as `url` is, so it runs the same token\n\t\t\t// grammar. Without this a manifest's `{objectId}` reached the router\n\t\t\t// as those nine literal characters and landed in the address bar.\n\t\t\tconst target = interpolateActionString(action.target || '', context.tokenCtx || {})\n\n\t\t\t// An external target is not a route. Rendering surfaces should give it\n\t\t\t// to the browser as a real link (CnActionButtons does); this is the\n\t\t\t// fallback for a programmatic dispatch, and it must not reach the\n\t\t\t// router — see isExternalActionTarget.\n\t\t\tif (isExternalActionTarget(target)) {\n\t\t\t\twindow.open(target, '_blank', 'noopener,noreferrer')\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tif (!context.router) {\n\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.warn('[dispatchAction] navigate requires context.router to be a Vue Router instance.')\n\t\t\t\treturn\n\t\t\t}\n\t\t\tcontext.router.push(target)\n\t\t\tbreak\n\t\t}\n\n\t\tcase 'export': {\n\t\t// Export launcher (Wave 1, nextcloud-vue#91): the host page opens the\n\t\t// shared CnMassExportDialog configured via the action's entities[] /\n\t\t// formats[]; the dialog's confirm payload routes to the action's\n\t\t// optional `handler` (the app's export service does the download).\n\t\t\tif (typeof context.openExport !== 'function') {\n\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.warn('[dispatchAction] export requires context.openExport to be a function.')\n\t\t\t\treturn\n\t\t\t}\n\t\t\tcontext.openExport(action)\n\t\t\tbreak\n\t\t}\n\n\t\tcase 'open-form': {\n\t\t// Schema-driven create dialog (Wave 3, nextcloud-vue#91): the\n\t\t// rendering surface (CnActionButtons) mounts the shared\n\t\t// CnAdvancedFormDialog and handles the save — mirroring how\n\t\t// `export` delegates to the host's CnMassExportDialog.\n\t\t\tif (typeof context.openForm !== 'function') {\n\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.warn('[dispatchAction] open-form requires context.openForm to be a function.')\n\t\t\t\treturn\n\t\t\t}\n\t\t\tcontext.openForm(action)\n\t\t\tbreak\n\t\t}\n\n\t\tcase 'run-node': {\n\t\t// Direct flow-node invocation (manifest-run-node-action / RN-4):\n\t\t// SAME shape as open-form, deliberately — the rendering surface\n\t\t// (CnActionButtons) resolves the node's own config form, opens a\n\t\t// generic dialog when it has fields (skips it when empty), and\n\t\t// POSTs subject+config to OpenRegister's\n\t\t// /api/flows/{flowId}/nodes/{nodeId}/run on submit. This case\n\t\t// resolves as soon as the dialog OPENS (or the empty-form call\n\t\t// starts) — it does NOT wait for the person to answer, matching\n\t\t// every other consumer's assumption that dispatchAction's Promise\n\t\t// means \"the call happened\", not \"the human decided\" (see design.md\n\t\t// RN-4 for why an awaiting-on-UI shape was rejected).\n\t\t\tif (typeof context.openRunNode !== 'function') {\n\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.warn('[dispatchAction] run-node requires context.openRunNode to be a function.')\n\t\t\t\treturn\n\t\t\t}\n\t\t\tcontext.openRunNode(action)\n\t\t\tbreak\n\t\t}\n\n\t\tcase 'refresh': {\n\t\t// Page-level refresh (Wave 3, nextcloud-vue#91): bump the SAME\n\t\t// `cn:page:refresh` event-bus signal the page overflow menu's\n\t\t// Refresh item broadcasts — every endpoint-bound / bus-subscribed\n\t\t// widget on the page force-refetches past its shared cache.\n\t\t\temit(PAGE_REFRESH_CHANNEL, {})\n\t\t\tbreak\n\t\t}\n\n\t\tcase 'api-call': {\n\t\t// POST/PUT an app endpoint + toast + refresh (Wave 3). Any\n\t\t// `confirm` on the action is INTENT the rendering surface consumed\n\t\t// BEFORE calling the dispatcher (object-op precedent) — no gating\n\t\t// happens here.\n\t\t\treturn executeApiCall(action, context)\n\t\t}\n\n\t\tcase 'agent': {\n\t\t// Run a governed hermiq agent against the page object (hermiq#41). A\n\t\t// first-class companion to api-call: resolves the object context\n\t\t// (register/schema/objectId) and POSTs run-on-object. Any `confirm`\n\t\t// on the action is INTENT the rendering surface consumed BEFORE\n\t\t// dispatch (api-call / object-op precedent) — no gating here. hermiq\n\t\t// is NOT hard-required: an app-level 404 surfaces a graceful toast.\n\t\t\treturn executeAgentAction(action, context)\n\t\t}\n\n\t\tcase 'toggle': {\n\t\t// A toggle is a stateful two-way control (GET state on mount,\n\t\t// write on click) — it is RENDERED by the header-actions surface\n\t\t// (CnActionButtons), never dispatched as a one-shot action.\n\t\t// eslint-disable-next-line no-console\n\t\t\tconsole.warn('[dispatchAction] \"toggle\" is a stateful header-actions control rendered by CnActionButtons — it cannot be dispatched.')\n\t\t\treturn\n\t\t}\n\n\t\tcase 'object-op': {\n\t\t// Declarative mutation of an OpenRegister object, dispatched via the\n\t\t// shared object store (ADR-049). The manifest declares INTENT only:\n\t\t// authorization-shaped fields on the action (`role`, `allow`, …) are\n\t\t// NEVER consulted here — OpenRegister RBAC is the single authority\n\t\t// (ADR-022 / ADR-023) and a forbidden mutation is rejected server-side.\n\t\t// The store mutates its caches only on success, so a rejected write\n\t\t// surfaces as an error with no local state change.\n\t\t\tconst op = action.op\n\t\t\tif (op !== 'patch' && op !== 'delete' && op !== 'create') {\n\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.warn(`[dispatchAction] object-op has invalid op \"${op}\" (expected patch | delete | create).`)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst store = context.objectStore\n\t\t\tif (!store || typeof store.saveObject !== 'function' || typeof store.deleteObject !== 'function') {\n\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.warn('[dispatchAction] object-op requires context.objectStore (useObjectStore shape).')\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst source = context.source\n\t\t\tif (!source || !source.register || !source.schema) {\n\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.warn('[dispatchAction] object-op requires context.source with register + schema.')\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst type = resolveObjectOpType(store, source)\n\n\t\t\tif (op === 'create') {\n\t\t\t\treturn store.saveObject(type, { ...(action.values || {}) })\n\t\t\t}\n\n\t\t\tconst row = context.row\n\t\t\tconst id = rowObjectId(row)\n\t\t\tif (id === null) {\n\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.warn(`[dispatchAction] object-op \"${op}\" is row-scoped and requires context.row with an id.`)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (op === 'delete') {\n\t\t\t\treturn store.deleteObject(type, id)\n\t\t\t}\n\t\t\t// patch: only the action's values, as a PATCH, so every other key\n\t\t\t// keeps its stored value. A store without patchObject writes the\n\t\t\t// row's object merged with the values.\n\t\t\tif (typeof store.patchObject === 'function') {\n\t\t\t\treturn store.patchObject(type, id, { ...(action.values || {}) })\n\t\t\t}\n\t\t\treturn store.saveObject(type, { ...row, ...(action.values || {}), id })\n\t\t}\n\n\t\tdefault:\n\t\t// eslint-disable-next-line no-console\n\t\t\tconsole.warn(`[dispatchAction] Unknown action type \"${type}\".`)\n\t}\n}\n"],"names":["t"],"mappings":"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AG;AACH,EAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE;AAC7B,EAAE;AACF,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;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,cAAc,CAAC,MAAM,EAAE,OAAO,GAAG,EAAE,EAAE;AACrD,CAAC,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE;AAC5C;AACA,EAAE,OAAO,CAAC,IAAI,CAAC,2CAA2C,EAAE,MAAM,EAAC;AACnE,EAAE,MAAM;AACR,EAAE;AACF;AACA;AACA,CAAC,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,IAAI,UAAS;AACtC;AACA,CAAC,QAAQ,IAAI;AACb,EAAE,KAAK,SAAS,EAAE;AAClB,GAAG,MAAM,WAAW,GAAG,MAAM,CAAC,QAAO;AACrC,GAAG,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,GAAE;AAC1C;AACA,GAAG,IAAI,CAAC,WAAW,IAAI,OAAO,QAAQ,CAAC,WAAW,CAAC,KAAK,UAAU,EAAE;AACpE;AACA,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,0BAA0B,EAAE,WAAW,CAAC,gCAAgC,CAAC,EAAC;AAC5F,IAAI,MAAM;AACV,I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"}
1
+ {"version":3,"file":"actionsDispatcher.js","sources":["../../../src/utils/actionsDispatcher.js"],"sourcesContent":["/**\n * SPDX-FileCopyrightText: 2024 Conduction B.V.\n * SPDX-License-Identifier: EUPL-1.2\n *\n * actionsDispatcher — unified action dispatcher for v2 manifest actions.\n *\n * Dispatches an action object against a context. All dispatch types are\n * handled without throwing — errors surface as console.warn calls.\n * Types: handler | open-modal | open-page | navigate | object-op (the\n * declarative OpenRegister mutation verb added by ADR-049 — dispatched\n * via the shared object store, intent-only, RBAC stays server-side) |\n * export (opens the shared CnMassExportDialog export launcher configured\n * via the action's `entities[]` / `formats[]` — Wave 1 of\n * nextcloud-vue#91; the host page provides `context.openExport`) |\n * open-form (Wave 3 — schema-driven create dialog; the rendering host\n * provides `context.openForm`) | refresh (Wave 3 — bumps the page-level\n * refresh signal on the `cn:page:refresh` event-bus channel) | api-call\n * (Wave 3 — POST/PUT a configured app endpoint with success/error toasts\n * and an automatic page refresh; any `confirm` on the action is INTENT\n * consumed by the rendering surface BEFORE dispatch, like object-op) |\n * agent (run a governed hermiq agent against the page object via\n * POST /apps/hermiq/api/agents/{agent}/run-on-object — hermiq#41; a\n * first-class companion to api-call that resolves the register/schema/\n * objectId context for the author and fail-closes when hermiq is absent) |\n * run-node (manifest-run-node-action — invoke ONE OpenRegister flow node\n * directly against a subject object via\n * POST /api/flows/{flowId}/nodes/{nodeId}/run; the rendering surface\n * provides context.openRunNode, mirroring open-form, and resolves the\n * node's own declared config form before opening a dialog — see or-flow-run-node).\n *\n * `api-call`'s request body prefers `payload` (DEEP @-token resolution at\n * any nesting depth — object/array, e.g. a Filinq-style\n * `{ dataRefs: [{ id: '@objectId' }] }` body) over the legacy `params`\n * (shallow, one-level filter-map resolution, kept for back-compat). Set\n * `download: true` to request a binary blob response and trigger a\n * browser file download instead of a JSON toast+refresh cycle (filename:\n * `Content-Disposition` header, else the token-resolved `filename`, else\n * `'download.pdf'`; no auto-refresh unless `refresh: true` is explicit).\n *\n * `toggle` (Wave 3) is deliberately NOT dispatchable: a toggle is a\n * stateful two-way control (GET state on mount, write on click) rendered\n * by the header-actions surface (CnActionButtons); dispatching it here\n * warns and no-ops.\n *\n * Spec: REQ-MVR-011 (manifest-v2-renderer) — unified actions dispatcher\n * / ADR-036 Decision 7 / ADR-049 Decision 2 / #91 Wave 3\n */\n\nimport { emit } from '@nextcloud/event-bus'\nimport { translate as t } from '@nextcloud/l10n'\nimport { parseDispositionFilename, triggerBlobDownload } from '../components/CnIndexPage/selfModeIO.js'\nimport { interpolateUrlTokens } from '../composables/useEndpointSource.js'\nimport { routeHref } from './actionLink.js'\nimport { resolveModalEntry } from './builtInModals.js'\nimport {\n\tdropOptionalUnresolved,\n\tdropOptionalUnresolvedDeep,\n\thasUnresolvedDeepTokens,\n\thasUnresolvedTokens,\n\tresolveDeepTokens,\n\tresolveFilterTokens,\n} from './resolveFilterTokens.js'\nimport { schemaRefSlug } from './schemaRefSlug.js'\n\n/** Event-bus channel the page-level Refresh signal broadcasts on (Wave 2). */\nconst PAGE_REFRESH_CHANNEL = 'cn:page:refresh'\n\n/**\n * Whether a `navigate` target leaves the app: it is `http(s)://`,\n * protocol-relative (`//`), or a `mailto:` / `tel:` link. Anything else is an\n * in-app path for the router.\n *\n * vue-router happily accepts an absolute URL as a PATH — `router.push` on\n * `https://youtu.be/x?v=1` matches no route and lands on the fallback with the\n * query carried over, which reads as the app ignoring the link.\n *\n * An allowlist, not a generic `<scheme>://` match: manifests are\n * admin-editable app-wide config, and an external target renders into an\n * anchor `href` and a dispatcher `window.open` — a generic scheme match would\n * accept `javascript://` too.\n *\n * @param {unknown} target The action target to test.\n * @return {boolean} True when the target is external.\n */\nexport function isExternalActionTarget(target) {\n\tif (typeof target !== 'string') {\n\t\treturn false\n\t}\n\treturn /^\\/\\//.test(target) || /^(https?|mailto|tel):/i.test(target)\n}\n\n/**\n * Resolve the object-store type slug for a widget `source` register/schema\n * pair. Reuses an already-registered type whose config matches (so an app's\n * own caches stay coherent); otherwise registers a deterministic\n * `<register>/<schema>` slug on the fly.\n *\n * `source.schema` is routed through {@link schemaRefSlug} before it ever\n * reaches the store or the objects API: a caller that passes a `$ref`\n * schema TITLE (`ReportPeriod`) rather than its slug (`report-period`)\n * would otherwise register — and fetch — a 404 (defect 7, learniq round\n * 1). Idempotent for a caller that already passes a correct slug.\n *\n * A caller that already holds the schema SLUG (not a `$ref` title) passes\n * `{ exactSchema: true }`: the slug is then used exactly as given. Kebab-casing\n * a real camelCase slug (`productCategory` -> `product-category`) asks the\n * objects API for a schema that does not exist and 404s (pipelinq review,\n * round two).\n *\n * @spec openspec/changes/review-round-two/specs/schema-utilities/spec.md\n *\n * A title is not always registered under its kebab form: learniq holds\n * `LearniqSettings` and `SubjectTeacherAssignment` as written. So a type\n * registered here for a value the kebab rule CHANGED also carries the value\n * as written as its `schemaFallback`, and the store retries with it once\n * when the kebab form answers 404 (keeping it from then on). The kebab form\n * is still tried first, so a schema registered under it costs nothing.\n *\n * @spec openspec/changes/zuiddrecht-pixel-gaps-2/specs/zuiddrecht-pixel-gaps-2/spec.md#requirement-a-schema-title-falls-back-to-its-written-form\n * @param {object} store The object store instance (useObjectStore shape).\n * @param {{register: (string|number), schema: (string|number)}} source The widget source.\n * @param {{exactSchema: (boolean|undefined)}} [options] `exactSchema: true` skips the title-to-slug step.\n * @return {string} The type slug to use for store CRUD calls.\n */\nexport function resolveObjectOpType(store, source, options = {}) {\n\tconst register = String(source.register)\n\tconst schema = options.exactSchema === true ? String(source.schema) : String(schemaRefSlug(source.schema))\n\tconst written = typeof source.schema === 'string'\n\t\t? source.schema.substring(source.schema.lastIndexOf('/') + 1)\n\t\t: ''\n\tconst registry = store.objectTypeRegistry || {}\n\tfor (const [slug, config] of Object.entries(registry)) {\n\t\tif (!config) {\n\t\t\tcontinue\n\t\t}\n\t\tif ((String(config.register) === register && String(config.schema) === schema)\n\t\t\t|| (config.registerSlug === register && config.schemaSlug === schema)) {\n\t\t\treturn slug\n\t\t}\n\t}\n\tconst slug = `${register}/${schema}`\n\tif (!registry[slug]) {\n\t\tstore.registerObjectType(slug, schema, register)\n\t\tif (written !== '' && written !== schema && typeof store.setSchemaFallback === 'function') {\n\t\t\tstore.setSchemaFallback(slug, written)\n\t\t}\n\t}\n\treturn slug\n}\n\n/**\n * Extract an OpenRegister object's id from a row (top-level `id` wins,\n * `@self.id` metadata fallback).\n *\n * @param {object} row The row object.\n * @return {string|number|null} The object id, or null when absent.\n */\nfunction rowObjectId(row) {\n\tif (!row || typeof row !== 'object') {\n\t\treturn null\n\t}\n\tif (row.id !== undefined && row.id !== null) {\n\t\treturn row.id\n\t}\n\tconst self = row['@self']\n\tif (self && typeof self === 'object' && self.id !== undefined && self.id !== null) {\n\t\treturn self.id\n\t}\n\treturn null\n}\n\n/**\n * Extract a saved OpenRegister object's id for a post-save deep-link:\n * top-level `id`, then `uuid`, then the `@self.id` metadata fallback.\n *\n * @param {object} saved The saved record returned by the object store.\n * @return {string|number|null} The object id, or null when absent.\n */\nexport function savedObjectId(saved) {\n\tif (!saved || typeof saved !== 'object') {\n\t\treturn null\n\t}\n\tif (saved.id !== undefined && saved.id !== null) {\n\t\treturn saved.id\n\t}\n\tif (saved.uuid !== undefined && saved.uuid !== null) {\n\t\treturn saved.uuid\n\t}\n\tconst self = saved['@self']\n\tif (self && typeof self === 'object' && self.id !== undefined && self.id !== null) {\n\t\treturn self.id\n\t}\n\treturn null\n}\n\n/**\n * Resolve a manifest-named FUNCTION out of the v2 registry, falling back to the\n * legacy customComponents map.\n *\n * A manifest names a behaviour the same way it names a component — by string —\n * so every surface that dispatches one (`actions[].handler`,\n * `bulkActions[].handler`, `headerActions[].handler`, `config.createOverride`)\n * has to agree on where that string is looked up and what counts as a match.\n * Recognised shapes, in order:\n * 1. a registry entry exposing the function as `.handler` / `.fn` (the\n * `kind: 'handler'` and `kind: 'create-override'` entries),\n * 2. a directly function-valued registry entry,\n * 3. a function-valued legacy `customComponents` entry.\n *\n * The legacy map stays last so an app that has not migrated is unchanged, and\n * so an app mid-migration can move its handlers over one at a time.\n *\n * @param {string} name The registered handler name.\n * @param {object} registry The v2 component registry.\n * @param {object} customComponents The legacy customComponents map.\n * @return {?((scope?: object) => unknown)} The handler, or null when nothing of that name is a function.\n */\nexport function resolveRegisteredHandler(name, registry, customComponents) {\n\tif (typeof name !== 'string' || name === '') {\n\t\treturn null\n\t}\n\tconst entry = (registry || {})[name]\n\tif (typeof entry === 'function') {\n\t\treturn entry\n\t}\n\tif (entry && typeof entry === 'object') {\n\t\tif (typeof entry.handler === 'function') {\n\t\t\treturn entry.handler\n\t\t}\n\t\tif (typeof entry.fn === 'function') {\n\t\t\treturn entry.fn\n\t\t}\n\t}\n\tconst legacy = (customComponents || {})[name]\n\treturn typeof legacy === 'function' ? legacy : null\n}\n\n/**\n * Resolve a named create-override handler out of the v2 registry (or the\n * legacy customComponents map) by value shape.\n *\n * A create-override is a plain async function that replaces the default\n * `objectStore.saveObject` persist path — needed whenever a schema requires a\n * field the create form cannot supply on its own (a server-minted foreign key,\n * say).\n *\n * Shared by CnPageRenderer (page-level `config.createOverride` → CnIndexPage's\n * prop) and CnActionButtons (per-action `createOverride` on an `open-form`), so\n * the two surfaces cannot drift on what counts as a valid handler.\n *\n * @param {string} name The registered handler name.\n * @param {object} registry The v2 component registry.\n * @param {object} customComponents The legacy customComponents map.\n * @return {?((props?: object) => Promise<unknown>)} The async create handler, or null when unresolved.\n */\nexport function resolveCreateOverrideHandler(name, registry, customComponents) {\n\treturn resolveRegisteredHandler(name, registry, customComponents)\n}\n\n/**\n * Build the vue-router push location for an `open-form` action's\n * `onSuccessRoute`, merging the saved object's id into the route params so\n * the post-save navigation can deep-link to the created object's detail page\n * (#91).\n *\n * `onSuccessRoute` may be:\n * - a STRING route NAME → `{ name, params: { id } }`. The saved id lands\n * under the default `id` param; a route without an `:id` segment simply\n * ignores the extra param, so a bare-name route keeps working unchanged\n * (backward compatible).\n * - an OBJECT `{ name, paramField?, objectParam? }` → the id is placed\n * under `paramField` (default `id`), and — when `objectParam` is set —\n * the whole saved object is passed under that param key too (so a\n * `props: true` detail route can render the record without a refetch).\n *\n * The id is read via {@link savedObjectId} (`saved.id` → `saved.uuid` →\n * `saved['@self'].id`). Returns `null` when no route name is resolvable, so\n * the caller can skip the navigation.\n *\n * @param {(string|{name: string, paramField?: string, objectParam?: string})} onSuccessRoute The action's onSuccessRoute config.\n * @param {object} saved The saved OpenRegister object.\n * @return {{name: string, params: object}|null} The router push location, or null.\n */\nexport function buildOnSuccessRoute(onSuccessRoute, saved) {\n\tconst spec = typeof onSuccessRoute === 'string'\n\t\t? { name: onSuccessRoute }\n\t\t: (onSuccessRoute && typeof onSuccessRoute === 'object' ? onSuccessRoute : null)\n\tif (!spec || typeof spec.name !== 'string' || spec.name === '') {\n\t\treturn null\n\t}\n\tconst params = {}\n\tconst id = savedObjectId(saved)\n\tif (id !== null && id !== undefined) {\n\t\tparams[spec.paramField || 'id'] = id\n\t}\n\tif (spec.objectParam && saved && typeof saved === 'object') {\n\t\tparams[spec.objectParam] = saved\n\t}\n\treturn { name: spec.name, params }\n}\n\n/**\n * Run a manifest-authored toast message through the host translate function.\n *\n * `successMessage` / `errorMessage` are English source strings authored in the\n * manifest (ADR-007), so they need the SAME translator the rest of the page\n * chrome uses — the consumer's bound `t()`, handed to the dispatcher by the\n * rendering surface as `context.translate` (which itself comes from the\n * `cnTranslate` CnAppRoot provides).\n *\n * A pure pass-through: with no translator, no message, or a catalogue that\n * lacks the key, the message is returned byte-identical. Server-supplied\n * messages are data and are never routed through here.\n *\n * @param {unknown} message The manifest-authored message (may be undefined).\n * @param {object} context The dispatch context (`context.translate` optional).\n * @return {unknown} The translated message, or the input unchanged.\n */\nfunction translateMessage(message, context) {\n\tconst fn = context && context.translate\n\tif (!message || typeof fn !== 'function') {\n\t\treturn message\n\t}\n\treturn fn(message)\n}\n\n/**\n * Interpolate the `api-call` URL/filename token grammar inside a string:\n * the `{objectId}` BRACE convention (a literal placeholder some manifests\n * use for path templates, matching the OpenRegister credential-broker path\n * style) as well as the full `@objectId` / `@object.<field>` /\n * `@workspace.<key>` / `@config.<key>` grammar {@link interpolateUrlTokens}\n * already understands. Unresolved `@`-tokens and an unresolved\n * `{objectId}` both collapse to an empty string (never leak a literal\n * placeholder into a request URL or a downloaded filename).\n *\n * @param {string} str The raw string (an action's `url` or `filename`).\n * @param {{objectId?: (string|number), object?: object, workspace?: object, config?: object}} ctx Token context.\n * @return {string} The interpolated string.\n */\nfunction interpolateActionString(str, ctx) {\n\tif (typeof str !== 'string') {\n\t\treturn str\n\t}\n\tconst braced = str.replace(/\\{objectId\\}/g, () => {\n\t\tconst id = ctx.objectId\n\t\treturn (id === undefined || id === null) ? '' : String(id)\n\t})\n\treturn interpolateUrlTokens(braced, ctx)\n}\n\n/**\n * Interpolate an action's `target` URL — the same grammar `url` runs.\n *\n * Exported because the rendering surface resolves a target BEFORE deciding\n * whether it is an external link, and that decision happens there rather than\n * in the dispatcher.\n *\n * @param {string} target The action's raw `target`.\n * @param {object} ctx Token context (`{ objectId?, object?, workspace?, config? }`).\n *\n * @return {string} The interpolated target.\n */\nexport function interpolateActionTarget(target, ctx) {\n\treturn interpolateActionString(target || '', ctx || {})\n}\n\n// The tokens interpolateActionString resolves; a bare `@` or `{` is not one.\nconst ACTION_TARGET_TOKEN = /@(?:objectId|object\\.|page\\.|workspace\\.|config\\.|range\\.)|\\{objectId\\}/\n\n/**\n * Whether an action target carries a token that interpolation would resolve,\n * so it can only be known once the page context is. A `mailto:` address or a\n * URL with an `@handle` in it has none.\n *\n * @param {string} target The action's raw `target`.\n * @return {boolean}\n */\nexport function hasActionTargetTokens(target) {\n\treturn typeof target === 'string' && ACTION_TARGET_TOKEN.test(target)\n}\n\n/**\n * The link an action renders as when its only job is to navigate to a target\n * known at render time: `navigate` (token-interpolated like the dispatcher)\n * and `open-page`. Anything else, a `confirm: true` action, or an in-app\n * target the router cannot resolve answers null and keeps dispatching.\n *\n * `to` is what a plain click hands the router (null for an external URL,\n * which the browser opens in a new tab like the dispatcher's `window.open`).\n *\n * @param {object} action The manifest action.\n * @param {{router?: object, tokenCtx?: object}} [context] The dispatch context.\n * @return {{href: string, to: (string|object|null), external: boolean}|null} The link, or null.\n */\nexport function actionLink(action, context = {}) {\n\tif (!action || typeof action !== 'object' || action.confirm) {\n\t\treturn null\n\t}\n\tif (action.type === 'navigate') {\n\t\tconst target = interpolateActionString(action.target || '', context.tokenCtx || {})\n\t\tif (!target) {\n\t\t\treturn null\n\t\t}\n\t\tif (isExternalActionTarget(target)) {\n\t\t\treturn { href: target, to: null, external: true }\n\t\t}\n\t\tconst href = routeHref(target, context.router)\n\t\treturn href ? { href, to: target, external: false } : null\n\t}\n\tif (action.type === 'open-page') {\n\t\tif (typeof action.target !== 'string' || action.target.length === 0) {\n\t\t\treturn null\n\t\t}\n\t\tconst to = { name: action.target }\n\t\tconst href = routeHref(to, context.router)\n\t\treturn href ? { href, to, external: false } : null\n\t}\n\treturn null\n}\n\n/**\n * Execute a Wave-3 `api-call` action: POST/PUT the configured app endpoint\n * (URL + body run the SAME @-token grammar endpoint sources use), toast the\n * outcome via @nextcloud/dialogs, then — unless `action.refresh` is `false`\n * (or, for a `download` action, unless `action.refresh` is explicitly\n * `true`) — bump the page-level refresh signal so every endpoint-bound\n * widget refetches. Confirm-gating is the RENDERING SURFACE's job (the\n * `confirm` field is intent, object-op precedent): this runs after any\n * confirmation already happened.\n *\n * The request body prefers `action.payload` (DEEP token resolution, any\n * nesting — {@link resolveDeepTokens}) over the legacy `action.params`\n * (shallow, one-level filter-map resolution — unchanged for back-compat).\n * A required token left unresolved anywhere in the body BLOCKS the call\n * (error toast) rather than sending a literal `@objectId` to the server.\n *\n * `action.download === true` requests the response as a binary blob\n * (`responseType: 'blob'`) and triggers a browser file download — the\n * filename comes from the response's `Content-Disposition` header, else\n * the token-resolved `action.filename`, else `'download.pdf'`.\n *\n * Never throws: a failed call resolves `{ ok: false, error }` after the\n * error toast (so a confirm dialog can await the outcome).\n *\n * @param {object} action The api-call action (`url`, `method?`, `payload?`,\n * `params?`, `download?`, `filename?`, `successMessage?`, `errorMessage?`,\n * `refresh?`).\n * @param {object} context Runtime context; `context.tokenCtx` is the token\n * context (`{ objectId?, object?, workspace?, config? }`) the URL/body\n * resolve against.\n * @return {Promise<{ok: boolean, data?: unknown, error?: unknown}>} The call outcome.\n */\nasync function executeApiCall(action, context) {\n\tconst tokenCtx = context.tokenCtx || {}\n\tconst url = interpolateActionString(action.url || '', tokenCtx)\n\n\tconst hasPayload = action.payload && typeof action.payload === 'object' && !Array.isArray(action.payload)\n\tconst body = hasPayload\n\t\t? dropOptionalUnresolvedDeep(resolveDeepTokens(action.payload, tokenCtx))\n\t\t: dropOptionalUnresolved(resolveFilterTokens(action.params || {}, tokenCtx))\n\tconst bodyBlocked = hasPayload ? hasUnresolvedDeepTokens(body) : hasUnresolvedTokens(body)\n\n\tif (!url || bodyBlocked) {\n\t\t// eslint-disable-next-line no-console\n\t\tconsole.warn('[dispatchAction] api-call is missing its url or a required token is unresolved — skipping.', action)\n\t\treturn { ok: false, error: new Error('api-call blocked') }\n\t}\n\tconst method = String(action.method || 'POST').toUpperCase() === 'PUT' ? 'put' : 'post'\n\tconst isDownload = action.download === true\n\tconst [{ default: axios }, { generateUrl }, dialogs] = await Promise.all([\n\t\timport('@nextcloud/axios'),\n\t\timport('@nextcloud/router'),\n\t\timport('@nextcloud/dialogs'),\n\t])\n\tconst target = /^https?:\\/\\//i.test(url) ? url : generateUrl(url)\n\ttry {\n\t\t// Only pass a third axios config arg for a download call — an\n\t\t// explicit `undefined` third argument would otherwise change the\n\t\t// call shape for every existing (non-download) api-call consumer/test.\n\t\tconst res = isDownload\n\t\t\t? await axios[method](target, body, { responseType: 'blob' })\n\t\t\t: await axios[method](target, body)\n\t\tif (isDownload) {\n\t\t\tconst filename = parseDispositionFilename(\n\t\t\t\tres && res.headers && res.headers['content-disposition'],\n\t\t\t\tinterpolateActionString(action.filename, tokenCtx) || 'download.pdf',\n\t\t\t)\n\t\t\ttriggerBlobDownload(res.data, filename)\n\t\t}\n\t\tif (typeof dialogs.showSuccess === 'function') {\n\t\t\tdialogs.showSuccess(translateMessage(action.successMessage, context) || t('nextcloud-vue', 'Action completed.'))\n\t\t}\n\t\tconst shouldRefresh = isDownload ? action.refresh === true : action.refresh !== false\n\t\tif (shouldRefresh) {\n\t\t\temit(PAGE_REFRESH_CHANNEL, {})\n\t\t}\n\t\treturn { ok: true, data: res && res.data }\n\t} catch (error) {\n\t\tconst serverMessage = error && error.response && error.response.data\n\t\t\t&& (error.response.data.error || error.response.data.message)\n\t\tif (typeof dialogs.showError === 'function') {\n\t\t\tdialogs.showError(translateMessage(action.errorMessage, context) || serverMessage || t('nextcloud-vue', 'Action failed.'))\n\t\t}\n\t\treturn { ok: false, error }\n\t}\n}\n\n/**\n * Resolve an agent-action object reference (`register` / `schema` / `objectId`):\n * an explicitly-declared action value WINS (it may itself be an @-token string,\n * interpolated against the token context), otherwise it falls back to the page\n * object context default (`tokenCtx.register` / `.schema` / `.objectId`). An\n * unresolved token collapses to an empty string (never leaks a literal `@objectId`\n * to the server); a `{ slug | id }` object (a schema holder) is flattened to its\n * slug/id.\n *\n * @param {unknown} actionVal The action's explicit value (may be undefined or an @-token).\n * @param {unknown} ctxDefault The page-context default (`tokenCtx.<field>`).\n * @param {object} tokenCtx The token context the @-tokens resolve against.\n * @return {string} The resolved reference, or '' when unresolved/absent.\n */\nfunction resolveAgentRef(actionVal, ctxDefault, tokenCtx) {\n\tlet v = actionVal\n\tif (v === undefined || v === null || v === '') {\n\t\tv = ctxDefault\n\t} else if (typeof v === 'string') {\n\t\tv = interpolateActionString(v, tokenCtx)\n\t}\n\tif (v && typeof v === 'object') {\n\t\treturn String(v.slug || v.id || '')\n\t}\n\tif (v === undefined || v === null) {\n\t\treturn ''\n\t}\n\treturn String(v)\n}\n\n/**\n * Execute an `agent` action: run a governed hermiq agent against the page's\n * OpenRegister object. Resolves the object context (`register` / `schema` /\n * `objectId` — explicit action fields override, else default to the page's\n * `@register` / `@schema` / `@objectId` context) and POSTs\n * `{ register, schema, objectId, resultField?, skill?, prompt? }` to hermiq's\n * object-RBAC-scoped run endpoint `/apps/hermiq/api/agents/{agent}/run-on-object`\n * (hermiq#41), which dispatches the governed `AgentRunRequestedEvent`.\n *\n * A first-class companion to `type:\"api-call\"` — the author declares \"run agent\n * here\" without hand-wiring the URL/body. `type:\"api-call\"` remains the escape\n * hatch for a bespoke body.\n *\n * Fail-closed. An unresolved REQUIRED `@objectId` (or a missing agent/register/\n * schema) BLOCKS the call (warn) rather than POSTing a literal token. On the\n * server's 202 it toasts `successMessage` (default 'Run queued') and — unless\n * `refresh: false` — bumps the page refresh signal. A 403 / 404 with a structured\n * error body fail-closes with that message; a 404 with NO structured body is read\n * as \"hermiq absent\" and toasts a graceful 'agent runtime unavailable' — the\n * dispatcher NEVER hard-requires hermiq to be installed. Never throws.\n *\n * @param {object} action The agent action (`agent`, `skill?`, `prompt?`,\n * `resultField?`, `register?`, `schema?`, `objectId?`, `successMessage?`,\n * `errorMessage?`, `refresh?`).\n * @param {object} context Runtime context; `context.tokenCtx` is the token\n * context (`{ objectId?, object?, register?, schema?, workspace?, config? }`).\n * @return {Promise<{ok: boolean, data?: unknown, error?: unknown}>} The call outcome.\n */\nasync function executeAgentAction(action, context) {\n\tconst tokenCtx = context.tokenCtx || {}\n\tconst agent = resolveAgentRef(action.agent, undefined, tokenCtx)\n\tconst register = resolveAgentRef(action.register, tokenCtx.register, tokenCtx)\n\tconst schema = resolveAgentRef(action.schema, tokenCtx.schema, tokenCtx)\n\tconst objectId = resolveAgentRef(action.objectId, tokenCtx.objectId, tokenCtx)\n\n\tif (!agent || !register || !schema || !objectId) {\n\t\t// eslint-disable-next-line no-console\n\t\tconsole.warn('[dispatchAction] agent action is missing its agent or a required object-context token (register/schema/objectId) is unresolved — skipping.', action)\n\t\treturn { ok: false, error: new Error('agent action blocked') }\n\t}\n\n\tconst body = { register, schema, objectId }\n\tconst resultField = resolveAgentRef(action.resultField, undefined, tokenCtx)\n\tif (resultField) {\n\t\tbody.resultField = resultField\n\t}\n\tconst skill = resolveAgentRef(action.skill, undefined, tokenCtx)\n\tif (skill) {\n\t\tbody.skill = skill\n\t}\n\tif (typeof action.prompt === 'string' && action.prompt !== '') {\n\t\tbody.prompt = interpolateActionString(action.prompt, tokenCtx)\n\t}\n\n\tconst [{ default: axios }, { generateUrl }, dialogs] = await Promise.all([\n\t\timport('@nextcloud/axios'),\n\t\timport('@nextcloud/router'),\n\t\timport('@nextcloud/dialogs'),\n\t])\n\tconst target = generateUrl(`/apps/hermiq/api/agents/${encodeURIComponent(agent)}/run-on-object`)\n\ttry {\n\t\tconst res = await axios.post(target, body)\n\t\tif (typeof dialogs.showSuccess === 'function') {\n\t\t\tdialogs.showSuccess(translateMessage(action.successMessage, context) || t('nextcloud-vue', 'Run queued'))\n\t\t}\n\t\tif (action.refresh !== false) {\n\t\t\temit(PAGE_REFRESH_CHANNEL, {})\n\t\t}\n\t\treturn { ok: true, data: res && res.data }\n\t} catch (error) {\n\t\tconst response = error && error.response\n\t\tconst status = response && response.status\n\t\tconst serverMessage = response && response.data\n\t\t\t&& (response.data.error || response.data.message)\n\t\t// A 404 with NO structured error body = hermiq is not installed (the app\n\t\t// route 404s at the NC level) — surface a graceful \"runtime unavailable\"\n\t\t// rather than a fail-closed authorization message.\n\t\tconst hermiqAbsent = status === 404 && !serverMessage\n\t\tif (typeof dialogs.showError === 'function') {\n\t\t\tconst msg = hermiqAbsent\n\t\t\t\t? t('nextcloud-vue', 'Agent runtime unavailable')\n\t\t\t\t: (translateMessage(action.errorMessage, context) || serverMessage || t('nextcloud-vue', 'Action failed.'))\n\t\t\tdialogs.showError(msg)\n\t\t}\n\t\treturn { ok: false, error }\n\t}\n}\n\n/**\n * POST the run-node call: `POST /apps/openregister/api/flows/{flowId}/nodes/{nodeId}/run`.\n *\n * This is the SECOND half of `run-node` (manifest-run-node-action / or-flow-run-node) —\n * the first half is `context.openRunNode` in the `dispatchAction` switch below, which\n * only OPENS the config dialog (or decides none is needed) and never itself waits for\n * the person. Once the rendering surface has a `config` object (from the dialog's\n * submit, or `{}` when the node's declared form was empty), it calls this directly —\n * it is not reached through `dispatchAction`'s switch, because by that point there is\n * no further \"type\" dispatch to do, only the call itself, same as `executeAgentAction`\n * is called directly by `case 'api-call'`'s sibling rather than re-entering the switch.\n *\n * Fail-closed exactly like `executeAgentAction`: an unresolved REQUIRED subject\n * (`action.subject`, defaulting to the page's `@objectId`) or a missing\n * `flowId`/`nodeId` BLOCKS the call (warn) rather than POSTing a literal token or an\n * incomplete subject reference. The subject sent is `{ uuid, register, schema }` —\n * OpenRegister's `FlowNodeRunController::resolveAuthorizedSubject()` needs all three\n * to resolve the object and evaluate the caller's object-RBAC permission on it; `register`\n * / `schema` default to the page's own `@register` / `@schema` context, the same\n * defaulting `agent` already uses.\n *\n * A 403 here means the caller holds no update permission on the subject\n * (OpenRegister's object-RBAC, evaluated server-side — RN-1(c)) — this function does not\n * special-case it beyond surfacing the server's message, the same fail-closed handling\n * `api-call` / `agent` already give a rejected call.\n *\n * @param {object} action The run-node action (`flowId`, `nodeId`, `subject?`,\n * `register?`, `schema?`, `successMessage?`, `errorMessage?`, `refresh?`).\n * @param {object} context Runtime context — needs `context.tokenCtx` and, for a\n * localised toast, `context.translate`.\n * @param {object} [config] The node's collected config (from its `configForm()`\n * dialog), or `{}` for a node with no declared fields.\n * @return {Promise<{ok: boolean, data?: object, error?: Error}>} The call outcome —\n * `data` is the created `FlowRun` on success.\n *\n * @spec openspec/changes/manifest-run-node-action/specs/manifest-run-node-action/spec.md#requirement-a-run-node-action-invokes-one-flow-node-against-the-page-object\n */\nexport async function postRunNode(action, context, config = {}) {\n\tconst tokenCtx = context.tokenCtx || {}\n\tconst flowId = resolveAgentRef(action.flowId, undefined, tokenCtx)\n\tconst nodeId = resolveAgentRef(action.nodeId, undefined, tokenCtx)\n\tconst uuid = resolveAgentRef(action.subject, tokenCtx.objectId, tokenCtx)\n\tconst register = resolveAgentRef(action.register, tokenCtx.register, tokenCtx)\n\tconst schema = resolveAgentRef(action.schema, tokenCtx.schema, tokenCtx)\n\n\tif (!flowId || !nodeId || !uuid || !register || !schema) {\n\t\t// eslint-disable-next-line no-console\n\t\tconsole.warn('[dispatchAction] run-node is missing flowId/nodeId or a required subject token (objectId/register/schema) is unresolved — skipping.', action)\n\t\treturn { ok: false, error: new Error('run-node blocked') }\n\t}\n\n\tconst [{ default: axios }, { generateUrl }, dialogs] = await Promise.all([\n\t\timport('@nextcloud/axios'),\n\t\timport('@nextcloud/router'),\n\t\timport('@nextcloud/dialogs'),\n\t])\n\tconst target = generateUrl(`/apps/openregister/api/flows/${encodeURIComponent(flowId)}/nodes/${encodeURIComponent(nodeId)}/run`)\n\ttry {\n\t\tconst res = await axios.post(target, { subject: { uuid, register, schema }, config: config || {} })\n\t\tif (typeof dialogs.showSuccess === 'function') {\n\t\t\tdialogs.showSuccess(translateMessage(action.successMessage, context) || t('nextcloud-vue', 'Run completed.'))\n\t\t}\n\t\tif (action.refresh !== false) {\n\t\t\temit(PAGE_REFRESH_CHANNEL, {})\n\t\t}\n\t\treturn { ok: true, data: res && res.data }\n\t} catch (error) {\n\t\tconst response = error && error.response\n\t\tconst serverMessage = response && response.data\n\t\t\t&& (response.data.error || response.data.message)\n\t\tif (typeof dialogs.showError === 'function') {\n\t\t\tdialogs.showError(translateMessage(action.errorMessage, context) || serverMessage || t('nextcloud-vue', 'Action failed.'))\n\t\t}\n\t\treturn { ok: false, error }\n\t}\n}\n\n/**\n * Dispatch a v2 manifest action.\n *\n * @param {object} action The action object from the manifest.\n * @param {string} [action.type] Dispatch type: \"handler\" | \"open-modal\" | \"open-page\" | \"navigate\" |\n * \"object-op\" | \"export\" | \"open-form\" | \"refresh\" | \"api-call\" | \"agent\".\n * When absent, treated as \"handler\" for v1 backward compatibility.\n * @param {string} [action.handler] Registry key for \"handler\" type. For \"export\": the optional\n * handler invoked by the host with the dialog's confirm payload (`{ format, entity }`).\n * @param {Array} [action.args] Arguments spread to the handler function.\n * @param {string} [action.target] Target for \"open-modal\", \"open-page\", and \"navigate\" types.\n * @param {object} [action.props] Props forwarded to modal for \"open-modal\" type.\n * @param {string} [action.op] \"object-op\" only: mutation verb — \"patch\" | \"delete\" | \"create\".\n * @param {object} [action.values] \"object-op\" only: the verb's payload — the partial object\n * merged over the row for \"patch\", the new object's properties for \"create\"; ignored for \"delete\".\n * @param {boolean} [action.confirm] \"object-op\" only: confirm-gating INTENT consumed by the\n * rendering host (CnWidgetObjectTable routes it through CnConfirmDialog) — the dispatcher\n * itself never gates; it is called after any confirmation already happened.\n * @param {Array<{id: string, label: string}>} [action.entities] \"export\" only: selectable\n * entity types offered by the export launcher (e.g. Leads / Requests). Optional — when\n * absent the dialog shows only the format picker.\n * @param {Array<string|{id: string, label: string}>} [action.formats] \"export\" only: the\n * offered export formats (bare ids like \"csv\" or full `{id, label}` entries). Optional —\n * the dialog's built-in Excel/CSV defaults apply when absent.\n * @param {string} [action.description] \"export\" only: pre-translated description shown\n * above the pickers.\n * @param {string} [action.url] \"api-call\" only: the app endpoint — app-relative (routed\n * through generateUrl) or absolute. May interpolate the shared URL tokens\n * (`@objectId`, `@object.<field>`, `@workspace.<key>`, `@config.<key>`, and the\n * `{objectId}` brace form).\n * @param {string} [action.method] \"api-call\" only: \"POST\" (default) | \"PUT\".\n * @param {object} [action.payload] \"api-call\" only: the JSON body — preferred over `params`.\n * Values resolve the shared `@`-token grammar RECURSIVELY at any nesting depth (objects\n * and arrays of objects, e.g. `{ dataRefs: [{ id: '@objectId' }] }`); optional (`…?`)\n * tokens drop when unresolved anywhere in the tree, an unresolved REQUIRED token blocks\n * the call. When set, `params` is ignored.\n * @param {object} [action.params] \"api-call\" only: legacy JSON body (ignored when `payload`\n * is set). Values pass the shared filter-token grammar ONE level deep; optional (`…?`)\n * tokens drop when unresolved, an unresolved REQUIRED token blocks the call.\n * @param {boolean} [action.download] \"api-call\" only: request the response as a binary blob\n * (`responseType: 'blob'`) and trigger a browser file download instead of a JSON\n * toast+refresh cycle. Default `false`.\n * @param {string} [action.filename] \"api-call\" `download: true` only: fallback filename when\n * the response carries no `Content-Disposition` header (falls back further to\n * `'download.pdf'`). Interpolates the same token grammar as `url`.\n * @param {string} [action.successMessage] \"api-call\" / \"open-form\": pre-translated success\n * toast text (a library default applies when absent).\n * @param {string} [action.errorMessage] \"api-call\" / \"open-form\": pre-translated error toast\n * text (falls back to the server's `error`/`message`, then a library default).\n * @param {boolean} [action.refresh] \"api-call\" / \"agent\" only: bump the `cn:page:refresh` signal\n * after a successful call. Default `true` — EXCEPT for a `download: true` api-call, whose\n * default is `false` (a file download normally shouldn't also force-refetch every widget); set\n * the flag explicitly either way to override.\n * @param {string} [action.agent] \"agent\" only (REQUIRED): the hermiq agent uuid to run against\n * the page object. POSTed to `/apps/hermiq/api/agents/{agent}/run-on-object` (hermiq#41).\n * @param {string} [action.skill] \"agent\" only: optional skill id folded into the governed run.\n * @param {string} [action.prompt] \"agent\" only: optional prompt (interpolates the shared `@`-token\n * grammar inline — `@objectId`, `@object.<field>`, `@workspace.<key>`, `@config.<key>`).\n * @param {string} [action.resultField] \"agent\" only: object field the agent's result is written to.\n * @param {string} [action.register] \"agent\" / \"open-form\": OpenRegister register slug (agent:\n * defaults to the page object context's `@register`).\n * @param {string} [action.schema] \"agent\" / \"open-form\": OpenRegister schema slug (agent: defaults\n * to the page object context's `@schema`).\n * @param {string} [action.objectId] \"agent\" only: the target object id (defaults to the page\n * object context's `@objectId`). An unresolved required token BLOCKS the call (fail-closed).\n *\n * @param {object} context Runtime context.\n * @param {object} [context.router] Vue Router instance. Required for \"open-page\" and \"navigate\".\n * @param {object} [context.registry] Component registry (Record<string, { kind, component }>).\n * Required for \"open-modal\" type.\n * @param {object} [context.handlers] Map of handler name → function. Required for \"handler\" type.\n * @param {(key: string, props?: object) => void} [context.openModal] Opens a modal.\n * Required for \"open-modal\" type.\n * @param {(action: object) => void} [context.openExport] Opens the shared\n * CnMassExportDialog configured from the action. Required for \"export\" type —\n * CnPageRenderer pre-binds it in the `cnDispatchAction` context.\n * @param {(action: object) => void} [context.openForm] Opens the schema-driven\n * create dialog. Required for \"open-form\" type — the rendering surface\n * (CnActionButtons) provides it, mirroring `openExport`. On a successful save the\n * surface navigates to `action.onSuccessRoute` (a route NAME string, or\n * `{name, paramField?, objectParam?}`) via {@link buildOnSuccessRoute}, which merges\n * the saved object's id into the route params so the navigation can deep-link to the\n * created object.\n * @param {(action: object) => void} [context.openRunNode] Opens the\n * node-config dialog (or runs immediately for an empty config form) and\n * POSTs to OpenRegister's direct-invoke endpoint on submit. Required for\n * \"run-node\" type — the rendering surface (CnActionButtons) provides it,\n * mirroring `openForm`.\n * @param {{objectId?: (string|number), object?: object, workspace?: object, config?: object}} [context.tokenCtx]\n * Token context \"api-call\" URLs/params resolve against (the same shape\n * `resolveFilterTokens` / `interpolateUrlTokens` take).\n * @param {(app: string, text: string, vars?: object) => string} [context.translate] The consumer's bound `t()`, the same\n * `cnTranslate` CnAppRoot provides to the page chrome. Applied to the\n * manifest-authored `successMessage` / `errorMessage` of \"api-call\" and\n * \"agent\" so their toasts follow the user's language. Omitted (or a\n * catalogue miss) leaves the message byte-identical.\n * @param {object} [context.objectStore] Object store instance (useObjectStore shape).\n * Required for \"object-op\" type. All mutations go through `saveObject` / `deleteObject`\n * so store caches (and their no-mutation-on-error semantics) apply.\n * @param {{register: (string|number), schema: (string|number)}} [context.source] The widget's\n * declarative source the mutation targets. Required for \"object-op\" type.\n * @param {object} [context.row] The row object a row-scoped \"object-op\" (patch/delete) mutates.\n *\n * @return {Promise<object|boolean|null>|undefined} For \"object-op\": the store call's promise —\n * the saved object (or `null` on a rejected write) for patch/create, `true`/`false` for\n * delete. The store only mutates its local caches on SUCCESS, so a backend (RBAC) rejection\n * surfaces via the store's `errors[type]` without any local state change. For \"api-call\":\n * a promise of `{ ok, data?, error? }` (toasts + refresh already handled). All other types\n * return undefined.\n */\nexport function dispatchAction(action, context = {}) {\n\tif (!action || typeof action !== 'object') {\n\t\t// eslint-disable-next-line no-console\n\t\tconsole.warn('[dispatchAction] Received invalid action:', action)\n\t\treturn\n\t}\n\n\t// Missing type is treated as \"handler\" for v1 backward compatibility\n\tconst type = action.type || 'handler'\n\n\tswitch (type) {\n\t\tcase 'handler': {\n\t\t\tconst handlerName = action.handler\n\t\t\tconst handlers = context.handlers || {}\n\n\t\t\tif (!handlerName || typeof handlers[handlerName] !== 'function') {\n\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.warn(`[dispatchAction] Handler \"${handlerName}\" not found in context.handlers.`)\n\t\t\t\treturn\n\t\t\t}\n\t\t\thandlers[handlerName](...(action.args ?? []))\n\t\t\tbreak\n\t\t}\n\n\t\tcase 'open-modal': {\n\t\t\tconst target = action.target\n\t\t\tconst entry = resolveModalEntry(context.registry, target)\n\n\t\t\tif (!entry) {\n\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.warn(`[dispatchAction] open-modal target \"${target}\" not found in registry.`)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tif (entry.kind !== 'modal') {\n\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.warn(`[dispatchAction] open-modal target \"${target}\" has kind \"${entry.kind}\" (expected \"modal\").`)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tif (typeof context.openModal !== 'function') {\n\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.warn('[dispatchAction] open-modal requires context.openModal to be a function.')\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\t// A prop that is exactly a token (`\"objectId\": \"@objectId\"`) resolves\n\t\t\t// against the page's object; one the page cannot answer stays as written.\n\t\t\tconst props = context.tokenCtx ? resolveDeepTokens(action.props ?? {}, context.tokenCtx) : (action.props ?? {})\n\t\t\tcontext.openModal(target, props)\n\t\t\tbreak\n\t\t}\n\n\t\tcase 'open-page': {\n\t\t\tif (!context.router) {\n\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.warn('[dispatchAction] open-page requires context.router to be a Vue Router instance.')\n\t\t\t\treturn\n\t\t\t}\n\t\t\tcontext.router.push({ name: action.target })\n\t\t\tbreak\n\t\t}\n\n\t\tcase 'navigate': {\n\t\t\t// A target is a URL exactly as `url` is, so it runs the same token\n\t\t\t// grammar. Without this a manifest's `{objectId}` reached the router\n\t\t\t// as those nine literal characters and landed in the address bar.\n\t\t\tconst target = interpolateActionString(action.target || '', context.tokenCtx || {})\n\n\t\t\t// An external target is not a route. Rendering surfaces should give it\n\t\t\t// to the browser as a real link (CnActionButtons does); this is the\n\t\t\t// fallback for a programmatic dispatch, and it must not reach the\n\t\t\t// router — see isExternalActionTarget.\n\t\t\tif (isExternalActionTarget(target)) {\n\t\t\t\twindow.open(target, '_blank', 'noopener,noreferrer')\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tif (!context.router) {\n\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.warn('[dispatchAction] navigate requires context.router to be a Vue Router instance.')\n\t\t\t\treturn\n\t\t\t}\n\t\t\tcontext.router.push(target)\n\t\t\tbreak\n\t\t}\n\n\t\tcase 'export': {\n\t\t// Export launcher (Wave 1, nextcloud-vue#91): the host page opens the\n\t\t// shared CnMassExportDialog configured via the action's entities[] /\n\t\t// formats[]; the dialog's confirm payload routes to the action's\n\t\t// optional `handler` (the app's export service does the download).\n\t\t\tif (typeof context.openExport !== 'function') {\n\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.warn('[dispatchAction] export requires context.openExport to be a function.')\n\t\t\t\treturn\n\t\t\t}\n\t\t\tcontext.openExport(action)\n\t\t\tbreak\n\t\t}\n\n\t\tcase 'open-form': {\n\t\t// Schema-driven create dialog (Wave 3, nextcloud-vue#91): the\n\t\t// rendering surface (CnActionButtons) mounts the shared\n\t\t// CnAdvancedFormDialog and handles the save — mirroring how\n\t\t// `export` delegates to the host's CnMassExportDialog.\n\t\t\tif (typeof context.openForm !== 'function') {\n\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.warn('[dispatchAction] open-form requires context.openForm to be a function.')\n\t\t\t\treturn\n\t\t\t}\n\t\t\tcontext.openForm(action)\n\t\t\tbreak\n\t\t}\n\n\t\tcase 'run-node': {\n\t\t// Direct flow-node invocation (manifest-run-node-action / RN-4):\n\t\t// SAME shape as open-form, deliberately — the rendering surface\n\t\t// (CnActionButtons) resolves the node's own config form, opens a\n\t\t// generic dialog when it has fields (skips it when empty), and\n\t\t// POSTs subject+config to OpenRegister's\n\t\t// /api/flows/{flowId}/nodes/{nodeId}/run on submit. This case\n\t\t// resolves as soon as the dialog OPENS (or the empty-form call\n\t\t// starts) — it does NOT wait for the person to answer, matching\n\t\t// every other consumer's assumption that dispatchAction's Promise\n\t\t// means \"the call happened\", not \"the human decided\" (see design.md\n\t\t// RN-4 for why an awaiting-on-UI shape was rejected).\n\t\t\tif (typeof context.openRunNode !== 'function') {\n\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.warn('[dispatchAction] run-node requires context.openRunNode to be a function.')\n\t\t\t\treturn\n\t\t\t}\n\t\t\tcontext.openRunNode(action)\n\t\t\tbreak\n\t\t}\n\n\t\tcase 'refresh': {\n\t\t// Page-level refresh (Wave 3, nextcloud-vue#91): bump the SAME\n\t\t// `cn:page:refresh` event-bus signal the page overflow menu's\n\t\t// Refresh item broadcasts — every endpoint-bound / bus-subscribed\n\t\t// widget on the page force-refetches past its shared cache.\n\t\t\temit(PAGE_REFRESH_CHANNEL, {})\n\t\t\tbreak\n\t\t}\n\n\t\tcase 'api-call': {\n\t\t// POST/PUT an app endpoint + toast + refresh (Wave 3). Any\n\t\t// `confirm` on the action is INTENT the rendering surface consumed\n\t\t// BEFORE calling the dispatcher (object-op precedent) — no gating\n\t\t// happens here.\n\t\t\treturn executeApiCall(action, context)\n\t\t}\n\n\t\tcase 'agent': {\n\t\t// Run a governed hermiq agent against the page object (hermiq#41). A\n\t\t// first-class companion to api-call: resolves the object context\n\t\t// (register/schema/objectId) and POSTs run-on-object. Any `confirm`\n\t\t// on the action is INTENT the rendering surface consumed BEFORE\n\t\t// dispatch (api-call / object-op precedent) — no gating here. hermiq\n\t\t// is NOT hard-required: an app-level 404 surfaces a graceful toast.\n\t\t\treturn executeAgentAction(action, context)\n\t\t}\n\n\t\tcase 'toggle': {\n\t\t// A toggle is a stateful two-way control (GET state on mount,\n\t\t// write on click) — it is RENDERED by the header-actions surface\n\t\t// (CnActionButtons), never dispatched as a one-shot action.\n\t\t// eslint-disable-next-line no-console\n\t\t\tconsole.warn('[dispatchAction] \"toggle\" is a stateful header-actions control rendered by CnActionButtons — it cannot be dispatched.')\n\t\t\treturn\n\t\t}\n\n\t\tcase 'object-op': {\n\t\t// Declarative mutation of an OpenRegister object, dispatched via the\n\t\t// shared object store (ADR-049). The manifest declares INTENT only:\n\t\t// authorization-shaped fields on the action (`role`, `allow`, …) are\n\t\t// NEVER consulted here — OpenRegister RBAC is the single authority\n\t\t// (ADR-022 / ADR-023) and a forbidden mutation is rejected server-side.\n\t\t// The store mutates its caches only on success, so a rejected write\n\t\t// surfaces as an error with no local state change.\n\t\t\tconst op = action.op\n\t\t\tif (op !== 'patch' && op !== 'delete' && op !== 'create') {\n\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.warn(`[dispatchAction] object-op has invalid op \"${op}\" (expected patch | delete | create).`)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst store = context.objectStore\n\t\t\tif (!store || typeof store.saveObject !== 'function' || typeof store.deleteObject !== 'function') {\n\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.warn('[dispatchAction] object-op requires context.objectStore (useObjectStore shape).')\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst source = context.source\n\t\t\tif (!source || !source.register || !source.schema) {\n\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.warn('[dispatchAction] object-op requires context.source with register + schema.')\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst type = resolveObjectOpType(store, source)\n\n\t\t\tif (op === 'create') {\n\t\t\t\treturn store.saveObject(type, { ...(action.values || {}) })\n\t\t\t}\n\n\t\t\tconst row = context.row\n\t\t\tconst id = rowObjectId(row)\n\t\t\tif (id === null) {\n\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.warn(`[dispatchAction] object-op \"${op}\" is row-scoped and requires context.row with an id.`)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (op === 'delete') {\n\t\t\t\treturn store.deleteObject(type, id)\n\t\t\t}\n\t\t\t// patch: only the action's values, as a PATCH, so every other key\n\t\t\t// keeps its stored value. A store without patchObject writes the\n\t\t\t// row's object merged with the values.\n\t\t\tif (typeof store.patchObject === 'function') {\n\t\t\t\treturn store.patchObject(type, id, { ...(action.values || {}) })\n\t\t\t}\n\t\t\treturn store.saveObject(type, { ...row, ...(action.values || {}), id })\n\t\t}\n\n\t\tdefault:\n\t\t// eslint-disable-next-line no-console\n\t\t\tconsole.warn(`[dispatchAction] Unknown action type \"${type}\".`)\n\t}\n}\n"],"names":["t"],"mappings":"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AG;AACH,EAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE;AAC7B,EAAE;AACF,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;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,cAAc,CAAC,MAAM,EAAE,OAAO,GAAG,EAAE,EAAE;AACrD,CAAC,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE;AAC5C;AACA,EAAE,OAAO,CAAC,IAAI,CAAC,2CAA2C,EAAE,MAAM,EAAC;AACnE,EAAE,MAAM;AACR,EAAE;AACF;AACA;AACA,CAAC,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,IAAI,UAAS;AACtC;AACA,CAAC,QAAQ,IAAI;AACb,EAAE,KAAK,SAAS,EAAE;AAClB,GAAG,MAAM,WAAW,GAAG,MAAM,CAAC,QAAO;AACrC,GAAG,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,GAAE;AAC1C;AACA,GAAG,IAAI,CAAC,WAAW,IAAI,OAAO,QAAQ,CAAC,WAAW,CAAC,KAAK,UAAU,EAAE;AACpE;AACA,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,0BAA0B,EAAE,WAAW,CAAC,gCAAgC,CAAC,EAAC;AAC5F,IAAI,MAAM;AACV,I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"}
@@ -258,15 +258,18 @@ function schemaSlug(schema) {
258
258
  * it: three case indexes share their views, the organisations index does
259
259
  * not. `savedViewsScope` on a page overrides that, for pages that should
260
260
  * share views although they read different sources, or keep them apart
261
- * although they read the same one.
261
+ * although they read the same one. A page over a named source
262
+ * (`entitySource`) and no schema shares its views with the pages over that
263
+ * source.
262
264
  *
263
265
  * @param {object} page The page.
264
266
  * @param {string} [page.scope] The explicit `savedViewsScope`, when set.
265
267
  * @param {string} [page.register] The page's register.
266
268
  * @param {object|string} [page.schema] The page's schema, slug or object.
269
+ * @param {string} [page.source] The page's `entitySource`, when it reads one.
267
270
  * @return {string} The scope key, or the empty string for a page with no source.
268
271
  */
269
- function savedViewScope({ scope, register, schema } = {}) {
272
+ function savedViewScope({ scope, register, schema, source } = {}) {
270
273
  if (typeof scope === 'string' && scope !== '') {
271
274
  return scope
272
275
  }
@@ -274,9 +277,43 @@ function savedViewScope({ scope, register, schema } = {}) {
274
277
  if (typeof register === 'string' && register !== '' && slug !== '') {
275
278
  return `${register}/${slug}`
276
279
  }
280
+ if (typeof source === 'string' && source !== '') {
281
+ return `source:${source}`
282
+ }
277
283
  return ''
278
284
  }
279
285
 
286
+ /**
287
+ * Whether an index page offers saved views in its sidebar.
288
+ *
289
+ * `allowSavedViews` decides when it is set. Unset, every index page that has
290
+ * a sidebar and a source a view can be scoped to (a register and schema, a
291
+ * named source, or `savedViewsScope`) offers them, so managing views is
292
+ * there on every list without each page opting in.
293
+ *
294
+ * @param {object} config The page's index config, or CnIndexPage's props.
295
+ * @param {boolean|null} [config.allowSavedViews] The explicit choice, when made.
296
+ * @param {object} [config.sidebar] The sidebar config.
297
+ * @param {string} [config.savedViewsScope] The explicit scope.
298
+ * @param {string} [config.register] The register.
299
+ * @param {object|string} [config.schema] The schema.
300
+ * @param {string} [config.entitySource] The named source.
301
+ * @return {boolean}
302
+ */
303
+ function pageOffersSavedViews(config) {
304
+ if (!config || typeof config !== 'object') {
305
+ return false
306
+ }
307
+ if (typeof config.allowSavedViews === 'boolean') {
308
+ return config.allowSavedViews
309
+ }
310
+ const sidebar = config.sidebar;
311
+ if (!sidebar || typeof sidebar !== 'object' || sidebar.enabled !== true || sidebar.show === false) {
312
+ return false
313
+ }
314
+ return savedViewScope({ scope: config.savedViewsScope, register: config.register, schema: config.schema, source: config.entitySource }) !== ''
315
+ }
316
+
280
317
  /**
281
318
  * Whether a saved view belongs on a page.
282
319
  *
@@ -410,5 +447,5 @@ function defaultFilterViews(defaults, page = {}) {
410
447
  })
411
448
  }
412
449
 
413
- export { buildRouteQueryFromViewState, buildViewCreatePayload, defaultFilterViews, extractViewState, extractViewStateFromRouteQuery, isOwnView, normalizeSharedWith, savedViewScope, schemaSlug, viewAccess, viewMatchesScope };
450
+ export { buildRouteQueryFromViewState, buildViewCreatePayload, defaultFilterViews, extractViewState, extractViewStateFromRouteQuery, isOwnView, normalizeSharedWith, pageOffersSavedViews, savedViewScope, schemaSlug, viewAccess, viewMatchesScope };
414
451
  //# sourceMappingURL=savedViewHelpers.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"savedViewHelpers.js","sources":["../../../src/utils/savedViewHelpers.js"],"sourcesContent":["// SPDX-FileCopyrightText: 2026 Conduction B.V.\n// SPDX-License-Identifier: EUPL-1.2\n\n/**\n * Pure helpers for CnIndexPage's saved-views feature (saved-views-ui).\n *\n * OpenRegister ships a saved-search Views backend\n * (`/apps/openregister/api/views`, ViewsController + ViewService); these\n * helpers translate between the three state shapes involved:\n *\n * 1. **Route query** — CnIndexPage's deep-link contract: every `$route.query`\n * key NOT starting with `_` is a fetch filter (see\n * `useSelfFetchList.resolveQueryFilters`); `_`-prefixed keys are reserved\n * list params. Search is `_search` and sort is `_order`, the JSON-encoded\n * ordered array `[{ key, order }, …]` — the one spelling CnIndexPage,\n * listNavigation, CnPageRenderer and OpenRegister's object API all agree\n * on. This module writes NO spelling of its own.\n * 2. **View state** — the normalized internal object\n * `{ filters, search, sortKeys, sortKey, sortOrder }`, where `sortKeys` is\n * the truth and the last two mirror its first entry, exactly as\n * `useListView` holds the same state.\n * 3. **OR View payload** — the `POST/PUT /api/views` body whose opaque\n * `query` field round-trips through OpenRegister unchanged.\n *\n * All functions are pure and defensive: malformed input degrades to the\n * empty/default state, never throws.\n *\n * @module utils/savedViewHelpers\n */\n\nimport { parseSortKeys } from './routeFilters.js'\n\n/** The default (empty) view state. @return {object} A fresh empty state. */\nfunction emptyState() {\n\treturn { filters: {}, search: '', sortKeys: [], sortKey: null, sortOrder: 'asc' }\n}\n\n/**\n * Coerce anything into an ordered sort-key list.\n *\n * The single defensive entry point, and the whole of the stored-shape\n * compatibility: a view saved before sorts could be chained holds `sort` as one\n * `{ key, order }` object, and that must keep opening exactly as it does today.\n *\n * @param {unknown} value An array, a single `{ key, order }`, or anything else.\n * @return {Array<{key: string, order: 'asc'|'desc'}>} The normalized list.\n */\nfunction normalizeSortKeys(value) {\n\tconst list = Array.isArray(value) ? value : [value]\n\tconst seen = new Set()\n\tconst keys = []\n\tfor (const entry of list) {\n\t\tif (!entry || typeof entry !== 'object' || typeof entry.key !== 'string' || entry.key === '') {\n\t\t\tcontinue\n\t\t}\n\t\tif (seen.has(entry.key)) {\n\t\t\tcontinue\n\t\t}\n\t\tseen.add(entry.key)\n\t\tkeys.push({ key: entry.key, order: entry.order === 'desc' ? 'desc' : 'asc' })\n\t}\n\treturn keys\n}\n\n/**\n * Write a sort onto a state, keeping the single-key mirror in step.\n *\n * @param {object} state The state to write onto (mutated and returned).\n * @param {Array<{key: string, order: 'asc'|'desc'}>} keys The normalized sort.\n * @return {object} The same state.\n */\nfunction withSort(state, keys) {\n\tstate.sortKeys = keys\n\tstate.sortKey = keys.length > 0 ? keys[0].key : null\n\tstate.sortOrder = keys.length > 0 ? keys[0].order : 'asc'\n\treturn state\n}\n\n/**\n * The sort a caller handed in, whichever of the two shapes they hold.\n *\n * @param {object} src A view state, possibly carrying only `sortKey`/`sortOrder`.\n * @return {Array<{key: string, order: 'asc'|'desc'}>} The normalized sort.\n */\nfunction sortKeysOf(src) {\n\tif (src.sortKeys !== undefined && src.sortKeys !== null) {\n\t\treturn normalizeSortKeys(src.sortKeys)\n\t}\n\treturn src.sortKey ? normalizeSortKeys({ key: src.sortKey, order: src.sortOrder }) : []\n}\n\n/**\n * Extract the current view state from a `$route.query`-shaped object.\n *\n * Non-underscore-prefixed keys become `filters` entries (values passed\n * through as-is, including arrays from `?status[]=a&status[]=b` deep\n * links). Reserved keys map onto the dedicated state fields: `_search` and\n * `_order`. Other reserved keys (`_page`, `_limit`, …) are ignored —\n * pagination is never part of a saved view.\n *\n * @param {object|null|undefined} query The `$route.query` object.\n * @return {{ filters: object, search: string, sortKeys: Array<{key: string, order: string}>, sortKey: ?string, sortOrder: string }} The normalized view state.\n */\nexport function extractViewStateFromRouteQuery(query) {\n\tconst state = emptyState()\n\tif (!query || typeof query !== 'object' || Array.isArray(query)) {\n\t\treturn state\n\t}\n\tfor (const [key, value] of Object.entries(query)) {\n\t\tif (key.startsWith('_')) {\n\t\t\tcontinue\n\t\t}\n\t\tif (value === undefined || value === null || value === '') {\n\t\t\tcontinue\n\t\t}\n\t\tstate.filters[key] = value\n\t}\n\tif (typeof query._search === 'string' && query._search !== '') {\n\t\tstate.search = query._search\n\t}\n\treturn withSort(state, parseSortKeys(query._order))\n}\n\n/**\n * Build a fresh route-query object that APPLIES a view state.\n *\n * Spreads `state.filters` (skipping null/undefined/empty-string/empty-array\n * values, matching what `CnIndexPage.persistViewStateToRoute` skips — the two\n * write the same query and must agree on what an absent filter looks like),\n * then sets the reserved keys only when meaningful: `_search` for a non-empty\n * search term, `_order` for an active sort. Deliberately omits `_page` —\n * applying a view is a full state replace that implicitly resets pagination.\n *\n * @param {{ filters?: object, search?: string, sortKeys?: Array<{key: string, order: string}>, sortKey?: ?string, sortOrder?: string }} state The view state to serialize.\n * @return {object} A plain object suitable for `$router.replace({ query })`.\n */\nexport function buildRouteQueryFromViewState(state) {\n\tconst query = {}\n\tconst src = (state && typeof state === 'object') ? state : {}\n\tconst filters = (src.filters && typeof src.filters === 'object' && !Array.isArray(src.filters)) ? src.filters : {}\n\tfor (const [key, value] of Object.entries(filters)) {\n\t\tif (value === undefined || value === null || value === '' || (Array.isArray(value) && value.length === 0)) {\n\t\t\tcontinue\n\t\t}\n\t\tquery[key] = value\n\t}\n\tif (typeof src.search === 'string' && src.search !== '') {\n\t\tquery._search = src.search\n\t}\n\tconst keys = sortKeysOf(src)\n\tif (keys.length > 0) {\n\t\tquery._order = JSON.stringify(keys)\n\t}\n\treturn query\n}\n\n/**\n * Build the exact `POST /apps/openregister/api/views` (and PUT) request\n * body for persisting a view. The `query` field is OpenRegister's opaque\n * JSON blob — ViewsController stores `$data['query']` verbatim when it is\n * an array/object, so the shape below round-trips unchanged and\n * {@link extractViewState} is its inverse.\n *\n * @param {object} options Payload options.\n * @param {string} options.name Required view name.\n * @param {string} [options.description] Optional description.\n * @param {boolean} [options.isPublic] Share the view with other users.\n * @param {boolean} [options.isDefault] Mark as the user's default view.\n * @param {{ filters?: object, search?: string, sortKeys?: Array<{key: string, order: string}>, sortKey?: ?string, sortOrder?: string }} options.state The view state to persist.\n * @param {string} [options.scope] The pages this view belongs to, from {@link savedViewScope}; omitted when empty.\n * @param {string} [options.register] The page's register, written as OpenRegister's own `registers` list.\n * @param {object|string} [options.schema] The page's schema (slug or object), written as OpenRegister's own `schemas` list.\n * @param {Array<{group: string, mode: string}>} [options.sharedWith] Groups to share with; omitted from the body when empty.\n * @param {object} [options.presentation] How the view shows (OpenRegister's shape); omitted from the body for a table, which is the default.\n * @return {object} The request body for the OR views API.\n */\nexport function buildViewCreatePayload({ name, description, isPublic, isDefault, state, scope, register, schema, sharedWith, presentation } = {}) {\n\tconst src = (state && typeof state === 'object') ? state : {}\n\tconst keys = sortKeysOf(src)\n\tconst query = {\n\t\tfilters: (src.filters && typeof src.filters === 'object' && !Array.isArray(src.filters)) ? src.filters : {},\n\t\tsearch: (typeof src.search === 'string') ? src.search : '',\n\t\t// `null` rather than `[]` for no sort: every view stored before sorts\n\t\t// could be chained says `null`, and one spelling for \"no sort\" is worth\n\t\t// more than the symmetry.\n\t\tsort: keys.length > 0 ? keys : null,\n\t}\n\tif (typeof scope === 'string' && scope !== '') {\n\t\tquery.scope = scope\n\t}\n\tif (typeof register === 'string' && register !== '') {\n\t\tquery.registers = [register]\n\t}\n\tconst slug = schemaSlug(schema)\n\tif (slug !== '') {\n\t\tquery.schemas = [slug]\n\t}\n\tconst body = {\n\t\tname,\n\t\tdescription: description || '',\n\t\tisPublic: !!isPublic,\n\t\tisDefault: !!isDefault,\n\t\tquery,\n\t}\n\tif (presentation && typeof presentation === 'object' && (presentation.viewType === 'kanban' || presentation.viewType === 'calendar')) {\n\t\tbody.presentation = presentation\n\t}\n\tconst audience = normalizeSharedWith(sharedWith)\n\tif (audience.length > 0) {\n\t\tbody.sharedWith = audience\n\t}\n\treturn body\n}\n\n/**\n * Clean an audience list: keep `{ group, mode }` and `{ user, mode }` entries\n * that name exactly one target, drop repeats, and coerce any mode but `write`\n * to `read`.\n *\n * @param {unknown} sharedWith The audience as given.\n * @return {Array<{group?: string, user?: string, mode: 'read'|'write'}>} The cleaned list.\n * @spec openspec/changes/saved-views-manage-and-defaults/tasks.md#task-5\n */\nexport function normalizeSharedWith(sharedWith) {\n\tconst seen = new Set()\n\tconst out = []\n\tfor (const entry of Array.isArray(sharedWith) ? sharedWith : []) {\n\t\tconst group = entry && typeof entry.group === 'string' ? entry.group : ''\n\t\tconst user = entry && typeof entry.user === 'string' ? entry.user : ''\n\t\tif ((group === '') === (user === '')) {\n\t\t\tcontinue\n\t\t}\n\t\tconst key = user !== '' ? `user:${user}` : `group:${group}`\n\t\tif (seen.has(key)) {\n\t\t\tcontinue\n\t\t}\n\t\tseen.add(key)\n\t\tconst mode = entry.mode === 'write' ? 'write' : 'read'\n\t\tout.push(user !== '' ? { user, mode } : { group, mode })\n\t}\n\treturn out\n}\n\n/**\n * What the current user may do with a view: `owner`, `write` or `read`.\n *\n * The server decides: `@self.access` wins. A view without it (an older\n * OpenRegister) counts as `owner` when its `owner` is the current user and as\n * `read` otherwise.\n *\n * @param {object|null|undefined} view The View API object.\n * @param {string|null|undefined} currentUserId The signed-in NC user id.\n * @return {'owner'|'write'|'read'} The access.\n */\nexport function viewAccess(view, currentUserId) {\n\tconst access = view && view['@self'] && view['@self'].access\n\tif (access === 'owner' || access === 'write' || access === 'read') {\n\t\treturn access\n\t}\n\treturn isOwnView(view, currentUserId) ? 'owner' : 'read'\n}\n\n/**\n * The slug of a schema given as a slug or as a schema object.\n *\n * @param {object|string|null|undefined} schema The page's `schema` prop.\n * @return {string} The slug, or the empty string.\n */\nexport function schemaSlug(schema) {\n\tif (typeof schema === 'string') {\n\t\treturn schema\n\t}\n\tif (schema && typeof schema === 'object' && typeof schema.slug === 'string') {\n\t\treturn schema.slug\n\t}\n\treturn ''\n}\n\n/**\n * The key naming which pages share a view.\n *\n * A view is a set of filters over one schema's fields, so by default every\n * page over the same register and schema shares it and no other page sees\n * it: three case indexes share their views, the organisations index does\n * not. `savedViewsScope` on a page overrides that, for pages that should\n * share views although they read different sources, or keep them apart\n * although they read the same one.\n *\n * @param {object} page The page.\n * @param {string} [page.scope] The explicit `savedViewsScope`, when set.\n * @param {string} [page.register] The page's register.\n * @param {object|string} [page.schema] The page's schema, slug or object.\n * @return {string} The scope key, or the empty string for a page with no source.\n */\nexport function savedViewScope({ scope, register, schema } = {}) {\n\tif (typeof scope === 'string' && scope !== '') {\n\t\treturn scope\n\t}\n\tconst slug = schemaSlug(schema)\n\tif (typeof register === 'string' && register !== '' && slug !== '') {\n\t\treturn `${register}/${slug}`\n\t}\n\treturn ''\n}\n\n/**\n * Whether a saved view belongs on a page.\n *\n * A view saved with a `scope` is shown where the scope matches. A view that\n * names `schemas` (OpenRegister's own search UI writes those) is shown on a\n * page over one of them. A view that says neither, saved before views were\n * scoped, is shown everywhere as it always was: hiding it would lose the\n * view, and nothing can tell which page it was made on.\n *\n * @param {object|null|undefined} view The View API object.\n * @param {object} page The page, as {@link savedViewScope} takes it.\n * @return {boolean} True when the view is shown on this page.\n */\nexport function viewMatchesScope(view, page = {}) {\n\tconst query = view && typeof view === 'object' ? view.query : null\n\tif (!query || typeof query !== 'object' || Array.isArray(query)) {\n\t\treturn true\n\t}\n\tif (typeof query.scope === 'string' && query.scope !== '') {\n\t\treturn query.scope === savedViewScope(page)\n\t}\n\tif (Array.isArray(query.schemas) && query.schemas.length > 0) {\n\t\tconst slug = schemaSlug(page.schema)\n\t\tif (slug === '' || !query.schemas.map(String).includes(slug)) {\n\t\t\treturn false\n\t\t}\n\t\tif (Array.isArray(query.registers) && query.registers.length > 0 && page.register) {\n\t\t\treturn query.registers.map(String).includes(String(page.register))\n\t\t}\n\t\treturn true\n\t}\n\treturn true\n}\n\n/**\n * Normalize a View API object (as returned by `GET /api/views`) back into\n * the internal view state. Accepts either a full view object (reads its\n * `query` property) or a raw query blob directly. Every field degrades\n * defensively: missing/null/malformed `query`, non-object `filters`,\n * malformed `sort` all yield the empty/default state — never throws.\n *\n * @param {object|null|undefined} view The View API object (or its raw `query` blob).\n * @return {{ filters: object, search: string, sortKeys: Array<{key: string, order: string}>, sortKey: ?string, sortOrder: string }} The normalized view state.\n */\nexport function extractViewState(view) {\n\tconst state = emptyState()\n\tif (!view || typeof view !== 'object' || Array.isArray(view)) {\n\t\treturn state\n\t}\n\t// Full view object (has a `query` key) or a raw query blob itself.\n\tconst query = (Object.hasOwn(view, 'query')) ? view.query : view\n\tif (!query || typeof query !== 'object' || Array.isArray(query)) {\n\t\treturn state\n\t}\n\tif (query.filters && typeof query.filters === 'object' && !Array.isArray(query.filters)) {\n\t\tfor (const [key, value] of Object.entries(query.filters)) {\n\t\t\tif (value === undefined || value === null || value === '') {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tstate.filters[key] = value\n\t\t}\n\t}\n\tif (typeof query.search === 'string') {\n\t\tstate.search = query.search\n\t}\n\treturn withSort(state, normalizeSortKeys(query.sort))\n}\n\n/**\n * Whether the given view is owned by the given user. Drives the delete\n * affordance in CnSavedViewsControl — OpenRegister scopes destroy() to the\n * owner server-side (a foreign id 404s), so this only hides the button for\n * views the API would refuse to delete anyway.\n *\n * @param {object|null|undefined} view The View API object.\n * @param {string|null|undefined} currentUserId The signed-in NC user id.\n * @return {boolean} True when the view belongs to the current user.\n */\nexport function isOwnView(view, currentUserId) {\n\treturn !!view && !!currentUserId && view.owner === currentUserId\n}\n\n/**\n * The default views an index page declares (`config.defaultSavedViews`), as\n * read-only views the saved-views control lists. They are never stored: the\n * manifest installs them, so every user has the same set and none can delete\n * one. `seeded: true` puts them in the control's default group; the query\n * keeps its `@`-tokens, which resolve when a default is applied.\n *\n * A default's `overrides` (page config laid over the page while it is\n * active, see `utils/savedViewOverrides.js`) ride in `query.overrides`, so a\n * copy of the default keeps them.\n *\n * @param {Array<object>|null|undefined} defaults The declared entries `{ slug, name, filters, search?, sort?, label?, overrides? }`.\n * @param {{ scope?: string, register?: string, schema?: object|string|null }} [page] The page, as `savedViewScope` takes it.\n * @return {Array<object>} The views, in declaration order; entries without a slug or name are left out.\n * @spec openspec/changes/saved-views-manage-and-defaults/tasks.md#task-4\n */\nexport function defaultFilterViews(defaults, page = {}) {\n\tif (!Array.isArray(defaults)) {\n\t\treturn []\n\t}\n\treturn defaults\n\t\t.filter((entry) => entry && typeof entry.slug === 'string' && entry.slug !== '' && typeof entry.name === 'string' && entry.name !== '')\n\t\t.map((entry) => {\n\t\t\tconst { query } = buildViewCreatePayload({\n\t\t\t\tname: entry.name,\n\t\t\t\tstate: {\n\t\t\t\t\tfilters: (entry.filters && typeof entry.filters === 'object' && !Array.isArray(entry.filters)) ? entry.filters : {},\n\t\t\t\t\tsearch: typeof entry.search === 'string' ? entry.search : '',\n\t\t\t\t\tsortKeys: Array.isArray(entry.sort) ? entry.sort : [],\n\t\t\t\t},\n\t\t\t\tscope: savedViewScope(page),\n\t\t\t\tregister: page.register,\n\t\t\t\tschema: page.schema,\n\t\t\t})\n\t\t\tif (entry.overrides && typeof entry.overrides === 'object' && !Array.isArray(entry.overrides)) {\n\t\t\t\tquery.overrides = entry.overrides\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tid: `default:${entry.slug}`,\n\t\t\t\tslug: entry.slug,\n\t\t\t\tname: entry.name,\n\t\t\t\towner: '',\n\t\t\t\tseeded: true,\n\t\t\t\tisPublic: false,\n\t\t\t\tlabels: typeof entry.label === 'string' && entry.label !== '' ? [entry.label] : [],\n\t\t\t\t'@self': { access: 'read' },\n\t\t\t\tquery,\n\t\t\t}\n\t\t})\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"savedViewHelpers.js","sources":["../../../src/utils/savedViewHelpers.js"],"sourcesContent":["// SPDX-FileCopyrightText: 2026 Conduction B.V.\n// SPDX-License-Identifier: EUPL-1.2\n\n/**\n * Pure helpers for CnIndexPage's saved-views feature (saved-views-ui).\n *\n * OpenRegister ships a saved-search Views backend\n * (`/apps/openregister/api/views`, ViewsController + ViewService); these\n * helpers translate between the three state shapes involved:\n *\n * 1. **Route query** — CnIndexPage's deep-link contract: every `$route.query`\n * key NOT starting with `_` is a fetch filter (see\n * `useSelfFetchList.resolveQueryFilters`); `_`-prefixed keys are reserved\n * list params. Search is `_search` and sort is `_order`, the JSON-encoded\n * ordered array `[{ key, order }, …]` — the one spelling CnIndexPage,\n * listNavigation, CnPageRenderer and OpenRegister's object API all agree\n * on. This module writes NO spelling of its own.\n * 2. **View state** — the normalized internal object\n * `{ filters, search, sortKeys, sortKey, sortOrder }`, where `sortKeys` is\n * the truth and the last two mirror its first entry, exactly as\n * `useListView` holds the same state.\n * 3. **OR View payload** — the `POST/PUT /api/views` body whose opaque\n * `query` field round-trips through OpenRegister unchanged.\n *\n * All functions are pure and defensive: malformed input degrades to the\n * empty/default state, never throws.\n *\n * @module utils/savedViewHelpers\n */\n\nimport { parseSortKeys } from './routeFilters.js'\n\n/** The default (empty) view state. @return {object} A fresh empty state. */\nfunction emptyState() {\n\treturn { filters: {}, search: '', sortKeys: [], sortKey: null, sortOrder: 'asc' }\n}\n\n/**\n * Coerce anything into an ordered sort-key list.\n *\n * The single defensive entry point, and the whole of the stored-shape\n * compatibility: a view saved before sorts could be chained holds `sort` as one\n * `{ key, order }` object, and that must keep opening exactly as it does today.\n *\n * @param {unknown} value An array, a single `{ key, order }`, or anything else.\n * @return {Array<{key: string, order: 'asc'|'desc'}>} The normalized list.\n */\nfunction normalizeSortKeys(value) {\n\tconst list = Array.isArray(value) ? value : [value]\n\tconst seen = new Set()\n\tconst keys = []\n\tfor (const entry of list) {\n\t\tif (!entry || typeof entry !== 'object' || typeof entry.key !== 'string' || entry.key === '') {\n\t\t\tcontinue\n\t\t}\n\t\tif (seen.has(entry.key)) {\n\t\t\tcontinue\n\t\t}\n\t\tseen.add(entry.key)\n\t\tkeys.push({ key: entry.key, order: entry.order === 'desc' ? 'desc' : 'asc' })\n\t}\n\treturn keys\n}\n\n/**\n * Write a sort onto a state, keeping the single-key mirror in step.\n *\n * @param {object} state The state to write onto (mutated and returned).\n * @param {Array<{key: string, order: 'asc'|'desc'}>} keys The normalized sort.\n * @return {object} The same state.\n */\nfunction withSort(state, keys) {\n\tstate.sortKeys = keys\n\tstate.sortKey = keys.length > 0 ? keys[0].key : null\n\tstate.sortOrder = keys.length > 0 ? keys[0].order : 'asc'\n\treturn state\n}\n\n/**\n * The sort a caller handed in, whichever of the two shapes they hold.\n *\n * @param {object} src A view state, possibly carrying only `sortKey`/`sortOrder`.\n * @return {Array<{key: string, order: 'asc'|'desc'}>} The normalized sort.\n */\nfunction sortKeysOf(src) {\n\tif (src.sortKeys !== undefined && src.sortKeys !== null) {\n\t\treturn normalizeSortKeys(src.sortKeys)\n\t}\n\treturn src.sortKey ? normalizeSortKeys({ key: src.sortKey, order: src.sortOrder }) : []\n}\n\n/**\n * Extract the current view state from a `$route.query`-shaped object.\n *\n * Non-underscore-prefixed keys become `filters` entries (values passed\n * through as-is, including arrays from `?status[]=a&status[]=b` deep\n * links). Reserved keys map onto the dedicated state fields: `_search` and\n * `_order`. Other reserved keys (`_page`, `_limit`, …) are ignored —\n * pagination is never part of a saved view.\n *\n * @param {object|null|undefined} query The `$route.query` object.\n * @return {{ filters: object, search: string, sortKeys: Array<{key: string, order: string}>, sortKey: ?string, sortOrder: string }} The normalized view state.\n */\nexport function extractViewStateFromRouteQuery(query) {\n\tconst state = emptyState()\n\tif (!query || typeof query !== 'object' || Array.isArray(query)) {\n\t\treturn state\n\t}\n\tfor (const [key, value] of Object.entries(query)) {\n\t\tif (key.startsWith('_')) {\n\t\t\tcontinue\n\t\t}\n\t\tif (value === undefined || value === null || value === '') {\n\t\t\tcontinue\n\t\t}\n\t\tstate.filters[key] = value\n\t}\n\tif (typeof query._search === 'string' && query._search !== '') {\n\t\tstate.search = query._search\n\t}\n\treturn withSort(state, parseSortKeys(query._order))\n}\n\n/**\n * Build a fresh route-query object that APPLIES a view state.\n *\n * Spreads `state.filters` (skipping null/undefined/empty-string/empty-array\n * values, matching what `CnIndexPage.persistViewStateToRoute` skips — the two\n * write the same query and must agree on what an absent filter looks like),\n * then sets the reserved keys only when meaningful: `_search` for a non-empty\n * search term, `_order` for an active sort. Deliberately omits `_page` —\n * applying a view is a full state replace that implicitly resets pagination.\n *\n * @param {{ filters?: object, search?: string, sortKeys?: Array<{key: string, order: string}>, sortKey?: ?string, sortOrder?: string }} state The view state to serialize.\n * @return {object} A plain object suitable for `$router.replace({ query })`.\n */\nexport function buildRouteQueryFromViewState(state) {\n\tconst query = {}\n\tconst src = (state && typeof state === 'object') ? state : {}\n\tconst filters = (src.filters && typeof src.filters === 'object' && !Array.isArray(src.filters)) ? src.filters : {}\n\tfor (const [key, value] of Object.entries(filters)) {\n\t\tif (value === undefined || value === null || value === '' || (Array.isArray(value) && value.length === 0)) {\n\t\t\tcontinue\n\t\t}\n\t\tquery[key] = value\n\t}\n\tif (typeof src.search === 'string' && src.search !== '') {\n\t\tquery._search = src.search\n\t}\n\tconst keys = sortKeysOf(src)\n\tif (keys.length > 0) {\n\t\tquery._order = JSON.stringify(keys)\n\t}\n\treturn query\n}\n\n/**\n * Build the exact `POST /apps/openregister/api/views` (and PUT) request\n * body for persisting a view. The `query` field is OpenRegister's opaque\n * JSON blob — ViewsController stores `$data['query']` verbatim when it is\n * an array/object, so the shape below round-trips unchanged and\n * {@link extractViewState} is its inverse.\n *\n * @param {object} options Payload options.\n * @param {string} options.name Required view name.\n * @param {string} [options.description] Optional description.\n * @param {boolean} [options.isPublic] Share the view with other users.\n * @param {boolean} [options.isDefault] Mark as the user's default view.\n * @param {{ filters?: object, search?: string, sortKeys?: Array<{key: string, order: string}>, sortKey?: ?string, sortOrder?: string }} options.state The view state to persist.\n * @param {string} [options.scope] The pages this view belongs to, from {@link savedViewScope}; omitted when empty.\n * @param {string} [options.register] The page's register, written as OpenRegister's own `registers` list.\n * @param {object|string} [options.schema] The page's schema (slug or object), written as OpenRegister's own `schemas` list.\n * @param {Array<{group: string, mode: string}>} [options.sharedWith] Groups to share with; omitted from the body when empty.\n * @param {object} [options.presentation] How the view shows (OpenRegister's shape); omitted from the body for a table, which is the default.\n * @return {object} The request body for the OR views API.\n */\nexport function buildViewCreatePayload({ name, description, isPublic, isDefault, state, scope, register, schema, sharedWith, presentation } = {}) {\n\tconst src = (state && typeof state === 'object') ? state : {}\n\tconst keys = sortKeysOf(src)\n\tconst query = {\n\t\tfilters: (src.filters && typeof src.filters === 'object' && !Array.isArray(src.filters)) ? src.filters : {},\n\t\tsearch: (typeof src.search === 'string') ? src.search : '',\n\t\t// `null` rather than `[]` for no sort: every view stored before sorts\n\t\t// could be chained says `null`, and one spelling for \"no sort\" is worth\n\t\t// more than the symmetry.\n\t\tsort: keys.length > 0 ? keys : null,\n\t}\n\tif (typeof scope === 'string' && scope !== '') {\n\t\tquery.scope = scope\n\t}\n\tif (typeof register === 'string' && register !== '') {\n\t\tquery.registers = [register]\n\t}\n\tconst slug = schemaSlug(schema)\n\tif (slug !== '') {\n\t\tquery.schemas = [slug]\n\t}\n\tconst body = {\n\t\tname,\n\t\tdescription: description || '',\n\t\tisPublic: !!isPublic,\n\t\tisDefault: !!isDefault,\n\t\tquery,\n\t}\n\tif (presentation && typeof presentation === 'object' && (presentation.viewType === 'kanban' || presentation.viewType === 'calendar')) {\n\t\tbody.presentation = presentation\n\t}\n\tconst audience = normalizeSharedWith(sharedWith)\n\tif (audience.length > 0) {\n\t\tbody.sharedWith = audience\n\t}\n\treturn body\n}\n\n/**\n * Clean an audience list: keep `{ group, mode }` and `{ user, mode }` entries\n * that name exactly one target, drop repeats, and coerce any mode but `write`\n * to `read`.\n *\n * @param {unknown} sharedWith The audience as given.\n * @return {Array<{group?: string, user?: string, mode: 'read'|'write'}>} The cleaned list.\n * @spec openspec/changes/saved-views-manage-and-defaults/tasks.md#task-5\n */\nexport function normalizeSharedWith(sharedWith) {\n\tconst seen = new Set()\n\tconst out = []\n\tfor (const entry of Array.isArray(sharedWith) ? sharedWith : []) {\n\t\tconst group = entry && typeof entry.group === 'string' ? entry.group : ''\n\t\tconst user = entry && typeof entry.user === 'string' ? entry.user : ''\n\t\tif ((group === '') === (user === '')) {\n\t\t\tcontinue\n\t\t}\n\t\tconst key = user !== '' ? `user:${user}` : `group:${group}`\n\t\tif (seen.has(key)) {\n\t\t\tcontinue\n\t\t}\n\t\tseen.add(key)\n\t\tconst mode = entry.mode === 'write' ? 'write' : 'read'\n\t\tout.push(user !== '' ? { user, mode } : { group, mode })\n\t}\n\treturn out\n}\n\n/**\n * What the current user may do with a view: `owner`, `write` or `read`.\n *\n * The server decides: `@self.access` wins. A view without it (an older\n * OpenRegister) counts as `owner` when its `owner` is the current user and as\n * `read` otherwise.\n *\n * @param {object|null|undefined} view The View API object.\n * @param {string|null|undefined} currentUserId The signed-in NC user id.\n * @return {'owner'|'write'|'read'} The access.\n */\nexport function viewAccess(view, currentUserId) {\n\tconst access = view && view['@self'] && view['@self'].access\n\tif (access === 'owner' || access === 'write' || access === 'read') {\n\t\treturn access\n\t}\n\treturn isOwnView(view, currentUserId) ? 'owner' : 'read'\n}\n\n/**\n * The slug of a schema given as a slug or as a schema object.\n *\n * @param {object|string|null|undefined} schema The page's `schema` prop.\n * @return {string} The slug, or the empty string.\n */\nexport function schemaSlug(schema) {\n\tif (typeof schema === 'string') {\n\t\treturn schema\n\t}\n\tif (schema && typeof schema === 'object' && typeof schema.slug === 'string') {\n\t\treturn schema.slug\n\t}\n\treturn ''\n}\n\n/**\n * The key naming which pages share a view.\n *\n * A view is a set of filters over one schema's fields, so by default every\n * page over the same register and schema shares it and no other page sees\n * it: three case indexes share their views, the organisations index does\n * not. `savedViewsScope` on a page overrides that, for pages that should\n * share views although they read different sources, or keep them apart\n * although they read the same one. A page over a named source\n * (`entitySource`) and no schema shares its views with the pages over that\n * source.\n *\n * @param {object} page The page.\n * @param {string} [page.scope] The explicit `savedViewsScope`, when set.\n * @param {string} [page.register] The page's register.\n * @param {object|string} [page.schema] The page's schema, slug or object.\n * @param {string} [page.source] The page's `entitySource`, when it reads one.\n * @return {string} The scope key, or the empty string for a page with no source.\n */\nexport function savedViewScope({ scope, register, schema, source } = {}) {\n\tif (typeof scope === 'string' && scope !== '') {\n\t\treturn scope\n\t}\n\tconst slug = schemaSlug(schema)\n\tif (typeof register === 'string' && register !== '' && slug !== '') {\n\t\treturn `${register}/${slug}`\n\t}\n\tif (typeof source === 'string' && source !== '') {\n\t\treturn `source:${source}`\n\t}\n\treturn ''\n}\n\n/**\n * Whether an index page offers saved views in its sidebar.\n *\n * `allowSavedViews` decides when it is set. Unset, every index page that has\n * a sidebar and a source a view can be scoped to (a register and schema, a\n * named source, or `savedViewsScope`) offers them, so managing views is\n * there on every list without each page opting in.\n *\n * @param {object} config The page's index config, or CnIndexPage's props.\n * @param {boolean|null} [config.allowSavedViews] The explicit choice, when made.\n * @param {object} [config.sidebar] The sidebar config.\n * @param {string} [config.savedViewsScope] The explicit scope.\n * @param {string} [config.register] The register.\n * @param {object|string} [config.schema] The schema.\n * @param {string} [config.entitySource] The named source.\n * @return {boolean}\n */\nexport function pageOffersSavedViews(config) {\n\tif (!config || typeof config !== 'object') {\n\t\treturn false\n\t}\n\tif (typeof config.allowSavedViews === 'boolean') {\n\t\treturn config.allowSavedViews\n\t}\n\tconst sidebar = config.sidebar\n\tif (!sidebar || typeof sidebar !== 'object' || sidebar.enabled !== true || sidebar.show === false) {\n\t\treturn false\n\t}\n\treturn savedViewScope({ scope: config.savedViewsScope, register: config.register, schema: config.schema, source: config.entitySource }) !== ''\n}\n\n/**\n * Whether a saved view belongs on a page.\n *\n * A view saved with a `scope` is shown where the scope matches. A view that\n * names `schemas` (OpenRegister's own search UI writes those) is shown on a\n * page over one of them. A view that says neither, saved before views were\n * scoped, is shown everywhere as it always was: hiding it would lose the\n * view, and nothing can tell which page it was made on.\n *\n * @param {object|null|undefined} view The View API object.\n * @param {object} page The page, as {@link savedViewScope} takes it.\n * @return {boolean} True when the view is shown on this page.\n */\nexport function viewMatchesScope(view, page = {}) {\n\tconst query = view && typeof view === 'object' ? view.query : null\n\tif (!query || typeof query !== 'object' || Array.isArray(query)) {\n\t\treturn true\n\t}\n\tif (typeof query.scope === 'string' && query.scope !== '') {\n\t\treturn query.scope === savedViewScope(page)\n\t}\n\tif (Array.isArray(query.schemas) && query.schemas.length > 0) {\n\t\tconst slug = schemaSlug(page.schema)\n\t\tif (slug === '' || !query.schemas.map(String).includes(slug)) {\n\t\t\treturn false\n\t\t}\n\t\tif (Array.isArray(query.registers) && query.registers.length > 0 && page.register) {\n\t\t\treturn query.registers.map(String).includes(String(page.register))\n\t\t}\n\t\treturn true\n\t}\n\treturn true\n}\n\n/**\n * Normalize a View API object (as returned by `GET /api/views`) back into\n * the internal view state. Accepts either a full view object (reads its\n * `query` property) or a raw query blob directly. Every field degrades\n * defensively: missing/null/malformed `query`, non-object `filters`,\n * malformed `sort` all yield the empty/default state — never throws.\n *\n * @param {object|null|undefined} view The View API object (or its raw `query` blob).\n * @return {{ filters: object, search: string, sortKeys: Array<{key: string, order: string}>, sortKey: ?string, sortOrder: string }} The normalized view state.\n */\nexport function extractViewState(view) {\n\tconst state = emptyState()\n\tif (!view || typeof view !== 'object' || Array.isArray(view)) {\n\t\treturn state\n\t}\n\t// Full view object (has a `query` key) or a raw query blob itself.\n\tconst query = (Object.hasOwn(view, 'query')) ? view.query : view\n\tif (!query || typeof query !== 'object' || Array.isArray(query)) {\n\t\treturn state\n\t}\n\tif (query.filters && typeof query.filters === 'object' && !Array.isArray(query.filters)) {\n\t\tfor (const [key, value] of Object.entries(query.filters)) {\n\t\t\tif (value === undefined || value === null || value === '') {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tstate.filters[key] = value\n\t\t}\n\t}\n\tif (typeof query.search === 'string') {\n\t\tstate.search = query.search\n\t}\n\treturn withSort(state, normalizeSortKeys(query.sort))\n}\n\n/**\n * Whether the given view is owned by the given user. Drives the delete\n * affordance in CnSavedViewsControl — OpenRegister scopes destroy() to the\n * owner server-side (a foreign id 404s), so this only hides the button for\n * views the API would refuse to delete anyway.\n *\n * @param {object|null|undefined} view The View API object.\n * @param {string|null|undefined} currentUserId The signed-in NC user id.\n * @return {boolean} True when the view belongs to the current user.\n */\nexport function isOwnView(view, currentUserId) {\n\treturn !!view && !!currentUserId && view.owner === currentUserId\n}\n\n/**\n * The default views an index page declares (`config.defaultSavedViews`), as\n * read-only views the saved-views control lists. They are never stored: the\n * manifest installs them, so every user has the same set and none can delete\n * one. `seeded: true` puts them in the control's default group; the query\n * keeps its `@`-tokens, which resolve when a default is applied.\n *\n * A default's `overrides` (page config laid over the page while it is\n * active, see `utils/savedViewOverrides.js`) ride in `query.overrides`, so a\n * copy of the default keeps them.\n *\n * @param {Array<object>|null|undefined} defaults The declared entries `{ slug, name, filters, search?, sort?, label?, overrides? }`.\n * @param {{ scope?: string, register?: string, schema?: object|string|null }} [page] The page, as `savedViewScope` takes it.\n * @return {Array<object>} The views, in declaration order; entries without a slug or name are left out.\n * @spec openspec/changes/saved-views-manage-and-defaults/tasks.md#task-4\n */\nexport function defaultFilterViews(defaults, page = {}) {\n\tif (!Array.isArray(defaults)) {\n\t\treturn []\n\t}\n\treturn defaults\n\t\t.filter((entry) => entry && typeof entry.slug === 'string' && entry.slug !== '' && typeof entry.name === 'string' && entry.name !== '')\n\t\t.map((entry) => {\n\t\t\tconst { query } = buildViewCreatePayload({\n\t\t\t\tname: entry.name,\n\t\t\t\tstate: {\n\t\t\t\t\tfilters: (entry.filters && typeof entry.filters === 'object' && !Array.isArray(entry.filters)) ? entry.filters : {},\n\t\t\t\t\tsearch: typeof entry.search === 'string' ? entry.search : '',\n\t\t\t\t\tsortKeys: Array.isArray(entry.sort) ? entry.sort : [],\n\t\t\t\t},\n\t\t\t\tscope: savedViewScope(page),\n\t\t\t\tregister: page.register,\n\t\t\t\tschema: page.schema,\n\t\t\t})\n\t\t\tif (entry.overrides && typeof entry.overrides === 'object' && !Array.isArray(entry.overrides)) {\n\t\t\t\tquery.overrides = entry.overrides\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tid: `default:${entry.slug}`,\n\t\t\t\tslug: entry.slug,\n\t\t\t\tname: entry.name,\n\t\t\t\towner: '',\n\t\t\t\tseeded: true,\n\t\t\t\tisPublic: false,\n\t\t\t\tlabels: typeof entry.label === 'string' && entry.label !== '' ? [entry.label] : [],\n\t\t\t\t'@self': { access: 'read' },\n\t\t\t\tquery,\n\t\t\t}\n\t\t})\n}\n"],"names":[],"mappings":"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"}