@conduction/nextcloud-vue 2.62.0 → 2.63.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/CnAdminActionCard/CnAdminActionCard.vue.js +10 -0
- package/dist/esm/components/CnAdminActionCard/CnAdminActionCard.vue.js.map +1 -0
- package/dist/esm/components/CnAdminActionCard/CnAdminActionCard.vue2.js +189 -0
- package/dist/esm/components/CnAdminActionCard/CnAdminActionCard.vue2.js.map +1 -0
- package/dist/esm/components/CnAdminActionCard/CnAdminActionCard.vue3.js +72 -0
- package/dist/esm/components/CnAdminActionCard/CnAdminActionCard.vue3.js.map +1 -0
- package/dist/esm/components/CnAppNav/CnAppNav.vue2.js +271 -32
- package/dist/esm/components/CnAppNav/CnAppNav.vue2.js.map +1 -1
- package/dist/esm/components/CnAppNav/CnAppNav.vue3.js.map +1 -1
- package/dist/esm/components/CnAppRoot/CnAppRoot.vue2.js +99 -9
- package/dist/esm/components/CnAppRoot/CnAppRoot.vue2.js.map +1 -1
- package/dist/esm/components/CnAppRoot/CnAppRoot.vue3.js +39 -18
- package/dist/esm/components/CnAppRoot/CnAppRoot.vue3.js.map +1 -1
- package/dist/esm/components/CnChoiceCards/CnChoiceCards.vue2.js.map +1 -1
- package/dist/esm/components/CnChoiceCards/CnChoiceCards.vue3.js +53 -37
- package/dist/esm/components/CnChoiceCards/CnChoiceCards.vue3.js.map +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js.map +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js +2 -2
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js.map +1 -1
- package/dist/esm/components/CnDataTable/CnColumnFilterPopover.vue.js +10 -0
- package/dist/esm/components/CnDataTable/CnColumnFilterPopover.vue.js.map +1 -0
- package/dist/esm/components/CnDataTable/CnColumnFilterPopover.vue2.js +293 -0
- package/dist/esm/components/CnDataTable/CnColumnFilterPopover.vue2.js.map +1 -0
- package/dist/esm/components/CnDataTable/CnColumnFilterPopover.vue3.js +189 -0
- package/dist/esm/components/CnDataTable/CnColumnFilterPopover.vue3.js.map +1 -0
- package/dist/esm/components/CnDataTable/CnDataTable.vue2.js +216 -8
- package/dist/esm/components/CnDataTable/CnDataTable.vue2.js.map +1 -1
- package/dist/esm/components/CnDataTable/CnDataTable.vue3.js +118 -50
- package/dist/esm/components/CnDataTable/CnDataTable.vue3.js.map +1 -1
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue2.js.map +1 -1
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue3.js +2 -1
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue3.js.map +1 -1
- package/dist/esm/components/CnFieldHelper/CnFieldHelper.vue2.js +3 -1
- package/dist/esm/components/CnFieldHelper/CnFieldHelper.vue2.js.map +1 -1
- package/dist/esm/components/CnFieldHelper/CnFieldHelper.vue3.js +1 -1
- package/dist/esm/components/CnFieldHelper/CnFieldHelper.vue3.js.map +1 -1
- package/dist/esm/components/CnFormDialog/CnFormDialog.vue2.js +234 -9
- package/dist/esm/components/CnFormDialog/CnFormDialog.vue2.js.map +1 -1
- package/dist/esm/components/CnFormDialog/CnFormDialog.vue3.js +96 -57
- package/dist/esm/components/CnFormDialog/CnFormDialog.vue3.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +51 -2
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js +5 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
- package/dist/esm/components/CnIndexPage/selfModeActions.js +3 -3
- package/dist/esm/components/CnIndexPage/selfModeActions.js.map +1 -1
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js +36 -1
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue3.js +4 -1
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnResourceSelect/CnResourceSelect.vue2.js +121 -12
- package/dist/esm/components/CnResourceSelect/CnResourceSelect.vue2.js.map +1 -1
- package/dist/esm/components/CnResourceSelect/CnResourceSelect.vue3.js +3 -1
- package/dist/esm/components/CnResourceSelect/CnResourceSelect.vue3.js.map +1 -1
- package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue2.js +326 -1
- package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue2.js.map +1 -1
- package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue3.js +112 -26
- package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue3.js.map +1 -1
- package/dist/esm/components/CnTimelineWidget/CnTimelineWidget.vue.js +10 -0
- package/dist/esm/components/CnTimelineWidget/CnTimelineWidget.vue.js.map +1 -0
- package/dist/esm/components/CnTimelineWidget/CnTimelineWidget.vue2.js +337 -0
- package/dist/esm/components/CnTimelineWidget/CnTimelineWidget.vue2.js.map +1 -0
- package/dist/esm/components/CnTimelineWidget/CnTimelineWidget.vue3.js +102 -0
- package/dist/esm/components/CnTimelineWidget/CnTimelineWidget.vue3.js.map +1 -0
- package/dist/esm/components/CnTimelineWidget/dashboardRegistration.js +34 -0
- package/dist/esm/components/CnTimelineWidget/dashboardRegistration.js.map +1 -0
- package/dist/esm/components/CnWalkthrough/CnWalkthrough.vue2.js +131 -8
- package/dist/esm/components/CnWalkthrough/CnWalkthrough.vue2.js.map +1 -1
- package/dist/esm/components/CnWalkthrough/CnWalkthrough.vue3.js +40 -38
- package/dist/esm/components/CnWalkthrough/CnWalkthrough.vue3.js.map +1 -1
- package/dist/esm/components/CnWidgetGrid/builtInWidgets.js +8 -6
- package/dist/esm/components/CnWidgetGrid/builtInWidgets.js.map +1 -1
- package/dist/esm/components/CnWidgetGrid/registerDashboardWidgets.js +1 -0
- package/dist/esm/components/CnWidgetGrid/registerDashboardWidgets.js.map +1 -1
- package/dist/esm/components/CnWizardDialog/CnWizardDialog.vue2.js +19 -0
- package/dist/esm/components/CnWizardDialog/CnWizardDialog.vue2.js.map +1 -1
- package/dist/esm/components/CnWizardDialog/CnWizardDialog.vue3.js +1 -1
- package/dist/esm/components/CnWizardDialog/CnWizardDialog.vue3.js.map +1 -1
- package/dist/esm/composables/useDependencyCheck.js +65 -0
- package/dist/esm/composables/useDependencyCheck.js.map +1 -0
- package/dist/esm/composables/useWalkthrough.js +218 -6
- package/dist/esm/composables/useWalkthrough.js.map +1 -1
- package/dist/esm/index.js +2 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/l10n/en.json.js +43 -0
- package/dist/esm/l10n/en.json.js.map +1 -1
- package/dist/esm/l10n/nl.json.js +43 -0
- package/dist/esm/l10n/nl.json.js.map +1 -1
- package/dist/esm/nextcloud-vue.css +449 -0
- package/dist/esm/store/useObjectStore.js +8 -0
- package/dist/esm/store/useObjectStore.js.map +1 -1
- package/dist/esm/utils/columnFilters.js +311 -0
- package/dist/esm/utils/columnFilters.js.map +1 -0
- package/dist/esm/utils/groupAutocomplete.js +123 -0
- package/dist/esm/utils/groupAutocomplete.js.map +1 -0
- package/dist/esm/utils/libraryWidgetKeys.js +2 -0
- package/dist/esm/utils/libraryWidgetKeys.js.map +1 -1
- package/dist/esm/utils/pickerOptions.js +198 -0
- package/dist/esm/utils/pickerOptions.js.map +1 -0
- package/dist/esm/utils/schema.js +83 -7
- package/dist/esm/utils/schema.js.map +1 -1
- package/dist/esm/utils/timelineEvents.js +174 -0
- package/dist/esm/utils/timelineEvents.js.map +1 -0
- package/dist/esm/utils/validateManifestV2.compiled.js +2 -2
- package/dist/esm/utils/validateManifestV2.compiled.js.map +1 -1
- package/dist/esm/utils/walkthroughSignals.js +88 -0
- package/dist/esm/utils/walkthroughSignals.js.map +1 -0
- package/dist/nextcloud-vue.cjs.js +9369 -5193
- package/dist/nextcloud-vue.cjs.js.map +2 -2
- package/dist/nextcloud-vue.css +449 -0
- package/l10n/en.json +43 -0
- package/l10n/nl.json +43 -0
- package/package.json +1 -1
- package/src/components/CnAdminActionCard/CnAdminActionCard.vue +234 -0
- package/src/components/CnAdminActionCard/index.js +4 -0
- package/src/components/CnAppNav/CnAppNav.vue +271 -32
- package/src/components/CnAppRoot/CnAppRoot.vue +129 -15
- package/src/components/CnChoiceCards/CnChoiceCards.vue +56 -31
- package/src/components/CnDashboardPage/CnDashboardPage.vue +2 -2
- package/src/components/CnDataTable/CnColumnFilterPopover.vue +524 -0
- package/src/components/CnDataTable/CnDataTable.md +3 -0
- package/src/components/CnDataTable/CnDataTable.vue +260 -4
- package/src/components/CnDetailWidgetHost/CnDetailWidgetHost.vue +2 -2
- package/src/components/CnFieldHelper/CnFieldHelper.vue +4 -2
- package/src/components/CnFormDialog/CnFormDialog.vue +290 -31
- package/src/components/CnIndexPage/CnIndexPage.vue +55 -2
- package/src/components/CnIndexPage/selfModeActions.js +3 -3
- package/src/components/CnObjectListWidget/CnObjectListWidget.vue +39 -1
- package/src/components/CnResourceSelect/CnResourceSelect.vue +123 -12
- package/src/components/CnSetupWizard/CnSetupWizard.vue +392 -3
- package/src/components/CnTimelineWidget/CnTimelineWidget.vue +477 -0
- package/src/components/CnTimelineWidget/dashboardRegistration.js +32 -0
- package/src/components/CnTimelineWidget/index.js +4 -0
- package/src/components/CnWalkthrough/CnWalkthrough.vue +143 -10
- package/src/components/CnWidgetGrid/builtInWidgets.js +2 -0
- package/src/components/CnWidgetGrid/registerDashboardWidgets.js +1 -0
- package/src/components/CnWizardDialog/CnWizardDialog.vue +20 -1
- package/src/components/index.js +2 -0
- package/src/composables/useDependencyCheck.js +61 -0
- package/src/composables/useWalkthrough.js +217 -5
- package/src/css/dashboard.css +49 -0
- package/src/css/detail-page.css +19 -0
- package/src/css/table.css +81 -0
- package/src/index.js +2 -0
- package/src/schemas/app-manifest-v2.schema.json +23 -1
- package/src/store/useObjectStore.js +8 -0
- package/src/utils/columnFilters.js +324 -0
- package/src/utils/groupAutocomplete.js +119 -0
- package/src/utils/libraryWidgetKeys.js +2 -0
- package/src/utils/pickerOptions.js +194 -0
- package/src/utils/schema.js +83 -7
- package/src/utils/timelineEvents.js +171 -0
- package/src/utils/validateManifestV2.compiled.js +2 -2
- package/src/utils/walkthroughSignals.js +94 -0
|
@@ -12,7 +12,9 @@ import { TENANT_CONTEXT_KEY } from '../../composables/useTenantContext.js';
|
|
|
12
12
|
import { useObjectStore } from '../../store/useObjectStore.js';
|
|
13
13
|
import { extendsFormDeclarations, prefillDeclarations, definitionQueryParams, propertiesFromDefinitions, prefillValues, splitDynamicFormData, DYNAMIC_KEY_PREFIX } from '../../utils/dynamicProperties.js';
|
|
14
14
|
import { shouldShow } from '../../utils/fieldCondition.js';
|
|
15
|
+
import { resolveNextcloudGroup, searchNextcloudGroups } from '../../utils/groupAutocomplete.js';
|
|
15
16
|
import { objectDisplayName } from '../../utils/objectName.js';
|
|
17
|
+
import { resolveDefaultToken, languageOptions, timezoneOptions } from '../../utils/pickerOptions.js';
|
|
16
18
|
import { resolveFilterTokens } from '../../utils/resolveFilterTokens.js';
|
|
17
19
|
import { fieldsFromSchema, isTenantProperty } from '../../utils/schema.js';
|
|
18
20
|
import { resolveNextcloudUser, searchNextcloudUsers } from '../../utils/userAutocomplete.js';
|
|
@@ -543,6 +545,13 @@ var script = {
|
|
|
543
545
|
* `dynamicToken` guards the definitions fetch.
|
|
544
546
|
*/
|
|
545
547
|
prefillToken: '',
|
|
548
|
+
/**
|
|
549
|
+
* The inline create in progress, or null: `{ field, schema,
|
|
550
|
+
* register, slug, initialData, resolve }`. Set when "Create" is
|
|
551
|
+
* chosen on a select-or-create reference; renders a nested form
|
|
552
|
+
* for the referenced schema.
|
|
553
|
+
*/
|
|
554
|
+
nestedCreate: null,
|
|
546
555
|
}
|
|
547
556
|
},
|
|
548
557
|
|
|
@@ -813,6 +822,7 @@ var script = {
|
|
|
813
822
|
.filter((field) => shouldShow(field, this.formData))
|
|
814
823
|
.map((field) => this.applySemanticResolution(field))
|
|
815
824
|
.map((field) => this.degradeUnresolvableReference(field))
|
|
825
|
+
.map((field) => this.applyCodePicker(field))
|
|
816
826
|
},
|
|
817
827
|
|
|
818
828
|
/**
|
|
@@ -1327,11 +1337,16 @@ var script = {
|
|
|
1327
1337
|
// Create mode: initialize with field defaults
|
|
1328
1338
|
const data = {};
|
|
1329
1339
|
for (const field of this.resolvedFields) {
|
|
1340
|
+
const tokenDefault = field.defaultToken ? resolveDefaultToken(field.defaultToken, field) : null;
|
|
1330
1341
|
if (field.default !== null && field.default !== undefined) {
|
|
1331
1342
|
data[field.key] = field.default;
|
|
1343
|
+
} else if (tokenDefault !== null) {
|
|
1344
|
+
// `x-default: current-language` / `current-timezone`:
|
|
1345
|
+
// a NEW object starts with the user's own value.
|
|
1346
|
+
data[field.key] = tokenDefault;
|
|
1332
1347
|
} else if (field.widget === 'checkbox') {
|
|
1333
1348
|
data[field.key] = false;
|
|
1334
|
-
} else if (field.widget === 'tags' || field.widget === 'multiselect' || field.widget === 'user-multiselect') {
|
|
1349
|
+
} else if (field.widget === 'tags' || field.widget === 'multiselect' || field.widget === 'user-multiselect' || field.widget === 'group-multiselect') {
|
|
1335
1350
|
data[field.key] = [];
|
|
1336
1351
|
} else if (field.widget === 'code') {
|
|
1337
1352
|
data[field.key] = '';
|
|
@@ -1398,10 +1413,35 @@ var script = {
|
|
|
1398
1413
|
this.resolveUserLabel(uid);
|
|
1399
1414
|
}
|
|
1400
1415
|
}
|
|
1416
|
+
} else if (this.isGroupField(field) || this.isGroupArrayField(field)) {
|
|
1417
|
+
const value = this.formData[field.key];
|
|
1418
|
+
for (const gid of (Array.isArray(value) ? value : [value])) {
|
|
1419
|
+
if (gid) {
|
|
1420
|
+
this.resolveGroupLabel(gid);
|
|
1421
|
+
}
|
|
1422
|
+
}
|
|
1401
1423
|
}
|
|
1402
1424
|
}
|
|
1403
1425
|
},
|
|
1404
1426
|
|
|
1427
|
+
/**
|
|
1428
|
+
* Resolve a stored group id to its display name and cache it in
|
|
1429
|
+
* `referenceLabels`. No-op once cached; falls back to the gid.
|
|
1430
|
+
*
|
|
1431
|
+
* @spec openspec/changes/form-pickers-from-schema/specs/schema-utilities/spec.md
|
|
1432
|
+
* @param {string} gid The stored group id.
|
|
1433
|
+
* @return {Promise<void>}
|
|
1434
|
+
*/
|
|
1435
|
+
async resolveGroupLabel(gid) {
|
|
1436
|
+
if (!gid || this.referenceLabels[gid]) {
|
|
1437
|
+
return
|
|
1438
|
+
}
|
|
1439
|
+
const option = await resolveNextcloudGroup(gid);
|
|
1440
|
+
if (option && option.id) {
|
|
1441
|
+
this.referenceLabels = { ...this.referenceLabels, [option.id]: option.label || String(option.id) };
|
|
1442
|
+
}
|
|
1443
|
+
},
|
|
1444
|
+
|
|
1405
1445
|
/**
|
|
1406
1446
|
* Resolve a single user UID to its display name (edit mode) and cache it
|
|
1407
1447
|
* in `referenceLabels` so the select shows the name instead of the UID.
|
|
@@ -1898,6 +1938,67 @@ var script = {
|
|
|
1898
1938
|
return !!(field && field.userPicker && field.userPicker.multiple)
|
|
1899
1939
|
},
|
|
1900
1940
|
|
|
1941
|
+
/**
|
|
1942
|
+
* Whether a field is a single Nextcloud group (`format: 'nc-group'` or
|
|
1943
|
+
* `referenceType: 'nextcloud-group'`). Stores the group id.
|
|
1944
|
+
*
|
|
1945
|
+
* @spec openspec/changes/form-pickers-from-schema/specs/schema-utilities/spec.md
|
|
1946
|
+
* @param {object} field The field definition
|
|
1947
|
+
* @return {boolean}
|
|
1948
|
+
*/
|
|
1949
|
+
isGroupField(field) {
|
|
1950
|
+
return !!(field && field.groupPicker && !field.groupPicker.multiple)
|
|
1951
|
+
},
|
|
1952
|
+
|
|
1953
|
+
/**
|
|
1954
|
+
* Whether a field is an array of Nextcloud groups.
|
|
1955
|
+
*
|
|
1956
|
+
* @spec openspec/changes/form-pickers-from-schema/specs/schema-utilities/spec.md
|
|
1957
|
+
* @param {object} field The field definition
|
|
1958
|
+
* @return {boolean}
|
|
1959
|
+
*/
|
|
1960
|
+
isGroupArrayField(field) {
|
|
1961
|
+
return !!(field && field.groupPicker && field.groupPicker.multiple)
|
|
1962
|
+
},
|
|
1963
|
+
|
|
1964
|
+
/**
|
|
1965
|
+
* Whether a single-value field stores an id that maps to a label
|
|
1966
|
+
* fetched elsewhere: an object reference, a user or a group.
|
|
1967
|
+
*
|
|
1968
|
+
* @param {object} field The field definition
|
|
1969
|
+
* @return {boolean}
|
|
1970
|
+
*/
|
|
1971
|
+
isIdPickerField(field) {
|
|
1972
|
+
return this.isReferenceField(field) || this.isUserField(field) || this.isGroupField(field)
|
|
1973
|
+
},
|
|
1974
|
+
|
|
1975
|
+
/**
|
|
1976
|
+
* The multi-value sibling of `isIdPickerField`.
|
|
1977
|
+
*
|
|
1978
|
+
* @param {object} field The field definition
|
|
1979
|
+
* @return {boolean}
|
|
1980
|
+
*/
|
|
1981
|
+
isIdPickerArrayField(field) {
|
|
1982
|
+
return this.isReferenceArrayField(field) || this.isUserArrayField(field) || this.isGroupArrayField(field)
|
|
1983
|
+
},
|
|
1984
|
+
|
|
1985
|
+
/**
|
|
1986
|
+
* Turn a language or time zone field into a searchable select over
|
|
1987
|
+
* a fixed code list: labels in the user's language, the code stored.
|
|
1988
|
+
* Other fields pass through unchanged.
|
|
1989
|
+
*
|
|
1990
|
+
* @spec openspec/changes/form-pickers-from-schema/specs/schema-utilities/spec.md
|
|
1991
|
+
* @param {object} field A resolved field descriptor.
|
|
1992
|
+
* @return {object} The field, as a `select` when it is a code picker.
|
|
1993
|
+
*/
|
|
1994
|
+
applyCodePicker(field) {
|
|
1995
|
+
if (!field || (field.widget !== 'language' && field.widget !== 'timezone')) {
|
|
1996
|
+
return field
|
|
1997
|
+
}
|
|
1998
|
+
const list = field.widget === 'language' ? languageOptions() : timezoneOptions();
|
|
1999
|
+
return { ...field, widget: 'select', codePicker: field.widget, enum: list.codes, enumLabels: list.labels }
|
|
2000
|
+
},
|
|
2001
|
+
|
|
1901
2002
|
/**
|
|
1902
2003
|
* Check if a field has an async enum (function instead of static array).
|
|
1903
2004
|
* Object references (`$ref`) and Nextcloud user references are treated
|
|
@@ -1907,7 +2008,7 @@ var script = {
|
|
|
1907
2008
|
* @return {boolean}
|
|
1908
2009
|
*/
|
|
1909
2010
|
isAsyncEnum(field) {
|
|
1910
|
-
return typeof field.enum === 'function' || this.
|
|
2011
|
+
return typeof field.enum === 'function' || this.isIdPickerField(field)
|
|
1911
2012
|
},
|
|
1912
2013
|
|
|
1913
2014
|
/**
|
|
@@ -1919,7 +2020,7 @@ var script = {
|
|
|
1919
2020
|
* @return {boolean}
|
|
1920
2021
|
*/
|
|
1921
2022
|
isAsyncItemsEnum(field) {
|
|
1922
|
-
return !!(field.items && typeof field.items.enum === 'function') || this.
|
|
2023
|
+
return !!(field.items && typeof field.items.enum === 'function') || this.isIdPickerArrayField(field)
|
|
1923
2024
|
},
|
|
1924
2025
|
|
|
1925
2026
|
/**
|
|
@@ -1986,12 +2087,119 @@ var script = {
|
|
|
1986
2087
|
* @return {void}
|
|
1987
2088
|
*/
|
|
1988
2089
|
onReferenceSelected(field, value) {
|
|
2090
|
+
if (Array.isArray(value)) {
|
|
2091
|
+
this.updateField(field.key, value);
|
|
2092
|
+
return
|
|
2093
|
+
}
|
|
1989
2094
|
this.updateField(field.key, value || null);
|
|
1990
2095
|
if (value) {
|
|
1991
2096
|
this.applyTemplateFill(field, value);
|
|
1992
2097
|
}
|
|
1993
2098
|
},
|
|
1994
2099
|
|
|
2100
|
+
/**
|
|
2101
|
+
* The value CnResourceSelect binds for a select-or-create reference:
|
|
2102
|
+
* an array of ids for a multi-value reference, else the id string.
|
|
2103
|
+
*
|
|
2104
|
+
* @param {object} field The reference field descriptor.
|
|
2105
|
+
* @return {string|string[]} The bound value.
|
|
2106
|
+
*/
|
|
2107
|
+
referenceModelValue(field) {
|
|
2108
|
+
const value = this.formData[field.key];
|
|
2109
|
+
if (field.reference && field.reference.multiple) {
|
|
2110
|
+
return Array.isArray(value) ? value.map((v) => String(v)) : []
|
|
2111
|
+
}
|
|
2112
|
+
return value !== null && value !== undefined ? String(value) : ''
|
|
2113
|
+
},
|
|
2114
|
+
|
|
2115
|
+
/**
|
|
2116
|
+
* "Create" on a select-or-create reference: open the referenced
|
|
2117
|
+
* schema's own form, prefilled with the typed term, on top of this one.
|
|
2118
|
+
*
|
|
2119
|
+
* Resolves with the created object once that form is saved, or with
|
|
2120
|
+
* null when it is closed without saving. CnResourceSelect then selects
|
|
2121
|
+
* the new object. When the referenced schema cannot be loaded, the
|
|
2122
|
+
* term alone is saved as before, so the field never dead-ends.
|
|
2123
|
+
*
|
|
2124
|
+
* @spec openspec/changes/form-pickers-from-schema/specs/schema-utilities/spec.md
|
|
2125
|
+
* @param {object} field The reference field descriptor.
|
|
2126
|
+
* @param {string} term The typed search term.
|
|
2127
|
+
* @return {Promise<object|null>} The created object, or null.
|
|
2128
|
+
*/
|
|
2129
|
+
async openNestedCreate(field, term) {
|
|
2130
|
+
const store = this.getObjectStore();
|
|
2131
|
+
const register = this.referenceRegister(field);
|
|
2132
|
+
if (!store || !register || !field.reference) {
|
|
2133
|
+
return null
|
|
2134
|
+
}
|
|
2135
|
+
const schemaRef = String(field.reference.schema);
|
|
2136
|
+
const slug = store.createObjectTypeSlug(register, schemaRef);
|
|
2137
|
+
if (!store.objectTypeRegistry[slug]) {
|
|
2138
|
+
store.registerObjectType(slug, schemaRef, register);
|
|
2139
|
+
}
|
|
2140
|
+
const labelField = this.referenceLabelField(field);
|
|
2141
|
+
let schema = null;
|
|
2142
|
+
try {
|
|
2143
|
+
schema = await store.fetchSchema(slug);
|
|
2144
|
+
} catch {
|
|
2145
|
+
schema = null;
|
|
2146
|
+
}
|
|
2147
|
+
if (!schema || !schema.properties) {
|
|
2148
|
+
return store.saveObject(slug, { [labelField]: term })
|
|
2149
|
+
}
|
|
2150
|
+
const initialData = {};
|
|
2151
|
+
if (term && schema.properties[labelField]) {
|
|
2152
|
+
initialData[labelField] = term;
|
|
2153
|
+
}
|
|
2154
|
+
return new Promise((resolve) => {
|
|
2155
|
+
this.nestedCreate = { field, schema, register, slug, initialData, resolve };
|
|
2156
|
+
})
|
|
2157
|
+
},
|
|
2158
|
+
|
|
2159
|
+
/**
|
|
2160
|
+
* The nested create form was confirmed: save the object, hand it to
|
|
2161
|
+
* the waiting picker and close the nested form. A refused save keeps
|
|
2162
|
+
* the nested form open with the server's message.
|
|
2163
|
+
*
|
|
2164
|
+
* @spec openspec/changes/form-pickers-from-schema/specs/schema-utilities/spec.md
|
|
2165
|
+
* @param {object} formData The nested form's values.
|
|
2166
|
+
* @return {Promise<void>}
|
|
2167
|
+
*/
|
|
2168
|
+
async onNestedCreateConfirm(formData) {
|
|
2169
|
+
const pending = this.nestedCreate;
|
|
2170
|
+
if (!pending) {
|
|
2171
|
+
return
|
|
2172
|
+
}
|
|
2173
|
+
const store = this.getObjectStore();
|
|
2174
|
+
const created = store ? await store.saveObject(pending.slug, formData) : null;
|
|
2175
|
+
if (!created) {
|
|
2176
|
+
const error = store && store.errors ? store.errors[pending.slug] : null;
|
|
2177
|
+
const message = (error && error.message)
|
|
2178
|
+
|| translate('nextcloud-vue', 'The item could not be created.');
|
|
2179
|
+
const dialog = this.$refs.nestedCreateDialog;
|
|
2180
|
+
if (dialog && typeof dialog.setValidationErrors === 'function') {
|
|
2181
|
+
dialog.setValidationErrors({}, message);
|
|
2182
|
+
}
|
|
2183
|
+
return
|
|
2184
|
+
}
|
|
2185
|
+
this.nestedCreate = null;
|
|
2186
|
+
pending.resolve(created);
|
|
2187
|
+
},
|
|
2188
|
+
|
|
2189
|
+
/**
|
|
2190
|
+
* The nested create form was closed without saving: leave the field
|
|
2191
|
+
* as it was.
|
|
2192
|
+
*
|
|
2193
|
+
* @return {void}
|
|
2194
|
+
*/
|
|
2195
|
+
onNestedCreateClose() {
|
|
2196
|
+
const pending = this.nestedCreate;
|
|
2197
|
+
this.nestedCreate = null;
|
|
2198
|
+
if (pending) {
|
|
2199
|
+
pending.resolve(null);
|
|
2200
|
+
}
|
|
2201
|
+
},
|
|
2202
|
+
|
|
1995
2203
|
/**
|
|
1996
2204
|
* Copy template values off a selected/created reference object into the
|
|
1997
2205
|
* form, per the field's `fillFrom` map (`{ formKey: sourceKey }`). When
|
|
@@ -2438,9 +2646,14 @@ var script = {
|
|
|
2438
2646
|
}
|
|
2439
2647
|
this.asyncState = newState;
|
|
2440
2648
|
|
|
2441
|
-
// Trigger initial load for each async field
|
|
2649
|
+
// Trigger initial load for each async field. A select-or-create
|
|
2650
|
+
// reference loads its own options (CnResourceSelect), so it is
|
|
2651
|
+
// skipped here rather than fetched twice.
|
|
2442
2652
|
this.$nextTick(() => {
|
|
2443
2653
|
for (const field of fields) {
|
|
2654
|
+
if (field.allowCreate && field.reference) {
|
|
2655
|
+
continue
|
|
2656
|
+
}
|
|
2444
2657
|
if (this.isAsyncEnum(field) || this.isAsyncItemsEnum(field)) {
|
|
2445
2658
|
this.loadAsyncOptions(field, '');
|
|
2446
2659
|
}
|
|
@@ -2481,6 +2694,18 @@ var script = {
|
|
|
2481
2694
|
if (Object.keys(labels).length > 0) {
|
|
2482
2695
|
this.referenceLabels = { ...this.referenceLabels, ...labels };
|
|
2483
2696
|
}
|
|
2697
|
+
} else if (this.isGroupField(field) || this.isGroupArrayField(field)) {
|
|
2698
|
+
// Nextcloud group: search groups, store the gid, show the name.
|
|
2699
|
+
results = await searchNextcloudGroups(query);
|
|
2700
|
+
const labels = {};
|
|
2701
|
+
for (const opt of results) {
|
|
2702
|
+
if (opt && opt.id) {
|
|
2703
|
+
labels[opt.id] = opt.label || String(opt.id);
|
|
2704
|
+
}
|
|
2705
|
+
}
|
|
2706
|
+
if (Object.keys(labels).length > 0) {
|
|
2707
|
+
this.referenceLabels = { ...this.referenceLabels, ...labels };
|
|
2708
|
+
}
|
|
2484
2709
|
} else {
|
|
2485
2710
|
const enumFn = typeof field.enum === 'function' ? field.enum : field.items.enum;
|
|
2486
2711
|
results = await enumFn(query);
|
|
@@ -2539,7 +2764,7 @@ var script = {
|
|
|
2539
2764
|
* @return {object|null}
|
|
2540
2765
|
*/
|
|
2541
2766
|
getEffectiveSelectedOption(field) {
|
|
2542
|
-
if (this.
|
|
2767
|
+
if (this.isIdPickerField(field)) {
|
|
2543
2768
|
// Reference / user fields store the UUID/UID — resolve it to a
|
|
2544
2769
|
// display option `{ id, label }` (label from the resolved-labels
|
|
2545
2770
|
// cache, falling back to the id until it loads).
|
|
@@ -2566,7 +2791,7 @@ var script = {
|
|
|
2566
2791
|
* @param {object|null} option The selected option
|
|
2567
2792
|
*/
|
|
2568
2793
|
onEffectiveSelectChange(field, option) {
|
|
2569
|
-
if (this.
|
|
2794
|
+
if (this.isIdPickerField(field)) {
|
|
2570
2795
|
// Reference / user fields store the chosen id (UUID / UID),
|
|
2571
2796
|
// not the full option. Cache its label so the selection displays.
|
|
2572
2797
|
if (option && option.id) {
|
|
@@ -2575,7 +2800,7 @@ var script = {
|
|
|
2575
2800
|
this.updateField(field.key, option ? option.id : null);
|
|
2576
2801
|
// Reference options are label-only ({id,label}) — pass the id so
|
|
2577
2802
|
// template pre-fill fetches the full object.
|
|
2578
|
-
if (option && option.id) {
|
|
2803
|
+
if (option && option.id && this.isReferenceField(field)) {
|
|
2579
2804
|
this.applyTemplateFill(field, String(option.id));
|
|
2580
2805
|
}
|
|
2581
2806
|
} else if (this.isAsyncEnum(field)) {
|
|
@@ -2607,7 +2832,7 @@ var script = {
|
|
|
2607
2832
|
* @return {Array}
|
|
2608
2833
|
*/
|
|
2609
2834
|
getEffectiveSelectedArrayOptions(field) {
|
|
2610
|
-
if (this.
|
|
2835
|
+
if (this.isIdPickerArrayField(field)) {
|
|
2611
2836
|
// Reference / user arrays store an array of ids (UUIDs / UIDs) —
|
|
2612
2837
|
// resolve each to a display option `{ id, label }`.
|
|
2613
2838
|
const uuids = this.formData[field.key];
|
|
@@ -2630,7 +2855,7 @@ var script = {
|
|
|
2630
2855
|
* @param {Array} options The selected options
|
|
2631
2856
|
*/
|
|
2632
2857
|
onEffectiveMultiSelectChange(field, options) {
|
|
2633
|
-
if (this.
|
|
2858
|
+
if (this.isIdPickerArrayField(field)) {
|
|
2634
2859
|
// Reference / user arrays store an array of ids (UUIDs / UIDs).
|
|
2635
2860
|
// Cache labels so the chips still display the human names.
|
|
2636
2861
|
const list = options || [];
|