@conduction/nextcloud-vue 2.56.0-beta.15 → 2.56.0-beta.16

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.
@@ -462,6 +462,11 @@
462
462
  :register="nestedCreate.register"
463
463
  :item="null"
464
464
  :initialData="nestedCreate.initialData"
465
+ :excludeFields="nestedCreate.form.excludeFields"
466
+ :includeFields="nestedCreate.form.includeFields"
467
+ :fieldOverrides="nestedCreate.form.fieldOverrides"
468
+ :size="nestedCreate.form.size"
469
+ :columns="nestedCreate.form.columns"
465
470
  :recoverDraft="false"
466
471
  data-testid="cn-form-dialog-nested-create"
467
472
  @confirm="onNestedCreateConfirm"
@@ -2645,7 +2650,12 @@ export default {
2645
2650
  * the new object. When the referenced schema cannot be loaded, the
2646
2651
  * term alone is saved as before, so the field never dead-ends.
2647
2652
  *
2653
+ * The form is the one the schema's index page shows for its own Add
2654
+ * button: that page's `createOverride` saves it and its form settings
2655
+ * shape it, with the typed term in the name.
2656
+ *
2648
2657
  * @spec openspec/changes/form-pickers-from-schema/specs/schema-utilities/spec.md
2658
+ * @spec openspec/changes/nested-create-uses-page-config/specs/schema-utilities/spec.md
2649
2659
  * @param {object} field The reference field descriptor.
2650
2660
  * @param {string} term The typed search term.
2651
2661
  * @return {Promise<object|null>} The created object, or null.
@@ -2662,21 +2672,37 @@ export default {
2662
2672
  store.registerObjectType(slug, schemaRef, register)
2663
2673
  }
2664
2674
  const labelField = this.referenceLabelField(field)
2675
+ const loadSchema = async () => {
2676
+ try {
2677
+ return await store.fetchSchema(slug)
2678
+ } catch {
2679
+ return null
2680
+ }
2681
+ }
2665
2682
  // The app may own how this schema is created (pipelinq's client and
2666
2683
  // contact need a contact-first endpoint; a plain save 400s). A
2667
2684
  // create override keeps this form and saves through the app's
2668
2685
  // handler; a create modal (only when no override exists) opens the
2669
2686
  // app's own dialog instead of the generic form.
2670
- const appCreate = this.appCreateFor(register, schemaRef)
2687
+ //
2688
+ // A stored schema usually names its reference by id (`$ref: 28`)
2689
+ // while the manifest page names it by slug (`schema: 'client'`), so
2690
+ // when the reference itself matches no page, the referenced schema
2691
+ // is loaded and its slug, id and uuid are tried too.
2692
+ let schema
2693
+ let appCreate = this.appCreateFor(register, [schemaRef])
2694
+ if (!appCreate.page) {
2695
+ schema = await loadSchema()
2696
+ if (schema) {
2697
+ appCreate = this.appCreateFor(register, [schemaRef, schema.slug, schema.id, schema.uuid])
2698
+ }
2699
+ }
2671
2700
  if (!appCreate.override && appCreate.modal) {
2672
2701
  return this.openAppCreateModal(appCreate.modal, store, slug, labelField, term)
2673
2702
  }
2674
2703
  const override = appCreate.override
2675
- let schema = null
2676
- try {
2677
- schema = await store.fetchSchema(slug)
2678
- } catch {
2679
- schema = null
2704
+ if (schema === undefined) {
2705
+ schema = await loadSchema()
2680
2706
  }
2681
2707
  if (!schema || !schema.properties) {
2682
2708
  const payload = { [labelField]: term }
@@ -2685,36 +2711,84 @@ export default {
2685
2711
  : store.saveObject(slug, payload)
2686
2712
  }
2687
2713
  const initialData = {}
2688
- if (term && schema.properties[labelField]) {
2689
- initialData[labelField] = term
2714
+ const prefillKey = this.nestedPrefillKey(schema, labelField)
2715
+ if (term && prefillKey) {
2716
+ initialData[prefillKey] = term
2690
2717
  }
2718
+ const form = appCreate.form || this.nestedFormConfig(null)
2691
2719
  return new Promise((resolve) => {
2692
- this.nestedCreate = { field, schema, register, slug, schemaRef, initialData, override, resolve }
2720
+ this.nestedCreate = { field, schema, register, slug, schemaRef, initialData, override, form, resolve }
2693
2721
  })
2694
2722
  },
2695
2723
 
2724
+ /**
2725
+ * The property of the referenced schema the typed term belongs in: the
2726
+ * reference's label field when the schema has it, else its name, title
2727
+ * or label. Visibility is decided by the form (a page `fieldOverrides`
2728
+ * entry can make a read-only name editable), not here.
2729
+ *
2730
+ * @spec openspec/changes/nested-create-uses-page-config/specs/schema-utilities/spec.md
2731
+ * @param {object} schema The referenced schema.
2732
+ * @param {string} labelField The reference's label field.
2733
+ * @return {string|null} The property key, or null when none fits.
2734
+ */
2735
+ nestedPrefillKey(schema, labelField) {
2736
+ const properties = (schema && schema.properties) || {}
2737
+ return [labelField, 'name', 'title', 'label'].find((key) => properties[key]) || null
2738
+ },
2739
+
2740
+ /**
2741
+ * The create-form settings of the index page that lists a schema, in
2742
+ * the shape the nested CnFormDialog binds: the same `excludeFields`,
2743
+ * `includeFields`, `fieldOverrides`, `formSize` and `formColumns`
2744
+ * CnIndexPage hands its own Add form, so creating from a picker shows
2745
+ * the form the page shows. Without a page, the form's defaults.
2746
+ *
2747
+ * @spec openspec/changes/nested-create-uses-page-config/specs/schema-utilities/spec.md
2748
+ * @param {object|null} config The page's `config`, or null.
2749
+ * @return {{excludeFields: string[], includeFields: (string[]|null), fieldOverrides: object, size: string, columns: number}} The form settings.
2750
+ */
2751
+ nestedFormConfig(config) {
2752
+ const c = config || {}
2753
+ const isMap = (v) => v !== null && typeof v === 'object' && !Array.isArray(v)
2754
+ return {
2755
+ excludeFields: Array.isArray(c.excludeFields) ? c.excludeFields : [],
2756
+ includeFields: Array.isArray(c.includeFields) ? c.includeFields : null,
2757
+ fieldOverrides: isMap(c.fieldOverrides) ? c.fieldOverrides : {},
2758
+ size: typeof c.formSize === 'string' && c.formSize !== '' ? c.formSize : 'normal',
2759
+ columns: c.formColumns === 2 ? 2 : 1,
2760
+ }
2761
+ },
2762
+
2696
2763
  /**
2697
2764
  * How the app creates objects of a schema, read off the manifest page
2698
2765
  * that lists them: the index page whose `config.schema` (and, when it
2699
2766
  * names one, `config.register`) matches. Its `config.createOverride` is
2700
2767
  * resolved to the registered handler; its `config.createModal` is the
2701
- * registry key of a `kind: 'modal'` dialog.
2768
+ * registry key of a `kind: 'modal'` dialog; its form settings
2769
+ * (`fieldOverrides` and friends) shape the nested form.
2702
2770
  *
2703
- * @spec openspec/changes/review-round-two/specs/schema-utilities/spec.md
2771
+ * The schema is matched on any of the given references, so a caller
2772
+ * holding the referenced schema can pass its slug, id and uuid: the
2773
+ * manifest names a schema by slug, a stored `$ref` often by id.
2774
+ *
2775
+ * @spec openspec/changes/nested-create-uses-page-config/specs/schema-utilities/spec.md
2704
2776
  * @param {string} register The reference's register.
2705
- * @param {string} schemaRef The reference's schema slug or id.
2706
- * @return {{override: (((formData: object, ctx: object) => Promise<object>)|null), modal: (string|null)}} What the app declared.
2777
+ * @param {string|Array<string|number>} schemaRefs The schema's slug, id or uuid, one or several.
2778
+ * @return {{page: (object|null), override: (((formData: object, ctx: object) => Promise<object>)|null), modal: (string|null), form: (object|null)}} What the app declared.
2707
2779
  */
2708
- appCreateFor(register, schemaRef) {
2709
- const none = { override: null, modal: null }
2780
+ appCreateFor(register, schemaRefs) {
2781
+ const none = { page: null, override: null, modal: null, form: null }
2710
2782
  const pages = this.cnManifest && Array.isArray(this.cnManifest.pages) ? this.cnManifest.pages : []
2711
- const wanted = String(schemaRef).toLowerCase()
2783
+ const wanted = (Array.isArray(schemaRefs) ? schemaRefs : [schemaRefs])
2784
+ .filter((ref) => ref !== undefined && ref !== null && ref !== '')
2785
+ .map((ref) => String(ref).toLowerCase())
2712
2786
  const page = pages.find((p) => {
2713
2787
  const config = p && p.config
2714
2788
  if (!config || config.schema === undefined || config.schema === null) {
2715
2789
  return false
2716
2790
  }
2717
- if (String(config.schema).toLowerCase() !== wanted) {
2791
+ if (!wanted.includes(String(config.schema).toLowerCase())) {
2718
2792
  return false
2719
2793
  }
2720
2794
  return !config.register || String(config.register) === String(register)
@@ -2732,7 +2806,7 @@ export default {
2732
2806
  const modal = modalEntry && modalEntry.kind === 'modal' && typeof this.cnOpenModal === 'function'
2733
2807
  ? config.createModal
2734
2808
  : null
2735
- return { override: override || null, modal }
2809
+ return { page, override: override || null, modal, form: this.nestedFormConfig(config) }
2736
2810
  },
2737
2811
 
2738
2812
  /**
@@ -641,9 +641,15 @@ export default {
641
641
  value = this.choiceLabel(step, raw)
642
642
  }
643
643
  } else if (step.type === 'config-fields') {
644
+ // Only the fields the reader filled in: a row of empty
645
+ // "Name: , KvK: ," reads as broken, not as "not set".
644
646
  value = this.fieldsFor(step)
645
- .map((f) => `${f.label}: ${this.configModel[f.key] !== null && this.configModel[f.key] !== undefined ? this.configModel[f.key] : ''}`)
646
- .join(', ')
647
+ .filter((f) => {
648
+ const v = this.configModel[f.key]
649
+ return v !== null && v !== undefined && String(v).trim() !== ''
650
+ })
651
+ .map((f) => `${f.label}: ${this.configModel[f.key]}`)
652
+ .join(', ') || t('nextcloud-vue', 'Not set')
647
653
  }
648
654
  if (this.isOnDemand(step)) {
649
655
  const ran = this.ranThisSession(step.id)