@ditojs/admin 2.99.1 → 3.0.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/dito-admin.css +1 -1
- package/dist/dito-admin.es.js +3532 -2763
- package/dist/dito-admin.umd.js +6 -6
- package/package.json +82 -46
- package/src/DitoComponent.js +1 -1
- package/src/DitoContext.js +51 -0
- package/src/DitoTypeComponent.js +6 -1
- package/src/components/DitoAffixes.vue +6 -3
- package/src/components/DitoContainer.vue +19 -10
- package/src/components/DitoCreateButton.vue +11 -2
- package/src/components/DitoDialog.vue +21 -2
- package/src/components/DitoForm.vue +156 -83
- package/src/components/DitoLabel.vue +3 -2
- package/src/components/DitoPane.vue +55 -11
- package/src/components/DitoPanel.vue +33 -5
- package/src/components/DitoPanels.vue +2 -1
- package/src/components/DitoRoot.vue +13 -6
- package/src/components/DitoSchema.vue +278 -145
- package/src/components/DitoSchemaInlined.vue +1 -1
- package/src/components/DitoTabs.vue +16 -18
- package/src/components/DitoTrail.vue +5 -4
- package/src/components/DitoTreeItem.vue +17 -6
- package/src/components/DitoView.vue +25 -2
- package/src/mixins/DitoMixin.js +42 -7
- package/src/mixins/ItemMixin.js +3 -6
- package/src/mixins/NumberMixin.js +47 -31
- package/src/mixins/OptionsMixin.js +122 -71
- package/src/mixins/ResourceMixin.js +5 -2
- package/src/mixins/RouteMixin.js +39 -1
- package/src/mixins/SortableMixin.js +0 -13
- package/src/mixins/SourceMixin.js +142 -95
- package/src/mixins/TextMixin.js +1 -1
- package/src/mixins/TypeMixin.js +37 -22
- package/src/mixins/ValidationMixin.js +9 -27
- package/src/mixins/ValidatorMixin.js +5 -7
- package/src/mixins/ValueMixin.js +5 -2
- package/src/types/DitoTypeButton.vue +1 -1
- package/src/types/DitoTypeCheckbox.vue +1 -1
- package/src/types/DitoTypeCheckboxes.vue +1 -1
- package/src/types/DitoTypeCode.vue +8 -1
- package/src/types/DitoTypeColor.vue +20 -34
- package/src/types/DitoTypeComponent.vue +1 -1
- package/src/types/DitoTypeComputed.vue +4 -27
- package/src/types/DitoTypeDate.vue +16 -5
- package/src/types/DitoTypeLabel.vue +1 -4
- package/src/types/DitoTypeList.vue +9 -5
- package/src/types/DitoTypeMarkup.vue +25 -13
- package/src/types/DitoTypeMultiselect.vue +26 -6
- package/src/types/DitoTypeNumber.vue +1 -1
- package/src/types/DitoTypeObject.vue +10 -7
- package/src/types/DitoTypePanel.vue +19 -6
- package/src/types/DitoTypeProgress.vue +1 -1
- package/src/types/DitoTypeRadio.vue +1 -1
- package/src/types/DitoTypeSection.vue +32 -4
- package/src/types/DitoTypeSelect.vue +1 -1
- package/src/types/DitoTypeSlider.vue +1 -1
- package/src/types/DitoTypeSwitch.vue +1 -1
- package/src/types/DitoTypeText.vue +13 -15
- package/src/types/DitoTypeTextarea.vue +1 -1
- package/src/types/DitoTypeTreeList.vue +12 -7
- package/src/types/DitoTypeUpload.vue +1 -2
- package/src/utils/DataSchemaResolver.js +141 -0
- package/src/utils/DataSchemaResolver.test.js +132 -0
- package/src/utils/FormModel.js +556 -0
- package/src/utils/FormModel.test.js +808 -0
- package/src/utils/data.js +20 -0
- package/src/utils/data.test.js +28 -0
- package/src/utils/filter.js +3 -2
- package/src/utils/options.js +3 -0
- package/src/utils/schema/data.js +617 -0
- package/src/utils/schema/data.test.js +471 -0
- package/src/utils/schema/lookup.js +266 -0
- package/src/utils/schema/lookup.test.js +61 -0
- package/src/utils/schema/setup.js +354 -0
- package/src/utils/schema/structure.js +172 -0
- package/src/utils/schema/structure.test.js +57 -0
- package/src/utils/schema/types.js +34 -0
- package/src/utils/schema/validation.js +142 -0
- package/src/utils/schema/validation.test.js +395 -0
- package/src/utils/units.js +70 -3
- package/src/utils/units.test.js +71 -0
- package/types/index.d.ts +149 -59
- package/src/mixins/DataMixin.js +0 -131
- package/src/utils/schema.js +0 -1121
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ditojs/admin",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Dito.js Admin is a schema based admin interface for Dito.js Server, featuring auto-generated views and forms and built with Vue.js",
|
|
6
6
|
"repository": "https://github.com/ditojs/dito/tree/main/packages/admin",
|
|
@@ -27,8 +27,7 @@
|
|
|
27
27
|
"scripts": {
|
|
28
28
|
"build": "vite build",
|
|
29
29
|
"watch": "pnpm run build --mode 'development' --watch",
|
|
30
|
-
"prepare": "pnpm run build"
|
|
31
|
-
"types": "tsc --noEmit types/index.d.ts"
|
|
30
|
+
"prepare": "pnpm run build"
|
|
32
31
|
},
|
|
33
32
|
"engines": {
|
|
34
33
|
"node": ">= 24.0.0"
|
|
@@ -40,58 +39,95 @@
|
|
|
40
39
|
"not ie_mob > 0"
|
|
41
40
|
],
|
|
42
41
|
"dependencies": {
|
|
43
|
-
"@ditojs/ui": "^
|
|
44
|
-
"@ditojs/utils": "^
|
|
42
|
+
"@ditojs/ui": "^3.0.0",
|
|
43
|
+
"@ditojs/utils": "^3.0.0"
|
|
45
44
|
},
|
|
46
45
|
"peerDependencies": {
|
|
47
46
|
"@kyvg/vue3-notification": "^3.4.2",
|
|
48
|
-
"@
|
|
49
|
-
"@tiptap/
|
|
50
|
-
"@tiptap/extension-
|
|
51
|
-
"@tiptap/extension-
|
|
52
|
-
"@tiptap/extension-
|
|
53
|
-
"@tiptap/extension-code": "^3.
|
|
54
|
-
"@tiptap/extension-
|
|
55
|
-
"@tiptap/extension-
|
|
56
|
-
"@tiptap/extension-
|
|
57
|
-
"@tiptap/extension-
|
|
58
|
-
"@tiptap/extension-
|
|
59
|
-
"@tiptap/extension-
|
|
60
|
-
"@tiptap/extension-
|
|
61
|
-
"@tiptap/extension-
|
|
62
|
-
"@tiptap/extension-list": "^3.
|
|
63
|
-
"@tiptap/extension-list
|
|
64
|
-
"@tiptap/extension-
|
|
65
|
-
"@tiptap/extension-
|
|
66
|
-
"@tiptap/extension-
|
|
67
|
-
"@tiptap/extension-
|
|
68
|
-
"@tiptap/extension-
|
|
69
|
-
"@tiptap/extension-text": "^3.
|
|
70
|
-
"@tiptap/extension-
|
|
71
|
-
"@tiptap/
|
|
72
|
-
"@tiptap/
|
|
73
|
-
"@tiptap/
|
|
74
|
-
"@
|
|
75
|
-
"@vueuse/integrations": "^14.2.1",
|
|
47
|
+
"@tiptap/core": "^3.31.4",
|
|
48
|
+
"@tiptap/extension-blockquote": "^3.31.4",
|
|
49
|
+
"@tiptap/extension-bold": "^3.31.4",
|
|
50
|
+
"@tiptap/extension-bullet-list": "^3.31.4",
|
|
51
|
+
"@tiptap/extension-code": "^3.31.4",
|
|
52
|
+
"@tiptap/extension-code-block": "^3.31.4",
|
|
53
|
+
"@tiptap/extension-document": "^3.31.4",
|
|
54
|
+
"@tiptap/extension-hard-break": "^3.31.4",
|
|
55
|
+
"@tiptap/extension-heading": "^3.31.4",
|
|
56
|
+
"@tiptap/extension-history": "^3.31.4",
|
|
57
|
+
"@tiptap/extension-horizontal-rule": "^3.31.4",
|
|
58
|
+
"@tiptap/extension-italic": "^3.31.4",
|
|
59
|
+
"@tiptap/extension-link": "^3.31.4",
|
|
60
|
+
"@tiptap/extension-list": "^3.31.4",
|
|
61
|
+
"@tiptap/extension-list-item": "^3.31.4",
|
|
62
|
+
"@tiptap/extension-ordered-list": "^3.31.4",
|
|
63
|
+
"@tiptap/extension-paragraph": "^3.31.4",
|
|
64
|
+
"@tiptap/extension-strike": "^3.31.4",
|
|
65
|
+
"@tiptap/extension-subscript": "^3.31.4",
|
|
66
|
+
"@tiptap/extension-superscript": "^3.31.4",
|
|
67
|
+
"@tiptap/extension-text": "^3.31.4",
|
|
68
|
+
"@tiptap/extension-text-style": "^3.31.4",
|
|
69
|
+
"@tiptap/extension-underline": "^3.31.4",
|
|
70
|
+
"@tiptap/extensions": "^3.31.4",
|
|
71
|
+
"@tiptap/pm": "^3.31.4",
|
|
72
|
+
"@tiptap/vue-3": "^3.31.4",
|
|
73
|
+
"@vueuse/integrations": "^15.0.0",
|
|
76
74
|
"codeflask": "^1.4.1",
|
|
77
|
-
"
|
|
78
|
-
"
|
|
79
|
-
"focus-trap": "^8.0.0",
|
|
80
|
-
"nanoid": "^5.1.6",
|
|
75
|
+
"focus-trap": "^8.2.2",
|
|
76
|
+
"nanoid": "^6.0.1",
|
|
81
77
|
"sortablejs": "^1.15.7",
|
|
82
|
-
"tinycolor2": "^1.6.0",
|
|
83
78
|
"tippy.js": "^6.3.7",
|
|
84
79
|
"tiptap-footnotes": "^3.0.1",
|
|
85
|
-
"type-fest": "^5.
|
|
86
|
-
"vue": "^3.5.
|
|
87
|
-
"vue-
|
|
88
|
-
"vue-
|
|
89
|
-
"vue-
|
|
80
|
+
"type-fest": "^5.10.0",
|
|
81
|
+
"vue": "^3.5.43",
|
|
82
|
+
"vue-color": "^3.3.3",
|
|
83
|
+
"vue-multiselect": "^3.5.0",
|
|
84
|
+
"vue-router": "^5.3.1",
|
|
85
|
+
"vue-upload-component": "^3.2.2"
|
|
90
86
|
},
|
|
91
87
|
"devDependencies": {
|
|
92
|
-
"@ditojs/build": "^
|
|
88
|
+
"@ditojs/build": "^3.0.0",
|
|
89
|
+
"@kyvg/vue3-notification": "^3.4.2",
|
|
90
|
+
"@tiptap/core": "^3.31.4",
|
|
91
|
+
"@tiptap/extension-blockquote": "^3.31.4",
|
|
92
|
+
"@tiptap/extension-bold": "^3.31.4",
|
|
93
|
+
"@tiptap/extension-bullet-list": "^3.31.4",
|
|
94
|
+
"@tiptap/extension-code": "^3.31.4",
|
|
95
|
+
"@tiptap/extension-code-block": "^3.31.4",
|
|
96
|
+
"@tiptap/extension-document": "^3.31.4",
|
|
97
|
+
"@tiptap/extension-hard-break": "^3.31.4",
|
|
98
|
+
"@tiptap/extension-heading": "^3.31.4",
|
|
99
|
+
"@tiptap/extension-history": "^3.31.4",
|
|
100
|
+
"@tiptap/extension-horizontal-rule": "^3.31.4",
|
|
101
|
+
"@tiptap/extension-italic": "^3.31.4",
|
|
102
|
+
"@tiptap/extension-link": "^3.31.4",
|
|
103
|
+
"@tiptap/extension-list": "^3.31.4",
|
|
104
|
+
"@tiptap/extension-list-item": "^3.31.4",
|
|
105
|
+
"@tiptap/extension-ordered-list": "^3.31.4",
|
|
106
|
+
"@tiptap/extension-paragraph": "^3.31.4",
|
|
107
|
+
"@tiptap/extension-strike": "^3.31.4",
|
|
108
|
+
"@tiptap/extension-subscript": "^3.31.4",
|
|
109
|
+
"@tiptap/extension-superscript": "^3.31.4",
|
|
110
|
+
"@tiptap/extension-text": "^3.31.4",
|
|
111
|
+
"@tiptap/extension-text-style": "^3.31.4",
|
|
112
|
+
"@tiptap/extension-underline": "^3.31.4",
|
|
113
|
+
"@tiptap/extensions": "^3.31.4",
|
|
114
|
+
"@tiptap/pm": "^3.31.4",
|
|
115
|
+
"@tiptap/vue-3": "^3.31.4",
|
|
116
|
+
"@vueuse/integrations": "^15.0.0",
|
|
117
|
+
"codeflask": "^1.4.1",
|
|
118
|
+
"focus-trap": "^8.2.2",
|
|
119
|
+
"nanoid": "^6.0.1",
|
|
120
|
+
"sortablejs": "^1.15.7",
|
|
121
|
+
"tippy.js": "^6.3.7",
|
|
122
|
+
"tiptap-footnotes": "^3.0.1",
|
|
123
|
+
"type-fest": "^5.10.0",
|
|
93
124
|
"typescript": "^6.0.3",
|
|
94
|
-
"vite": "^8.
|
|
125
|
+
"vite": "^8.3.2",
|
|
126
|
+
"vue": "^3.5.43",
|
|
127
|
+
"vue-color": "^3.3.3",
|
|
128
|
+
"vue-multiselect": "^3.5.0",
|
|
129
|
+
"vue-router": "^5.3.1",
|
|
130
|
+
"vue-upload-component": "^3.2.2"
|
|
95
131
|
},
|
|
96
|
-
"gitHead": "
|
|
132
|
+
"gitHead": "399f683a6ca227a03cfc0978fee9055383e6b3d8"
|
|
97
133
|
}
|
package/src/DitoComponent.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import DitoMixin from './mixins/DitoMixin.js'
|
|
2
|
-
import { getTypeComponent } from './utils/schema.js'
|
|
2
|
+
import { getTypeComponent } from './utils/schema/types.js'
|
|
3
3
|
import { resolveMergedOptions } from './utils/options.js'
|
|
4
4
|
import { isPlainObject } from '@ditojs/utils'
|
|
5
5
|
|
package/src/DitoContext.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { toRaw } from 'vue'
|
|
2
2
|
import { getValueAtDataPath, isFunction } from '@ditojs/utils'
|
|
3
3
|
import {
|
|
4
|
+
appendDataPath,
|
|
4
5
|
getItemDataPath,
|
|
5
6
|
getParentItemDataPath,
|
|
6
7
|
getParentItem,
|
|
@@ -8,6 +9,7 @@ import {
|
|
|
8
9
|
getLastDataPathName,
|
|
9
10
|
getLastDataPathIndex
|
|
10
11
|
} from './utils/data.js'
|
|
12
|
+
import { isNested } from './utils/schema/structure.js'
|
|
11
13
|
|
|
12
14
|
const { hasOwnProperty } = Object.prototype
|
|
13
15
|
|
|
@@ -81,6 +83,55 @@ export default class DitoContext {
|
|
|
81
83
|
: new DitoContext(component, context)
|
|
82
84
|
}
|
|
83
85
|
|
|
86
|
+
// Creates the context of the component described by `schema` and `name` in
|
|
87
|
+
// `data`, e.g. to evaluate its `if` before it's rendered, the same way as
|
|
88
|
+
// once it's rendered. Its `value` is read from `data` only when it's used,
|
|
89
|
+
// so that watchers only depend on it if it's used, and missing values don't
|
|
90
|
+
// need to be resolved through the data path.
|
|
91
|
+
static createForSchema(component, {
|
|
92
|
+
schema,
|
|
93
|
+
name,
|
|
94
|
+
nested = isNested(schema),
|
|
95
|
+
data,
|
|
96
|
+
dataPath,
|
|
97
|
+
rootData
|
|
98
|
+
}) {
|
|
99
|
+
// Pass a function, so that the `value` getter isn't evaluated when the
|
|
100
|
+
// context is created.
|
|
101
|
+
return new DitoContext(component, () => ({
|
|
102
|
+
schema,
|
|
103
|
+
name,
|
|
104
|
+
nested,
|
|
105
|
+
data,
|
|
106
|
+
dataPath,
|
|
107
|
+
rootData,
|
|
108
|
+
get value() {
|
|
109
|
+
return name != null ? data?.[name] : undefined
|
|
110
|
+
}
|
|
111
|
+
}))
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Creates the context of a component of this context's schema, e.g. of a
|
|
115
|
+
// section, the same way as when that component is rendered: Its data is the
|
|
116
|
+
// value of this context's component if that is nested, or else the same
|
|
117
|
+
// data. The data path adds `name` if the child component is nested.
|
|
118
|
+
createChildContext(schema, name) {
|
|
119
|
+
const nested = isNested(schema)
|
|
120
|
+
// Contexts without a schema don't hold a value either, e.g. the ones of
|
|
121
|
+
// `DitoMenu` and `DitoPanels`, evaluating views and panels.
|
|
122
|
+
const holdsOwnValue = !!this.schema && isNested(this.schema)
|
|
123
|
+
return DitoContext.createForSchema(this.component, {
|
|
124
|
+
schema,
|
|
125
|
+
name,
|
|
126
|
+
nested,
|
|
127
|
+
// Read the value from the item that holds it rather than through the data
|
|
128
|
+
// path, as items that are being created aren't part of the root data.
|
|
129
|
+
data: holdsOwnValue ? this.item?.[this.name] : this.item,
|
|
130
|
+
dataPath: nested ? appendDataPath(this.dataPath, name) : this.dataPath,
|
|
131
|
+
rootData: this.rootItem
|
|
132
|
+
})
|
|
133
|
+
}
|
|
134
|
+
|
|
84
135
|
extend(object) {
|
|
85
136
|
// Create a copy of this context that inherits from the real one, but
|
|
86
137
|
// overrides some properties with the ones from the passed `object`.
|
package/src/DitoTypeComponent.js
CHANGED
|
@@ -4,7 +4,10 @@
|
|
|
4
4
|
import { asArray, camelize } from '@ditojs/utils'
|
|
5
5
|
import DitoComponent from './DitoComponent.js'
|
|
6
6
|
import TypeMixin from './mixins/TypeMixin.js'
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
registerTypeComponent,
|
|
9
|
+
getTypeComponent
|
|
10
|
+
} from './utils/schema/types.js'
|
|
8
11
|
|
|
9
12
|
// @vue/component
|
|
10
13
|
export default {
|
|
@@ -22,7 +25,9 @@ export default {
|
|
|
22
25
|
generateLabel: true,
|
|
23
26
|
excludeValue: false,
|
|
24
27
|
ignoreMissingValue: null,
|
|
28
|
+
treatNullAsMissing: null,
|
|
25
29
|
omitSpacing: false,
|
|
30
|
+
getTypeValidations: null,
|
|
26
31
|
|
|
27
32
|
component: DitoComponent.component,
|
|
28
33
|
|
|
@@ -32,7 +32,7 @@ import DitoComponent from '../DitoComponent.js'
|
|
|
32
32
|
import DitoAffix from './DitoAffix.vue'
|
|
33
33
|
import { asArray, isString } from '@ditojs/utils'
|
|
34
34
|
import { hasSlotContent } from '@ditojs/ui/src'
|
|
35
|
-
import { shouldRenderSchema } from '../utils/schema.js'
|
|
35
|
+
import { shouldRenderSchema } from '../utils/schema/data.js'
|
|
36
36
|
|
|
37
37
|
export default DitoComponent.component('DitoAffixes', {
|
|
38
38
|
components: { DitoAffix },
|
|
@@ -175,7 +175,10 @@ export default DitoComponent.component('DitoAffixes', {
|
|
|
175
175
|
padding: 0;
|
|
176
176
|
border: 0;
|
|
177
177
|
|
|
178
|
-
|
|
178
|
+
// Only show when hovering the component itself, not its open popup, e.g.
|
|
179
|
+
// the color picker.
|
|
180
|
+
@at-root .dito-component:not(:has(.dito-component, .dito-popup:hover)):hover
|
|
181
|
+
& {
|
|
179
182
|
display: block;
|
|
180
183
|
}
|
|
181
184
|
|
|
@@ -192,7 +195,7 @@ export default DitoComponent.component('DitoAffixes', {
|
|
|
192
195
|
|
|
193
196
|
// Hide other affixes when clear button is shown
|
|
194
197
|
// prettier-ignore
|
|
195
|
-
@at-root .dito-component:hover:not(:has(.dito-component))
|
|
198
|
+
@at-root .dito-component:hover:not(:has(.dito-component, .dito-popup:hover))
|
|
196
199
|
#{$self}:has(#{$self}__clear) > *:not(#{$self}__clear) {
|
|
197
200
|
display: none;
|
|
198
201
|
}
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
DitoLabel(
|
|
19
19
|
v-if="hasLabel"
|
|
20
20
|
:class="labelClasses"
|
|
21
|
-
:
|
|
21
|
+
:htmlFor="labelHtmlFor"
|
|
22
22
|
:label="label"
|
|
23
23
|
:info="info"
|
|
24
24
|
)
|
|
@@ -50,13 +50,11 @@ import ValueMixin from '../mixins/ValueMixin.js'
|
|
|
50
50
|
import ContextMixin from '../mixins/ContextMixin.js'
|
|
51
51
|
import DitoContext from '../DitoContext.js'
|
|
52
52
|
import { getSchemaAccessor } from '../utils/accessor.js'
|
|
53
|
-
import {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
hasLabel,
|
|
57
|
-
omitSpacing
|
|
58
|
-
} from '../utils/schema.js'
|
|
53
|
+
import { getTypeComponent } from '../utils/schema/types.js'
|
|
54
|
+
import { hasLabel, omitSpacing } from '../utils/schema/structure.js'
|
|
55
|
+
import { getAllPanelEntries } from '../utils/schema/lookup.js'
|
|
59
56
|
import { parseFraction } from '../utils/math.js'
|
|
57
|
+
import { appendDataPath } from '../utils/data.js'
|
|
60
58
|
|
|
61
59
|
// @vue/component
|
|
62
60
|
export default DitoComponent.component('DitoContainer', {
|
|
@@ -105,6 +103,12 @@ export default DitoComponent.component('DitoContainer', {
|
|
|
105
103
|
return this.schema.name
|
|
106
104
|
},
|
|
107
105
|
|
|
106
|
+
componentPath() {
|
|
107
|
+
// Add the component's name, also for unnested components that don't
|
|
108
|
+
// add it to their data path, see `DitoMixin.componentPath`.
|
|
109
|
+
return appendDataPath(this.parentComponent.componentPath, this.name)
|
|
110
|
+
},
|
|
111
|
+
|
|
108
112
|
type() {
|
|
109
113
|
return this.schema.type
|
|
110
114
|
},
|
|
@@ -125,9 +129,10 @@ export default DitoComponent.component('DitoContainer', {
|
|
|
125
129
|
return this.hasLabel ? this.getLabel(this.schema) : null
|
|
126
130
|
},
|
|
127
131
|
|
|
128
|
-
|
|
129
|
-
//
|
|
130
|
-
|
|
132
|
+
labelHtmlFor() {
|
|
133
|
+
// Type components use their component path as DOM id. Unnested types
|
|
134
|
+
// don't display a value of their own to label:
|
|
135
|
+
return this.nested ? this.componentPath : null
|
|
131
136
|
},
|
|
132
137
|
|
|
133
138
|
info: getSchemaAccessor('info', {
|
|
@@ -252,6 +257,10 @@ export default DitoComponent.component('DitoContainer', {
|
|
|
252
257
|
this.api,
|
|
253
258
|
this.schema,
|
|
254
259
|
this.dataPath,
|
|
260
|
+
// The panel of the type is addressed relative to the data path, which
|
|
261
|
+
// unnested components don't add their name to:
|
|
262
|
+
this.nested ? this.componentPath : this.parentComponent.componentPath,
|
|
263
|
+
this.componentPath,
|
|
255
264
|
this.$refs.component,
|
|
256
265
|
this.tabComponent
|
|
257
266
|
)
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
v-if="creatableForm"
|
|
5
5
|
:type="isInlined ? 'button' : 'submit'"
|
|
6
6
|
:disabled="disabled"
|
|
7
|
-
v-bind="getButtonAttributes(verb)"
|
|
7
|
+
v-bind="getButtonAttributes(verb, formLabel)"
|
|
8
8
|
@click="createItem(creatableForm)"
|
|
9
9
|
) {{ text }}
|
|
10
10
|
template(
|
|
@@ -38,7 +38,8 @@
|
|
|
38
38
|
import DitoComponent from '../DitoComponent.js'
|
|
39
39
|
import ContextMixin from '../mixins/ContextMixin.js'
|
|
40
40
|
import PulldownMixin from '../mixins/PulldownMixin.js'
|
|
41
|
-
import {
|
|
41
|
+
import { isInlined } from '../utils/schema/structure.js'
|
|
42
|
+
import { getFormSchemas } from '../utils/schema/lookup.js'
|
|
42
43
|
|
|
43
44
|
// @vue/component
|
|
44
45
|
export default DitoComponent.component('DitoCreateButton', {
|
|
@@ -93,6 +94,14 @@ export default DitoComponent.component('DitoCreateButton', {
|
|
|
93
94
|
return forms && Object.keys(forms).length === 1 && forms.default || null
|
|
94
95
|
},
|
|
95
96
|
|
|
97
|
+
formLabel() {
|
|
98
|
+
// Only use labels declared on the form, not ones derived from its name.
|
|
99
|
+
const form = this.creatableForm
|
|
100
|
+
return form
|
|
101
|
+
? this.getSchemaValue('label', { schema: form, type: String })
|
|
102
|
+
: null
|
|
103
|
+
},
|
|
104
|
+
|
|
96
105
|
isInlined() {
|
|
97
106
|
return isInlined(this.schema)
|
|
98
107
|
}
|
|
@@ -35,7 +35,8 @@
|
|
|
35
35
|
import { clone } from '@ditojs/utils'
|
|
36
36
|
import DitoComponent from '../DitoComponent.js'
|
|
37
37
|
import DomMixin from '../mixins/DomMixin.js'
|
|
38
|
-
import { getButtonSchemas } from '../utils/schema.js'
|
|
38
|
+
import { getButtonSchemas } from '../utils/schema/lookup.js'
|
|
39
|
+
import { FormModel } from '../utils/FormModel.js'
|
|
39
40
|
import { UseFocusTrap } from '@vueuse/integrations/useFocusTrap/component'
|
|
40
41
|
|
|
41
42
|
// @vue/component
|
|
@@ -126,6 +127,16 @@ export default DitoComponent.component('DitoDialog', {
|
|
|
126
127
|
}
|
|
127
128
|
},
|
|
128
129
|
|
|
130
|
+
created() {
|
|
131
|
+
// Writes defaults and computed values into the dialog's data and resolves
|
|
132
|
+
// options, see `FormModel`:
|
|
133
|
+
this.formModel = new FormModel({
|
|
134
|
+
component: this,
|
|
135
|
+
getSchema: () => this.schema,
|
|
136
|
+
getData: () => this.dialogData
|
|
137
|
+
})
|
|
138
|
+
},
|
|
139
|
+
|
|
129
140
|
mounted() {
|
|
130
141
|
this.domOn(window, {
|
|
131
142
|
keyup: event => {
|
|
@@ -136,6 +147,12 @@ export default DitoComponent.component('DitoDialog', {
|
|
|
136
147
|
})
|
|
137
148
|
},
|
|
138
149
|
|
|
150
|
+
beforeUnmount() {
|
|
151
|
+
// Stop the model before the component's own watchers are stopped, as the
|
|
152
|
+
// model's watchers aren't part of the component, see `FormModel`.
|
|
153
|
+
this.formModel.stop()
|
|
154
|
+
},
|
|
155
|
+
|
|
139
156
|
methods: {
|
|
140
157
|
remove() {
|
|
141
158
|
this.$emit('remove')
|
|
@@ -160,7 +177,9 @@ export default DitoComponent.component('DitoDialog', {
|
|
|
160
177
|
}
|
|
161
178
|
},
|
|
162
179
|
|
|
163
|
-
submit() {
|
|
180
|
+
async submit() {
|
|
181
|
+
// Wait for computed values that depend on pending loads, e.g. options.
|
|
182
|
+
await this.formModel.waitForPendingLoads()
|
|
164
183
|
this.resolve(this.dialogData)
|
|
165
184
|
},
|
|
166
185
|
|