@conduction/nextcloud-vue 2.77.0 → 2.79.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/bundled-packages.json +0 -2
- package/dist/esm/bundled-packages.json +0 -2
- package/dist/esm/components/CnActionsBar/CnActionsBar.vue2.js.map +1 -1
- package/dist/esm/components/CnActionsBar/CnActionsBar.vue3.js +113 -104
- package/dist/esm/components/CnActionsBar/CnActionsBar.vue3.js.map +1 -1
- package/dist/esm/components/CnAiCompanion/CnAiCompanion.vue2.js +23 -0
- package/dist/esm/components/CnAiCompanion/CnAiCompanion.vue2.js.map +1 -1
- package/dist/esm/components/CnAiCompanion/CnAiCompanion.vue3.js.map +1 -1
- package/dist/esm/components/CnAppRoot/CnAppRoot.vue2.js +12 -2
- package/dist/esm/components/CnAppRoot/CnAppRoot.vue2.js.map +1 -1
- package/dist/esm/components/CnAppRoot/CnAppRoot.vue3.js.map +1 -1
- package/dist/esm/components/CnBoardView/CnBoardView.vue2.js +2 -1
- package/dist/esm/components/CnBoardView/CnBoardView.vue2.js.map +1 -1
- package/dist/esm/components/CnBoardView/CnBoardView.vue3.js.map +1 -1
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue2.js +117 -0
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue2.js.map +1 -1
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue3.js +122 -97
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue3.js.map +1 -1
- package/dist/esm/components/CnChartWidget/CnChartWidget.vue2.js +37 -0
- package/dist/esm/components/CnChartWidget/CnChartWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnChartWidget/CnChartWidget.vue3.js +2 -2
- package/dist/esm/components/CnChartWidget/CnChartWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js +168 -5
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js.map +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js +140 -92
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js.map +1 -1
- package/dist/esm/components/CnDataTable/CnDataTable.vue2.js +84 -2
- package/dist/esm/components/CnDataTable/CnDataTable.vue2.js.map +1 -1
- package/dist/esm/components/CnDataTable/CnDataTable.vue3.js +4 -2
- package/dist/esm/components/CnDataTable/CnDataTable.vue3.js.map +1 -1
- package/dist/esm/components/CnDateRangePicker/CnDateRangePicker.vue.js +1 -1
- package/dist/esm/components/CnDateRangePicker/CnDateRangePicker.vue2.js +45 -2
- package/dist/esm/components/CnDateRangePicker/CnDateRangePicker.vue2.js.map +1 -1
- package/dist/esm/components/CnDateRangePicker/CnDateRangePicker.vue3.js.map +1 -1
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue2.js +61 -1
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue2.js.map +1 -1
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue3.js.map +1 -1
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js +173 -5
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js.map +1 -1
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js +181 -99
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js.map +1 -1
- package/dist/esm/components/CnFilesBrowser/filesBrowser.js +29 -11
- package/dist/esm/components/CnFilesBrowser/filesBrowser.js.map +1 -1
- package/dist/esm/components/CnFilesBrowser/openRegisterSource.js +252 -0
- package/dist/esm/components/CnFilesBrowser/openRegisterSource.js.map +1 -0
- package/dist/esm/components/CnFormDialog/CnFormDialog.vue2.js +8 -2
- package/dist/esm/components/CnFormDialog/CnFormDialog.vue2.js.map +1 -1
- package/dist/esm/components/CnFormDialog/CnFormDialog.vue3.js.map +1 -1
- package/dist/esm/components/CnFormPage/CnFormPage.vue2.js +4 -1
- package/dist/esm/components/CnFormPage/CnFormPage.vue2.js.map +1 -1
- package/dist/esm/components/CnFormPage/CnFormPage.vue3.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +31 -2
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js +3 -2
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue2.js +100 -3
- package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue3.js +4 -2
- package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue3.js.map +1 -1
- package/dist/esm/components/CnQuickFilterBar/CnQuickFilterBar.vue2.js +3 -2
- package/dist/esm/components/CnQuickFilterBar/CnQuickFilterBar.vue2.js.map +1 -1
- package/dist/esm/components/CnQuickFilterBar/CnQuickFilterBar.vue3.js.map +1 -1
- package/dist/esm/components/CnSavedViewsControl/CnSavedViewsControl.vue2.js.map +1 -1
- package/dist/esm/components/CnSavedViewsControl/CnSavedViewsControl.vue3.js +1 -1
- package/dist/esm/components/CnSavedViewsControl/CnSavedViewsControl.vue3.js.map +1 -1
- package/dist/esm/components/CnStatWidget/CnStatWidget.vue2.js +36 -0
- package/dist/esm/components/CnStatWidget/CnStatWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnStatWidget/CnStatWidget.vue3.js +35 -23
- package/dist/esm/components/CnStatWidget/CnStatWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnStatusBadge/CnStatusBadge.vue2.js +6 -2
- package/dist/esm/components/CnStatusBadge/CnStatusBadge.vue2.js.map +1 -1
- package/dist/esm/components/CnStatusBadge/CnStatusBadge.vue3.js.map +1 -1
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js +30 -1
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnWidgetObjectTable/CnWidgetObjectTable.vue2.js +13 -0
- package/dist/esm/components/CnWidgetObjectTable/CnWidgetObjectTable.vue2.js.map +1 -1
- package/dist/esm/components/CnWidgetObjectTable/CnWidgetObjectTable.vue3.js.map +1 -1
- package/dist/esm/composables/useAppManifest.js +8 -3
- package/dist/esm/composables/useAppManifest.js.map +1 -1
- package/dist/esm/composables/useFormDraft.js +11 -1
- package/dist/esm/composables/useFormDraft.js.map +1 -1
- package/dist/esm/composables/useObjectPresence.js +15 -4
- package/dist/esm/composables/useObjectPresence.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 +68 -1
- package/dist/esm/l10n/en.json.js.map +1 -1
- package/dist/esm/l10n/nl.json.js +113 -2
- package/dist/esm/l10n/nl.json.js.map +1 -1
- package/dist/esm/nextcloud-vue.css +526 -16
- package/dist/esm/utils/badgeVariants.js +32 -0
- package/dist/esm/utils/badgeVariants.js.map +1 -0
- package/dist/esm/utils/boardDate.js +193 -0
- package/dist/esm/utils/boardDate.js.map +1 -0
- package/dist/esm/utils/dynamicProperties.js +5 -1
- package/dist/esm/utils/dynamicProperties.js.map +1 -1
- package/dist/esm/utils/validateManifestV2.compiled.js +57 -6
- package/dist/esm/utils/validateManifestV2.compiled.js.map +1 -1
- package/dist/nextcloud-vue.cjs.js +2569 -811
- package/dist/nextcloud-vue.cjs.js.map +2 -2
- package/dist/nextcloud-vue.css +526 -16
- package/l10n/en.json +68 -1
- package/l10n/nl.json +113 -2
- package/package.json +1 -1
- package/scripts/build-validators.js +26 -0
- package/src/components/CnActionsBar/CnActionsBar.vue +48 -39
- package/src/components/CnAiCompanion/CnAiCompanion.vue +23 -0
- package/src/components/CnAppRoot/CnAppRoot.vue +12 -2
- package/src/components/CnBoardView/CnBoardView.vue +2 -1
- package/src/components/CnCellRenderer/CnCellRenderer.md +1 -0
- package/src/components/CnCellRenderer/CnCellRenderer.vue +169 -10
- package/src/components/CnChartWidget/CnChartWidget.vue +39 -2
- package/src/components/CnDashboardPage/CnDashboardPage.vue +248 -8
- package/src/components/CnDataTable/CnDataTable.md +2 -0
- package/src/components/CnDataTable/CnDataTable.vue +88 -4
- package/src/components/CnDateRangePicker/CnDateRangePicker.vue +44 -1
- package/src/components/CnDetailWidgetHost/CnDetailWidgetHost.vue +61 -1
- package/src/components/CnFilesBrowser/CnFilesBrowser.vue +232 -11
- package/src/components/CnFilesBrowser/filesBrowser.js +43 -2
- package/src/components/CnFilesBrowser/index.js +1 -0
- package/src/components/CnFilesBrowser/openRegisterSource.js +248 -0
- package/src/components/CnFormDialog/CnFormDialog.vue +8 -2
- package/src/components/CnFormPage/CnFormPage.vue +4 -1
- package/src/components/CnIndexPage/CnIndexPage.vue +33 -3
- package/src/components/CnObjectSidebar/CnFilesTab.vue +103 -4
- package/src/components/CnQuickFilterBar/CnQuickFilterBar.vue +3 -2
- package/src/components/CnSavedViewsControl/CnSavedViewsControl.vue +1 -1
- package/src/components/CnStatWidget/CnStatWidget.vue +52 -2
- package/src/components/CnStatusBadge/CnStatusBadge.vue +6 -2
- package/src/components/CnTabsWidget/CnTabsWidget.vue +30 -1
- package/src/components/CnWidgetObjectTable/CnWidgetObjectTable.vue +13 -0
- package/src/components/index.js +1 -1
- package/src/composables/__tests__/useObjectPresence.spec.js +24 -0
- package/src/composables/useAppManifest.js +8 -3
- package/src/composables/useFormDraft.js +11 -1
- package/src/composables/useObjectPresence.js +15 -4
- package/src/css/badge.css +31 -0
- package/src/css/kpi-card.css +51 -0
- package/src/css/look-board-detail.css +10 -0
- package/src/css/look-board-index.css +128 -14
- package/src/css/look-board.css +85 -0
- package/src/css/table.css +37 -0
- package/src/index.js +4 -0
- package/src/schemas/app-manifest-v2.schema.json +50 -5
- package/src/utils/badgeVariants.js +29 -0
- package/src/utils/boardDate.js +189 -0
- package/src/utils/dynamicProperties.js +5 -1
- package/src/utils/validateManifestV2.compiled.js +57 -2
- package/dist/esm/_virtual/equal.js +0 -4
- package/dist/esm/_virtual/equal.js.map +0 -1
- package/dist/esm/_virtual/ucs2length.js +0 -4
- package/dist/esm/_virtual/ucs2length.js.map +0 -1
- package/dist/esm/node_modules/ajv/dist/runtime/equal.js +0 -9
- package/dist/esm/node_modules/ajv/dist/runtime/equal.js.map +0 -1
- package/dist/esm/node_modules/ajv/dist/runtime/ucs2length.js +0 -25
- package/dist/esm/node_modules/ajv/dist/runtime/ucs2length.js.map +0 -1
- package/dist/esm/node_modules/fast-deep-equal/index.js +0 -47
- package/dist/esm/node_modules/fast-deep-equal/index.js.map +0 -1
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SPDX-FileCopyrightText: 2026 Conduction B.V.
|
|
3
|
+
* SPDX-License-Identifier: EUPL-1.2
|
|
4
|
+
*
|
|
5
|
+
* badgeVariants: the colour variants a CnStatusBadge (a status pill) may take.
|
|
6
|
+
*
|
|
7
|
+
* The first six follow the Nextcloud colour roles. `purple` and `teal` are the
|
|
8
|
+
* two tones the drawn boards use for a status that has no Nextcloud role, such
|
|
9
|
+
* as "In behandeling" (work in progress) and "Omgezet naar een zaak" (handed
|
|
10
|
+
* on). One list, so the badge, the board card pill and the manifest schema
|
|
11
|
+
* accept the same names.
|
|
12
|
+
*
|
|
13
|
+
* @module utils/badgeVariants
|
|
14
|
+
* @spec openspec/changes/screens-cell-pill-parity/specs/cell-pill-tones/spec.md#requirement-a-status-pill-has-eight-tones
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/** Every variant a status pill accepts, in the order the docs list them. */
|
|
18
|
+
const BADGE_VARIANTS = Object.freeze(['default', 'primary', 'success', 'warning', 'error', 'info', 'purple', 'teal']);
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Whether a value names a badge variant.
|
|
22
|
+
*
|
|
23
|
+
* @param {unknown} variant The candidate variant.
|
|
24
|
+
* @return {boolean} True for one of `BADGE_VARIANTS`.
|
|
25
|
+
* @spec openspec/changes/screens-cell-pill-parity/specs/cell-pill-tones/spec.md#requirement-a-status-pill-has-eight-tones
|
|
26
|
+
*/
|
|
27
|
+
function isBadgeVariant(variant) {
|
|
28
|
+
return typeof variant === 'string' && BADGE_VARIANTS.includes(variant)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export { BADGE_VARIANTS, isBadgeVariant };
|
|
32
|
+
//# sourceMappingURL=badgeVariants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"badgeVariants.js","sources":["../../../src/utils/badgeVariants.js"],"sourcesContent":["/**\n * SPDX-FileCopyrightText: 2026 Conduction B.V.\n * SPDX-License-Identifier: EUPL-1.2\n *\n * badgeVariants: the colour variants a CnStatusBadge (a status pill) may take.\n *\n * The first six follow the Nextcloud colour roles. `purple` and `teal` are the\n * two tones the drawn boards use for a status that has no Nextcloud role, such\n * as \"In behandeling\" (work in progress) and \"Omgezet naar een zaak\" (handed\n * on). One list, so the badge, the board card pill and the manifest schema\n * accept the same names.\n *\n * @module utils/badgeVariants\n * @spec openspec/changes/screens-cell-pill-parity/specs/cell-pill-tones/spec.md#requirement-a-status-pill-has-eight-tones\n */\n\n/** Every variant a status pill accepts, in the order the docs list them. */\nexport const BADGE_VARIANTS = Object.freeze(['default', 'primary', 'success', 'warning', 'error', 'info', 'purple', 'teal'])\n\n/**\n * Whether a value names a badge variant.\n *\n * @param {unknown} variant The candidate variant.\n * @return {boolean} True for one of `BADGE_VARIANTS`.\n * @spec openspec/changes/screens-cell-pill-parity/specs/cell-pill-tones/spec.md#requirement-a-status-pill-has-eight-tones\n */\nexport function isBadgeVariant(variant) {\n\treturn typeof variant === 'string' && BADGE_VARIANTS.includes(variant)\n}\n"],"names":[],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACY,MAAC,cAAc,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAC;AAC5H;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,cAAc,CAAC,OAAO,EAAE;AACxC,CAAC,OAAO,OAAO,OAAO,KAAK,QAAQ,IAAI,cAAc,CAAC,QAAQ,CAAC,OAAO,CAAC;AACvE;;;;"}
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import { translatePlural, getLanguage, getCanonicalLocale } from '@nextcloud/l10n';
|
|
2
|
+
import { parseDateValue } from './dateVariant.js';
|
|
3
|
+
import { compareVisibleWhen } from './visibleWhen.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* SPDX-FileCopyrightText: 2026 Conduction B.V.
|
|
7
|
+
* SPDX-License-Identifier: EUPL-1.2
|
|
8
|
+
*
|
|
9
|
+
* boardDate: the two short time readings the drawn boards put in a table cell.
|
|
10
|
+
*
|
|
11
|
+
* - A date ("5 okt", "30 okt", "14 feb 2024"): day and short month in the
|
|
12
|
+
* user's language, the year only when it is not the current year.
|
|
13
|
+
* - An age ("4 uur", "1 dag", "3 dagen"): how long something has been
|
|
14
|
+
* waiting, in hours under a day and in whole calendar days after that.
|
|
15
|
+
*
|
|
16
|
+
* Both read the Nextcloud user LANGUAGE for the month and unit names. A
|
|
17
|
+
* Nextcloud account keeps its locale (date order) apart from its language,
|
|
18
|
+
* and a Dutch reader whose locale was left at the en_US default saw
|
|
19
|
+
* "Feb 14, 2024": the language decides the words, so it decides here, and the
|
|
20
|
+
* locale is only used when it is a region of that same language.
|
|
21
|
+
*
|
|
22
|
+
* @module utils/boardDate
|
|
23
|
+
* @spec openspec/changes/screens-cell-date-parity/specs/cell-date-age/spec.md
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
const MS_PER_HOUR = 3600000;
|
|
28
|
+
const MS_PER_DAY = 86400000;
|
|
29
|
+
|
|
30
|
+
/** Variants an age rule may name. `danger` is accepted as an alias of `error`. */
|
|
31
|
+
const AGE_VARIANTS = Object.freeze(['default', 'success', 'warning', 'error']);
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Read a language or locale tag from an @nextcloud/l10n getter, which throws
|
|
35
|
+
* when Nextcloud has not set one (outside a Nextcloud page, in a test).
|
|
36
|
+
*
|
|
37
|
+
* @param {() => string} getter `getLanguage` or `getCanonicalLocale`.
|
|
38
|
+
* @return {string} The tag with `-` separators, or ''.
|
|
39
|
+
*/
|
|
40
|
+
function readTag(getter) {
|
|
41
|
+
try {
|
|
42
|
+
return String(getter() || '').replace(/_/g, '-')
|
|
43
|
+
} catch {
|
|
44
|
+
return ''
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* The BCP 47 tag the board dates are written in: the user's locale when it is
|
|
50
|
+
* a region of the user's language (`nl-BE` for language `nl`), else the
|
|
51
|
+
* language itself.
|
|
52
|
+
*
|
|
53
|
+
* @return {string|undefined} The tag, or undefined to let Intl choose.
|
|
54
|
+
* @spec openspec/changes/screens-cell-date-parity/specs/cell-date-age/spec.md#requirement-a-board-date-cell-reads-day-and-short-month-in-the-user-language
|
|
55
|
+
*/
|
|
56
|
+
function boardDateLocale() {
|
|
57
|
+
const language = readTag(getLanguage);
|
|
58
|
+
const locale = readTag(getCanonicalLocale);
|
|
59
|
+
const base = (tag) => tag.split('-')[0].toLowerCase();
|
|
60
|
+
if (language && locale && base(language) === base(locale)) {
|
|
61
|
+
return locale
|
|
62
|
+
}
|
|
63
|
+
return language || locale || undefined
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* A date in the board's short form: "5 okt", or "14 feb 2024" outside the
|
|
68
|
+
* current year.
|
|
69
|
+
*
|
|
70
|
+
* @param {unknown} value A Date, a timestamp or an ISO string.
|
|
71
|
+
* @param {Date} [now] The reference moment (defaults to the current time).
|
|
72
|
+
* @param {string} [locale] BCP 47 tag (defaults to `boardDateLocale()`).
|
|
73
|
+
* @return {string} The short date, or '' when the value is not a date.
|
|
74
|
+
* @spec openspec/changes/screens-cell-date-parity/specs/cell-date-age/spec.md#requirement-a-board-date-cell-reads-day-and-short-month-in-the-user-language
|
|
75
|
+
*/
|
|
76
|
+
function formatBoardDate(value, now = new Date(), locale = boardDateLocale()) {
|
|
77
|
+
const date = parseDateValue(value);
|
|
78
|
+
if (date === null) {
|
|
79
|
+
return ''
|
|
80
|
+
}
|
|
81
|
+
const options = { day: 'numeric', month: 'short' };
|
|
82
|
+
if (date.getFullYear() !== now.getFullYear()) {
|
|
83
|
+
options.year = 'numeric';
|
|
84
|
+
}
|
|
85
|
+
try {
|
|
86
|
+
return new Intl.DateTimeFormat(locale, options).format(date)
|
|
87
|
+
} catch {
|
|
88
|
+
return new Intl.DateTimeFormat(undefined, options).format(date)
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Whole calendar days from the date until `now` (0 today, 1 yesterday), or
|
|
94
|
+
* null when the value is not a date. A future date gives a negative number.
|
|
95
|
+
*
|
|
96
|
+
* @param {unknown} value The date.
|
|
97
|
+
* @param {Date} [now] The reference moment.
|
|
98
|
+
* @return {number|null} The day count.
|
|
99
|
+
* @spec openspec/changes/screens-cell-date-parity/specs/cell-date-age/spec.md#requirement-an-age-cell-says-how-long-something-has-waited
|
|
100
|
+
*/
|
|
101
|
+
function ageInDays(value, now = new Date()) {
|
|
102
|
+
const date = parseDateValue(value);
|
|
103
|
+
if (date === null) {
|
|
104
|
+
return null
|
|
105
|
+
}
|
|
106
|
+
// UTC midnights of the two LOCAL days, so a daylight-saving hour never
|
|
107
|
+
// turns one day into zero or two.
|
|
108
|
+
const start = Date.UTC(date.getFullYear(), date.getMonth(), date.getDate());
|
|
109
|
+
const today = Date.UTC(now.getFullYear(), now.getMonth(), now.getDate());
|
|
110
|
+
return Math.round((today - start) / MS_PER_DAY)
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* How long something has waited: "4 uur" under 24 hours (at least 1), else
|
|
115
|
+
* "1 dag" / "3 dagen" in whole calendar days. Plural forms come from the
|
|
116
|
+
* library's own catalogue (`nextcloud-vue`). A date in the future reads as
|
|
117
|
+
* waiting no time: "0 hours".
|
|
118
|
+
*
|
|
119
|
+
* @param {unknown} value The moment the wait started.
|
|
120
|
+
* @param {Date} [now] The reference moment.
|
|
121
|
+
* @return {string} The age, or '' when the value is not a date.
|
|
122
|
+
* @spec openspec/changes/screens-cell-date-parity/specs/cell-date-age/spec.md#requirement-an-age-cell-says-how-long-something-has-waited
|
|
123
|
+
*/
|
|
124
|
+
function formatAge(value, now = new Date()) {
|
|
125
|
+
const date = parseDateValue(value);
|
|
126
|
+
if (date === null) {
|
|
127
|
+
return ''
|
|
128
|
+
}
|
|
129
|
+
const elapsed = now.getTime() - date.getTime();
|
|
130
|
+
if (elapsed < MS_PER_DAY) {
|
|
131
|
+
const hours = elapsed <= 0 ? 0 : Math.max(1, Math.floor(elapsed / MS_PER_HOUR));
|
|
132
|
+
return translatePlural('nextcloud-vue', '%n hour', '%n hours', hours)
|
|
133
|
+
}
|
|
134
|
+
const days = shownAgeDays(date, now);
|
|
135
|
+
return translatePlural('nextcloud-vue', '%n day', '%n days', days)
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* The number of days an age cell shows: 0 under 24 hours (the cell then reads
|
|
140
|
+
* hours), else the whole calendar days, at least 1. The threshold rules
|
|
141
|
+
* compare against this number, so the colour always agrees with the text.
|
|
142
|
+
*
|
|
143
|
+
* @param {unknown} value The moment the wait started.
|
|
144
|
+
* @param {Date} [now] The reference moment.
|
|
145
|
+
* @return {number|null} The day count, or null when the value is not a date.
|
|
146
|
+
* @spec openspec/changes/screens-cell-date-parity/specs/cell-date-age/spec.md#requirement-an-age-cell-turns-red-past-its-threshold
|
|
147
|
+
*/
|
|
148
|
+
function shownAgeDays(value, now = new Date()) {
|
|
149
|
+
const date = parseDateValue(value);
|
|
150
|
+
if (date === null) {
|
|
151
|
+
return null
|
|
152
|
+
}
|
|
153
|
+
if (now.getTime() - date.getTime() < MS_PER_DAY) {
|
|
154
|
+
return 0
|
|
155
|
+
}
|
|
156
|
+
return Math.max(1, ageInDays(date, now))
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* The variant of the first `variantWhen` rule the age in days matches, or ''
|
|
161
|
+
* when none does. Same rule shape as the `date` widget (`{ op, value,
|
|
162
|
+
* variant }`, first match wins), compared against the number of days the cell
|
|
163
|
+
* shows (`shownAgeDays`): `[{ op: "gte", value: 3, variant: "error" }]` turns a wait of three
|
|
164
|
+
* days or more red.
|
|
165
|
+
*
|
|
166
|
+
* @param {unknown} value The moment the wait started.
|
|
167
|
+
* @param {Array<{op: string, value: number, variant: string}>} rules The rules.
|
|
168
|
+
* @param {Date} [now] The reference moment.
|
|
169
|
+
* @return {string} `success | warning | error | default`, or ''.
|
|
170
|
+
* @spec openspec/changes/screens-cell-date-parity/specs/cell-date-age/spec.md#requirement-an-age-cell-turns-red-past-its-threshold
|
|
171
|
+
*/
|
|
172
|
+
function resolveAgeVariant(value, rules, now = new Date()) {
|
|
173
|
+
if (!Array.isArray(rules) || rules.length === 0) {
|
|
174
|
+
return ''
|
|
175
|
+
}
|
|
176
|
+
const days = shownAgeDays(value, now);
|
|
177
|
+
if (days === null) {
|
|
178
|
+
return ''
|
|
179
|
+
}
|
|
180
|
+
for (const rule of rules) {
|
|
181
|
+
if (!rule || typeof rule !== 'object') {
|
|
182
|
+
continue
|
|
183
|
+
}
|
|
184
|
+
if (compareVisibleWhen(days, rule.op || 'eq', rule.value) === true) {
|
|
185
|
+
const variant = rule.variant === 'danger' ? 'error' : rule.variant;
|
|
186
|
+
return AGE_VARIANTS.includes(variant) ? variant : ''
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
return ''
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
export { AGE_VARIANTS, ageInDays, boardDateLocale, formatAge, formatBoardDate, resolveAgeVariant, shownAgeDays };
|
|
193
|
+
//# sourceMappingURL=boardDate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"boardDate.js","sources":["../../../src/utils/boardDate.js"],"sourcesContent":["/**\n * SPDX-FileCopyrightText: 2026 Conduction B.V.\n * SPDX-License-Identifier: EUPL-1.2\n *\n * boardDate: the two short time readings the drawn boards put in a table cell.\n *\n * - A date (\"5 okt\", \"30 okt\", \"14 feb 2024\"): day and short month in the\n * user's language, the year only when it is not the current year.\n * - An age (\"4 uur\", \"1 dag\", \"3 dagen\"): how long something has been\n * waiting, in hours under a day and in whole calendar days after that.\n *\n * Both read the Nextcloud user LANGUAGE for the month and unit names. A\n * Nextcloud account keeps its locale (date order) apart from its language,\n * and a Dutch reader whose locale was left at the en_US default saw\n * \"Feb 14, 2024\": the language decides the words, so it decides here, and the\n * locale is only used when it is a region of that same language.\n *\n * @module utils/boardDate\n * @spec openspec/changes/screens-cell-date-parity/specs/cell-date-age/spec.md\n */\n\nimport { getCanonicalLocale, getLanguage, translatePlural as n } from '@nextcloud/l10n'\nimport { parseDateValue } from './dateVariant.js'\nimport { compareVisibleWhen } from './visibleWhen.js'\n\nconst MS_PER_HOUR = 3600000\nconst MS_PER_DAY = 86400000\n\n/** Variants an age rule may name. `danger` is accepted as an alias of `error`. */\nexport const AGE_VARIANTS = Object.freeze(['default', 'success', 'warning', 'error'])\n\n/**\n * Read a language or locale tag from an @nextcloud/l10n getter, which throws\n * when Nextcloud has not set one (outside a Nextcloud page, in a test).\n *\n * @param {() => string} getter `getLanguage` or `getCanonicalLocale`.\n * @return {string} The tag with `-` separators, or ''.\n */\nfunction readTag(getter) {\n\ttry {\n\t\treturn String(getter() || '').replace(/_/g, '-')\n\t} catch {\n\t\treturn ''\n\t}\n}\n\n/**\n * The BCP 47 tag the board dates are written in: the user's locale when it is\n * a region of the user's language (`nl-BE` for language `nl`), else the\n * language itself.\n *\n * @return {string|undefined} The tag, or undefined to let Intl choose.\n * @spec openspec/changes/screens-cell-date-parity/specs/cell-date-age/spec.md#requirement-a-board-date-cell-reads-day-and-short-month-in-the-user-language\n */\nexport function boardDateLocale() {\n\tconst language = readTag(getLanguage)\n\tconst locale = readTag(getCanonicalLocale)\n\tconst base = (tag) => tag.split('-')[0].toLowerCase()\n\tif (language && locale && base(language) === base(locale)) {\n\t\treturn locale\n\t}\n\treturn language || locale || undefined\n}\n\n/**\n * A date in the board's short form: \"5 okt\", or \"14 feb 2024\" outside the\n * current year.\n *\n * @param {unknown} value A Date, a timestamp or an ISO string.\n * @param {Date} [now] The reference moment (defaults to the current time).\n * @param {string} [locale] BCP 47 tag (defaults to `boardDateLocale()`).\n * @return {string} The short date, or '' when the value is not a date.\n * @spec openspec/changes/screens-cell-date-parity/specs/cell-date-age/spec.md#requirement-a-board-date-cell-reads-day-and-short-month-in-the-user-language\n */\nexport function formatBoardDate(value, now = new Date(), locale = boardDateLocale()) {\n\tconst date = parseDateValue(value)\n\tif (date === null) {\n\t\treturn ''\n\t}\n\tconst options = { day: 'numeric', month: 'short' }\n\tif (date.getFullYear() !== now.getFullYear()) {\n\t\toptions.year = 'numeric'\n\t}\n\ttry {\n\t\treturn new Intl.DateTimeFormat(locale, options).format(date)\n\t} catch {\n\t\treturn new Intl.DateTimeFormat(undefined, options).format(date)\n\t}\n}\n\n/**\n * Whole calendar days from the date until `now` (0 today, 1 yesterday), or\n * null when the value is not a date. A future date gives a negative number.\n *\n * @param {unknown} value The date.\n * @param {Date} [now] The reference moment.\n * @return {number|null} The day count.\n * @spec openspec/changes/screens-cell-date-parity/specs/cell-date-age/spec.md#requirement-an-age-cell-says-how-long-something-has-waited\n */\nexport function ageInDays(value, now = new Date()) {\n\tconst date = parseDateValue(value)\n\tif (date === null) {\n\t\treturn null\n\t}\n\t// UTC midnights of the two LOCAL days, so a daylight-saving hour never\n\t// turns one day into zero or two.\n\tconst start = Date.UTC(date.getFullYear(), date.getMonth(), date.getDate())\n\tconst today = Date.UTC(now.getFullYear(), now.getMonth(), now.getDate())\n\treturn Math.round((today - start) / MS_PER_DAY)\n}\n\n/**\n * How long something has waited: \"4 uur\" under 24 hours (at least 1), else\n * \"1 dag\" / \"3 dagen\" in whole calendar days. Plural forms come from the\n * library's own catalogue (`nextcloud-vue`). A date in the future reads as\n * waiting no time: \"0 hours\".\n *\n * @param {unknown} value The moment the wait started.\n * @param {Date} [now] The reference moment.\n * @return {string} The age, or '' when the value is not a date.\n * @spec openspec/changes/screens-cell-date-parity/specs/cell-date-age/spec.md#requirement-an-age-cell-says-how-long-something-has-waited\n */\nexport function formatAge(value, now = new Date()) {\n\tconst date = parseDateValue(value)\n\tif (date === null) {\n\t\treturn ''\n\t}\n\tconst elapsed = now.getTime() - date.getTime()\n\tif (elapsed < MS_PER_DAY) {\n\t\tconst hours = elapsed <= 0 ? 0 : Math.max(1, Math.floor(elapsed / MS_PER_HOUR))\n\t\treturn n('nextcloud-vue', '%n hour', '%n hours', hours)\n\t}\n\tconst days = shownAgeDays(date, now)\n\treturn n('nextcloud-vue', '%n day', '%n days', days)\n}\n\n/**\n * The number of days an age cell shows: 0 under 24 hours (the cell then reads\n * hours), else the whole calendar days, at least 1. The threshold rules\n * compare against this number, so the colour always agrees with the text.\n *\n * @param {unknown} value The moment the wait started.\n * @param {Date} [now] The reference moment.\n * @return {number|null} The day count, or null when the value is not a date.\n * @spec openspec/changes/screens-cell-date-parity/specs/cell-date-age/spec.md#requirement-an-age-cell-turns-red-past-its-threshold\n */\nexport function shownAgeDays(value, now = new Date()) {\n\tconst date = parseDateValue(value)\n\tif (date === null) {\n\t\treturn null\n\t}\n\tif (now.getTime() - date.getTime() < MS_PER_DAY) {\n\t\treturn 0\n\t}\n\treturn Math.max(1, ageInDays(date, now))\n}\n\n/**\n * The variant of the first `variantWhen` rule the age in days matches, or ''\n * when none does. Same rule shape as the `date` widget (`{ op, value,\n * variant }`, first match wins), compared against the number of days the cell\n * shows (`shownAgeDays`): `[{ op: \"gte\", value: 3, variant: \"error\" }]` turns a wait of three\n * days or more red.\n *\n * @param {unknown} value The moment the wait started.\n * @param {Array<{op: string, value: number, variant: string}>} rules The rules.\n * @param {Date} [now] The reference moment.\n * @return {string} `success | warning | error | default`, or ''.\n * @spec openspec/changes/screens-cell-date-parity/specs/cell-date-age/spec.md#requirement-an-age-cell-turns-red-past-its-threshold\n */\nexport function resolveAgeVariant(value, rules, now = new Date()) {\n\tif (!Array.isArray(rules) || rules.length === 0) {\n\t\treturn ''\n\t}\n\tconst days = shownAgeDays(value, now)\n\tif (days === null) {\n\t\treturn ''\n\t}\n\tfor (const rule of rules) {\n\t\tif (!rule || typeof rule !== 'object') {\n\t\t\tcontinue\n\t\t}\n\t\tif (compareVisibleWhen(days, rule.op || 'eq', rule.value) === true) {\n\t\t\tconst variant = rule.variant === 'danger' ? 'error' : rule.variant\n\t\t\treturn AGE_VARIANTS.includes(variant) ? variant : ''\n\t\t}\n\t}\n\treturn ''\n}\n"],"names":["n"],"mappings":"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"}
|
|
@@ -76,6 +76,7 @@ const DEFAULT_MAP = {
|
|
|
76
76
|
enum: 'enumValues',
|
|
77
77
|
required: 'isRequired',
|
|
78
78
|
default: 'defaultValue',
|
|
79
|
+
hideOnCreate: 'hideOnCreate',
|
|
79
80
|
};
|
|
80
81
|
|
|
81
82
|
/**
|
|
@@ -287,6 +288,8 @@ function definitionQueryParams(config, value, formData = {}) {
|
|
|
287
288
|
* @param {object} [config] The `x-openregister-extends-form` block (`map`, `typeMap`).
|
|
288
289
|
* @param {object} [options] Extra options.
|
|
289
290
|
* @param {number} [options.orderFrom] Order assigned to the first field; each subsequent field takes the next integer. Dynamic fields sort after the schema's own, so pass a number above every declared `order`.
|
|
291
|
+
* @param {boolean} [options.create] The form creates a new object: a definition whose `hideOnCreate` (or the field `config.map.hideOnCreate` names) is `true` gets no field, because the app fills that answer itself at creation. Edit forms still show it.
|
|
292
|
+
* @spec openspec/changes/dynamic-question-hide-on-create/specs/dynamic-question-hide-on-create/spec.md#requirement-a-question-can-stay-off-the-create-form
|
|
290
293
|
* @return {{properties: object, required: string[]}} Properties keyed by prefixed id, plus the required key list.
|
|
291
294
|
*/
|
|
292
295
|
function propertiesFromDefinitions(definitions, config = {}, options = {}) {
|
|
@@ -296,7 +299,8 @@ function propertiesFromDefinitions(definitions, config = {}, options = {}) {
|
|
|
296
299
|
|
|
297
300
|
const properties = {};
|
|
298
301
|
const required = [];
|
|
299
|
-
const list = Array.isArray(definitions) ? definitions : []
|
|
302
|
+
const list = (Array.isArray(definitions) ? definitions : [])
|
|
303
|
+
.filter((record) => !(options.create === true && record && mapped(record, map, 'hideOnCreate') === true));
|
|
300
304
|
|
|
301
305
|
list.forEach((record, index) => {
|
|
302
306
|
if (!record || !record.id) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dynamicProperties.js","sources":["../../../src/utils/dynamicProperties.js"],"sourcesContent":["// SPDX-FileCopyrightText: 2026 Conduction B.V.\n// SPDX-License-Identifier: EUPL-1.2\n\n/**\n * Form fields that a record's own data decides, rather than its schema.\n *\n * Some domains keep half of an object's shape in the database instead of the\n * schema. A municipal case type declares which extra questions its cases must\n * answer; a product line declares which attributes its orders carry. The\n * schema cannot enumerate those, because a functional admin adds them at\n * runtime without a release.\n *\n * The pattern is always the same three parts, so this module names them once:\n *\n * - a **driving property** on the schema — a reference the user picks first\n * (`case.caseType`), carrying an `x-openregister-extends-form` block;\n * - a **definitions schema** whose records describe the extra fields\n * (`propertyDefinition`), filtered by the driving property's value;\n * - a **values schema** that stores one answer per definition per object\n * (`caseProperty`), written after the parent object exists.\n *\n * Definitions are mapped into ordinary JSON Schema properties and handed to\n * `fieldsFromSchema`, so widget resolution, enum labels, validation and\n * description splitting all come from the one engine. A dynamic field is not\n * a second kind of field; it is a normal field whose declaration arrived late.\n *\n * @module utils/dynamicProperties\n */\n\nimport { resolveFilterTokens } from './resolveFilterTokens.js'\n\n/**\n * The vendor extension a driving property carries.\n *\n * @type {string}\n */\nexport const EXTENDS_FORM_KEY = 'x-openregister-extends-form'\n\n/**\n * The vendor extension a driving property carries to prefill its siblings.\n *\n * Where `x-openregister-extends-form` adds NEW fields, this one fills fields\n * the schema already declares. A case type knows the status a case of its\n * kind starts in and who normally handles it, so a person should not have to\n * retype what the chosen type already answers.\n *\n * @type {string}\n */\nexport const PREFILL_KEY = 'x-openregister-prefill'\n\n/**\n * Prefix that namespaces a dynamic field's key inside form data.\n *\n * Definition records are named by a functional admin, so a definition called\n * `title` or `status` is not merely possible but likely. Without a namespace\n * it would overwrite the real schema property of that name — silently, since\n * a form has no way to tell the two apart once they share a key.\n *\n * @type {string}\n */\nexport const DYNAMIC_KEY_PREFIX = 'x-prop:'\n\n/**\n * How a definition record's declared type becomes a JSON Schema property.\n *\n * Covers the JSON Schema type names themselves plus the shorthands a\n * definitions schema tends to use, because an admin picking a type from a\n * dropdown picks `date`, not `string`/`format: date`.\n *\n * @type {Record<string, object>}\n */\nconst TYPE_MAP = {\n\tstring: { type: 'string' },\n\ttext: { type: 'string' },\n\ttextarea: { type: 'string', format: 'textarea' },\n\tmarkdown: { type: 'string', format: 'markdown' },\n\tnumber: { type: 'number' },\n\tinteger: { type: 'integer' },\n\tboolean: { type: 'boolean' },\n\tdate: { type: 'string', format: 'date' },\n\tdatetime: { type: 'string', format: 'date-time' },\n\t'date-time': { type: 'string', format: 'date-time' },\n\turl: { type: 'string', format: 'uri' },\n\turi: { type: 'string', format: 'uri' },\n\temail: { type: 'string', format: 'email' },\n\tenum: { type: 'string' },\n\tjson: { type: 'object', widget: 'json' },\n\tarray: { type: 'array' },\n\tobject: { type: 'object', widget: 'json' },\n}\n\n/**\n * Field names read off a definition record when the declaration omits `map`.\n *\n * @type {Record<string, string>}\n */\nconst DEFAULT_MAP = {\n\ttitle: 'name',\n\tdescription: 'description',\n\ttype: 'propertyType',\n\tenum: 'enumValues',\n\trequired: 'isRequired',\n\tdefault: 'defaultValue',\n}\n\n/**\n * Read a value off a record by mapped field name.\n *\n * @param {object} record The definition record.\n * @param {object} map The resolved field-name map.\n * @param {string} role The map role (`title`, `type`, …).\n * @return {unknown} The value, or undefined when the role is unmapped or absent.\n */\nfunction mapped(record, map, role) {\n\tconst field = map[role]\n\tif (!field) {\n\t\treturn undefined\n\t}\n\treturn record[field]\n}\n\n/**\n * The `x-openregister-extends-form` declarations on a schema, one per driving\n * property. Pure: reads the schema and nothing else.\n *\n * A schema may carry more than one — an order extended by both its product\n * line and its customer segment — so this always returns a list.\n *\n * @param {object} schema The schema object with a `properties` field.\n * @return {Array<{key: string, config: object}>} The declarations, in property order.\n */\nexport function extendsFormDeclarations(schema) {\n\tif (!schema || !schema.properties) {\n\t\treturn []\n\t}\n\tconst out = []\n\tfor (const [key, prop] of Object.entries(schema.properties)) {\n\t\tconst config = prop && prop[EXTENDS_FORM_KEY]\n\t\tif (config && typeof config === 'object' && config.definitions) {\n\t\t\tout.push({ key, config })\n\t\t}\n\t}\n\treturn out\n}\n\n/**\n * A definition's name as a person should read it.\n *\n * Definition names are typed by a functional admin, and in practice a good\n * many arrive as identifiers rather than labels: real seeded data in dossiq\n * carries `auditorsStatementThreshold` and `interimReportTermWeeks`, which\n * render verbatim on a form a case handler is supposed to find friendly.\n *\n * Only an identifier-shaped name is touched. Anything containing a space is\n * already a label someone wrote deliberately, and reformatting it would be\n * this function deciding it knows better than the person who typed it.\n *\n * @param {string} name The definition's name.\n * @return {string} The name, made readable when it was an identifier.\n */\nfunction humaniseName(name) {\n\tconst value = String(name || '')\n\tif (!value || value.includes(' ')) {\n\t\treturn value\n\t}\n\n\tconst words = value\n\t\t// `camelCase` and `snake_case` / `kebab-case` both become words. The\n\t\t// lookahead pair keeps an acronym whole: `defaultBSNPolicy` splits to\n\t\t// `default BSN Policy`, not `default B S N Policy`.\n\t\t.replace(/([a-z0-9])([A-Z])/g, '$1 $2')\n\t\t.replace(/([A-Z]+)([A-Z][a-z])/g, '$1 $2')\n\t\t.replace(/[_-]+/g, ' ')\n\t\t.trim()\n\t\t.split(/\\s+/)\n\t\t.filter(Boolean)\n\tif (words.length === 0) {\n\t\treturn value\n\t}\n\n\t// Sentence case, not Title Case: splitting `auditorsStatementThreshold`\n\t// leaves each word capitalised, and shipping that would put a Title Case\n\t// label on every form. An all-caps word is an acronym and keeps its shape.\n\tconst cased = words.map((word, index) => {\n\t\tif (word.length > 1 && word === word.toUpperCase()) {\n\t\t\treturn word\n\t\t}\n\t\tconst lower = word.toLowerCase()\n\t\treturn index === 0 ? lower.charAt(0).toUpperCase() + lower.slice(1) : lower\n\t})\n\n\treturn cased.join(' ')\n}\n\n/**\n * The schema's `x-openregister-prefill` declarations, in property order.\n *\n * A declaration needs a `fields` map to be worth acting on: without it there\n * is nothing to copy, and returning it anyway would cost a fetch per change\n * for no effect.\n *\n * @param {object} schema The schema object with a `properties` field.\n * @return {Array<{key: string, config: object}>} The declarations, in property order.\n */\nexport function prefillDeclarations(schema) {\n\tif (!schema || !schema.properties) {\n\t\treturn []\n\t}\n\tconst out = []\n\tfor (const [key, prop] of Object.entries(schema.properties)) {\n\t\tconst config = prop && prop[PREFILL_KEY]\n\t\tif (config && typeof config === 'object' && config.fields\n\t\t\t&& Object.keys(config.fields).length > 0) {\n\t\t\tout.push({ key, config })\n\t\t}\n\t}\n\treturn out\n}\n\n/**\n * The values one chosen record offers its siblings.\n *\n * Reads `config.fields` as `{ targetProperty: sourceProperty }` and returns\n * only the pairs the record can actually answer. A source field the record\n * leaves empty yields nothing, so a case type with no default assignee\n * prefills the status it does know and leaves the assignee alone, rather\n * than blanking a value.\n *\n * @param {object} record The chosen record, as the API returned it.\n * @param {object} config The `x-openregister-prefill` block (needs `fields`).\n * @return {object} Target property keys mapped to the values to apply.\n */\nexport function prefillValues(record, config) {\n\tconst fields = (config && config.fields) || null\n\tif (!record || !fields) {\n\t\treturn {}\n\t}\n\n\tconst out = {}\n\tfor (const [target, source] of Object.entries(fields)) {\n\t\tif (typeof source !== 'string' || !source) {\n\t\t\tcontinue\n\t\t}\n\t\tconst value = record[source]\n\t\tif (value === undefined || value === null || value === '') {\n\t\t\tcontinue\n\t\t}\n\t\tif (Array.isArray(value) && value.length === 0) {\n\t\t\tcontinue\n\t\t}\n\t\tout[target] = value\n\t}\n\treturn out\n}\n\n/**\n * The query parameters that fetch the definitions for one driving value.\n *\n * `config.definitions.filter` is token-resolved the way `x-relation-filter`\n * is, with the driving property's value available as `$value` and the whole\n * form as `@object.<field>`. A filter entry whose token stays unresolved is\n * dropped rather than sent, because a literal `@object.foo` reaching the API\n * filters on nonsense and returns zero rows — which reads exactly like a\n * case type that has no extra properties.\n *\n * @param {object} config The `x-openregister-extends-form` block.\n * @param {unknown} value The driving property's current value.\n * @param {object} [formData] The full form data, for `@object.<field>` tokens.\n * @return {object} Query parameters for `fetchCollection`.\n */\nexport function definitionQueryParams(config, value, formData = {}) {\n\tconst params = { _limit: 100 }\n\tconst raw = (config && config.definitions && config.definitions.filter) || null\n\tif (!raw || typeof raw !== 'object') {\n\t\treturn params\n\t}\n\n\t// `$value` is the driving property itself; substitute it before token\n\t// resolution so the generic resolver never sees a token it cannot answer.\n\tconst seeded = {}\n\tfor (const [key, entry] of Object.entries(raw)) {\n\t\tseeded[key] = entry === '$value' ? value : entry\n\t}\n\tconst resolved = resolveFilterTokens(seeded, { object: { ...formData }, objectId: formData.id })\n\tfor (const [key, entry] of Object.entries(resolved)) {\n\t\tif (typeof entry === 'string' && entry.charAt(0) === '@') {\n\t\t\tcontinue\n\t\t}\n\t\tif (entry && typeof entry === 'object' && !Array.isArray(entry)) {\n\t\t\tfor (const [op, operand] of Object.entries(entry)) {\n\t\t\t\tparams[`${key}[${op}]`] = operand\n\t\t\t}\n\t\t} else if (entry !== '' && entry !== null && entry !== undefined) {\n\t\t\tparams[key] = entry\n\t\t}\n\t}\n\treturn params\n}\n\n/**\n * Turn definition records into JSON Schema properties.\n *\n * The result is an ordinary `properties` map — the same shape a schema\n * carries — so the caller can hand it straight to `fieldsFromSchema` and get\n * widgets, enum labels, validation and required-marking for free.\n *\n * Each key is `DYNAMIC_KEY_PREFIX` + the record's id, never the admin-authored\n * name, so a definition can be renamed without orphaning the answers already\n * stored against it.\n *\n * @param {Array<object>} definitions The definition records.\n * @param {object} [config] The `x-openregister-extends-form` block (`map`, `typeMap`).\n * @param {object} [options] Extra options.\n * @param {number} [options.orderFrom] Order assigned to the first field; each subsequent field takes the next integer. Dynamic fields sort after the schema's own, so pass a number above every declared `order`.\n * @return {{properties: object, required: string[]}} Properties keyed by prefixed id, plus the required key list.\n */\nexport function propertiesFromDefinitions(definitions, config = {}, options = {}) {\n\tconst map = { ...DEFAULT_MAP, ...(config.map || {}) }\n\tconst typeMap = { ...TYPE_MAP, ...(config.typeMap || {}) }\n\tconst orderFrom = typeof options.orderFrom === 'number' ? options.orderFrom : 1000\n\n\tconst properties = {}\n\tconst required = []\n\tconst list = Array.isArray(definitions) ? definitions : []\n\n\tlist.forEach((record, index) => {\n\t\tif (!record || !record.id) {\n\t\t\treturn\n\t\t}\n\t\tconst key = DYNAMIC_KEY_PREFIX + record.id\n\t\tconst declaredType = mapped(record, map, 'type')\n\t\tconst base = typeMap[declaredType] || typeMap.string\n\n\t\tconst title = mapped(record, map, 'title')\n\t\tconst description = mapped(record, map, 'description')\n\t\tconst enumValues = mapped(record, map, 'enum')\n\t\tconst defaultValue = mapped(record, map, 'default')\n\t\tconst maxLength = mapped(record, map, 'maxLength')\n\t\tconst format = mapped(record, map, 'format')\n\n\t\tconst prop = {\n\t\t\t...base,\n\t\t\ttitle: humaniseName(title) || key,\n\t\t\t// A definition record separates its short `definition` from its\n\t\t\t// longer `description`; either may be absent, and an empty string\n\t\t\t// must not become the helper text \"undefined\".\n\t\t\tdescription: description || mapped(record, map, 'definition') || '',\n\t\t}\n\t\t// An explicitly mapped format wins over the one the type shorthand\n\t\t// implied, so a definition can say `string` + `date` and still get a\n\t\t// date picker.\n\t\tif (format) {\n\t\t\tprop.format = format\n\t\t}\n\t\tif (typeof maxLength === 'number' && maxLength > 0) {\n\t\t\tprop.maxLength = maxLength\n\t\t}\n\t\tif (Array.isArray(enumValues) && enumValues.length > 0) {\n\t\t\tprop.enum = [...enumValues]\n\t\t}\n\t\tif (defaultValue !== undefined && defaultValue !== null && defaultValue !== '') {\n\t\t\tprop.default = defaultValue\n\t\t}\n\t\tprop.order = orderFrom + index\n\n\t\tproperties[key] = prop\n\t\tif (mapped(record, map, 'required') === true) {\n\t\t\trequired.push(key)\n\t\t}\n\t})\n\n\treturn { properties, required }\n}\n\n/**\n * Whether a form-data key holds a dynamic field's answer.\n *\n * @param {string} key The form-data key.\n * @return {boolean} True for a dynamic key.\n */\nexport function isDynamicKey(key) {\n\treturn typeof key === 'string' && key.startsWith(DYNAMIC_KEY_PREFIX)\n}\n\n/**\n * The definition id a dynamic key refers to.\n *\n * @param {string} key The dynamic form-data key.\n * @return {string} The definition id, or '' when the key is not dynamic.\n */\nexport function definitionIdFromKey(key) {\n\treturn isDynamicKey(key) ? key.slice(DYNAMIC_KEY_PREFIX.length) : ''\n}\n\n/**\n * Split a submitted form payload into the object's own fields and the answers\n * that belong in the values schema.\n *\n * The parent object must be saved first — a value row references it — so the\n * two halves cannot go out in one call, and mixing them would post keys the\n * parent schema does not declare. OpenRegister drops undeclared properties\n * silently, so an unsplit payload loses every answer with a 200 and no error.\n *\n * @param {object} formData The dialog's confirmed payload.\n * @return {{base: object, answers: Array<{definitionId: string, value: unknown}>}} The parent's fields, and one answer per dynamic field.\n */\nexport function splitDynamicFormData(formData) {\n\tconst base = {}\n\tconst answers = []\n\tfor (const [key, value] of Object.entries(formData || {})) {\n\t\tif (isDynamicKey(key)) {\n\t\t\tanswers.push({ definitionId: definitionIdFromKey(key), value })\n\t\t} else {\n\t\t\tbase[key] = value\n\t\t}\n\t}\n\treturn { base, answers }\n}\n\n/**\n * Whether a declaration stores its answers as an array on the parent.\n *\n * Two shapes are supported. The default writes one child record per answer\n * (`values.schema` + `objectRef` + `definitionRef`), which is normalised and\n * queryable. Setting `values.mode: 'array'` instead folds the answers into an\n * array property on the parent object itself, which reads in one request and\n * saves in one write, at the cost of not being queryable per answer.\n *\n * @param {object} config One `x-openregister-extends-form` declaration.\n * @return {boolean} True when the declaration stores an array on the parent.\n */\nexport function usesArrayValues(config) {\n\tconst values = (config && config.values) || null\n\treturn !!(values && values.mode === 'array' && values.arrayKey)\n}\n\n/**\n * Build the array a declaration stores on its parent object.\n *\n * Each entry carries the definition it answers as well as its name, so a\n * reader can render the answers without resolving every definition first.\n * That denormalisation is the point of the array shape: one read, no joins.\n *\n * @param {Array<object>} answers `{ definitionId, value }` entries.\n * @param {object} config One `x-openregister-extends-form` declaration.\n * @param {Array<object>} definitions The definition records, for their names.\n * @return {Array<object>} Entries for the parent's array property.\n */\nexport function valueArrayFor(answers, config, definitions = []) {\n\tif (!usesArrayValues(config)) {\n\t\treturn []\n\t}\n\tconst values = config.values\n\tconst definitionRef = values.definitionRef || 'definition'\n\tconst valueKey = values.valueKey || 'value'\n\tconst nameKey = values.nameKey || 'name'\n\tconst nameFrom = (config.map && config.map.title) || 'name'\n\tconst byId = new Map((definitions || []).map((d) => [String(d.id ?? d.uuid ?? ''), d]))\n\n\treturn (answers || [])\n\t\t.filter(({ value }) => value !== undefined && value !== null && value !== '')\n\t\t.map(({ definitionId, value }) => {\n\t\t\tconst def = byId.get(String(definitionId))\n\t\t\treturn {\n\t\t\t\t[definitionRef]: definitionId,\n\t\t\t\t[nameKey]: def ? String(def[nameFrom] ?? '') : '',\n\t\t\t\t// Same rule as the record shape: a non-scalar answer is\n\t\t\t\t// serialised rather than dropped.\n\t\t\t\t[valueKey]: (typeof value === 'object') ? JSON.stringify(value) : String(value),\n\t\t\t}\n\t\t})\n}\n\n/**\n * The value-schema records to write for one saved parent object.\n *\n * An answer left empty writes no row: an absent row and a row holding `''`\n * mean the same thing to every reader, and not writing it keeps the value\n * schema free of rows that only record that someone opened the form.\n *\n * @param {Array<{definitionId: string, value: unknown}>} answers The answers from `splitDynamicFormData`.\n * @param {object} config The `x-openregister-extends-form` block (needs `values`).\n * @param {string} objectId The saved parent object's id.\n * @return {Array<object>} One payload per row to create; empty when nothing is to be written.\n */\nexport function valueRecordsFor(answers, config, objectId) {\n\tconst values = (config && config.values) || null\n\tif (!values || !values.schema || !objectId) {\n\t\treturn []\n\t}\n\tconst objectRef = values.objectRef || 'object'\n\tconst definitionRef = values.definitionRef || 'definition'\n\tconst valueKey = values.valueKey || 'value'\n\n\treturn (answers || [])\n\t\t.filter(({ value }) => value !== undefined && value !== null && value !== '')\n\t\t.map(({ definitionId, value }) => ({\n\t\t\t[objectRef]: objectId,\n\t\t\t[definitionRef]: definitionId,\n\t\t\t// A value schema stores one column for every type it carries, so a\n\t\t\t// non-scalar answer is serialised rather than dropped.\n\t\t\t[valueKey]: (typeof value === 'object') ? JSON.stringify(value) : String(value),\n\t\t}))\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"dynamicProperties.js","sources":["../../../src/utils/dynamicProperties.js"],"sourcesContent":["// SPDX-FileCopyrightText: 2026 Conduction B.V.\n// SPDX-License-Identifier: EUPL-1.2\n\n/**\n * Form fields that a record's own data decides, rather than its schema.\n *\n * Some domains keep half of an object's shape in the database instead of the\n * schema. A municipal case type declares which extra questions its cases must\n * answer; a product line declares which attributes its orders carry. The\n * schema cannot enumerate those, because a functional admin adds them at\n * runtime without a release.\n *\n * The pattern is always the same three parts, so this module names them once:\n *\n * - a **driving property** on the schema — a reference the user picks first\n * (`case.caseType`), carrying an `x-openregister-extends-form` block;\n * - a **definitions schema** whose records describe the extra fields\n * (`propertyDefinition`), filtered by the driving property's value;\n * - a **values schema** that stores one answer per definition per object\n * (`caseProperty`), written after the parent object exists.\n *\n * Definitions are mapped into ordinary JSON Schema properties and handed to\n * `fieldsFromSchema`, so widget resolution, enum labels, validation and\n * description splitting all come from the one engine. A dynamic field is not\n * a second kind of field; it is a normal field whose declaration arrived late.\n *\n * @module utils/dynamicProperties\n */\n\nimport { resolveFilterTokens } from './resolveFilterTokens.js'\n\n/**\n * The vendor extension a driving property carries.\n *\n * @type {string}\n */\nexport const EXTENDS_FORM_KEY = 'x-openregister-extends-form'\n\n/**\n * The vendor extension a driving property carries to prefill its siblings.\n *\n * Where `x-openregister-extends-form` adds NEW fields, this one fills fields\n * the schema already declares. A case type knows the status a case of its\n * kind starts in and who normally handles it, so a person should not have to\n * retype what the chosen type already answers.\n *\n * @type {string}\n */\nexport const PREFILL_KEY = 'x-openregister-prefill'\n\n/**\n * Prefix that namespaces a dynamic field's key inside form data.\n *\n * Definition records are named by a functional admin, so a definition called\n * `title` or `status` is not merely possible but likely. Without a namespace\n * it would overwrite the real schema property of that name — silently, since\n * a form has no way to tell the two apart once they share a key.\n *\n * @type {string}\n */\nexport const DYNAMIC_KEY_PREFIX = 'x-prop:'\n\n/**\n * How a definition record's declared type becomes a JSON Schema property.\n *\n * Covers the JSON Schema type names themselves plus the shorthands a\n * definitions schema tends to use, because an admin picking a type from a\n * dropdown picks `date`, not `string`/`format: date`.\n *\n * @type {Record<string, object>}\n */\nconst TYPE_MAP = {\n\tstring: { type: 'string' },\n\ttext: { type: 'string' },\n\ttextarea: { type: 'string', format: 'textarea' },\n\tmarkdown: { type: 'string', format: 'markdown' },\n\tnumber: { type: 'number' },\n\tinteger: { type: 'integer' },\n\tboolean: { type: 'boolean' },\n\tdate: { type: 'string', format: 'date' },\n\tdatetime: { type: 'string', format: 'date-time' },\n\t'date-time': { type: 'string', format: 'date-time' },\n\turl: { type: 'string', format: 'uri' },\n\turi: { type: 'string', format: 'uri' },\n\temail: { type: 'string', format: 'email' },\n\tenum: { type: 'string' },\n\tjson: { type: 'object', widget: 'json' },\n\tarray: { type: 'array' },\n\tobject: { type: 'object', widget: 'json' },\n}\n\n/**\n * Field names read off a definition record when the declaration omits `map`.\n *\n * @type {Record<string, string>}\n */\nconst DEFAULT_MAP = {\n\ttitle: 'name',\n\tdescription: 'description',\n\ttype: 'propertyType',\n\tenum: 'enumValues',\n\trequired: 'isRequired',\n\tdefault: 'defaultValue',\n\thideOnCreate: 'hideOnCreate',\n}\n\n/**\n * Read a value off a record by mapped field name.\n *\n * @param {object} record The definition record.\n * @param {object} map The resolved field-name map.\n * @param {string} role The map role (`title`, `type`, …).\n * @return {unknown} The value, or undefined when the role is unmapped or absent.\n */\nfunction mapped(record, map, role) {\n\tconst field = map[role]\n\tif (!field) {\n\t\treturn undefined\n\t}\n\treturn record[field]\n}\n\n/**\n * The `x-openregister-extends-form` declarations on a schema, one per driving\n * property. Pure: reads the schema and nothing else.\n *\n * A schema may carry more than one — an order extended by both its product\n * line and its customer segment — so this always returns a list.\n *\n * @param {object} schema The schema object with a `properties` field.\n * @return {Array<{key: string, config: object}>} The declarations, in property order.\n */\nexport function extendsFormDeclarations(schema) {\n\tif (!schema || !schema.properties) {\n\t\treturn []\n\t}\n\tconst out = []\n\tfor (const [key, prop] of Object.entries(schema.properties)) {\n\t\tconst config = prop && prop[EXTENDS_FORM_KEY]\n\t\tif (config && typeof config === 'object' && config.definitions) {\n\t\t\tout.push({ key, config })\n\t\t}\n\t}\n\treturn out\n}\n\n/**\n * A definition's name as a person should read it.\n *\n * Definition names are typed by a functional admin, and in practice a good\n * many arrive as identifiers rather than labels: real seeded data in dossiq\n * carries `auditorsStatementThreshold` and `interimReportTermWeeks`, which\n * render verbatim on a form a case handler is supposed to find friendly.\n *\n * Only an identifier-shaped name is touched. Anything containing a space is\n * already a label someone wrote deliberately, and reformatting it would be\n * this function deciding it knows better than the person who typed it.\n *\n * @param {string} name The definition's name.\n * @return {string} The name, made readable when it was an identifier.\n */\nfunction humaniseName(name) {\n\tconst value = String(name || '')\n\tif (!value || value.includes(' ')) {\n\t\treturn value\n\t}\n\n\tconst words = value\n\t\t// `camelCase` and `snake_case` / `kebab-case` both become words. The\n\t\t// lookahead pair keeps an acronym whole: `defaultBSNPolicy` splits to\n\t\t// `default BSN Policy`, not `default B S N Policy`.\n\t\t.replace(/([a-z0-9])([A-Z])/g, '$1 $2')\n\t\t.replace(/([A-Z]+)([A-Z][a-z])/g, '$1 $2')\n\t\t.replace(/[_-]+/g, ' ')\n\t\t.trim()\n\t\t.split(/\\s+/)\n\t\t.filter(Boolean)\n\tif (words.length === 0) {\n\t\treturn value\n\t}\n\n\t// Sentence case, not Title Case: splitting `auditorsStatementThreshold`\n\t// leaves each word capitalised, and shipping that would put a Title Case\n\t// label on every form. An all-caps word is an acronym and keeps its shape.\n\tconst cased = words.map((word, index) => {\n\t\tif (word.length > 1 && word === word.toUpperCase()) {\n\t\t\treturn word\n\t\t}\n\t\tconst lower = word.toLowerCase()\n\t\treturn index === 0 ? lower.charAt(0).toUpperCase() + lower.slice(1) : lower\n\t})\n\n\treturn cased.join(' ')\n}\n\n/**\n * The schema's `x-openregister-prefill` declarations, in property order.\n *\n * A declaration needs a `fields` map to be worth acting on: without it there\n * is nothing to copy, and returning it anyway would cost a fetch per change\n * for no effect.\n *\n * @param {object} schema The schema object with a `properties` field.\n * @return {Array<{key: string, config: object}>} The declarations, in property order.\n */\nexport function prefillDeclarations(schema) {\n\tif (!schema || !schema.properties) {\n\t\treturn []\n\t}\n\tconst out = []\n\tfor (const [key, prop] of Object.entries(schema.properties)) {\n\t\tconst config = prop && prop[PREFILL_KEY]\n\t\tif (config && typeof config === 'object' && config.fields\n\t\t\t&& Object.keys(config.fields).length > 0) {\n\t\t\tout.push({ key, config })\n\t\t}\n\t}\n\treturn out\n}\n\n/**\n * The values one chosen record offers its siblings.\n *\n * Reads `config.fields` as `{ targetProperty: sourceProperty }` and returns\n * only the pairs the record can actually answer. A source field the record\n * leaves empty yields nothing, so a case type with no default assignee\n * prefills the status it does know and leaves the assignee alone, rather\n * than blanking a value.\n *\n * @param {object} record The chosen record, as the API returned it.\n * @param {object} config The `x-openregister-prefill` block (needs `fields`).\n * @return {object} Target property keys mapped to the values to apply.\n */\nexport function prefillValues(record, config) {\n\tconst fields = (config && config.fields) || null\n\tif (!record || !fields) {\n\t\treturn {}\n\t}\n\n\tconst out = {}\n\tfor (const [target, source] of Object.entries(fields)) {\n\t\tif (typeof source !== 'string' || !source) {\n\t\t\tcontinue\n\t\t}\n\t\tconst value = record[source]\n\t\tif (value === undefined || value === null || value === '') {\n\t\t\tcontinue\n\t\t}\n\t\tif (Array.isArray(value) && value.length === 0) {\n\t\t\tcontinue\n\t\t}\n\t\tout[target] = value\n\t}\n\treturn out\n}\n\n/**\n * The query parameters that fetch the definitions for one driving value.\n *\n * `config.definitions.filter` is token-resolved the way `x-relation-filter`\n * is, with the driving property's value available as `$value` and the whole\n * form as `@object.<field>`. A filter entry whose token stays unresolved is\n * dropped rather than sent, because a literal `@object.foo` reaching the API\n * filters on nonsense and returns zero rows — which reads exactly like a\n * case type that has no extra properties.\n *\n * @param {object} config The `x-openregister-extends-form` block.\n * @param {unknown} value The driving property's current value.\n * @param {object} [formData] The full form data, for `@object.<field>` tokens.\n * @return {object} Query parameters for `fetchCollection`.\n */\nexport function definitionQueryParams(config, value, formData = {}) {\n\tconst params = { _limit: 100 }\n\tconst raw = (config && config.definitions && config.definitions.filter) || null\n\tif (!raw || typeof raw !== 'object') {\n\t\treturn params\n\t}\n\n\t// `$value` is the driving property itself; substitute it before token\n\t// resolution so the generic resolver never sees a token it cannot answer.\n\tconst seeded = {}\n\tfor (const [key, entry] of Object.entries(raw)) {\n\t\tseeded[key] = entry === '$value' ? value : entry\n\t}\n\tconst resolved = resolveFilterTokens(seeded, { object: { ...formData }, objectId: formData.id })\n\tfor (const [key, entry] of Object.entries(resolved)) {\n\t\tif (typeof entry === 'string' && entry.charAt(0) === '@') {\n\t\t\tcontinue\n\t\t}\n\t\tif (entry && typeof entry === 'object' && !Array.isArray(entry)) {\n\t\t\tfor (const [op, operand] of Object.entries(entry)) {\n\t\t\t\tparams[`${key}[${op}]`] = operand\n\t\t\t}\n\t\t} else if (entry !== '' && entry !== null && entry !== undefined) {\n\t\t\tparams[key] = entry\n\t\t}\n\t}\n\treturn params\n}\n\n/**\n * Turn definition records into JSON Schema properties.\n *\n * The result is an ordinary `properties` map — the same shape a schema\n * carries — so the caller can hand it straight to `fieldsFromSchema` and get\n * widgets, enum labels, validation and required-marking for free.\n *\n * Each key is `DYNAMIC_KEY_PREFIX` + the record's id, never the admin-authored\n * name, so a definition can be renamed without orphaning the answers already\n * stored against it.\n *\n * @param {Array<object>} definitions The definition records.\n * @param {object} [config] The `x-openregister-extends-form` block (`map`, `typeMap`).\n * @param {object} [options] Extra options.\n * @param {number} [options.orderFrom] Order assigned to the first field; each subsequent field takes the next integer. Dynamic fields sort after the schema's own, so pass a number above every declared `order`.\n * @param {boolean} [options.create] The form creates a new object: a definition whose `hideOnCreate` (or the field `config.map.hideOnCreate` names) is `true` gets no field, because the app fills that answer itself at creation. Edit forms still show it.\n * @spec openspec/changes/dynamic-question-hide-on-create/specs/dynamic-question-hide-on-create/spec.md#requirement-a-question-can-stay-off-the-create-form\n * @return {{properties: object, required: string[]}} Properties keyed by prefixed id, plus the required key list.\n */\nexport function propertiesFromDefinitions(definitions, config = {}, options = {}) {\n\tconst map = { ...DEFAULT_MAP, ...(config.map || {}) }\n\tconst typeMap = { ...TYPE_MAP, ...(config.typeMap || {}) }\n\tconst orderFrom = typeof options.orderFrom === 'number' ? options.orderFrom : 1000\n\n\tconst properties = {}\n\tconst required = []\n\tconst list = (Array.isArray(definitions) ? definitions : [])\n\t\t.filter((record) => !(options.create === true && record && mapped(record, map, 'hideOnCreate') === true))\n\n\tlist.forEach((record, index) => {\n\t\tif (!record || !record.id) {\n\t\t\treturn\n\t\t}\n\t\tconst key = DYNAMIC_KEY_PREFIX + record.id\n\t\tconst declaredType = mapped(record, map, 'type')\n\t\tconst base = typeMap[declaredType] || typeMap.string\n\n\t\tconst title = mapped(record, map, 'title')\n\t\tconst description = mapped(record, map, 'description')\n\t\tconst enumValues = mapped(record, map, 'enum')\n\t\tconst defaultValue = mapped(record, map, 'default')\n\t\tconst maxLength = mapped(record, map, 'maxLength')\n\t\tconst format = mapped(record, map, 'format')\n\n\t\tconst prop = {\n\t\t\t...base,\n\t\t\ttitle: humaniseName(title) || key,\n\t\t\t// A definition record separates its short `definition` from its\n\t\t\t// longer `description`; either may be absent, and an empty string\n\t\t\t// must not become the helper text \"undefined\".\n\t\t\tdescription: description || mapped(record, map, 'definition') || '',\n\t\t}\n\t\t// An explicitly mapped format wins over the one the type shorthand\n\t\t// implied, so a definition can say `string` + `date` and still get a\n\t\t// date picker.\n\t\tif (format) {\n\t\t\tprop.format = format\n\t\t}\n\t\tif (typeof maxLength === 'number' && maxLength > 0) {\n\t\t\tprop.maxLength = maxLength\n\t\t}\n\t\tif (Array.isArray(enumValues) && enumValues.length > 0) {\n\t\t\tprop.enum = [...enumValues]\n\t\t}\n\t\tif (defaultValue !== undefined && defaultValue !== null && defaultValue !== '') {\n\t\t\tprop.default = defaultValue\n\t\t}\n\t\tprop.order = orderFrom + index\n\n\t\tproperties[key] = prop\n\t\tif (mapped(record, map, 'required') === true) {\n\t\t\trequired.push(key)\n\t\t}\n\t})\n\n\treturn { properties, required }\n}\n\n/**\n * Whether a form-data key holds a dynamic field's answer.\n *\n * @param {string} key The form-data key.\n * @return {boolean} True for a dynamic key.\n */\nexport function isDynamicKey(key) {\n\treturn typeof key === 'string' && key.startsWith(DYNAMIC_KEY_PREFIX)\n}\n\n/**\n * The definition id a dynamic key refers to.\n *\n * @param {string} key The dynamic form-data key.\n * @return {string} The definition id, or '' when the key is not dynamic.\n */\nexport function definitionIdFromKey(key) {\n\treturn isDynamicKey(key) ? key.slice(DYNAMIC_KEY_PREFIX.length) : ''\n}\n\n/**\n * Split a submitted form payload into the object's own fields and the answers\n * that belong in the values schema.\n *\n * The parent object must be saved first — a value row references it — so the\n * two halves cannot go out in one call, and mixing them would post keys the\n * parent schema does not declare. OpenRegister drops undeclared properties\n * silently, so an unsplit payload loses every answer with a 200 and no error.\n *\n * @param {object} formData The dialog's confirmed payload.\n * @return {{base: object, answers: Array<{definitionId: string, value: unknown}>}} The parent's fields, and one answer per dynamic field.\n */\nexport function splitDynamicFormData(formData) {\n\tconst base = {}\n\tconst answers = []\n\tfor (const [key, value] of Object.entries(formData || {})) {\n\t\tif (isDynamicKey(key)) {\n\t\t\tanswers.push({ definitionId: definitionIdFromKey(key), value })\n\t\t} else {\n\t\t\tbase[key] = value\n\t\t}\n\t}\n\treturn { base, answers }\n}\n\n/**\n * Whether a declaration stores its answers as an array on the parent.\n *\n * Two shapes are supported. The default writes one child record per answer\n * (`values.schema` + `objectRef` + `definitionRef`), which is normalised and\n * queryable. Setting `values.mode: 'array'` instead folds the answers into an\n * array property on the parent object itself, which reads in one request and\n * saves in one write, at the cost of not being queryable per answer.\n *\n * @param {object} config One `x-openregister-extends-form` declaration.\n * @return {boolean} True when the declaration stores an array on the parent.\n */\nexport function usesArrayValues(config) {\n\tconst values = (config && config.values) || null\n\treturn !!(values && values.mode === 'array' && values.arrayKey)\n}\n\n/**\n * Build the array a declaration stores on its parent object.\n *\n * Each entry carries the definition it answers as well as its name, so a\n * reader can render the answers without resolving every definition first.\n * That denormalisation is the point of the array shape: one read, no joins.\n *\n * @param {Array<object>} answers `{ definitionId, value }` entries.\n * @param {object} config One `x-openregister-extends-form` declaration.\n * @param {Array<object>} definitions The definition records, for their names.\n * @return {Array<object>} Entries for the parent's array property.\n */\nexport function valueArrayFor(answers, config, definitions = []) {\n\tif (!usesArrayValues(config)) {\n\t\treturn []\n\t}\n\tconst values = config.values\n\tconst definitionRef = values.definitionRef || 'definition'\n\tconst valueKey = values.valueKey || 'value'\n\tconst nameKey = values.nameKey || 'name'\n\tconst nameFrom = (config.map && config.map.title) || 'name'\n\tconst byId = new Map((definitions || []).map((d) => [String(d.id ?? d.uuid ?? ''), d]))\n\n\treturn (answers || [])\n\t\t.filter(({ value }) => value !== undefined && value !== null && value !== '')\n\t\t.map(({ definitionId, value }) => {\n\t\t\tconst def = byId.get(String(definitionId))\n\t\t\treturn {\n\t\t\t\t[definitionRef]: definitionId,\n\t\t\t\t[nameKey]: def ? String(def[nameFrom] ?? '') : '',\n\t\t\t\t// Same rule as the record shape: a non-scalar answer is\n\t\t\t\t// serialised rather than dropped.\n\t\t\t\t[valueKey]: (typeof value === 'object') ? JSON.stringify(value) : String(value),\n\t\t\t}\n\t\t})\n}\n\n/**\n * The value-schema records to write for one saved parent object.\n *\n * An answer left empty writes no row: an absent row and a row holding `''`\n * mean the same thing to every reader, and not writing it keeps the value\n * schema free of rows that only record that someone opened the form.\n *\n * @param {Array<{definitionId: string, value: unknown}>} answers The answers from `splitDynamicFormData`.\n * @param {object} config The `x-openregister-extends-form` block (needs `values`).\n * @param {string} objectId The saved parent object's id.\n * @return {Array<object>} One payload per row to create; empty when nothing is to be written.\n */\nexport function valueRecordsFor(answers, config, objectId) {\n\tconst values = (config && config.values) || null\n\tif (!values || !values.schema || !objectId) {\n\t\treturn []\n\t}\n\tconst objectRef = values.objectRef || 'object'\n\tconst definitionRef = values.definitionRef || 'definition'\n\tconst valueKey = values.valueKey || 'value'\n\n\treturn (answers || [])\n\t\t.filter(({ value }) => value !== undefined && value !== null && value !== '')\n\t\t.map(({ definitionId, value }) => ({\n\t\t\t[objectRef]: objectId,\n\t\t\t[definitionRef]: definitionId,\n\t\t\t// A value schema stores one column for every type it carries, so a\n\t\t\t// non-scalar answer is serialised rather than dropped.\n\t\t\t[valueKey]: (typeof value === 'object') ? JSON.stringify(value) : String(value),\n\t\t}))\n}\n"],"names":[],"mappings":"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"}
|