@conduction/nextcloud-vue 2.65.0 → 2.67.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 (103) hide show
  1. package/dist/esm/components/CnActionsBar/CnActionsBar.vue2.js +19 -0
  2. package/dist/esm/components/CnActionsBar/CnActionsBar.vue2.js.map +1 -1
  3. package/dist/esm/components/CnActionsBar/CnActionsBar.vue3.js +10 -3
  4. package/dist/esm/components/CnActionsBar/CnActionsBar.vue3.js.map +1 -1
  5. package/dist/esm/components/CnAppNav/CnAppNav.vue2.js +2 -2
  6. package/dist/esm/components/CnAppNav/CnAppNav.vue2.js.map +1 -1
  7. package/dist/esm/components/CnAppNav/CnAppNav.vue3.js.map +1 -1
  8. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js +99 -2
  9. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js.map +1 -1
  10. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js +438 -383
  11. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js.map +1 -1
  12. package/dist/esm/components/CnDataTable/CnColumnFilterPopover.vue2.js +9 -3
  13. package/dist/esm/components/CnDataTable/CnColumnFilterPopover.vue2.js.map +1 -1
  14. package/dist/esm/components/CnDataTable/CnColumnFilterPopover.vue3.js +1 -1
  15. package/dist/esm/components/CnDataTable/CnColumnFilterPopover.vue3.js.map +1 -1
  16. package/dist/esm/components/CnDataTable/CnDataTable.vue2.js +4 -4
  17. package/dist/esm/components/CnDataTable/CnDataTable.vue2.js.map +1 -1
  18. package/dist/esm/components/CnDataTable/CnDataTable.vue3.js.map +1 -1
  19. package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js +78 -21
  20. package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js.map +1 -1
  21. package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js +129 -96
  22. package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js.map +1 -1
  23. package/dist/esm/components/CnFkResolveCell/CnFkResolveCell.vue2.js +3 -1
  24. package/dist/esm/components/CnFkResolveCell/CnFkResolveCell.vue2.js.map +1 -1
  25. package/dist/esm/components/CnFormDialog/CnFormDialog.vue2.js +144 -4
  26. package/dist/esm/components/CnFormDialog/CnFormDialog.vue2.js.map +1 -1
  27. package/dist/esm/components/CnFormDialog/CnFormDialog.vue3.js.map +1 -1
  28. package/dist/esm/components/CnHeaderWidget/CnHeaderWidget.vue2.js +63 -7
  29. package/dist/esm/components/CnHeaderWidget/CnHeaderWidget.vue2.js.map +1 -1
  30. package/dist/esm/components/CnHeaderWidget/CnHeaderWidget.vue3.js +2 -1
  31. package/dist/esm/components/CnHeaderWidget/CnHeaderWidget.vue3.js.map +1 -1
  32. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +31 -1
  33. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
  34. package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js +335 -313
  35. package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
  36. package/dist/esm/components/CnSegmentedControl/CnSegmentedControl.vue2.js +11 -0
  37. package/dist/esm/components/CnSegmentedControl/CnSegmentedControl.vue2.js.map +1 -1
  38. package/dist/esm/components/CnSegmentedControl/CnSegmentedControl.vue3.js +2 -1
  39. package/dist/esm/components/CnSegmentedControl/CnSegmentedControl.vue3.js.map +1 -1
  40. package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue2.js +5 -11
  41. package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue2.js.map +1 -1
  42. package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue3.js.map +1 -1
  43. package/dist/esm/composables/useDependencyCheck.js +44 -1
  44. package/dist/esm/composables/useDependencyCheck.js.map +1 -1
  45. package/dist/esm/composables/useListView.js +43 -1
  46. package/dist/esm/composables/useListView.js.map +1 -1
  47. package/dist/esm/composables/useSetupStatus.js +26 -3
  48. package/dist/esm/composables/useSetupStatus.js.map +1 -1
  49. package/dist/esm/l10n/en.json.js +7 -1
  50. package/dist/esm/l10n/en.json.js.map +1 -1
  51. package/dist/esm/l10n/nl.json.js +7 -1
  52. package/dist/esm/l10n/nl.json.js.map +1 -1
  53. package/dist/esm/mixins/pageViews.js +400 -0
  54. package/dist/esm/mixins/pageViews.js.map +1 -0
  55. package/dist/esm/nextcloud-vue.css +38 -2
  56. package/dist/esm/store/plugins/liveUpdates.js +19 -9
  57. package/dist/esm/store/plugins/liveUpdates.js.map +1 -1
  58. package/dist/esm/store/useObjectStore.js +20 -9
  59. package/dist/esm/store/useObjectStore.js.map +1 -1
  60. package/dist/esm/utils/actionsDispatcher.js +11 -2
  61. package/dist/esm/utils/actionsDispatcher.js.map +1 -1
  62. package/dist/esm/utils/columnFilters.js +27 -3
  63. package/dist/esm/utils/columnFilters.js.map +1 -1
  64. package/dist/esm/utils/schema.js +40 -2
  65. package/dist/esm/utils/schema.js.map +1 -1
  66. package/dist/esm/utils/validateManifestV2.compiled.js +2 -2
  67. package/dist/esm/utils/validateManifestV2.compiled.js.map +1 -1
  68. package/dist/nextcloud-vue.cjs.js +2377 -1247
  69. package/dist/nextcloud-vue.cjs.js.map +2 -2
  70. package/dist/nextcloud-vue.css +38 -2
  71. package/l10n/en.json +7 -1
  72. package/l10n/nl.json +7 -1
  73. package/package.json +1 -1
  74. package/src/components/CnActionsBar/CnActionsBar.md +2 -1
  75. package/src/components/CnActionsBar/CnActionsBar.vue +25 -1
  76. package/src/components/CnAppNav/CnAppNav.vue +2 -2
  77. package/src/components/CnDashboardPage/CnDashboardPage.vue +165 -8
  78. package/src/components/CnDataTable/CnColumnFilterPopover.vue +11 -5
  79. package/src/components/CnDataTable/CnDataTable.md +1 -1
  80. package/src/components/CnDataTable/CnDataTable.vue +4 -4
  81. package/src/components/CnDetailPage/CnDetailPage.vue +94 -5
  82. package/src/components/CnFkResolveCell/CnFkResolveCell.vue +3 -1
  83. package/src/components/CnFormDialog/CnFormDialog.vue +144 -4
  84. package/src/components/CnHeaderWidget/CnHeaderWidget.vue +67 -8
  85. package/src/components/CnIndexPage/CnIndexPage.md +2 -1
  86. package/src/components/CnIndexPage/CnIndexPage.vue +47 -1
  87. package/src/components/CnSegmentedControl/CnSegmentedControl.md +1 -1
  88. package/src/components/CnSegmentedControl/CnSegmentedControl.vue +12 -0
  89. package/src/components/CnSetupWizard/CnSetupWizard.vue +5 -11
  90. package/src/composables/useDependencyCheck.js +43 -0
  91. package/src/composables/useListView.js +43 -1
  92. package/src/composables/useSetupStatus.js +26 -3
  93. package/src/css/actions-bar.css +20 -2
  94. package/src/css/detail-page.css +5 -0
  95. package/src/mixins/pageViews.js +396 -0
  96. package/src/schemas/app-manifest-v2.schema.json +31 -3
  97. package/src/schemas/app-manifest.schema.json +1 -1
  98. package/src/store/plugins/liveUpdates.js +19 -9
  99. package/src/store/useObjectStore.js +19 -8
  100. package/src/utils/actionsDispatcher.js +11 -2
  101. package/src/utils/columnFilters.js +29 -2
  102. package/src/utils/schema.js +40 -2
  103. package/src/utils/validateManifestV2.compiled.js +2 -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 {\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 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 * @return {string} The type slug to use for store CRUD calls.\n */\nexport function resolveObjectOpType(store, source) {\n\tconst register = String(source.register)\n\tconst 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 registry = context.registry || {}\n\t\t\tconst entry = 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: the row's object merged with the action's values.\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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A;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,IAAI;AACJ,GAAG,QAAQ,CAAC,WAAW,CAAC,CAAC,IAAI,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC,EAAC;AAChD,GAAG,KAAK;AACR,GAAG;AACH;AACA,EAAE,KAAK,YAAY,EA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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 {\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 registry = context.registry || {}\n\t\t\tconst entry = 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: the row's object merged with the action's values.\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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;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,IAA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"}
@@ -6,6 +6,9 @@ import { schemaRefSlug } from './schemaRefSlug.js';
6
6
  */
7
7
 
8
8
 
9
+ /** OpenRegister's case-insensitive contains operator, used by the text filter. */
10
+ const CONTAINS_OPERATOR = 'like';
11
+
9
12
  /** Column keys that mark a value computed on the client, never stored. */
10
13
  const COMPUTED_MARKERS = ['aggregate', 'compute', 'computed', 'virtual'];
11
14
 
@@ -144,7 +147,7 @@ function referenceTarget(column, prop) {
144
147
  *
145
148
  * Kinds: `enum` (checkbox list), `boolean` (yes, no, any), `reference`
146
149
  * (searchable list of the referenced objects), `number` and `date` (from and
147
- * to), and `string` (equals). `filterable: false` on the column turns it
150
+ * to), and `string` (contains, through OpenRegister's `[like]`). `filterable: false` on the column turns it
148
151
  * off. A column with no schema property behind it only filters when it
149
152
  * carries an enum hint (`enum`, or a badge widget's colour map), because the
150
153
  * server cannot filter on a value it does not store.
@@ -218,9 +221,25 @@ function columnFilterParamKeys(def) {
218
221
  if (def.kind === 'number' || def.kind === 'date') {
219
222
  return [`${def.key}[gte]`, `${def.key}[lte]`]
220
223
  }
224
+ if (def.kind === 'string') {
225
+ return [containsKey(def)]
226
+ }
221
227
  return [def.key]
222
228
  }
223
229
 
230
+ /**
231
+ * The parameter a text filter writes: `{key}[like]`. An exact `key=value`
232
+ * from the facet sidebar or a fixed filter is a different key, so the header
233
+ * neither shows nor clears it.
234
+ *
235
+ * @param {object} def A filter definition of kind `string`.
236
+ * @return {string} The parameter key.
237
+ * @spec openspec/changes/header-filter-contains/specs/cn-data-table/spec.md#requirement-a-text-header-filter-matches-on-contains
238
+ */
239
+ function containsKey(def) {
240
+ return `${def.key}[${CONTAINS_OPERATOR}]`
241
+ }
242
+
224
243
  /**
225
244
  * A column filter's current state, read from the active-filter map.
226
245
  *
@@ -246,6 +265,9 @@ function columnFilterState(def, activeFilters) {
246
265
  to: def.kind === 'date' ? to.slice(0, 10) : to,
247
266
  }
248
267
  }
268
+ if (def.kind === 'string') {
269
+ return { value: asList(filters[containsKey(def)])[0] || '' }
270
+ }
249
271
  return { value: asList(filters[def.key])[0] || '' }
250
272
  }
251
273
 
@@ -293,8 +315,10 @@ function columnFilterParams(def, state) {
293
315
  if (def.kind === 'boolean') {
294
316
  return { [def.key]: (s.value === 'true' || s.value === 'false') ? [s.value] : [] }
295
317
  }
318
+ // Text: the raw term under `[like]`. No wildcards: OpenRegister wraps
319
+ // the term itself and escapes `%`, `_` and `\` in it.
296
320
  const value = s.value === undefined || s.value === null ? '' : String(s.value).trim();
297
- return { [def.key]: value === '' ? [] : [value] }
321
+ return { [containsKey(def)]: value === '' ? [] : [value] }
298
322
  }
299
323
 
300
324
  /**
@@ -307,5 +331,5 @@ function clearedColumnFilterParams(def) {
307
331
  return Object.fromEntries(columnFilterParamKeys(def).map((key) => [key, []]))
308
332
  }
309
333
 
310
- export { clearedColumnFilterParams, columnFilterDef, columnFilterParamKeys, columnFilterParams, columnFilterState, columnProperty, isColumnFilterActive, isColumnSortable };
334
+ export { CONTAINS_OPERATOR, clearedColumnFilterParams, columnFilterDef, columnFilterParamKeys, columnFilterParams, columnFilterState, columnProperty, isColumnFilterActive, isColumnSortable };
311
335
  //# sourceMappingURL=columnFilters.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"columnFilters.js","sources":["../../../src/utils/columnFilters.js"],"sourcesContent":["/**\n * SPDX-FileCopyrightText: 2026 Conduction B.V.\n * SPDX-License-Identifier: EUPL-1.2\n */\n\n/**\n * Per-column sorting and filtering for table headers.\n *\n * Pure helpers: which column can sort, which can filter and how, and the\n * translation between a header filter's state and the OpenRegister query\n * parameters the facet sidebar already sends. A header filter writes into the\n * SAME active-filter map (`{ paramKey: values[] }`) the sidebar uses, so the\n * fetch, the route query and saved views need nothing new.\n *\n * Parameter shapes, as OpenRegister reads them:\n * - equality and \"any of\": `key=value`, `key[]=a&key[]=b`\n * - ranges: `key[gte]=from`, `key[lte]=to`\n *\n * @module utils/columnFilters\n * @spec openspec/changes/table-header-sort-and-filter/specs/cn-data-table/spec.md\n */\n\nimport { schemaRefSlug } from './schemaRefSlug.js'\n\n/** Column keys that mark a value computed on the client, never stored. */\nconst COMPUTED_MARKERS = ['aggregate', 'compute', 'computed', 'virtual']\n\n/**\n * Normalise a `$ref` to the referenced schema slug, or null.\n *\n * @param {unknown} ref A `$ref` value.\n * @return {string|number|null} The slug.\n */\nfunction refSlug(ref) {\n\tif (typeof ref === 'number' && !Number.isNaN(ref)) {\n\t\treturn ref\n\t}\n\tif (typeof ref !== 'string' || ref === '') {\n\t\treturn null\n\t}\n\tconst tail = ref.includes('/') ? ref.substring(ref.lastIndexOf('/') + 1) : ref\n\tconst slug = tail === '' ? '' : schemaRefSlug(tail)\n\treturn slug !== '' ? slug : null\n}\n\n/**\n * The schema property behind a column, or null when the column has none.\n *\n * @param {object} column The column definition.\n * @param {object|null} schema The table's schema.\n * @return {object|null} The property.\n */\nexport function columnProperty(column, schema) {\n\tif (!column || !schema || !schema.properties || typeof column.key !== 'string') {\n\t\treturn null\n\t}\n\tconst prop = schema.properties[column.key]\n\treturn (prop && typeof prop === 'object') ? prop : null\n}\n\n/**\n * Whether a column computes its value on the client, so the server cannot\n * sort or filter on it.\n *\n * @param {object} column The column definition.\n * @return {boolean} True for a computed column.\n */\nfunction isComputedColumn(column) {\n\treturn COMPUTED_MARKERS.some((marker) => column[marker] !== undefined && column[marker] !== null && column[marker] !== false)\n}\n\n/**\n * Whether a column header sorts.\n *\n * `sortable: false` always wins, and so does an explicit `sortable: true`.\n * Otherwise, with a schema, a column sorts when a stored schema property backs\n * it: OpenRegister orders on schema properties, so a widget or computed column\n * with no property behind it stays unsortable. Without a schema nothing says\n * the server can sort, so only an explicit flag makes the column sortable,\n * which is how such tables behaved before.\n *\n * @param {object} column The column definition.\n * @param {object|null} schema The table's schema.\n * @return {boolean} True when the header sorts.\n * @spec openspec/changes/table-header-sort-and-filter/specs/cn-data-table/spec.md#requirement-every-backed-column-sorts-by-default\n */\nexport function isColumnSortable(column, schema) {\n\tif (!column || typeof column !== 'object') {\n\t\treturn false\n\t}\n\tif (column.sortable === false) {\n\t\treturn false\n\t}\n\tif (column.sortable === true) {\n\t\treturn true\n\t}\n\tif (!schema || isComputedColumn(column)) {\n\t\treturn false\n\t}\n\tconst prop = columnProperty(column, schema)\n\treturn !!prop && prop.type !== 'object'\n}\n\n/**\n * Display options for an enum filter: schema `enum` (or `items.enum`) with\n * `x-enum-labels`, else a column `enum` hint, else a badge column's colour\n * map keys.\n *\n * @param {object} column The column definition.\n * @param {object|null} prop The schema property.\n * @return {Array<{value: string, label: string}>} The options, or [].\n */\nfunction enumOptions(column, prop) {\n\tconst p = prop || {}\n\tconst labels = p.enumLabels || p['x-enum-labels'] || (p.items && (p.items.enumLabels || p.items['x-enum-labels'])) || {}\n\tlet values = null\n\tif (Array.isArray(p.enum) && p.enum.length > 0) {\n\t\tvalues = p.enum\n\t} else if (p.items && Array.isArray(p.items.enum) && p.items.enum.length > 0) {\n\t\tvalues = p.items.enum\n\t} else if (Array.isArray(column.enum) && column.enum.length > 0) {\n\t\tvalues = column.enum\n\t} else if (column.widget === 'badge' && column.widgetProps && column.widgetProps.colorMap) {\n\t\tvalues = Object.keys(column.widgetProps.colorMap)\n\t}\n\tif (!values) {\n\t\treturn []\n\t}\n\treturn values\n\t\t.filter((v) => v !== null && v !== undefined && v !== '')\n\t\t.map((v) => ({ value: String(v), label: String(labels[v] !== undefined ? labels[v] : v) }))\n}\n\n/**\n * The reference a column points at, for a searchable object filter: a schema\n * `$ref` (or `items.$ref`), else an `fkResolve` cell widget's config.\n *\n * @param {object} column The column definition.\n * @param {object|null} prop The schema property.\n * @return {{schema: (string|number), register: string, labelField: string}|null} The reference.\n */\nfunction referenceTarget(column, prop) {\n\tconst widgetProps = (column.widget === 'fkResolve' && column.widgetProps) || null\n\tconst p = prop || {}\n\tconst schemaRef = refSlug(p.$ref) ?? (p.items ? refSlug(p.items.$ref) : null)\n\tconst schema = schemaRef ?? (widgetProps && widgetProps.schema ? widgetProps.schema : null)\n\tif (schema === null || schema === undefined || schema === '') {\n\t\treturn null\n\t}\n\tconst register = (widgetProps && widgetProps.register)\n\t\t|| p['x-external-register']\n\t\t|| (p.items && p.items['x-external-register'])\n\t\t|| ''\n\tconst labelField = (widgetProps && widgetProps.labelField) || ''\n\treturn { schema, register, labelField }\n}\n\n/**\n * How a column filters, or null when it does not.\n *\n * Kinds: `enum` (checkbox list), `boolean` (yes, no, any), `reference`\n * (searchable list of the referenced objects), `number` and `date` (from and\n * to), and `string` (equals). `filterable: false` on the column turns it\n * off. A column with no schema property behind it only filters when it\n * carries an enum hint (`enum`, or a badge widget's colour map), because the\n * server cannot filter on a value it does not store.\n *\n * @param {object} column The column definition.\n * @param {object|null} schema The table's schema.\n * @return {{key: string, kind: string, label: string, options: Array<{value: string, label: string}>, reference: object|null, dateTime: boolean}|null} The filter definition.\n * @spec openspec/changes/table-header-sort-and-filter/specs/cn-data-table/spec.md#requirement-every-backed-column-filters-from-its-header\n */\nexport function columnFilterDef(column, schema) {\n\tif (!column || typeof column !== 'object' || typeof column.key !== 'string' || column.key === '') {\n\t\treturn null\n\t}\n\tif (column.filterable === false || isComputedColumn(column)) {\n\t\treturn null\n\t}\n\tconst prop = columnProperty(column, schema)\n\tconst base = { key: column.key, label: column.label || (prop && prop.title) || column.key, options: [], reference: null, dateTime: false }\n\n\tconst options = enumOptions(column, prop)\n\tif (options.length > 0) {\n\t\treturn { ...base, kind: 'enum', options }\n\t}\n\tif (!prop) {\n\t\treturn null\n\t}\n\tconst reference = referenceTarget(column, prop)\n\tif (reference) {\n\t\treturn { ...base, kind: 'reference', reference }\n\t}\n\tconst type = Array.isArray(prop.type) ? prop.type.find((t) => t !== 'null') : prop.type\n\tconst format = prop.format || ''\n\tif (type === 'boolean') {\n\t\treturn { ...base, kind: 'boolean' }\n\t}\n\tif (type === 'number' || type === 'integer') {\n\t\treturn { ...base, kind: 'number' }\n\t}\n\tif (type === 'string' && (format === 'date' || format === 'date-time')) {\n\t\treturn { ...base, kind: 'date', dateTime: format === 'date-time' }\n\t}\n\tif (type === 'string') {\n\t\treturn { ...base, kind: 'string' }\n\t}\n\treturn null\n}\n\n/**\n * Read one active-filter entry as a list of strings.\n *\n * @param {unknown} raw An active-filter value: an array, a scalar, or absent.\n * @return {Array<string>} The values.\n */\nfunction asList(raw) {\n\tif (raw === undefined || raw === null || raw === '') {\n\t\treturn []\n\t}\n\treturn (Array.isArray(raw) ? raw : [raw]).filter((v) => v !== undefined && v !== null && v !== '').map((v) => String(v))\n}\n\n/**\n * The parameter keys one column filter owns.\n *\n * @param {object} def A filter definition from `columnFilterDef`.\n * @return {Array<string>} The keys.\n */\nexport function columnFilterParamKeys(def) {\n\tif (!def) {\n\t\treturn []\n\t}\n\tif (def.kind === 'number' || def.kind === 'date') {\n\t\treturn [`${def.key}[gte]`, `${def.key}[lte]`]\n\t}\n\treturn [def.key]\n}\n\n/**\n * A column filter's current state, read from the active-filter map.\n *\n * @param {object} def A filter definition.\n * @param {object} activeFilters The active-filter map (`{ paramKey: values }`).\n * @return {object} `{ values }` for enum and reference, `{ value }` for boolean and string, `{ from, to }` for number and date.\n */\nexport function columnFilterState(def, activeFilters) {\n\tconst filters = (activeFilters && typeof activeFilters === 'object') ? activeFilters : {}\n\tif (!def) {\n\t\treturn {}\n\t}\n\tif (def.kind === 'enum' || def.kind === 'reference') {\n\t\treturn { values: asList(filters[def.key]) }\n\t}\n\tif (def.kind === 'number' || def.kind === 'date') {\n\t\tconst from = asList(filters[`${def.key}[gte]`])[0] || ''\n\t\tconst to = asList(filters[`${def.key}[lte]`])[0] || ''\n\t\t// A date-time column is queried up to the end of the day; the input\n\t\t// shows the date the person picked.\n\t\treturn {\n\t\t\tfrom: def.kind === 'date' ? from.slice(0, 10) : from,\n\t\t\tto: def.kind === 'date' ? to.slice(0, 10) : to,\n\t\t}\n\t}\n\treturn { value: asList(filters[def.key])[0] || '' }\n}\n\n/**\n * Whether a column filter is active.\n *\n * @param {object} def A filter definition.\n * @param {object} activeFilters The active-filter map.\n * @return {boolean} True when any of its parameters is set.\n */\nexport function isColumnFilterActive(def, activeFilters) {\n\tconst filters = (activeFilters && typeof activeFilters === 'object') ? activeFilters : {}\n\treturn columnFilterParamKeys(def).some((key) => asList(filters[key]).length > 0)\n}\n\n/**\n * The active-filter entries a column filter state produces. Every key the\n * column owns is present; an empty list clears that key, so changing a range\n * from \"from and to\" to \"from\" drops the old upper bound.\n *\n * @param {object} def A filter definition.\n * @param {object} state The column filter state (see `columnFilterState`).\n * @return {object} `{ paramKey: values[] }`.\n * @spec openspec/changes/table-header-sort-and-filter/specs/cn-data-table/spec.md#requirement-a-header-filter-speaks-the-sidebars-query-language\n */\nexport function columnFilterParams(def, state) {\n\tconst s = state || {}\n\tif (!def) {\n\t\treturn {}\n\t}\n\tif (def.kind === 'enum' || def.kind === 'reference') {\n\t\treturn { [def.key]: asList(s.values) }\n\t}\n\tif (def.kind === 'number' || def.kind === 'date') {\n\t\tconst from = s.from === undefined || s.from === null ? '' : String(s.from).trim()\n\t\tlet to = s.to === undefined || s.to === null ? '' : String(s.to).trim()\n\t\tif (def.kind === 'date' && def.dateTime && to !== '' && to.length === 10) {\n\t\t\tto = `${to}T23:59:59`\n\t\t}\n\t\treturn {\n\t\t\t[`${def.key}[gte]`]: from === '' ? [] : [from],\n\t\t\t[`${def.key}[lte]`]: to === '' ? [] : [to],\n\t\t}\n\t}\n\tif (def.kind === 'boolean') {\n\t\treturn { [def.key]: (s.value === 'true' || s.value === 'false') ? [s.value] : [] }\n\t}\n\tconst value = s.value === undefined || s.value === null ? '' : String(s.value).trim()\n\treturn { [def.key]: value === '' ? [] : [value] }\n}\n\n/**\n * Clear-all entries for one column: every key it owns, emptied.\n *\n * @param {object} def A filter definition.\n * @return {object} `{ paramKey: [] }`.\n */\nexport function clearedColumnFilterParams(def) {\n\treturn Object.fromEntries(columnFilterParamKeys(def).map((key) => [key, []]))\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"columnFilters.js","sources":["../../../src/utils/columnFilters.js"],"sourcesContent":["/**\n * SPDX-FileCopyrightText: 2026 Conduction B.V.\n * SPDX-License-Identifier: EUPL-1.2\n */\n\n/**\n * Per-column sorting and filtering for table headers.\n *\n * Pure helpers: which column can sort, which can filter and how, and the\n * translation between a header filter's state and the OpenRegister query\n * parameters the facet sidebar already sends. A header filter writes into the\n * SAME active-filter map (`{ paramKey: values[] }`) the sidebar uses, so the\n * fetch, the route query and saved views need nothing new.\n *\n * Parameter shapes, as OpenRegister reads them:\n * - equality and \"any of\": `key=value`, `key[]=a&key[]=b`\n * - ranges: `key[gte]=from`, `key[lte]=to`\n * - contains (text): `key[like]=term`, case-insensitive (openregister#4430);\n * the server escapes `%`, `_` and `\\`, so the raw term goes out as typed\n *\n * @module utils/columnFilters\n * @spec openspec/changes/table-header-sort-and-filter/specs/cn-data-table/spec.md\n * @spec openspec/changes/header-filter-contains/specs/cn-data-table/spec.md#requirement-a-text-header-filter-matches-on-contains\n */\n\nimport { schemaRefSlug } from './schemaRefSlug.js'\n\n/** OpenRegister's case-insensitive contains operator, used by the text filter. */\nexport const CONTAINS_OPERATOR = 'like'\n\n/** Column keys that mark a value computed on the client, never stored. */\nconst COMPUTED_MARKERS = ['aggregate', 'compute', 'computed', 'virtual']\n\n/**\n * Normalise a `$ref` to the referenced schema slug, or null.\n *\n * @param {unknown} ref A `$ref` value.\n * @return {string|number|null} The slug.\n */\nfunction refSlug(ref) {\n\tif (typeof ref === 'number' && !Number.isNaN(ref)) {\n\t\treturn ref\n\t}\n\tif (typeof ref !== 'string' || ref === '') {\n\t\treturn null\n\t}\n\tconst tail = ref.includes('/') ? ref.substring(ref.lastIndexOf('/') + 1) : ref\n\tconst slug = tail === '' ? '' : schemaRefSlug(tail)\n\treturn slug !== '' ? slug : null\n}\n\n/**\n * The schema property behind a column, or null when the column has none.\n *\n * @param {object} column The column definition.\n * @param {object|null} schema The table's schema.\n * @return {object|null} The property.\n */\nexport function columnProperty(column, schema) {\n\tif (!column || !schema || !schema.properties || typeof column.key !== 'string') {\n\t\treturn null\n\t}\n\tconst prop = schema.properties[column.key]\n\treturn (prop && typeof prop === 'object') ? prop : null\n}\n\n/**\n * Whether a column computes its value on the client, so the server cannot\n * sort or filter on it.\n *\n * @param {object} column The column definition.\n * @return {boolean} True for a computed column.\n */\nfunction isComputedColumn(column) {\n\treturn COMPUTED_MARKERS.some((marker) => column[marker] !== undefined && column[marker] !== null && column[marker] !== false)\n}\n\n/**\n * Whether a column header sorts.\n *\n * `sortable: false` always wins, and so does an explicit `sortable: true`.\n * Otherwise, with a schema, a column sorts when a stored schema property backs\n * it: OpenRegister orders on schema properties, so a widget or computed column\n * with no property behind it stays unsortable. Without a schema nothing says\n * the server can sort, so only an explicit flag makes the column sortable,\n * which is how such tables behaved before.\n *\n * @param {object} column The column definition.\n * @param {object|null} schema The table's schema.\n * @return {boolean} True when the header sorts.\n * @spec openspec/changes/table-header-sort-and-filter/specs/cn-data-table/spec.md#requirement-every-backed-column-sorts-by-default\n */\nexport function isColumnSortable(column, schema) {\n\tif (!column || typeof column !== 'object') {\n\t\treturn false\n\t}\n\tif (column.sortable === false) {\n\t\treturn false\n\t}\n\tif (column.sortable === true) {\n\t\treturn true\n\t}\n\tif (!schema || isComputedColumn(column)) {\n\t\treturn false\n\t}\n\tconst prop = columnProperty(column, schema)\n\treturn !!prop && prop.type !== 'object'\n}\n\n/**\n * Display options for an enum filter: schema `enum` (or `items.enum`) with\n * `x-enum-labels`, else a column `enum` hint, else a badge column's colour\n * map keys.\n *\n * @param {object} column The column definition.\n * @param {object|null} prop The schema property.\n * @return {Array<{value: string, label: string}>} The options, or [].\n */\nfunction enumOptions(column, prop) {\n\tconst p = prop || {}\n\tconst labels = p.enumLabels || p['x-enum-labels'] || (p.items && (p.items.enumLabels || p.items['x-enum-labels'])) || {}\n\tlet values = null\n\tif (Array.isArray(p.enum) && p.enum.length > 0) {\n\t\tvalues = p.enum\n\t} else if (p.items && Array.isArray(p.items.enum) && p.items.enum.length > 0) {\n\t\tvalues = p.items.enum\n\t} else if (Array.isArray(column.enum) && column.enum.length > 0) {\n\t\tvalues = column.enum\n\t} else if (column.widget === 'badge' && column.widgetProps && column.widgetProps.colorMap) {\n\t\tvalues = Object.keys(column.widgetProps.colorMap)\n\t}\n\tif (!values) {\n\t\treturn []\n\t}\n\treturn values\n\t\t.filter((v) => v !== null && v !== undefined && v !== '')\n\t\t.map((v) => ({ value: String(v), label: String(labels[v] !== undefined ? labels[v] : v) }))\n}\n\n/**\n * The reference a column points at, for a searchable object filter: a schema\n * `$ref` (or `items.$ref`), else an `fkResolve` cell widget's config.\n *\n * @param {object} column The column definition.\n * @param {object|null} prop The schema property.\n * @return {{schema: (string|number), register: string, labelField: string}|null} The reference.\n */\nfunction referenceTarget(column, prop) {\n\tconst widgetProps = (column.widget === 'fkResolve' && column.widgetProps) || null\n\tconst p = prop || {}\n\tconst schemaRef = refSlug(p.$ref) ?? (p.items ? refSlug(p.items.$ref) : null)\n\tconst schema = schemaRef ?? (widgetProps && widgetProps.schema ? widgetProps.schema : null)\n\tif (schema === null || schema === undefined || schema === '') {\n\t\treturn null\n\t}\n\tconst register = (widgetProps && widgetProps.register)\n\t\t|| p['x-external-register']\n\t\t|| (p.items && p.items['x-external-register'])\n\t\t|| ''\n\tconst labelField = (widgetProps && widgetProps.labelField) || ''\n\treturn { schema, register, labelField }\n}\n\n/**\n * How a column filters, or null when it does not.\n *\n * Kinds: `enum` (checkbox list), `boolean` (yes, no, any), `reference`\n * (searchable list of the referenced objects), `number` and `date` (from and\n * to), and `string` (contains, through OpenRegister's `[like]`). `filterable: false` on the column turns it\n * off. A column with no schema property behind it only filters when it\n * carries an enum hint (`enum`, or a badge widget's colour map), because the\n * server cannot filter on a value it does not store.\n *\n * @param {object} column The column definition.\n * @param {object|null} schema The table's schema.\n * @return {{key: string, kind: string, label: string, options: Array<{value: string, label: string}>, reference: object|null, dateTime: boolean}|null} The filter definition.\n * @spec openspec/changes/table-header-sort-and-filter/specs/cn-data-table/spec.md#requirement-every-backed-column-filters-from-its-header\n */\nexport function columnFilterDef(column, schema) {\n\tif (!column || typeof column !== 'object' || typeof column.key !== 'string' || column.key === '') {\n\t\treturn null\n\t}\n\tif (column.filterable === false || isComputedColumn(column)) {\n\t\treturn null\n\t}\n\tconst prop = columnProperty(column, schema)\n\tconst base = { key: column.key, label: column.label || (prop && prop.title) || column.key, options: [], reference: null, dateTime: false }\n\n\tconst options = enumOptions(column, prop)\n\tif (options.length > 0) {\n\t\treturn { ...base, kind: 'enum', options }\n\t}\n\tif (!prop) {\n\t\treturn null\n\t}\n\tconst reference = referenceTarget(column, prop)\n\tif (reference) {\n\t\treturn { ...base, kind: 'reference', reference }\n\t}\n\tconst type = Array.isArray(prop.type) ? prop.type.find((t) => t !== 'null') : prop.type\n\tconst format = prop.format || ''\n\tif (type === 'boolean') {\n\t\treturn { ...base, kind: 'boolean' }\n\t}\n\tif (type === 'number' || type === 'integer') {\n\t\treturn { ...base, kind: 'number' }\n\t}\n\tif (type === 'string' && (format === 'date' || format === 'date-time')) {\n\t\treturn { ...base, kind: 'date', dateTime: format === 'date-time' }\n\t}\n\tif (type === 'string') {\n\t\treturn { ...base, kind: 'string' }\n\t}\n\treturn null\n}\n\n/**\n * Read one active-filter entry as a list of strings.\n *\n * @param {unknown} raw An active-filter value: an array, a scalar, or absent.\n * @return {Array<string>} The values.\n */\nfunction asList(raw) {\n\tif (raw === undefined || raw === null || raw === '') {\n\t\treturn []\n\t}\n\treturn (Array.isArray(raw) ? raw : [raw]).filter((v) => v !== undefined && v !== null && v !== '').map((v) => String(v))\n}\n\n/**\n * The parameter keys one column filter owns.\n *\n * @param {object} def A filter definition from `columnFilterDef`.\n * @return {Array<string>} The keys.\n */\nexport function columnFilterParamKeys(def) {\n\tif (!def) {\n\t\treturn []\n\t}\n\tif (def.kind === 'number' || def.kind === 'date') {\n\t\treturn [`${def.key}[gte]`, `${def.key}[lte]`]\n\t}\n\tif (def.kind === 'string') {\n\t\treturn [containsKey(def)]\n\t}\n\treturn [def.key]\n}\n\n/**\n * The parameter a text filter writes: `{key}[like]`. An exact `key=value`\n * from the facet sidebar or a fixed filter is a different key, so the header\n * neither shows nor clears it.\n *\n * @param {object} def A filter definition of kind `string`.\n * @return {string} The parameter key.\n * @spec openspec/changes/header-filter-contains/specs/cn-data-table/spec.md#requirement-a-text-header-filter-matches-on-contains\n */\nfunction containsKey(def) {\n\treturn `${def.key}[${CONTAINS_OPERATOR}]`\n}\n\n/**\n * A column filter's current state, read from the active-filter map.\n *\n * @param {object} def A filter definition.\n * @param {object} activeFilters The active-filter map (`{ paramKey: values }`).\n * @return {object} `{ values }` for enum and reference, `{ value }` for boolean and string, `{ from, to }` for number and date.\n */\nexport function columnFilterState(def, activeFilters) {\n\tconst filters = (activeFilters && typeof activeFilters === 'object') ? activeFilters : {}\n\tif (!def) {\n\t\treturn {}\n\t}\n\tif (def.kind === 'enum' || def.kind === 'reference') {\n\t\treturn { values: asList(filters[def.key]) }\n\t}\n\tif (def.kind === 'number' || def.kind === 'date') {\n\t\tconst from = asList(filters[`${def.key}[gte]`])[0] || ''\n\t\tconst to = asList(filters[`${def.key}[lte]`])[0] || ''\n\t\t// A date-time column is queried up to the end of the day; the input\n\t\t// shows the date the person picked.\n\t\treturn {\n\t\t\tfrom: def.kind === 'date' ? from.slice(0, 10) : from,\n\t\t\tto: def.kind === 'date' ? to.slice(0, 10) : to,\n\t\t}\n\t}\n\tif (def.kind === 'string') {\n\t\treturn { value: asList(filters[containsKey(def)])[0] || '' }\n\t}\n\treturn { value: asList(filters[def.key])[0] || '' }\n}\n\n/**\n * Whether a column filter is active.\n *\n * @param {object} def A filter definition.\n * @param {object} activeFilters The active-filter map.\n * @return {boolean} True when any of its parameters is set.\n */\nexport function isColumnFilterActive(def, activeFilters) {\n\tconst filters = (activeFilters && typeof activeFilters === 'object') ? activeFilters : {}\n\treturn columnFilterParamKeys(def).some((key) => asList(filters[key]).length > 0)\n}\n\n/**\n * The active-filter entries a column filter state produces. Every key the\n * column owns is present; an empty list clears that key, so changing a range\n * from \"from and to\" to \"from\" drops the old upper bound.\n *\n * @param {object} def A filter definition.\n * @param {object} state The column filter state (see `columnFilterState`).\n * @return {object} `{ paramKey: values[] }`.\n * @spec openspec/changes/table-header-sort-and-filter/specs/cn-data-table/spec.md#requirement-a-header-filter-speaks-the-sidebars-query-language\n */\nexport function columnFilterParams(def, state) {\n\tconst s = state || {}\n\tif (!def) {\n\t\treturn {}\n\t}\n\tif (def.kind === 'enum' || def.kind === 'reference') {\n\t\treturn { [def.key]: asList(s.values) }\n\t}\n\tif (def.kind === 'number' || def.kind === 'date') {\n\t\tconst from = s.from === undefined || s.from === null ? '' : String(s.from).trim()\n\t\tlet to = s.to === undefined || s.to === null ? '' : String(s.to).trim()\n\t\tif (def.kind === 'date' && def.dateTime && to !== '' && to.length === 10) {\n\t\t\tto = `${to}T23:59:59`\n\t\t}\n\t\treturn {\n\t\t\t[`${def.key}[gte]`]: from === '' ? [] : [from],\n\t\t\t[`${def.key}[lte]`]: to === '' ? [] : [to],\n\t\t}\n\t}\n\tif (def.kind === 'boolean') {\n\t\treturn { [def.key]: (s.value === 'true' || s.value === 'false') ? [s.value] : [] }\n\t}\n\t// Text: the raw term under `[like]`. No wildcards: OpenRegister wraps\n\t// the term itself and escapes `%`, `_` and `\\` in it.\n\tconst value = s.value === undefined || s.value === null ? '' : String(s.value).trim()\n\treturn { [containsKey(def)]: value === '' ? [] : [value] }\n}\n\n/**\n * Clear-all entries for one column: every key it owns, emptied.\n *\n * @param {object} def A filter definition.\n * @return {object} `{ paramKey: [] }`.\n */\nexport function clearedColumnFilterParams(def) {\n\treturn Object.fromEntries(columnFilterParamKeys(def).map((key) => [key, []]))\n}\n"],"names":[],"mappings":";;AAAA;AACA;AACA;AACA;AACA;AAsBA;AACA;AACY,MAAC,iBAAiB,GAAG,OAAM;AACvC;AACA;AACA,MAAM,gBAAgB,GAAG,CAAC,WAAW,EAAE,SAAS,EAAE,UAAU,EAAE,SAAS,EAAC;AACxE;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS,OAAO,CAAC,GAAG,EAAE;AACtB,CAAC,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE;AACpD,EAAE,OAAO,GAAG;AACZ,EAAE;AACF,CAAC,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,EAAE,EAAE;AAC5C,EAAE,OAAO,IAAI;AACb,EAAE;AACF,CAAC,MAAM,IAAI,GAAG,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,IAAG;AAC/E,CAAC,MAAM,IAAI,GAAG,IAAI,KAAK,EAAE,GAAG,EAAE,GAAG,aAAa,CAAC,IAAI,EAAC;AACpD,CAAC,OAAO,IAAI,KAAK,EAAE,GAAG,IAAI,GAAG,IAAI;AACjC,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE;AAC/C,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,UAAU,IAAI,OAAO,MAAM,CAAC,GAAG,KAAK,QAAQ,EAAE;AACjF,EAAE,OAAO,IAAI;AACb,EAAE;AACF,CAAC,MAAM,IAAI,GAAG,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,GAAG,EAAC;AAC3C,CAAC,OAAO,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,GAAG,IAAI;AACxD,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS,gBAAgB,CAAC,MAAM,EAAE;AAClC,CAAC,OAAO,gBAAgB,CAAC,IAAI,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,KAAK,SAAS,IAAI,MAAM,CAAC,MAAM,CAAC,KAAK,IAAI,IAAI,MAAM,CAAC,MAAM,CAAC,KAAK,KAAK,CAAC;AAC9H,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE;AACjD,CAAC,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE;AAC5C,EAAE,OAAO,KAAK;AACd,EAAE;AACF,CAAC,IAAI,MAAM,CAAC,QAAQ,KAAK,KAAK,EAAE;AAChC,EAAE,OAAO,KAAK;AACd,EAAE;AACF,CAAC,IAAI,MAAM,CAAC,QAAQ,KAAK,IAAI,EAAE;AAC/B,EAAE,OAAO,IAAI;AACb,EAAE;AACF,CAAC,IAAI,CAAC,MAAM,IAAI,gBAAgB,CAAC,MAAM,CAAC,EAAE;AAC1C,EAAE,OAAO,KAAK;AACd,EAAE;AACF,CAAC,MAAM,IAAI,GAAG,cAAc,CAAC,MAAM,EAAE,MAAM,EAAC;AAC5C,CAAC,OAAO,CAAC,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,KAAK,QAAQ;AACxC,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS,WAAW,CAAC,MAAM,EAAE,IAAI,EAAE;AACnC,CAAC,MAAM,CAAC,GAAG,IAAI,IAAI,GAAE;AACrB,CAAC,MAAM,MAAM,GAAG,CAAC,CAAC,UAAU,IAAI,CAAC,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,KAAK,CAAC,UAAU,IAAI,CAAC,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC,CAAC,IAAI,GAAE;AACzH,CAAC,IAAI,MAAM,GAAG,KAAI;AAClB,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE;AACjD,EAAE,MAAM,GAAG,CAAC,CAAC,KAAI;AACjB,EAAE,MAAM,IAAI,CAAC,CAAC,KAAK,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE;AAC/E,EAAE,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,KAAI;AACvB,EAAE,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE;AAClE,EAAE,MAAM,GAAG,MAAM,CAAC,KAAI;AACtB,EAAE,MAAM,IAAI,MAAM,CAAC,MAAM,KAAK,OAAO,IAAI,MAAM,CAAC,WAAW,IAAI,MAAM,CAAC,WAAW,CAAC,QAAQ,EAAE;AAC5F,EAAE,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,QAAQ,EAAC;AACnD,EAAE;AACF,CAAC,IAAI,CAAC,MAAM,EAAE;AACd,EAAE,OAAO,EAAE;AACX,EAAE;AACF,CAAC,OAAO,MAAM;AACd,GAAG,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,SAAS,IAAI,CAAC,KAAK,EAAE,CAAC;AAC3D,GAAG,GAAG,CAAC,CAAC,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,SAAS,GAAG,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC;AAC7F,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS,eAAe,CAAC,MAAM,EAAE,IAAI,EAAE;AACvC,CAAC,MAAM,WAAW,GAAG,CAAC,MAAM,CAAC,MAAM,KAAK,WAAW,IAAI,MAAM,CAAC,WAAW,KAAK,KAAI;AAClF,CAAC,MAAM,CAAC,GAAG,IAAI,IAAI,GAAE;AACrB,CAAC,MAAM,SAAS,GAAG,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,KAAK,GAAG,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,IAAI,EAAC;AAC9E,CAAC,MAAM,MAAM,GAAG,SAAS,KAAK,WAAW,IAAI,WAAW,CAAC,MAAM,GAAG,WAAW,CAAC,MAAM,GAAG,IAAI,EAAC;AAC5F,CAAC,IAAI,MAAM,KAAK,IAAI,IAAI,MAAM,KAAK,SAAS,IAAI,MAAM,KAAK,EAAE,EAAE;AAC/D,EAAE,OAAO,IAAI;AACb,EAAE;AACF,CAAC,MAAM,QAAQ,GAAG,CAAC,WAAW,IAAI,WAAW,CAAC,QAAQ;AACtD,KAAK,CAAC,CAAC,qBAAqB,CAAC;AAC7B,MAAM,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,KAAK,CAAC,qBAAqB,CAAC,CAAC;AAChD,KAAK,GAAE;AACP,CAAC,MAAM,UAAU,GAAG,CAAC,WAAW,IAAI,WAAW,CAAC,UAAU,KAAK,GAAE;AACjE,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE;AACxC,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE;AAChD,CAAC,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,OAAO,MAAM,CAAC,GAAG,KAAK,QAAQ,IAAI,MAAM,CAAC,GAAG,KAAK,EAAE,EAAE;AACnG,EAAE,OAAO,IAAI;AACb,EAAE;AACF,CAAC,IAAI,MAAM,CAAC,UAAU,KAAK,KAAK,IAAI,gBAAgB,CAAC,MAAM,CAAC,EAAE;AAC9D,EAAE,OAAO,IAAI;AACb,EAAE;AACF,CAAC,MAAM,IAAI,GAAG,cAAc,CAAC,MAAM,EAAE,MAAM,EAAC;AAC5C,CAAC,MAAM,IAAI,GAAG,EAAE,GAAG,EAAE,MAAM,CAAC,GAAG,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,KAAK,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC,GAAG,EAAE,OAAO,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,GAAE;AAC3I;AACA,CAAC,MAAM,OAAO,GAAG,WAAW,CAAC,MAAM,EAAE,IAAI,EAAC;AAC1C,CAAC,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE;AACzB,EAAE,OAAO,EAAE,GAAG,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE;AAC3C,EAAE;AACF,CAAC,IAAI,CAAC,IAAI,EAAE;AACZ,EAAE,OAAO,IAAI;AACb,EAAE;AACF,CAAC,MAAM,SAAS,GAAG,eAAe,CAAC,MAAM,EAAE,IAAI,EAAC;AAChD,CAAC,IAAI,SAAS,EAAE;AAChB,EAAE,OAAO,EAAE,GAAG,IAAI,EAAE,IAAI,EAAE,WAAW,EAAE,SAAS,EAAE;AAClD,EAAE;AACF,CAAC,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,MAAM,CAAC,GAAG,IAAI,CAAC,KAAI;AACxF,CAAC,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,GAAE;AACjC,CAAC,IAAI,IAAI,KAAK,SAAS,EAAE;AACzB,EAAE,OAAO,EAAE,GAAG,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE;AACrC,EAAE;AACF,CAAC,IAAI,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,SAAS,EAAE;AAC9C,EAAE,OAAO,EAAE,GAAG,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE;AACpC,EAAE;AACF,CAAC,IAAI,IAAI,KAAK,QAAQ,KAAK,MAAM,KAAK,MAAM,IAAI,MAAM,KAAK,WAAW,CAAC,EAAE;AACzE,EAAE,OAAO,EAAE,GAAG,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,WAAW,EAAE;AACpE,EAAE;AACF,CAAC,IAAI,IAAI,KAAK,QAAQ,EAAE;AACxB,EAAE,OAAO,EAAE,GAAG,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE;AACpC,EAAE;AACF,CAAC,OAAO,IAAI;AACZ,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS,MAAM,CAAC,GAAG,EAAE;AACrB,CAAC,IAAI,GAAG,KAAK,SAAS,IAAI,GAAG,KAAK,IAAI,IAAI,GAAG,KAAK,EAAE,EAAE;AACtD,EAAE,OAAO,EAAE;AACX,EAAE;AACF,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,SAAS,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC;AACzH,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,qBAAqB,CAAC,GAAG,EAAE;AAC3C,CAAC,IAAI,CAAC,GAAG,EAAE;AACX,EAAE,OAAO,EAAE;AACX,EAAE;AACF,CAAC,IAAI,GAAG,CAAC,IAAI,KAAK,QAAQ,IAAI,GAAG,CAAC,IAAI,KAAK,MAAM,EAAE;AACnD,EAAE,OAAO,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;AAC/C,EAAE;AACF,CAAC,IAAI,GAAG,CAAC,IAAI,KAAK,QAAQ,EAAE;AAC5B,EAAE,OAAO,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;AAC3B,EAAE;AACF,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC;AACjB,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS,WAAW,CAAC,GAAG,EAAE;AAC1B,CAAC,OAAO,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,iBAAiB,CAAC,CAAC,CAAC;AAC1C,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,iBAAiB,CAAC,GAAG,EAAE,aAAa,EAAE;AACtD,CAAC,MAAM,OAAO,GAAG,CAAC,aAAa,IAAI,OAAO,aAAa,KAAK,QAAQ,IAAI,aAAa,GAAG,GAAE;AAC1F,CAAC,IAAI,CAAC,GAAG,EAAE;AACX,EAAE,OAAO,EAAE;AACX,EAAE;AACF,CAAC,IAAI,GAAG,CAAC,IAAI,KAAK,MAAM,IAAI,GAAG,CAAC,IAAI,KAAK,WAAW,EAAE;AACtD,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE;AAC7C,EAAE;AACF,CAAC,IAAI,GAAG,CAAC,IAAI,KAAK,QAAQ,IAAI,GAAG,CAAC,IAAI,KAAK,MAAM,EAAE;AACnD,EAAE,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,GAAE;AAC1D,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,GAAE;AACxD;AACA;AACA,EAAE,OAAO;AACT,GAAG,IAAI,EAAE,GAAG,CAAC,IAAI,KAAK,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,IAAI;AACvD,GAAG,EAAE,EAAE,GAAG,CAAC,IAAI,KAAK,MAAM,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,EAAE;AACjD,GAAG;AACH,EAAE;AACF,CAAC,IAAI,GAAG,CAAC,IAAI,KAAK,QAAQ,EAAE;AAC5B,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE;AAC9D,EAAE;AACF,CAAC,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE;AACpD,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,oBAAoB,CAAC,GAAG,EAAE,aAAa,EAAE;AACzD,CAAC,MAAM,OAAO,GAAG,CAAC,aAAa,IAAI,OAAO,aAAa,KAAK,QAAQ,IAAI,aAAa,GAAG,GAAE;AAC1F,CAAC,OAAO,qBAAqB,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,KAAK,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;AACjF,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,kBAAkB,CAAC,GAAG,EAAE,KAAK,EAAE;AAC/C,CAAC,MAAM,CAAC,GAAG,KAAK,IAAI,GAAE;AACtB,CAAC,IAAI,CAAC,GAAG,EAAE;AACX,EAAE,OAAO,EAAE;AACX,EAAE;AACF,CAAC,IAAI,GAAG,CAAC,IAAI,KAAK,MAAM,IAAI,GAAG,CAAC,IAAI,KAAK,WAAW,EAAE;AACtD,EAAE,OAAO,EAAE,CAAC,GAAG,CAAC,GAAG,GAAG,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE;AACxC,EAAE;AACF,CAAC,IAAI,GAAG,CAAC,IAAI,KAAK,QAAQ,IAAI,GAAG,CAAC,IAAI,KAAK,MAAM,EAAE;AACnD,EAAE,MAAM,IAAI,GAAG,CAAC,CAAC,IAAI,KAAK,SAAS,IAAI,CAAC,CAAC,IAAI,KAAK,IAAI,GAAG,EAAE,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,GAAE;AACnF,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC,EAAE,KAAK,SAAS,IAAI,CAAC,CAAC,EAAE,KAAK,IAAI,GAAG,EAAE,GAAG,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,GAAE;AACzE,EAAE,IAAI,GAAG,CAAC,IAAI,KAAK,MAAM,IAAI,GAAG,CAAC,QAAQ,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,MAAM,KAAK,EAAE,EAAE;AAC5E,GAAG,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC,SAAS,EAAC;AACxB,GAAG;AACH,EAAE,OAAO;AACT,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,IAAI,KAAK,EAAE,GAAG,EAAE,GAAG,CAAC,IAAI,CAAC;AACjD,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,CAAC,EAAE,CAAC;AAC7C,GAAG;AACH,EAAE;AACF,CAAC,IAAI,GAAG,CAAC,IAAI,KAAK,SAAS,EAAE;AAC7B,EAAE,OAAO,EAAE,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,KAAK,KAAK,MAAM,IAAI,CAAC,CAAC,KAAK,KAAK,OAAO,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,EAAE;AACpF,EAAE;AACF;AACA;AACA,CAAC,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,KAAK,SAAS,IAAI,CAAC,CAAC,KAAK,KAAK,IAAI,GAAG,EAAE,GAAG,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,GAAE;AACtF,CAAC,OAAO,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,KAAK,KAAK,EAAE,GAAG,EAAE,GAAG,CAAC,KAAK,CAAC,EAAE;AAC3D,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,yBAAyB,CAAC,GAAG,EAAE;AAC/C,CAAC,OAAO,MAAM,CAAC,WAAW,CAAC,qBAAqB,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC;AAC9E;;;;"}
@@ -368,7 +368,7 @@ function isUserProp(prop) {
368
368
  if (!prop || typeof prop !== 'object') {
369
369
  return false
370
370
  }
371
- if (prop.referenceType === 'nextcloud-user') {
371
+ if (prop.referenceType === 'nextcloud-user' || prop.widget === 'user') {
372
372
  return true
373
373
  }
374
374
  const format = prop.format || '';
@@ -390,7 +390,44 @@ function isGroupProp(prop) {
390
390
  if (!prop || typeof prop !== 'object') {
391
391
  return false
392
392
  }
393
- return prop.referenceType === 'nextcloud-group' || prop.format === 'nc-group'
393
+ return prop.referenceType === 'nextcloud-group' || prop.format === 'nc-group' || prop.widget === 'group'
394
+ }
395
+
396
+ /**
397
+ * Make a manifest field override that names a picker widget behave exactly
398
+ * like the schema format that triggers it.
399
+ *
400
+ * OpenRegister refuses formats it does not know (`nc-group`, `language`,
401
+ * `timezone`) at import, so an app cannot always put them in its schema. It
402
+ * declares `fieldOverrides.<key>.widget: 'group' | 'language' | 'timezone'`
403
+ * (or `'user'`) instead. The widget alone is not enough for the user and
404
+ * group pickers, which CnFormDialog recognises by `userPicker` /
405
+ * `groupPicker`, so set those here. An override may also carry its own
406
+ * `x-default` (`current-language`, `current-timezone`), which becomes the
407
+ * field's `defaultToken` just as the schema key does.
408
+ *
409
+ * Mutates `field` in place.
410
+ *
411
+ * @spec openspec/changes/review-round-two/specs/schema-utilities/spec.md
412
+ * @param {object} field The field descriptor, overrides already merged in.
413
+ * @param {object} override The raw override for this key.
414
+ * @return {void}
415
+ */
416
+ function applyPickerOverride(field, override) {
417
+ if (!override || typeof override !== 'object') {
418
+ return
419
+ }
420
+ const widget = override.widget;
421
+ if (widget === 'group' || widget === 'group-multiselect') {
422
+ field.groupPicker = { multiple: widget === 'group-multiselect' };
423
+ field.userPicker = null;
424
+ } else if (widget === 'user' || widget === 'user-multiselect') {
425
+ field.userPicker = { multiple: widget === 'user-multiselect' };
426
+ field.groupPicker = null;
427
+ }
428
+ if (typeof override['x-default'] === 'string' && override['x-default'] !== '') {
429
+ field.defaultToken = override['x-default'];
430
+ }
394
431
  }
395
432
 
396
433
  /**
@@ -845,6 +882,7 @@ function fieldsFromSchema(schema, options = {}) {
845
882
  // Apply per-field overrides
846
883
  if (overrides[key]) {
847
884
  Object.assign(field, overrides[key]);
885
+ applyPickerOverride(field, overrides[key]);
848
886
  }
849
887
 
850
888
  return field