@conduction/nextcloud-vue 2.104.0 → 2.105.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue.js +1 -1
- package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue2.js.map +1 -1
- package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue3.js +1 -1
- package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue3.js.map +1 -1
- package/dist/esm/components/CnChartWidget/CnChartWidget.vue.js +1 -1
- package/dist/esm/components/CnChartWidget/CnChartWidget.vue2.js +93 -1
- package/dist/esm/components/CnChartWidget/CnChartWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnChartWidget/CnChartWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue.js +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js +6 -3
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js.map +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js +3 -3
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js.map +1 -1
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js +59 -1
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js.map +1 -1
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js.map +1 -1
- package/dist/esm/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue.js +1 -1
- package/dist/esm/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue2.js +1 -1
- package/dist/esm/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue2.js.map +1 -1
- package/dist/esm/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue3.js.map +1 -1
- package/dist/esm/components/CnFeaturesBoard/CnFeaturesBoard.vue.js +1 -1
- package/dist/esm/components/CnFeaturesBoard/CnFeaturesBoard.vue2.js +2 -0
- package/dist/esm/components/CnFeaturesBoard/CnFeaturesBoard.vue2.js.map +1 -1
- package/dist/esm/components/CnFeaturesBoard/CnFeaturesBoard.vue3.js +32 -29
- package/dist/esm/components/CnFeaturesBoard/CnFeaturesBoard.vue3.js.map +1 -1
- package/dist/esm/components/CnFlowsPage/CnFlowBoard.vue.js +1 -1
- package/dist/esm/components/CnFlowsPage/CnFlowBoard.vue2.js +73 -4
- package/dist/esm/components/CnFlowsPage/CnFlowBoard.vue2.js.map +1 -1
- package/dist/esm/components/CnFlowsPage/CnFlowBoard.vue3.js +74 -27
- package/dist/esm/components/CnFlowsPage/CnFlowBoard.vue3.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +54 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
- package/dist/esm/components/CnIndexPage/useSelfFetchList.js +3 -2
- package/dist/esm/components/CnIndexPage/useSelfFetchList.js.map +1 -1
- package/dist/esm/components/CnNoticeWidget/CnNoticeWidget.vue.js +9 -0
- package/dist/esm/components/CnNoticeWidget/CnNoticeWidget.vue.js.map +1 -0
- package/dist/esm/components/CnNoticeWidget/CnNoticeWidget.vue2.js +88 -0
- package/dist/esm/components/CnNoticeWidget/CnNoticeWidget.vue2.js.map +1 -0
- package/dist/esm/components/CnNoticeWidget/CnNoticeWidget.vue3.js +39 -0
- package/dist/esm/components/CnNoticeWidget/CnNoticeWidget.vue3.js.map +1 -0
- package/dist/esm/components/CnSettingsField/CnSettingsField.vue.js +1 -1
- package/dist/esm/components/CnSettingsField/CnSettingsField.vue2.js.map +1 -1
- package/dist/esm/components/CnSettingsField/CnSettingsField.vue3.js +3 -3
- package/dist/esm/components/CnSettingsField/CnSettingsField.vue3.js.map +1 -1
- package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue.js +1 -1
- package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue2.js.map +1 -1
- package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue3.js +16 -4
- package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue3.js.map +1 -1
- package/dist/esm/components/CnVersionInfoCard/CnVersionInfoCard.vue.js +1 -1
- package/dist/esm/components/CnVersionInfoCard/CnVersionInfoCard.vue2.js +11 -0
- package/dist/esm/components/CnVersionInfoCard/CnVersionInfoCard.vue2.js.map +1 -1
- package/dist/esm/components/CnVersionInfoCard/CnVersionInfoCard.vue3.js +4 -4
- package/dist/esm/components/CnVersionInfoCard/CnVersionInfoCard.vue3.js.map +1 -1
- package/dist/esm/components/CnWidgetGrid/builtInWidgets.js +16 -14
- package/dist/esm/components/CnWidgetGrid/builtInWidgets.js.map +1 -1
- package/dist/esm/index.js +1 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/l10n/en.json.js +4 -1
- package/dist/esm/l10n/en.json.js.map +1 -1
- package/dist/esm/l10n/nl.json.js +4 -1
- package/dist/esm/l10n/nl.json.js.map +1 -1
- package/dist/esm/library-style.js +1 -1
- package/dist/esm/nextcloud-vue.css +566 -295
- package/dist/esm/utils/libraryWidgetKeys.js +1 -0
- package/dist/esm/utils/libraryWidgetKeys.js.map +1 -1
- package/dist/esm/utils/nextcloudApps.js +45 -0
- package/dist/esm/utils/nextcloudApps.js.map +1 -0
- package/dist/esm/utils/scopeListLayout.js +9 -2
- package/dist/esm/utils/scopeListLayout.js.map +1 -1
- package/dist/esm/utils/validateManifestV2.compiled.js +3 -3
- package/dist/esm/utils/validateManifestV2.compiled.js.map +1 -1
- package/dist/esm/utils/visibleWhen.js +12 -4
- package/dist/esm/utils/visibleWhen.js.map +1 -1
- package/dist/nextcloud-vue.cjs.js +3054 -2517
- package/dist/nextcloud-vue.cjs.js.map +2 -2
- package/dist/nextcloud-vue.css +566 -295
- package/l10n/en.json +4 -1
- package/l10n/nl.json +4 -1
- package/package.json +1 -1
- package/src/components/CnAdminSettingsShell/CnAdminSettingsShell.vue +1 -1
- package/src/components/CnChartWidget/CnChartWidget.md +2 -0
- package/src/components/CnChartWidget/CnChartWidget.vue +93 -1
- package/src/components/CnDashboardPage/CnDashboardPage.vue +9 -6
- package/src/components/CnDetailPage/CnDetailPage.md +1 -0
- package/src/components/CnDetailPage/CnDetailPage.vue +59 -1
- package/src/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue +1 -1
- package/src/components/CnFeaturesBoard/CnFeaturesBoard.vue +4 -1
- package/src/components/CnFlowsPage/CnFlowBoard.vue +132 -8
- package/src/components/CnIndexPage/CnIndexPage.md +1 -0
- package/src/components/CnIndexPage/CnIndexPage.vue +54 -1
- package/src/components/CnIndexPage/useSelfFetchList.js +3 -2
- package/src/components/CnNoticeWidget/CnNoticeWidget.vue +153 -0
- package/src/components/CnNoticeWidget/index.js +12 -0
- package/src/components/CnSettingsField/CnSettingsField.vue +4 -1
- package/src/components/CnSetupWizard/CnSetupWizard.vue +9 -1
- package/src/components/CnVersionInfoCard/CnVersionInfoCard.vue +15 -4
- package/src/components/CnWidgetGrid/builtInWidgets.js +2 -0
- package/src/components/index.js +1 -0
- package/src/css/dialog.css +20 -2
- package/src/css/look-board-detail.css +77 -4
- package/src/css/look-board-index.css +36 -2
- package/src/css/look-board.css +97 -12
- package/src/index.js +1 -0
- package/src/schemas/app-manifest-v2.schema.json +36 -3
- package/src/utils/libraryWidgetKeys.js +1 -0
- package/src/utils/nextcloudApps.js +50 -0
- package/src/utils/scopeListLayout.js +9 -2
- package/src/utils/validateManifestV2.compiled.js +3 -3
- package/src/utils/visibleWhen.js +12 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"libraryWidgetKeys.js","sources":["../../../src/utils/libraryWidgetKeys.js"],"sourcesContent":["/**\n * SPDX-FileCopyrightText: 2026 Conduction B.V.\n * SPDX-License-Identifier: EUPL-1.2\n *\n * libraryWidgetKeys — the one vocabulary of widget keys the LIBRARY itself\n * renders, and the only list `validateManifestV2` is allowed to consult.\n *\n * WHY THIS MODULE EXISTS\n * ----------------------\n * The validator used to carry its own hand-written array of \"library built-in\n * widget keys\", with a comment instructing whoever added a built-in to append\n * it \"in the same PR\". That instruction was followed for five keys and missed\n * for six, so the validator knew 11 keys while the library actually rendered\n * 45. Nothing failed when the two disagreed, because the only consumer is an\n * exemption: a key the validator does not recognise is treated as a CUSTOM\n * registry component, which makes a legitimate single-widget library dashboard\n * fail the ADR-036 Decision 1 anti-pattern rule with advice (\"declare it as\n * type:'custom'\") that is wrong for a library widget.\n *\n * A comment cannot enforce anything, so the array moved here and\n * `tests/utils/libraryWidgetKeys.spec.js` now binds it to the two registries\n * that actually resolve a key at runtime:\n *\n * 1. `BUILT_IN_WIDGETS` (components/CnWidgetGrid/builtInWidgets.js) — the v2\n * manifest widget set `CnWidgetGrid` resolves a `widgetKey` against.\n * 2. The dashboard widget catalog (`dashboardWidgetRegistry`), populated by\n * `registerDashboardWidgets.js`. `CnWidgetGrid` falls back to it (third in\n * the chain, after the consumer registry and `BUILT_IN_WIDGETS`), so a\n * catalog key renders on a v2 page exactly like a `BUILT_IN_WIDGETS` one.\n *\n * The test asserts SET EQUALITY in both directions against the live registries,\n * so adding a widget to either registry without touching this file fails CI,\n * and deleting one without removing it here fails too. The lists below are the\n * validator's view; the registries are the truth the test holds them to.\n *\n * THE CATALOG IS NOT LEGACY. It is a live half of the same vocabulary, and the\n * old array already conceded the point by exempting `chart` and `stats-block`,\n * which are catalog-only keys that `BUILT_IN_WIDGETS` has never held. What it\n * got wrong was doing that for two keys and not the other thirty-seven.\n * `widgetDispatch.js` unified the two resolution paths for the same reason: a\n * widget authored against one vocabulary was invisible to the other and said\n * nothing about why (101 of 236 detail widgets on hrmq).\n *\n * @module utils/libraryWidgetKeys\n */\n\nimport { WIDGET_TYPE_ALIASES } from './widgetTypeAliases.js'\n\n/**\n * Keys of `BUILT_IN_WIDGETS` — the v2 manifest widget set.\n *\n * Kept in the registry's own declaration order so a diff against\n * `builtInWidgets.js` reads straight down.\n *\n * @type {string[]} Frozen.\n */\nexport const BUILT_IN_WIDGET_KEYS = Object.freeze([\n\t'object-table',\n\t'form-renderer',\n\t'map-viewer',\n\t'object-geo',\n\t'card-grid',\n\t'nav-card-grid',\n\t'data',\n\t'metadata',\n\t'related',\n\t'integration',\n\t'banner',\n\t'audit-trail',\n\t'timeline',\n\t'header',\n\t'text',\n\t'divider',\n\t'saved-view-alert',\n\t'exports',\n])\n\n/**\n * Widget types the LIBRARY registers into the dashboard catalog at import time\n * (`registerDashboardWidgets.js` and the widget `index.js` modules it pulls in).\n *\n * Deliberately a static list rather than a read of `dashboardWidgetRegistry`:\n * that object is mutable and consumer-extensible, so deriving the exemption\n * from it at call time would let an app register its own full-page component in\n * the catalog and walk straight through the ADR-036 Decision 1 rule the\n * exemption exists to enforce. Only keys the library itself ships are exempt.\n *\n * Sorted, because unlike `BUILT_IN_WIDGETS` these registrations are spread over\n * ~30 files and have no meaningful declaration order.\n *\n * @type {string[]} Frozen.\n */\nexport const DASHBOARD_CATALOG_WIDGET_KEYS = Object.freeze([\n\t'audit-trail',\n\t'banner',\n\t'calendar',\n\t'chart',\n\t'checklist-run',\n\t'chips-field',\n\t'choice-picker',\n\t'container',\n\t'conversation',\n\t'countdown',\n\t'data',\n\t'delta',\n\t'device-frames',\n\t'divider',\n\t'document-review',\n\t'facts',\n\t'field-list',\n\t'files',\n\t'flow-runs',\n\t'gauge',\n\t'grouped-cards',\n\t'header',\n\t'image',\n\t'interaction-form',\n\t'kb-search',\n\t'label',\n\t'link',\n\t'links',\n\t'map',\n\t'markdown',\n\t'menu',\n\t'nc-widget',\n\t'next-step',\n\t'notepad',\n\t// `news` was here until the widget moved to LaunchPad, which owns the feed\n\t// fetching. An app that renders one now gets it from LaunchPad's registry.\n\t'object-geo',\n\t'object-list',\n\t'object-table',\n\t'party-actions',\n\t'people',\n\t'quicklinks',\n\t'radio-cards',\n\t'record-list',\n\t'related',\n\t'saved-view',\n\t'saved-views',\n\t'sections',\n\t'settings-form',\n\t'spend-analytics',\n\t'stacked-bar',\n\t'stages',\n\t'stat',\n\t'stats-block',\n\t'switch-rows',\n\t'table',\n\t'tabs',\n\t'tasks',\n\t'text',\n\t'tile',\n\t'timeline',\n\t'toggle-table',\n\t'video',\n\t'week-strip',\n\t'working-calendar',\n\t'workspace-filter',\n])\n\n/**\n * Expand a key set over `WIDGET_TYPE_ALIASES` so both spellings of an aliased\n * widget are present whenever either one is.\n *\n * `CnWidgetGrid` resolves a key and its canonical form (`object-table` ⇄\n * `table`, `map-viewer` ⇄ `map`), so both spellings render and both must be\n * exempt. Today each registry happens to hold one side of each pair, which is\n * exactly the accident that would silently stop being true when the next alias\n * lands.\n *\n * @param {Set<string>} keys The key set to expand, mutated in place.\n * @return {Set<string>} The same set.\n */\nfunction expandAliases(keys) {\n\tfor (const [alias, canonical] of Object.entries(WIDGET_TYPE_ALIASES)) {\n\t\tif (keys.has(alias) || keys.has(canonical)) {\n\t\t\tkeys.add(alias)\n\t\t\tkeys.add(canonical)\n\t\t}\n\t}\n\treturn keys\n}\n\n/**\n * Every widget key the library renders itself: both registries, plus both\n * spellings of every alias.\n *\n * A `widgetKey` in this list is served by a library `Cn*` SFC and does NOT\n * count as a custom registry component for the single-12×12-widget dashboard\n * rule (ADR-036 Decision 1).\n *\n * @type {string[]} Frozen.\n */\nexport const LIBRARY_WIDGET_KEYS = Object.freeze([\n\t...expandAliases(new Set([\n\t\t...BUILT_IN_WIDGET_KEYS,\n\t\t...DASHBOARD_CATALOG_WIDGET_KEYS,\n\t])),\n])\n"],"names":[],"mappings":";;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACY,MAAC,oBAAoB,GAAG,MAAM,CAAC,MAAM,CAAC;AAClD,CAAC,cAAc;AACf,CAAC,eAAe;AAChB,CAAC,YAAY;AACb,CAAC,YAAY;AACb,CAAC,WAAW;AACZ,CAAC,eAAe;AAChB,CAAC,MAAM;AACP,CAAC,UAAU;AACX,CAAC,SAAS;AACV,CAAC,aAAa;AACd,CAAC,QAAQ;AACT,CAAC,aAAa;AACd,CAAC,UAAU;AACX,CAAC,QAAQ;AACT,CAAC,MAAM;AACP,CAAC,SAAS;AACV,CAAC,kBAAkB;AACnB,CAAC,SAAS;AACV,CAAC,EAAC;AACF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACY,MAAC,6BAA6B,GAAG,MAAM,CAAC,MAAM,CAAC;AAC3D,CAAC,aAAa;AACd,CAAC,QAAQ;AACT,CAAC,UAAU;AACX,CAAC,OAAO;AACR,CAAC,eAAe;AAChB,CAAC,aAAa;AACd,CAAC,eAAe;AAChB,CAAC,WAAW;AACZ,CAAC,cAAc;AACf,CAAC,WAAW;AACZ,CAAC,MAAM;AACP,CAAC,OAAO;AACR,CAAC,eAAe;AAChB,CAAC,SAAS;AACV,CAAC,iBAAiB;AAClB,CAAC,OAAO;AACR,CAAC,YAAY;AACb,CAAC,OAAO;AACR,CAAC,WAAW;AACZ,CAAC,OAAO;AACR,CAAC,eAAe;AAChB,CAAC,QAAQ;AACT,CAAC,OAAO;AACR,CAAC,kBAAkB;AACnB,CAAC,WAAW;AACZ,CAAC,OAAO;AACR,CAAC,MAAM;AACP,CAAC,OAAO;AACR,CAAC,KAAK;AACN,CAAC,UAAU;AACX,CAAC,MAAM;AACP,CAAC,WAAW;AACZ,CAAC,WAAW;AACZ,CAAC,SAAS;AACV;AACA;AACA,CAAC,YAAY;AACb,CAAC,aAAa;AACd,CAAC,cAAc;AACf,CAAC,eAAe;AAChB,CAAC,QAAQ;AACT,CAAC,YAAY;AACb,CAAC,aAAa;AACd,CAAC,aAAa;AACd,CAAC,SAAS;AACV,CAAC,YAAY;AACb,CAAC,aAAa;AACd,CAAC,UAAU;AACX,CAAC,eAAe;AAChB,CAAC,iBAAiB;AAClB,CAAC,aAAa;AACd,CAAC,QAAQ;AACT,CAAC,MAAM;AACP,CAAC,aAAa;AACd,CAAC,aAAa;AACd,CAAC,OAAO;AACR,CAAC,MAAM;AACP,CAAC,OAAO;AACR,CAAC,MAAM;AACP,CAAC,MAAM;AACP,CAAC,UAAU;AACX,CAAC,cAAc;AACf,CAAC,OAAO;AACR,CAAC,YAAY;AACb,CAAC,kBAAkB;AACnB,CAAC,kBAAkB;AACnB,CAAC,EAAC;AACF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS,aAAa,CAAC,IAAI,EAAE;AAC7B,CAAC,KAAK,MAAM,CAAC,KAAK,EAAE,SAAS,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,mBAAmB,CAAC,EAAE;AACvE,EAAE,IAAI,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE;AAC9C,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,EAAC;AAClB,GAAG,IAAI,CAAC,GAAG,CAAC,SAAS,EAAC;AACtB,GAAG;AACH,EAAE;AACF,CAAC,OAAO,IAAI;AACZ,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACY,MAAC,mBAAmB,GAAG,MAAM,CAAC,MAAM,CAAC;AACjD,CAAC,GAAG,aAAa,CAAC,IAAI,GAAG,CAAC;AAC1B,EAAE,GAAG,oBAAoB;AACzB,EAAE,GAAG,6BAA6B;AAClC,EAAE,CAAC,CAAC;AACJ,CAAC;;;;"}
|
|
1
|
+
{"version":3,"file":"libraryWidgetKeys.js","sources":["../../../src/utils/libraryWidgetKeys.js"],"sourcesContent":["/**\n * SPDX-FileCopyrightText: 2026 Conduction B.V.\n * SPDX-License-Identifier: EUPL-1.2\n *\n * libraryWidgetKeys — the one vocabulary of widget keys the LIBRARY itself\n * renders, and the only list `validateManifestV2` is allowed to consult.\n *\n * WHY THIS MODULE EXISTS\n * ----------------------\n * The validator used to carry its own hand-written array of \"library built-in\n * widget keys\", with a comment instructing whoever added a built-in to append\n * it \"in the same PR\". That instruction was followed for five keys and missed\n * for six, so the validator knew 11 keys while the library actually rendered\n * 45. Nothing failed when the two disagreed, because the only consumer is an\n * exemption: a key the validator does not recognise is treated as a CUSTOM\n * registry component, which makes a legitimate single-widget library dashboard\n * fail the ADR-036 Decision 1 anti-pattern rule with advice (\"declare it as\n * type:'custom'\") that is wrong for a library widget.\n *\n * A comment cannot enforce anything, so the array moved here and\n * `tests/utils/libraryWidgetKeys.spec.js` now binds it to the two registries\n * that actually resolve a key at runtime:\n *\n * 1. `BUILT_IN_WIDGETS` (components/CnWidgetGrid/builtInWidgets.js) — the v2\n * manifest widget set `CnWidgetGrid` resolves a `widgetKey` against.\n * 2. The dashboard widget catalog (`dashboardWidgetRegistry`), populated by\n * `registerDashboardWidgets.js`. `CnWidgetGrid` falls back to it (third in\n * the chain, after the consumer registry and `BUILT_IN_WIDGETS`), so a\n * catalog key renders on a v2 page exactly like a `BUILT_IN_WIDGETS` one.\n *\n * The test asserts SET EQUALITY in both directions against the live registries,\n * so adding a widget to either registry without touching this file fails CI,\n * and deleting one without removing it here fails too. The lists below are the\n * validator's view; the registries are the truth the test holds them to.\n *\n * THE CATALOG IS NOT LEGACY. It is a live half of the same vocabulary, and the\n * old array already conceded the point by exempting `chart` and `stats-block`,\n * which are catalog-only keys that `BUILT_IN_WIDGETS` has never held. What it\n * got wrong was doing that for two keys and not the other thirty-seven.\n * `widgetDispatch.js` unified the two resolution paths for the same reason: a\n * widget authored against one vocabulary was invisible to the other and said\n * nothing about why (101 of 236 detail widgets on hrmq).\n *\n * @module utils/libraryWidgetKeys\n */\n\nimport { WIDGET_TYPE_ALIASES } from './widgetTypeAliases.js'\n\n/**\n * Keys of `BUILT_IN_WIDGETS` — the v2 manifest widget set.\n *\n * Kept in the registry's own declaration order so a diff against\n * `builtInWidgets.js` reads straight down.\n *\n * @type {string[]} Frozen.\n */\nexport const BUILT_IN_WIDGET_KEYS = Object.freeze([\n\t'object-table',\n\t'form-renderer',\n\t'map-viewer',\n\t'notice',\n\t'object-geo',\n\t'card-grid',\n\t'nav-card-grid',\n\t'data',\n\t'metadata',\n\t'related',\n\t'integration',\n\t'banner',\n\t'audit-trail',\n\t'timeline',\n\t'header',\n\t'text',\n\t'divider',\n\t'saved-view-alert',\n\t'exports',\n])\n\n/**\n * Widget types the LIBRARY registers into the dashboard catalog at import time\n * (`registerDashboardWidgets.js` and the widget `index.js` modules it pulls in).\n *\n * Deliberately a static list rather than a read of `dashboardWidgetRegistry`:\n * that object is mutable and consumer-extensible, so deriving the exemption\n * from it at call time would let an app register its own full-page component in\n * the catalog and walk straight through the ADR-036 Decision 1 rule the\n * exemption exists to enforce. Only keys the library itself ships are exempt.\n *\n * Sorted, because unlike `BUILT_IN_WIDGETS` these registrations are spread over\n * ~30 files and have no meaningful declaration order.\n *\n * @type {string[]} Frozen.\n */\nexport const DASHBOARD_CATALOG_WIDGET_KEYS = Object.freeze([\n\t'audit-trail',\n\t'banner',\n\t'calendar',\n\t'chart',\n\t'checklist-run',\n\t'chips-field',\n\t'choice-picker',\n\t'container',\n\t'conversation',\n\t'countdown',\n\t'data',\n\t'delta',\n\t'device-frames',\n\t'divider',\n\t'document-review',\n\t'facts',\n\t'field-list',\n\t'files',\n\t'flow-runs',\n\t'gauge',\n\t'grouped-cards',\n\t'header',\n\t'image',\n\t'interaction-form',\n\t'kb-search',\n\t'label',\n\t'link',\n\t'links',\n\t'map',\n\t'markdown',\n\t'menu',\n\t'nc-widget',\n\t'next-step',\n\t'notepad',\n\t// `news` was here until the widget moved to LaunchPad, which owns the feed\n\t// fetching. An app that renders one now gets it from LaunchPad's registry.\n\t'object-geo',\n\t'object-list',\n\t'object-table',\n\t'party-actions',\n\t'people',\n\t'quicklinks',\n\t'radio-cards',\n\t'record-list',\n\t'related',\n\t'saved-view',\n\t'saved-views',\n\t'sections',\n\t'settings-form',\n\t'spend-analytics',\n\t'stacked-bar',\n\t'stages',\n\t'stat',\n\t'stats-block',\n\t'switch-rows',\n\t'table',\n\t'tabs',\n\t'tasks',\n\t'text',\n\t'tile',\n\t'timeline',\n\t'toggle-table',\n\t'video',\n\t'week-strip',\n\t'working-calendar',\n\t'workspace-filter',\n])\n\n/**\n * Expand a key set over `WIDGET_TYPE_ALIASES` so both spellings of an aliased\n * widget are present whenever either one is.\n *\n * `CnWidgetGrid` resolves a key and its canonical form (`object-table` ⇄\n * `table`, `map-viewer` ⇄ `map`), so both spellings render and both must be\n * exempt. Today each registry happens to hold one side of each pair, which is\n * exactly the accident that would silently stop being true when the next alias\n * lands.\n *\n * @param {Set<string>} keys The key set to expand, mutated in place.\n * @return {Set<string>} The same set.\n */\nfunction expandAliases(keys) {\n\tfor (const [alias, canonical] of Object.entries(WIDGET_TYPE_ALIASES)) {\n\t\tif (keys.has(alias) || keys.has(canonical)) {\n\t\t\tkeys.add(alias)\n\t\t\tkeys.add(canonical)\n\t\t}\n\t}\n\treturn keys\n}\n\n/**\n * Every widget key the library renders itself: both registries, plus both\n * spellings of every alias.\n *\n * A `widgetKey` in this list is served by a library `Cn*` SFC and does NOT\n * count as a custom registry component for the single-12×12-widget dashboard\n * rule (ADR-036 Decision 1).\n *\n * @type {string[]} Frozen.\n */\nexport const LIBRARY_WIDGET_KEYS = Object.freeze([\n\t...expandAliases(new Set([\n\t\t...BUILT_IN_WIDGET_KEYS,\n\t\t...DASHBOARD_CATALOG_WIDGET_KEYS,\n\t])),\n])\n"],"names":[],"mappings":";;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACY,MAAC,oBAAoB,GAAG,MAAM,CAAC,MAAM,CAAC;AAClD,CAAC,cAAc;AACf,CAAC,eAAe;AAChB,CAAC,YAAY;AACb,CAAC,QAAQ;AACT,CAAC,YAAY;AACb,CAAC,WAAW;AACZ,CAAC,eAAe;AAChB,CAAC,MAAM;AACP,CAAC,UAAU;AACX,CAAC,SAAS;AACV,CAAC,aAAa;AACd,CAAC,QAAQ;AACT,CAAC,aAAa;AACd,CAAC,UAAU;AACX,CAAC,QAAQ;AACT,CAAC,MAAM;AACP,CAAC,SAAS;AACV,CAAC,kBAAkB;AACnB,CAAC,SAAS;AACV,CAAC,EAAC;AACF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACY,MAAC,6BAA6B,GAAG,MAAM,CAAC,MAAM,CAAC;AAC3D,CAAC,aAAa;AACd,CAAC,QAAQ;AACT,CAAC,UAAU;AACX,CAAC,OAAO;AACR,CAAC,eAAe;AAChB,CAAC,aAAa;AACd,CAAC,eAAe;AAChB,CAAC,WAAW;AACZ,CAAC,cAAc;AACf,CAAC,WAAW;AACZ,CAAC,MAAM;AACP,CAAC,OAAO;AACR,CAAC,eAAe;AAChB,CAAC,SAAS;AACV,CAAC,iBAAiB;AAClB,CAAC,OAAO;AACR,CAAC,YAAY;AACb,CAAC,OAAO;AACR,CAAC,WAAW;AACZ,CAAC,OAAO;AACR,CAAC,eAAe;AAChB,CAAC,QAAQ;AACT,CAAC,OAAO;AACR,CAAC,kBAAkB;AACnB,CAAC,WAAW;AACZ,CAAC,OAAO;AACR,CAAC,MAAM;AACP,CAAC,OAAO;AACR,CAAC,KAAK;AACN,CAAC,UAAU;AACX,CAAC,MAAM;AACP,CAAC,WAAW;AACZ,CAAC,WAAW;AACZ,CAAC,SAAS;AACV;AACA;AACA,CAAC,YAAY;AACb,CAAC,aAAa;AACd,CAAC,cAAc;AACf,CAAC,eAAe;AAChB,CAAC,QAAQ;AACT,CAAC,YAAY;AACb,CAAC,aAAa;AACd,CAAC,aAAa;AACd,CAAC,SAAS;AACV,CAAC,YAAY;AACb,CAAC,aAAa;AACd,CAAC,UAAU;AACX,CAAC,eAAe;AAChB,CAAC,iBAAiB;AAClB,CAAC,aAAa;AACd,CAAC,QAAQ;AACT,CAAC,MAAM;AACP,CAAC,aAAa;AACd,CAAC,aAAa;AACd,CAAC,OAAO;AACR,CAAC,MAAM;AACP,CAAC,OAAO;AACR,CAAC,MAAM;AACP,CAAC,MAAM;AACP,CAAC,UAAU;AACX,CAAC,cAAc;AACf,CAAC,OAAO;AACR,CAAC,YAAY;AACb,CAAC,kBAAkB;AACnB,CAAC,kBAAkB;AACnB,CAAC,EAAC;AACF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS,aAAa,CAAC,IAAI,EAAE;AAC7B,CAAC,KAAK,MAAM,CAAC,KAAK,EAAE,SAAS,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,mBAAmB,CAAC,EAAE;AACvE,EAAE,IAAI,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE;AAC9C,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,EAAC;AAClB,GAAG,IAAI,CAAC,GAAG,CAAC,SAAS,EAAC;AACtB,GAAG;AACH,EAAE;AACF,CAAC,OAAO,IAAI;AACZ,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACY,MAAC,mBAAmB,GAAG,MAAM,CAAC,MAAM,CAAC;AACjD,CAAC,GAAG,aAAa,CAAC,IAAI,GAAG,CAAC;AAC1B,EAAE,GAAG,oBAAoB;AACzB,EAAE,GAAG,6BAA6B;AAClC,EAAE,CAAC,CAAC;AACJ,CAAC;;;;"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { generateOcsUrl } from '@nextcloud/router';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* SPDX-FileCopyrightText: 2026 Conduction B.V.
|
|
5
|
+
* SPDX-License-Identifier: EUPL-1.2
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* The display names of the apps in Nextcloud's navigation, by app id, read
|
|
11
|
+
* once per page load from the OCS navigation endpoint with the reader's
|
|
12
|
+
* session. An app outside the navigation, or a failed read, has no entry.
|
|
13
|
+
*
|
|
14
|
+
* @module utils/nextcloudApps
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
let pending = null;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* The app display names by app id.
|
|
21
|
+
*
|
|
22
|
+
* @param {object} axios The axios instance.
|
|
23
|
+
* @return {Promise<Record<string, string>>} The names; empty when the read fails.
|
|
24
|
+
*/
|
|
25
|
+
function appDisplayNames(axios) {
|
|
26
|
+
if (!pending) {
|
|
27
|
+
pending = axios.get(generateOcsUrl('core/navigation/apps'), { params: { format: 'json' }, headers: { 'OCS-APIRequest': 'true' } })
|
|
28
|
+
.then((res) => {
|
|
29
|
+
const entries = (res && res.data && res.data.ocs && res.data.ocs.data) || [];
|
|
30
|
+
const names = {};
|
|
31
|
+
for (const entry of Array.isArray(entries) ? entries : Object.values(entries)) {
|
|
32
|
+
const id = entry && (entry.app || entry.id);
|
|
33
|
+
if (id && typeof entry.name === 'string' && entry.name !== '') {
|
|
34
|
+
names[String(id)] = entry.name;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return names
|
|
38
|
+
})
|
|
39
|
+
.catch(() => ({}));
|
|
40
|
+
}
|
|
41
|
+
return pending
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export { appDisplayNames };
|
|
45
|
+
//# sourceMappingURL=nextcloudApps.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nextcloudApps.js","sources":["../../../src/utils/nextcloudApps.js"],"sourcesContent":["/**\n * SPDX-FileCopyrightText: 2026 Conduction B.V.\n * SPDX-License-Identifier: EUPL-1.2\n */\n\nimport { generateOcsUrl } from '@nextcloud/router'\n\n/**\n * The display names of the apps in Nextcloud's navigation, by app id, read\n * once per page load from the OCS navigation endpoint with the reader's\n * session. An app outside the navigation, or a failed read, has no entry.\n *\n * @module utils/nextcloudApps\n */\n\nlet pending = null\n\n/**\n * The app display names by app id.\n *\n * @param {object} axios The axios instance.\n * @return {Promise<Record<string, string>>} The names; empty when the read fails.\n */\nexport function appDisplayNames(axios) {\n\tif (!pending) {\n\t\tpending = axios.get(generateOcsUrl('core/navigation/apps'), { params: { format: 'json' }, headers: { 'OCS-APIRequest': 'true' } })\n\t\t\t.then((res) => {\n\t\t\t\tconst entries = (res && res.data && res.data.ocs && res.data.ocs.data) || []\n\t\t\t\tconst names = {}\n\t\t\t\tfor (const entry of Array.isArray(entries) ? entries : Object.values(entries)) {\n\t\t\t\t\tconst id = entry && (entry.app || entry.id)\n\t\t\t\t\tif (id && typeof entry.name === 'string' && entry.name !== '') {\n\t\t\t\t\t\tnames[String(id)] = entry.name\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn names\n\t\t\t})\n\t\t\t.catch(() => ({}))\n\t}\n\treturn pending\n}\n\n/**\n * Forget the names read, so the next call reads them again.\n *\n * @return {void}\n */\nexport function clearAppDisplayNames() {\n\tpending = null\n}\n"],"names":[],"mappings":";;AAAA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,OAAO,GAAG,KAAI;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,eAAe,CAAC,KAAK,EAAE;AACvC,CAAC,IAAI,CAAC,OAAO,EAAE;AACf,EAAE,OAAO,GAAG,KAAK,CAAC,GAAG,CAAC,cAAc,CAAC,sBAAsB,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,EAAE,gBAAgB,EAAE,MAAM,EAAE,EAAE,CAAC;AACpI,IAAI,IAAI,CAAC,CAAC,GAAG,KAAK;AAClB,IAAI,MAAM,OAAO,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,CAAC,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,KAAK,GAAE;AAChF,IAAI,MAAM,KAAK,GAAG,GAAE;AACpB,IAAI,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE;AACnF,KAAK,MAAM,EAAE,GAAG,KAAK,KAAK,KAAK,CAAC,GAAG,IAAI,KAAK,CAAC,EAAE,EAAC;AAChD,KAAK,IAAI,EAAE,IAAI,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,KAAK,EAAE,EAAE;AACpE,MAAM,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,GAAG,KAAK,CAAC,KAAI;AACpC,MAAM;AACN,KAAK;AACL,IAAI,OAAO,KAAK;AAChB,IAAI,CAAC;AACL,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC,EAAC;AACrB,EAAE;AACF,CAAC,OAAO,OAAO;AACf;;;;"}
|
|
@@ -147,8 +147,15 @@ function resolveScopeLayout({ scope = null, row = null, pageColumns = [] } = {})
|
|
|
147
147
|
return
|
|
148
148
|
}
|
|
149
149
|
// The page's own entry is used, not the scope's, so the label and
|
|
150
|
-
// formatter a column was declared with survive being selected.
|
|
151
|
-
|
|
150
|
+
// formatter a column was declared with survive being selected. A
|
|
151
|
+
// column the page hides by default shows: the scope asked for it.
|
|
152
|
+
const own = byKey.get(key);
|
|
153
|
+
if (own && typeof own === 'object' && own.hidden === true) {
|
|
154
|
+
const { hidden, ...shown } = own;
|
|
155
|
+
columns.push(shown);
|
|
156
|
+
return
|
|
157
|
+
}
|
|
158
|
+
columns.push(own);
|
|
152
159
|
});
|
|
153
160
|
|
|
154
161
|
return { columns, sortKeys, searchFields }
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scopeListLayout.js","sources":["../../../src/utils/scopeListLayout.js"],"sourcesContent":["/**\n * SPDX-FileCopyrightText: 2026 Conduction B.V. <info@conduction.nl>\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport { QUERY_PRESET_KEYS } from './queryPresets.js'\n\n/**\n * The three list-layout keys a `folderSidebar` scope may carry.\n *\n * @type {string[]}\n */\nconst SCOPE_LAYOUT_KEYS = ['columns', 'defaultSort', 'searchFields']\n\n/**\n * The presentation keys a scope may carry beside its list layout: the keys a\n * query preset may set (`QUERY_PRESET_KEYS`), less the two the list layout\n * resolves itself (`columns`, `defaultSort`).\n *\n * @type {ReadonlyArray<string>}\n */\nconst SCOPE_PRESENTATION_KEYS = Object.freeze(QUERY_PRESET_KEYS.filter((key) => key !== 'columns' && key !== 'defaultSort'))\n\n/**\n * The key of a column entry, in either of the two shapes the manifest accepts:\n * a bare string (legacy shorthand) or a `{ key, label, ... }` object.\n *\n * @param {(string|object)} column A column entry.\n * @return {string} The column key, or '' when the entry carries none.\n */\nexport function columnKeyOf(column) {\n\tif (typeof column === 'string') {\n\t\treturn column\n\t}\n\tif (column && typeof column.key === 'string') {\n\t\treturn column.key\n\t}\n\treturn ''\n}\n\n/**\n * Normalise one sort entry to the `{ key, order }` shape the fetch uses.\n * Accepts `key` or `field` because the page prop spells it `field` and the\n * manifest spells it `key`; an entry naming neither is dropped rather than\n * sent as an empty sort key.\n *\n * @param {object} entry A sort entry.\n * @return {({key: string, order: string}|null)} The normalised entry, or null.\n */\nfunction normaliseSortEntry(entry) {\n\tif (!entry || typeof entry !== 'object') {\n\t\treturn null\n\t}\n\tconst key = typeof entry.key === 'string' && entry.key !== ''\n\t\t? entry.key\n\t\t: (typeof entry.field === 'string' ? entry.field : '')\n\tif (key === '') {\n\t\treturn null\n\t}\n\treturn { key, order: entry.order === 'desc' ? 'desc' : 'asc' }\n}\n\n/**\n * Normalise a `defaultSort` value, which may be a single entry or a list.\n *\n * @param {(object|object[]|undefined)} value The declared sort.\n * @return {Array<{key: string, order: string}>} The normalised sort keys.\n */\nfunction normaliseSort(value) {\n\tif (value === undefined || value === null) {\n\t\treturn []\n\t}\n\tconst list = Array.isArray(value) ? value : [value]\n\treturn list.map(normaliseSortEntry).filter(Boolean)\n}\n\n/**\n * Read one layout key from the scope entry, falling back to the schema row's\n * `x-index` block. A value declared on the folder entry WINS over the row's,\n * which is what makes the row a default rather than an override.\n *\n * @param {(object|null)} scope The folder entry for the active scope.\n * @param {(object|null)} row The schema row the folder derives from.\n * @param {string} key One of `columns`, `defaultSort`, `searchFields`.\n * @return {(Array|object|undefined)} The declared value, the row value, or undefined.\n */\nfunction declaredOrRow(scope, row, key) {\n\tif (scope && scope[key] !== undefined) {\n\t\treturn scope[key]\n\t}\n\tconst carried = row && row['x-index']\n\tif (carried && typeof carried === 'object' && carried[key] !== undefined) {\n\t\treturn carried[key]\n\t}\n\treturn undefined\n}\n\n/**\n * Resolve the list layout a `folderSidebar` scope asks for.\n *\n * Two declarations meet here and they do not decide the same thing:\n *\n * - The PAGE decides MEMBERSHIP. `config.columns` is the set of columns this\n * page has, and it carries each column's definition (label, formatter,\n * widget). A scope may reorder that set and narrow it; it cannot add to it.\n * A scope naming a column the page does not declare is DROPPED, so a scope\n * written before a column was removed cannot bring the column back.\n * - The SCOPE decides PRESENTATION: which of the page's columns are shown, in\n * what order, sorted by what, searched over what.\n *\n * The page declaring no columns at all is the one case where a scope's list is\n * taken as written: there is no declared set to measure it against, because the\n * columns are derived from the schema at runtime.\n *\n * @param {object} options Resolution inputs.\n * @param {(object|null)} [options.scope] The folder entry for the active scope.\n * @param {(object|null)} [options.row] The schema row the folder derives from.\n * @param {Array} [options.pageColumns] The page's declared `config.columns`.\n * @return {{columns: (Array|null), sortKeys: Array<{key: string, order: string}>, searchFields: string[]}}\n * `columns` is null when neither source declares any, meaning the page's own\n * list stands.\n */\nexport function resolveScopeLayout({ scope = null, row = null, pageColumns = [] } = {}) {\n\tconst declaredColumns = declaredOrRow(scope, row, 'columns')\n\tconst declaredSearch = declaredOrRow(scope, row, 'searchFields')\n\tconst sortKeys = normaliseSort(declaredOrRow(scope, row, 'defaultSort'))\n\n\tconst searchFields = Array.isArray(declaredSearch)\n\t\t? declaredSearch.filter((f) => typeof f === 'string' && f !== '')\n\t\t: []\n\n\tif (!Array.isArray(declaredColumns) || declaredColumns.length === 0) {\n\t\treturn { columns: null, sortKeys, searchFields }\n\t}\n\n\tconst page = Array.isArray(pageColumns) ? pageColumns : []\n\tif (page.length === 0) {\n\t\treturn { columns: [...declaredColumns], sortKeys, searchFields }\n\t}\n\n\tconst byKey = new Map()\n\tpage.forEach((col) => {\n\t\tconst key = columnKeyOf(col)\n\t\tif (key !== '') {\n\t\t\tbyKey.set(key, col)\n\t\t}\n\t})\n\n\tconst columns = []\n\tdeclaredColumns.forEach((col) => {\n\t\tconst key = columnKeyOf(col)\n\t\tif (key === '' || !byKey.has(key)) {\n\t\t\treturn\n\t\t}\n\t\t// The page's own entry is used, not the scope's, so the label and\n\t\t// formatter a column was declared with survive being selected.\n\t\tcolumns.push(byKey.get(key))\n\t})\n\n\treturn { columns, sortKeys, searchFields }\n}\n\n/**\n * The presentation a scope asks for: each of `SCOPE_PRESENTATION_KEYS` the\n * folder entry declares, else the one its schema row's `x-index` declares.\n * Only declared keys are in the result, so the page's own value stands for\n * every other key. These are the keys a query preset sets, under the same\n * names, and a scope's value wins over a preset's because it is applied on\n * top of the page config the preset produced.\n *\n * @param {object} options Resolution inputs.\n * @param {(object|null)} [options.scope] The folder entry for the active scope.\n * @param {(object|null)} [options.row] The schema row the folder derives from.\n * @return {object} The declared presentation keys.\n * @spec openspec/changes/index-scope-presentation/specs/index-page/spec.md#requirement-a-preset-or-a-scope-sets-the-list-s-presentation\n */\nexport function resolveScopePresentation({ scope = null, row = null } = {}) {\n\tconst out = {}\n\tfor (const key of SCOPE_PRESENTATION_KEYS) {\n\t\tconst value = declaredOrRow(scope, row, key)\n\t\tif (value !== undefined) {\n\t\t\tout[key] = value\n\t\t}\n\t}\n\treturn out\n}\n\nexport { SCOPE_LAYOUT_KEYS, SCOPE_PRESENTATION_KEYS }\n"],"names":[],"mappings":";;AAAA;AACA;AACA;AACA;AACA;AASA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACK,MAAC,uBAAuB,GAAG,MAAM,CAAC,MAAM,CAAC,iBAAiB,CAAC,MAAM,CAAC,CAAC,GAAG,KAAK,GAAG,KAAK,SAAS,IAAI,GAAG,KAAK,aAAa,CAAC,EAAC;AAC5H;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,WAAW,CAAC,MAAM,EAAE;AACpC,CAAC,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE;AACjC,EAAE,OAAO,MAAM;AACf,EAAE;AACF,CAAC,IAAI,MAAM,IAAI,OAAO,MAAM,CAAC,GAAG,KAAK,QAAQ,EAAE;AAC/C,EAAE,OAAO,MAAM,CAAC,GAAG;AACnB,EAAE;AACF,CAAC,OAAO,EAAE;AACV,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS,kBAAkB,CAAC,KAAK,EAAE;AACnC,CAAC,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE;AAC1C,EAAE,OAAO,IAAI;AACb,EAAE;AACF,CAAC,MAAM,GAAG,GAAG,OAAO,KAAK,CAAC,GAAG,KAAK,QAAQ,IAAI,KAAK,CAAC,GAAG,KAAK,EAAE;AAC9D,IAAI,KAAK,CAAC,GAAG;AACb,KAAK,OAAO,KAAK,CAAC,KAAK,KAAK,QAAQ,GAAG,KAAK,CAAC,KAAK,GAAG,EAAE,EAAC;AACxD,CAAC,IAAI,GAAG,KAAK,EAAE,EAAE;AACjB,EAAE,OAAO,IAAI;AACb,EAAE;AACF,CAAC,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,KAAK,MAAM,GAAG,MAAM,GAAG,KAAK,EAAE;AAC/D,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS,aAAa,CAAC,KAAK,EAAE;AAC9B,CAAC,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,EAAE;AAC5C,EAAE,OAAO,EAAE;AACX,EAAE;AACF,CAAC,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,KAAK,GAAG,CAAC,KAAK,EAAC;AACpD,CAAC,OAAO,IAAI,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC;AACpD,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS,aAAa,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE;AACxC,CAAC,IAAI,KAAK,IAAI,KAAK,CAAC,GAAG,CAAC,KAAK,SAAS,EAAE;AACxC,EAAE,OAAO,KAAK,CAAC,GAAG,CAAC;AACnB,EAAE;AACF,CAAC,MAAM,OAAO,GAAG,GAAG,IAAI,GAAG,CAAC,SAAS,EAAC;AACtC,CAAC,IAAI,OAAO,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,CAAC,GAAG,CAAC,KAAK,SAAS,EAAE;AAC3E,EAAE,OAAO,OAAO,CAAC,GAAG,CAAC;AACrB,EAAE;AACF,CAAC,OAAO,SAAS;AACjB,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;AACO,SAAS,kBAAkB,CAAC,EAAE,KAAK,GAAG,IAAI,EAAE,GAAG,GAAG,IAAI,EAAE,WAAW,GAAG,EAAE,EAAE,GAAG,EAAE,EAAE;AACxF,CAAC,MAAM,eAAe,GAAG,aAAa,CAAC,KAAK,EAAE,GAAG,EAAE,SAAS,EAAC;AAC7D,CAAC,MAAM,cAAc,GAAG,aAAa,CAAC,KAAK,EAAE,GAAG,EAAE,cAAc,EAAC;AACjE,CAAC,MAAM,QAAQ,GAAG,aAAa,CAAC,aAAa,CAAC,KAAK,EAAE,GAAG,EAAE,aAAa,CAAC,EAAC;AACzE;AACA,CAAC,MAAM,YAAY,GAAG,KAAK,CAAC,OAAO,CAAC,cAAc,CAAC;AACnD,IAAI,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,EAAE,CAAC;AACnE,IAAI,GAAE;AACN;AACA,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,eAAe,CAAC,IAAI,eAAe,CAAC,MAAM,KAAK,CAAC,EAAE;AACtE,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,YAAY,EAAE;AAClD,EAAE;AACF;AACA,CAAC,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,GAAG,WAAW,GAAG,GAAE;AAC3D,CAAC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE;AACxB,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,GAAG,eAAe,CAAC,EAAE,QAAQ,EAAE,YAAY,EAAE;AAClE,EAAE;AACF;AACA,CAAC,MAAM,KAAK,GAAG,IAAI,GAAG,GAAE;AACxB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,GAAG,KAAK;AACvB,EAAE,MAAM,GAAG,GAAG,WAAW,CAAC,GAAG,EAAC;AAC9B,EAAE,IAAI,GAAG,KAAK,EAAE,EAAE;AAClB,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,EAAC;AACtB,GAAG;AACH,EAAE,EAAC;AACH;AACA,CAAC,MAAM,OAAO,GAAG,GAAE;AACnB,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC,GAAG,KAAK;AAClC,EAAE,MAAM,GAAG,GAAG,WAAW,CAAC,GAAG,EAAC;AAC9B,EAAE,IAAI,GAAG,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE;AACrC,GAAG,MAAM;AACT,GAAG;AACH;AACA;AACA,EAAE,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,EAAC;AAC9B,EAAE,EAAC;AACH;AACA,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE;AAC3C,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,wBAAwB,CAAC,EAAE,KAAK,GAAG,IAAI,EAAE,GAAG,GAAG,IAAI,EAAE,GAAG,EAAE,EAAE;AAC5E,CAAC,MAAM,GAAG,GAAG,GAAE;AACf,CAAC,KAAK,MAAM,GAAG,IAAI,uBAAuB,EAAE;AAC5C,EAAE,MAAM,KAAK,GAAG,aAAa,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,EAAC;AAC9C,EAAE,IAAI,KAAK,KAAK,SAAS,EAAE;AAC3B,GAAG,GAAG,CAAC,GAAG,CAAC,GAAG,MAAK;AACnB,GAAG;AACH,EAAE;AACF,CAAC,OAAO,GAAG;AACX;;;;"}
|
|
1
|
+
{"version":3,"file":"scopeListLayout.js","sources":["../../../src/utils/scopeListLayout.js"],"sourcesContent":["/**\n * SPDX-FileCopyrightText: 2026 Conduction B.V. <info@conduction.nl>\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport { QUERY_PRESET_KEYS } from './queryPresets.js'\n\n/**\n * The three list-layout keys a `folderSidebar` scope may carry.\n *\n * @type {string[]}\n */\nconst SCOPE_LAYOUT_KEYS = ['columns', 'defaultSort', 'searchFields']\n\n/**\n * The presentation keys a scope may carry beside its list layout: the keys a\n * query preset may set (`QUERY_PRESET_KEYS`), less the two the list layout\n * resolves itself (`columns`, `defaultSort`).\n *\n * @type {ReadonlyArray<string>}\n */\nconst SCOPE_PRESENTATION_KEYS = Object.freeze(QUERY_PRESET_KEYS.filter((key) => key !== 'columns' && key !== 'defaultSort'))\n\n/**\n * The key of a column entry, in either of the two shapes the manifest accepts:\n * a bare string (legacy shorthand) or a `{ key, label, ... }` object.\n *\n * @param {(string|object)} column A column entry.\n * @return {string} The column key, or '' when the entry carries none.\n */\nexport function columnKeyOf(column) {\n\tif (typeof column === 'string') {\n\t\treturn column\n\t}\n\tif (column && typeof column.key === 'string') {\n\t\treturn column.key\n\t}\n\treturn ''\n}\n\n/**\n * Normalise one sort entry to the `{ key, order }` shape the fetch uses.\n * Accepts `key` or `field` because the page prop spells it `field` and the\n * manifest spells it `key`; an entry naming neither is dropped rather than\n * sent as an empty sort key.\n *\n * @param {object} entry A sort entry.\n * @return {({key: string, order: string}|null)} The normalised entry, or null.\n */\nfunction normaliseSortEntry(entry) {\n\tif (!entry || typeof entry !== 'object') {\n\t\treturn null\n\t}\n\tconst key = typeof entry.key === 'string' && entry.key !== ''\n\t\t? entry.key\n\t\t: (typeof entry.field === 'string' ? entry.field : '')\n\tif (key === '') {\n\t\treturn null\n\t}\n\treturn { key, order: entry.order === 'desc' ? 'desc' : 'asc' }\n}\n\n/**\n * Normalise a `defaultSort` value, which may be a single entry or a list.\n *\n * @param {(object|object[]|undefined)} value The declared sort.\n * @return {Array<{key: string, order: string}>} The normalised sort keys.\n */\nfunction normaliseSort(value) {\n\tif (value === undefined || value === null) {\n\t\treturn []\n\t}\n\tconst list = Array.isArray(value) ? value : [value]\n\treturn list.map(normaliseSortEntry).filter(Boolean)\n}\n\n/**\n * Read one layout key from the scope entry, falling back to the schema row's\n * `x-index` block. A value declared on the folder entry WINS over the row's,\n * which is what makes the row a default rather than an override.\n *\n * @param {(object|null)} scope The folder entry for the active scope.\n * @param {(object|null)} row The schema row the folder derives from.\n * @param {string} key One of `columns`, `defaultSort`, `searchFields`.\n * @return {(Array|object|undefined)} The declared value, the row value, or undefined.\n */\nfunction declaredOrRow(scope, row, key) {\n\tif (scope && scope[key] !== undefined) {\n\t\treturn scope[key]\n\t}\n\tconst carried = row && row['x-index']\n\tif (carried && typeof carried === 'object' && carried[key] !== undefined) {\n\t\treturn carried[key]\n\t}\n\treturn undefined\n}\n\n/**\n * Resolve the list layout a `folderSidebar` scope asks for.\n *\n * Two declarations meet here and they do not decide the same thing:\n *\n * - The PAGE decides MEMBERSHIP. `config.columns` is the set of columns this\n * page has, and it carries each column's definition (label, formatter,\n * widget). A scope may reorder that set and narrow it; it cannot add to it.\n * A scope naming a column the page does not declare is DROPPED, so a scope\n * written before a column was removed cannot bring the column back.\n * - The SCOPE decides PRESENTATION: which of the page's columns are shown, in\n * what order, sorted by what, searched over what.\n *\n * The page declaring no columns at all is the one case where a scope's list is\n * taken as written: there is no declared set to measure it against, because the\n * columns are derived from the schema at runtime.\n *\n * @param {object} options Resolution inputs.\n * @param {(object|null)} [options.scope] The folder entry for the active scope.\n * @param {(object|null)} [options.row] The schema row the folder derives from.\n * @param {Array} [options.pageColumns] The page's declared `config.columns`.\n * @return {{columns: (Array|null), sortKeys: Array<{key: string, order: string}>, searchFields: string[]}}\n * `columns` is null when neither source declares any, meaning the page's own\n * list stands.\n */\nexport function resolveScopeLayout({ scope = null, row = null, pageColumns = [] } = {}) {\n\tconst declaredColumns = declaredOrRow(scope, row, 'columns')\n\tconst declaredSearch = declaredOrRow(scope, row, 'searchFields')\n\tconst sortKeys = normaliseSort(declaredOrRow(scope, row, 'defaultSort'))\n\n\tconst searchFields = Array.isArray(declaredSearch)\n\t\t? declaredSearch.filter((f) => typeof f === 'string' && f !== '')\n\t\t: []\n\n\tif (!Array.isArray(declaredColumns) || declaredColumns.length === 0) {\n\t\treturn { columns: null, sortKeys, searchFields }\n\t}\n\n\tconst page = Array.isArray(pageColumns) ? pageColumns : []\n\tif (page.length === 0) {\n\t\treturn { columns: [...declaredColumns], sortKeys, searchFields }\n\t}\n\n\tconst byKey = new Map()\n\tpage.forEach((col) => {\n\t\tconst key = columnKeyOf(col)\n\t\tif (key !== '') {\n\t\t\tbyKey.set(key, col)\n\t\t}\n\t})\n\n\tconst columns = []\n\tdeclaredColumns.forEach((col) => {\n\t\tconst key = columnKeyOf(col)\n\t\tif (key === '' || !byKey.has(key)) {\n\t\t\treturn\n\t\t}\n\t\t// The page's own entry is used, not the scope's, so the label and\n\t\t// formatter a column was declared with survive being selected. A\n\t\t// column the page hides by default shows: the scope asked for it.\n\t\tconst own = byKey.get(key)\n\t\tif (own && typeof own === 'object' && own.hidden === true) {\n\t\t\tconst { hidden, ...shown } = own\n\t\t\tcolumns.push(shown)\n\t\t\treturn\n\t\t}\n\t\tcolumns.push(own)\n\t})\n\n\treturn { columns, sortKeys, searchFields }\n}\n\n/**\n * The presentation a scope asks for: each of `SCOPE_PRESENTATION_KEYS` the\n * folder entry declares, else the one its schema row's `x-index` declares.\n * Only declared keys are in the result, so the page's own value stands for\n * every other key. These are the keys a query preset sets, under the same\n * names, and a scope's value wins over a preset's because it is applied on\n * top of the page config the preset produced.\n *\n * @param {object} options Resolution inputs.\n * @param {(object|null)} [options.scope] The folder entry for the active scope.\n * @param {(object|null)} [options.row] The schema row the folder derives from.\n * @return {object} The declared presentation keys.\n * @spec openspec/changes/index-scope-presentation/specs/index-page/spec.md#requirement-a-preset-or-a-scope-sets-the-list-s-presentation\n */\nexport function resolveScopePresentation({ scope = null, row = null } = {}) {\n\tconst out = {}\n\tfor (const key of SCOPE_PRESENTATION_KEYS) {\n\t\tconst value = declaredOrRow(scope, row, key)\n\t\tif (value !== undefined) {\n\t\t\tout[key] = value\n\t\t}\n\t}\n\treturn out\n}\n\nexport { SCOPE_LAYOUT_KEYS, SCOPE_PRESENTATION_KEYS }\n"],"names":[],"mappings":"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"}
|