@ditojs/admin 2.26.2 → 2.27.1
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.es.js +1779 -1690
- package/dist/dito-admin.umd.js +5 -5
- package/dist/style.css +1 -1
- package/package.json +5 -5
- package/src/DitoAdmin.js +1 -3
- package/src/DitoContext.js +4 -0
- package/src/components/DitoContainer.vue +6 -0
- package/src/components/DitoForm.vue +17 -12
- package/src/components/DitoSchema.vue +25 -15
- package/src/components/DitoView.vue +1 -1
- package/src/mixins/DataMixin.js +10 -3
- package/src/mixins/DitoMixin.js +22 -10
- package/src/mixins/OptionsMixin.js +1 -1
- package/src/mixins/ResourceMixin.js +19 -9
- package/src/mixins/RouteMixin.js +1 -1
- package/src/mixins/SourceMixin.js +51 -16
- package/src/mixins/TextMixin.js +3 -2
- package/src/mixins/TypeMixin.js +26 -10
- package/src/types/DitoTypeComponent.vue +1 -1
- package/src/types/DitoTypeDate.vue +1 -1
- package/src/types/DitoTypeSection.vue +1 -1
- package/src/types/DitoTypeText.vue +1 -1
- package/src/types/DitoTypeUpload.vue +1 -1
- package/src/utils/resource.js +4 -1
- package/src/utils/schema.js +78 -66
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ditojs/admin",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.27.1",
|
|
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/master/packages/admin",
|
|
@@ -33,8 +33,8 @@
|
|
|
33
33
|
"not ie_mob > 0"
|
|
34
34
|
],
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@ditojs/ui": "^2.
|
|
37
|
-
"@ditojs/utils": "^2.
|
|
36
|
+
"@ditojs/ui": "^2.27.0",
|
|
37
|
+
"@ditojs/utils": "^2.27.0",
|
|
38
38
|
"@kyvg/vue3-notification": "^3.2.1",
|
|
39
39
|
"@lk77/vue3-color": "^3.0.6",
|
|
40
40
|
"@tiptap/core": "^2.3.0",
|
|
@@ -74,7 +74,7 @@
|
|
|
74
74
|
"vue-upload-component": "^3.1.15"
|
|
75
75
|
},
|
|
76
76
|
"devDependencies": {
|
|
77
|
-
"@ditojs/build": "^2.
|
|
77
|
+
"@ditojs/build": "^2.27.0",
|
|
78
78
|
"@vitejs/plugin-vue": "^5.0.4",
|
|
79
79
|
"@vue/compiler-sfc": "3.4.21",
|
|
80
80
|
"pug": "^3.0.2",
|
|
@@ -83,7 +83,7 @@
|
|
|
83
83
|
"vite": "^5.2.8"
|
|
84
84
|
},
|
|
85
85
|
"types": "types",
|
|
86
|
-
"gitHead": "
|
|
86
|
+
"gitHead": "f8e8c86149487d9a7b991c9c4b8d9165974fb0a2",
|
|
87
87
|
"scripts": {
|
|
88
88
|
"build": "vite build",
|
|
89
89
|
"watch": "yarn build --mode 'development' --watch",
|
package/src/DitoAdmin.js
CHANGED
|
@@ -124,9 +124,7 @@ export default class DitoAdmin {
|
|
|
124
124
|
},
|
|
125
125
|
|
|
126
126
|
member(resource) {
|
|
127
|
-
|
|
128
|
-
// to avoid excessive nesting of (sub-)collection routes.
|
|
129
|
-
return `${resource.path}/${resource.id}`
|
|
127
|
+
return `${this.default(resource)}/${resource.id}`
|
|
130
128
|
},
|
|
131
129
|
|
|
132
130
|
upload(resource) {
|
package/src/DitoContext.js
CHANGED
|
@@ -140,6 +140,10 @@ export default class DitoContext {
|
|
|
140
140
|
return get(this, 'processedData', null)
|
|
141
141
|
}
|
|
142
142
|
|
|
143
|
+
get processedRootItem() {
|
|
144
|
+
return get(this, 'processedRootData', null)
|
|
145
|
+
}
|
|
146
|
+
|
|
143
147
|
get clipboardItem() {
|
|
144
148
|
return get(this, 'clipboardData', null)
|
|
145
149
|
}
|
|
@@ -255,6 +255,12 @@ export default DitoComponent.component('DitoContainer', {
|
|
|
255
255
|
// percentages in flex-basis to work.
|
|
256
256
|
padding: $form-spacing-half;
|
|
257
257
|
|
|
258
|
+
> .dito-label:only-child {
|
|
259
|
+
// Used e.g. when sources hide themselves due to maxDepth, but the label
|
|
260
|
+
// is rendered above it.
|
|
261
|
+
display: none;
|
|
262
|
+
}
|
|
263
|
+
|
|
258
264
|
.dito-pane > & {
|
|
259
265
|
.dito-page--width-80 & {
|
|
260
266
|
flex-grow: 1;
|
|
@@ -7,13 +7,13 @@
|
|
|
7
7
|
//- nested form route, which will appear elsewhere in its own view.
|
|
8
8
|
RouterView(
|
|
9
9
|
v-if="!isLastUnnestedRoute && !isNestedRoute"
|
|
10
|
-
v-show="!
|
|
10
|
+
v-show="!isActiveRoute"
|
|
11
11
|
)
|
|
12
12
|
//- NOTE: Nested form components are kept alive by using `v-show` instead of
|
|
13
13
|
//- `v-if` here, so event handling and other things still work with nested
|
|
14
14
|
//- editing.
|
|
15
15
|
DitoFormInner(
|
|
16
|
-
v-show="
|
|
16
|
+
v-show="isActiveRoute"
|
|
17
17
|
:nested="isNestedRoute"
|
|
18
18
|
)
|
|
19
19
|
//- Prevent implicit submission of the form, for example when typing enter
|
|
@@ -31,6 +31,7 @@
|
|
|
31
31
|
:meta="meta"
|
|
32
32
|
:store="store"
|
|
33
33
|
:padding="isNestedRoute ? 'nested' : 'root'"
|
|
34
|
+
:active="isActiveRoute"
|
|
34
35
|
:disabled="isLoading"
|
|
35
36
|
:scrollable="!isNestedRoute"
|
|
36
37
|
generateLabels
|
|
@@ -125,7 +126,7 @@ export default DitoComponent.component('DitoForm', {
|
|
|
125
126
|
)
|
|
126
127
|
},
|
|
127
128
|
|
|
128
|
-
|
|
129
|
+
isActiveRoute() {
|
|
129
130
|
return this.isLastRoute || this.isLastUnnestedRoute
|
|
130
131
|
},
|
|
131
132
|
|
|
@@ -168,11 +169,6 @@ export default DitoComponent.component('DitoForm', {
|
|
|
168
169
|
return this.isCreating ? 'post' : 'patch'
|
|
169
170
|
},
|
|
170
171
|
|
|
171
|
-
resource() {
|
|
172
|
-
const resource = this.getResource()
|
|
173
|
-
return getMemberResource(this.itemId, resource) || resource
|
|
174
|
-
},
|
|
175
|
-
|
|
176
172
|
breadcrumbPrefix() {
|
|
177
173
|
return capitalize(this.isCreating ? this.verbs.create : this.verbs.edit)
|
|
178
174
|
},
|
|
@@ -325,6 +321,12 @@ export default DitoComponent.component('DitoForm', {
|
|
|
325
321
|
)
|
|
326
322
|
},
|
|
327
323
|
|
|
324
|
+
// @override ResourceMixin.getResource()
|
|
325
|
+
getResource(defaults) {
|
|
326
|
+
const resource = ResourceMixin.methods.getResource.call(this, defaults)
|
|
327
|
+
return getMemberResource(this.itemId, resource) || resource
|
|
328
|
+
},
|
|
329
|
+
|
|
328
330
|
// @override ResourceMixin.setupData()
|
|
329
331
|
setupData() {
|
|
330
332
|
if (this.isCreating) {
|
|
@@ -337,7 +339,8 @@ export default DitoComponent.component('DitoForm', {
|
|
|
337
339
|
setSourceData(data) {
|
|
338
340
|
if (this.sourceData && this.sourceKey !== null) {
|
|
339
341
|
const { mainSchemaComponent } = this
|
|
340
|
-
this.sourceData[this.sourceKey] =
|
|
342
|
+
this.sourceData[this.sourceKey] =
|
|
343
|
+
mainSchemaComponent.filterData(data).localData
|
|
341
344
|
mainSchemaComponent.onChange()
|
|
342
345
|
return true
|
|
343
346
|
}
|
|
@@ -400,11 +403,13 @@ export default DitoComponent.component('DitoForm', {
|
|
|
400
403
|
const getVerb = present => this.verbs[this.getSubmitVerb(present)]
|
|
401
404
|
|
|
402
405
|
// Allow buttons to override both method and resource path to submit to:
|
|
406
|
+
let { method } = this
|
|
407
|
+
let resource = this.getResource({ method })
|
|
403
408
|
const buttonResource = getResource(button.schema.resource, {
|
|
404
|
-
parent:
|
|
409
|
+
parent: resource
|
|
405
410
|
})
|
|
406
|
-
|
|
407
|
-
|
|
411
|
+
resource = buttonResource || resource
|
|
412
|
+
method = resource?.method || method
|
|
408
413
|
const data = this.getPayloadData(button, method)
|
|
409
414
|
let success
|
|
410
415
|
if (!buttonResource && this.isTransient) {
|
|
@@ -9,6 +9,7 @@ slot(name="before")
|
|
|
9
9
|
to=".dito-sidebar__teleport"
|
|
10
10
|
)
|
|
11
11
|
DitoPanels(
|
|
12
|
+
v-if="active"
|
|
12
13
|
:panels="panelEntries"
|
|
13
14
|
:data="data"
|
|
14
15
|
:meta="meta"
|
|
@@ -20,7 +21,9 @@ slot(name="before")
|
|
|
20
21
|
:to="headerTeleport"
|
|
21
22
|
:disabled="!headerTeleport"
|
|
22
23
|
)
|
|
23
|
-
.dito-schema-header
|
|
24
|
+
.dito-schema-header(
|
|
25
|
+
v-if="active"
|
|
26
|
+
)
|
|
24
27
|
DitoLabel(
|
|
25
28
|
v-if="hasLabel"
|
|
26
29
|
:label="label"
|
|
@@ -119,7 +122,8 @@ import {
|
|
|
119
122
|
getPanelEntries,
|
|
120
123
|
setDefaultValues,
|
|
121
124
|
processData,
|
|
122
|
-
isEmptySchema
|
|
125
|
+
isEmptySchema,
|
|
126
|
+
isNested
|
|
123
127
|
} from '../utils/schema.js'
|
|
124
128
|
import { getSchemaAccessor, getStoreAccessor } from '../utils/accessor.js'
|
|
125
129
|
|
|
@@ -147,6 +151,7 @@ export default DitoComponent.component('DitoSchema', {
|
|
|
147
151
|
store: { type: Object, default: () => ({}) },
|
|
148
152
|
label: { type: [String, Object], default: null },
|
|
149
153
|
padding: { type: String, default: null },
|
|
154
|
+
active: { type: Boolean, default: true },
|
|
150
155
|
inlined: { type: Boolean, default: false },
|
|
151
156
|
disabled: { type: Boolean, default: false },
|
|
152
157
|
collapsed: { type: Boolean, default: false },
|
|
@@ -223,7 +228,7 @@ export default DitoComponent.component('DitoSchema', {
|
|
|
223
228
|
},
|
|
224
229
|
|
|
225
230
|
headerTeleport() {
|
|
226
|
-
return this.
|
|
231
|
+
return this.isTopLevelSchema
|
|
227
232
|
? '.dito-header__teleport'
|
|
228
233
|
: this.labelNode
|
|
229
234
|
},
|
|
@@ -283,9 +288,8 @@ export default DitoComponent.component('DitoSchema', {
|
|
|
283
288
|
)
|
|
284
289
|
},
|
|
285
290
|
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
return this.dataPath === '' && !this.inlined
|
|
291
|
+
isNested() {
|
|
292
|
+
return isNested(this.schema)
|
|
289
293
|
},
|
|
290
294
|
|
|
291
295
|
isDirty() {
|
|
@@ -320,8 +324,12 @@ export default DitoComponent.component('DitoSchema', {
|
|
|
320
324
|
return !!this.tabs
|
|
321
325
|
},
|
|
322
326
|
|
|
323
|
-
|
|
324
|
-
return this.
|
|
327
|
+
isTopLevelSchema() {
|
|
328
|
+
return !this.isNested && !this.inlined
|
|
329
|
+
},
|
|
330
|
+
|
|
331
|
+
hasTopLevelTabs() {
|
|
332
|
+
return this.hasTabs && this.isTopLevelSchema
|
|
325
333
|
},
|
|
326
334
|
|
|
327
335
|
hasMainPane() {
|
|
@@ -385,7 +393,7 @@ export default DitoComponent.component('DitoSchema', {
|
|
|
385
393
|
// Remember the current path to know if tab changes should still be
|
|
386
394
|
// handled, but remove the trailing `/create` or `/:id` from it so that
|
|
387
395
|
// tabs informs that stay open after creation still work.
|
|
388
|
-
if (this.
|
|
396
|
+
if (this.hasTopLevelTabs) {
|
|
389
397
|
this.selectedTab = routeTab
|
|
390
398
|
}
|
|
391
399
|
}
|
|
@@ -399,7 +407,7 @@ export default DitoComponent.component('DitoSchema', {
|
|
|
399
407
|
content.scrollTop = this.scrollPositions[newTab] ?? 0
|
|
400
408
|
})
|
|
401
409
|
}
|
|
402
|
-
if (this.
|
|
410
|
+
if (this.hasTopLevelTabs) {
|
|
403
411
|
const tab = this.shouldRenderSchema(this.tabs[newTab])
|
|
404
412
|
? newTab
|
|
405
413
|
: this.defaultTab
|
|
@@ -687,20 +695,22 @@ export default DitoComponent.component('DitoSchema', {
|
|
|
687
695
|
},
|
|
688
696
|
|
|
689
697
|
filterData(data) {
|
|
690
|
-
// Filters out arrays and objects that are
|
|
691
|
-
// themselves, as those are already
|
|
698
|
+
// Filters out arrays and objects that are backed by data resources
|
|
699
|
+
// themselves, as those are already taken care of through their own API
|
|
692
700
|
// resource end-points and shouldn't be set.
|
|
693
|
-
const
|
|
701
|
+
const localData = {}
|
|
702
|
+
const foreignData = {}
|
|
694
703
|
for (const [name, value] of Object.entries(data)) {
|
|
695
704
|
if (isArray(value) || isObject(value)) {
|
|
696
705
|
const components = this.getComponentsByName(name)
|
|
697
706
|
if (components.some(component => component.providesData)) {
|
|
707
|
+
foreignData[name] = value
|
|
698
708
|
continue
|
|
699
709
|
}
|
|
700
710
|
}
|
|
701
|
-
|
|
711
|
+
localData[name] = value
|
|
702
712
|
}
|
|
703
|
-
return
|
|
713
|
+
return { localData, foreignData }
|
|
704
714
|
},
|
|
705
715
|
|
|
706
716
|
processData({ target = 'clipboard', schemaOnly = true } = {}) {
|
package/src/mixins/DataMixin.js
CHANGED
|
@@ -109,15 +109,22 @@ export default {
|
|
|
109
109
|
async resolveData(load, loadingOptions = {}) {
|
|
110
110
|
// Use a timeout to allow already resolved promises to return data without
|
|
111
111
|
// showing a loading indicator.
|
|
112
|
-
|
|
112
|
+
let clearLoading = false
|
|
113
|
+
const timer = setTimeout(() => {
|
|
114
|
+
this.setLoading(true, loadingOptions)
|
|
115
|
+
clearLoading = true
|
|
116
|
+
}, 0)
|
|
113
117
|
let data = null
|
|
114
118
|
try {
|
|
115
119
|
data = await (isFunction(load) ? load() : load)
|
|
116
120
|
} catch (error) {
|
|
117
121
|
this.addError(error.message || error)
|
|
118
122
|
}
|
|
119
|
-
|
|
120
|
-
|
|
123
|
+
if (clearLoading) {
|
|
124
|
+
this.setLoading(false, loadingOptions)
|
|
125
|
+
} else {
|
|
126
|
+
clearTimeout(timer)
|
|
127
|
+
}
|
|
121
128
|
return data
|
|
122
129
|
}
|
|
123
130
|
}
|
package/src/mixins/DitoMixin.js
CHANGED
|
@@ -155,15 +155,19 @@ export default {
|
|
|
155
155
|
},
|
|
156
156
|
|
|
157
157
|
parentSchemaComponent() {
|
|
158
|
-
return this
|
|
158
|
+
return getParentComponent(this, 'schemaComponent')
|
|
159
159
|
},
|
|
160
160
|
|
|
161
161
|
parentRouteComponent() {
|
|
162
|
-
return this
|
|
162
|
+
return getParentComponent(this, 'routeComponent')
|
|
163
163
|
},
|
|
164
164
|
|
|
165
165
|
parentFormComponent() {
|
|
166
|
-
return this
|
|
166
|
+
return getParentComponent(this, 'formComponent')
|
|
167
|
+
},
|
|
168
|
+
|
|
169
|
+
parentResourceComponent() {
|
|
170
|
+
return getParentComponent(this, 'resourceComponent')
|
|
167
171
|
},
|
|
168
172
|
|
|
169
173
|
// Returns the data of the first route component in the chain of parents
|
|
@@ -307,13 +311,12 @@ export default {
|
|
|
307
311
|
},
|
|
308
312
|
|
|
309
313
|
getResourcePath(resource) {
|
|
310
|
-
resource = getResource(resource
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
return this.api.resources.any(getResource(resource))
|
|
314
|
+
resource = getResource(resource, {
|
|
315
|
+
// Resources without a parent inherit the one from `dataComponent`
|
|
316
|
+
// automatically.
|
|
317
|
+
parent: this.dataComponent?.resource ?? null
|
|
318
|
+
})
|
|
319
|
+
return this.api.resources.any(resource)
|
|
317
320
|
},
|
|
318
321
|
|
|
319
322
|
getResourceUrl(resource) {
|
|
@@ -574,3 +577,12 @@ export default {
|
|
|
574
577
|
}
|
|
575
578
|
|
|
576
579
|
let nextUid = 0
|
|
580
|
+
|
|
581
|
+
function getParentComponent(component, key) {
|
|
582
|
+
const current = component[key]
|
|
583
|
+
let parent = component.parentComponent
|
|
584
|
+
while (parent && parent[key] === current) {
|
|
585
|
+
parent = parent.parentComponent
|
|
586
|
+
}
|
|
587
|
+
return parent?.[key] ?? null
|
|
588
|
+
}
|
|
@@ -260,7 +260,7 @@ export default {
|
|
|
260
260
|
}
|
|
261
261
|
},
|
|
262
262
|
|
|
263
|
-
processValue(schema, value, dataPath, graph) {
|
|
263
|
+
processValue({ schema, value, dataPath }, graph) {
|
|
264
264
|
if (schema.relate) {
|
|
265
265
|
// For internally relating data (`schema.options.dataPath`), we need to
|
|
266
266
|
// process both the options (for '#ref') and the value ('#id').
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import ItemMixin from './ItemMixin.js'
|
|
2
2
|
import LoadingMixin from './LoadingMixin.js'
|
|
3
3
|
import { setDefaultValues } from '../utils/schema.js'
|
|
4
|
-
import { isObject, isString, labelize } from '@ditojs/utils'
|
|
4
|
+
import { assignDeeply, isObject, isString, labelize } from '@ditojs/utils'
|
|
5
5
|
import { getResource } from '../utils/resource.js'
|
|
6
6
|
import DitoContext from '../DitoContext.js'
|
|
7
7
|
|
|
@@ -31,8 +31,6 @@ export default {
|
|
|
31
31
|
},
|
|
32
32
|
|
|
33
33
|
resource() {
|
|
34
|
-
// Returns the resource object representing the resource for the
|
|
35
|
-
// associated source schema.
|
|
36
34
|
return this.getResource()
|
|
37
35
|
},
|
|
38
36
|
|
|
@@ -126,12 +124,13 @@ export default {
|
|
|
126
124
|
},
|
|
127
125
|
|
|
128
126
|
methods: {
|
|
129
|
-
getResource() {
|
|
130
|
-
//
|
|
131
|
-
//
|
|
127
|
+
getResource(defaults = { method: 'get' }) {
|
|
128
|
+
// Returns the resource object representing the resource for the
|
|
129
|
+
// associated source schema.
|
|
132
130
|
return getResource(this.sourceSchema?.resource, {
|
|
133
131
|
type: 'collection',
|
|
134
|
-
parent: this.
|
|
132
|
+
parent: this.parentResourceComponent?.resource ?? null,
|
|
133
|
+
...defaults
|
|
135
134
|
})
|
|
136
135
|
},
|
|
137
136
|
|
|
@@ -230,7 +229,7 @@ export default {
|
|
|
230
229
|
async handleRequest(
|
|
231
230
|
{
|
|
232
231
|
method,
|
|
233
|
-
resource = this.
|
|
232
|
+
resource = this.getResource({ method }),
|
|
234
233
|
query,
|
|
235
234
|
data
|
|
236
235
|
},
|
|
@@ -244,6 +243,7 @@ export default {
|
|
|
244
243
|
const controller = new AbortController()
|
|
245
244
|
this.abortController = controller
|
|
246
245
|
const { signal } = controller
|
|
246
|
+
method = resource.method || method
|
|
247
247
|
const request = { method, resource, query, data, signal }
|
|
248
248
|
this.setLoading(true, loadingOptions)
|
|
249
249
|
try {
|
|
@@ -340,7 +340,17 @@ export default {
|
|
|
340
340
|
// Update the underlying data before calling `notify()` or
|
|
341
341
|
// `this.itemLabel`, so id is set after creating new items.
|
|
342
342
|
if (setData && data) {
|
|
343
|
-
|
|
343
|
+
// Preserve the foreign data entries when updating the data.
|
|
344
|
+
const { foreignData } = this.mainSchemaComponent.filterData(
|
|
345
|
+
this.data
|
|
346
|
+
)
|
|
347
|
+
// Tell the parent route to reload its data, so that it can
|
|
348
|
+
// update its foreign data entries.
|
|
349
|
+
const parentMeta = this.parentRouteComponent?.routeRecord?.meta
|
|
350
|
+
if (parentMeta) {
|
|
351
|
+
parentMeta.reload = true
|
|
352
|
+
}
|
|
353
|
+
this.setData(assignDeeply({}, foreignData, data))
|
|
344
354
|
}
|
|
345
355
|
onSuccess?.()
|
|
346
356
|
await this.emitButtonEvent(button, 'success', {
|
package/src/mixins/RouteMixin.js
CHANGED
|
@@ -33,9 +33,9 @@ import { raw } from '@ditojs/ui'
|
|
|
33
33
|
export default {
|
|
34
34
|
mixins: [ItemMixin, ResourceMixin, SchemaParentMixin],
|
|
35
35
|
|
|
36
|
-
defaultValue(schema)
|
|
37
|
-
|
|
38
|
-
|
|
36
|
+
defaultValue: context => (isListSource(context.schema) ? [] : null),
|
|
37
|
+
// Exclude all sources that have their own resource handling the data.
|
|
38
|
+
excludeValue: context => !!context.schema.resource,
|
|
39
39
|
|
|
40
40
|
provide() {
|
|
41
41
|
return {
|
|
@@ -68,10 +68,17 @@ export default {
|
|
|
68
68
|
return !!this.value
|
|
69
69
|
},
|
|
70
70
|
|
|
71
|
+
shouldRender() {
|
|
72
|
+
return this.sourceDepth < this.maxDepth
|
|
73
|
+
},
|
|
74
|
+
|
|
71
75
|
isReady() {
|
|
72
76
|
// Lists that have no data and no associated resource should still render,
|
|
73
77
|
// as they may be getting their data elsewhere, e.g. `compute()`.
|
|
74
|
-
return
|
|
78
|
+
return (
|
|
79
|
+
this.shouldRender &&
|
|
80
|
+
(this.hasData || !this.providesData)
|
|
81
|
+
)
|
|
75
82
|
},
|
|
76
83
|
|
|
77
84
|
isInView() {
|
|
@@ -147,6 +154,15 @@ export default {
|
|
|
147
154
|
return this.schema
|
|
148
155
|
},
|
|
149
156
|
|
|
157
|
+
sourceDepth() {
|
|
158
|
+
return this.$route.matched.reduce(
|
|
159
|
+
(depth, record) => (
|
|
160
|
+
depth + (record.meta.schema === this.sourceSchema ? 1 : 0)
|
|
161
|
+
),
|
|
162
|
+
0
|
|
163
|
+
)
|
|
164
|
+
},
|
|
165
|
+
|
|
150
166
|
path() {
|
|
151
167
|
// This is used in TypeList for DitoFormChooser.
|
|
152
168
|
return this.routeComponent.getChildPath(this.schema.path)
|
|
@@ -313,6 +329,11 @@ export default {
|
|
|
313
329
|
collapsed: getSchemaAccessor('collapsed', {
|
|
314
330
|
type: Boolean,
|
|
315
331
|
default: null
|
|
332
|
+
}),
|
|
333
|
+
|
|
334
|
+
maxDepth: getSchemaAccessor('maxDepth', {
|
|
335
|
+
type: Number,
|
|
336
|
+
default: 1
|
|
316
337
|
})
|
|
317
338
|
},
|
|
318
339
|
|
|
@@ -321,15 +342,25 @@ export default {
|
|
|
321
342
|
// https://github.com/vuejs/vue-router/issues/3393#issuecomment-1158470149
|
|
322
343
|
flush: 'post',
|
|
323
344
|
handler(to, from) {
|
|
324
|
-
if (
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
345
|
+
if (this.providesData) {
|
|
346
|
+
if (
|
|
347
|
+
from.path === to.path &&
|
|
348
|
+
from.hash === to.hash
|
|
349
|
+
) {
|
|
350
|
+
// Paths and hashes remain the same, so only queries have changed.
|
|
351
|
+
// Update filter and reload data without clearing.
|
|
352
|
+
this.query = to.query
|
|
353
|
+
this.loadData(false)
|
|
354
|
+
} else if (
|
|
355
|
+
this.meta.reload &&
|
|
356
|
+
from.path !== to.path &&
|
|
357
|
+
from.path.startsWith(to.path)
|
|
358
|
+
) {
|
|
359
|
+
// Reload the source when navigating back to a parent-route after
|
|
360
|
+
// changing data in a child-route.
|
|
361
|
+
this.meta.reload = false
|
|
362
|
+
this.loadData(false)
|
|
363
|
+
}
|
|
333
364
|
}
|
|
334
365
|
}
|
|
335
366
|
},
|
|
@@ -464,9 +495,13 @@ export default {
|
|
|
464
495
|
notify()
|
|
465
496
|
} else {
|
|
466
497
|
const itemId = this.getItemId(this.schema, item, index)
|
|
467
|
-
const
|
|
498
|
+
const method = 'delete'
|
|
499
|
+
const resource = getMemberResource(
|
|
500
|
+
itemId,
|
|
501
|
+
this.getResource({ method })
|
|
502
|
+
)
|
|
468
503
|
if (resource) {
|
|
469
|
-
this.handleRequest({ method
|
|
504
|
+
this.handleRequest({ method, resource }, err => {
|
|
470
505
|
if (!err) {
|
|
471
506
|
this.removeItem(item, index)
|
|
472
507
|
notify()
|
|
@@ -666,7 +701,7 @@ export default {
|
|
|
666
701
|
}
|
|
667
702
|
},
|
|
668
703
|
|
|
669
|
-
processValue(schema, value, dataPath, graph) {
|
|
704
|
+
processValue({ schema, value, dataPath }, graph) {
|
|
670
705
|
graph.addSource(dataPath, schema)
|
|
671
706
|
return value
|
|
672
707
|
}
|
package/src/mixins/TextMixin.js
CHANGED
|
@@ -11,14 +11,15 @@ export default {
|
|
|
11
11
|
})
|
|
12
12
|
},
|
|
13
13
|
|
|
14
|
-
processValue(
|
|
14
|
+
processValue(context) {
|
|
15
|
+
let { schema, value } = context
|
|
15
16
|
if (schema.trim && value != null && isString(value)) {
|
|
16
17
|
// Text fields don't necessarily have a `String` value when `format()`
|
|
17
18
|
// without `parse()` is used.
|
|
18
19
|
value = value.trim()
|
|
19
20
|
}
|
|
20
21
|
if (value === '') {
|
|
21
|
-
value = getDefaultValue(schema)
|
|
22
|
+
value = getDefaultValue(schema, context)
|
|
22
23
|
}
|
|
23
24
|
return value
|
|
24
25
|
}
|
package/src/mixins/TypeMixin.js
CHANGED
|
@@ -77,16 +77,11 @@ export default {
|
|
|
77
77
|
},
|
|
78
78
|
|
|
79
79
|
processedData() {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
return
|
|
85
|
-
schemaComponent.processedData,
|
|
86
|
-
// Get the dataPath relative to the schemaComponent's data:
|
|
87
|
-
this.dataPath.slice(schemaComponent.dataPath.length),
|
|
88
|
-
this.nested
|
|
89
|
-
)
|
|
80
|
+
return getProcessedParentData(this, this.dataPath, this.nested)
|
|
81
|
+
},
|
|
82
|
+
|
|
83
|
+
processedRootData() {
|
|
84
|
+
return getProcessedParentData(this, '', false)
|
|
90
85
|
},
|
|
91
86
|
|
|
92
87
|
// The following computed properties are similar to `DitoContext`
|
|
@@ -107,6 +102,10 @@ export default {
|
|
|
107
102
|
return this.processedData
|
|
108
103
|
},
|
|
109
104
|
|
|
105
|
+
processedRootItem() {
|
|
106
|
+
return this.processedRootData
|
|
107
|
+
},
|
|
108
|
+
|
|
110
109
|
labelNode() {
|
|
111
110
|
const node = this.isMounted ? this.$el.previousElementSibling : null
|
|
112
111
|
return node?.matches('.dito-label') ? node : null
|
|
@@ -327,3 +326,20 @@ export default {
|
|
|
327
326
|
}
|
|
328
327
|
}
|
|
329
328
|
}
|
|
329
|
+
|
|
330
|
+
function getProcessedParentData(component, dataPath, nested = false) {
|
|
331
|
+
// We can only get the processed data through the schemaComponent, but
|
|
332
|
+
// that's not necessarily the item represented by this component.
|
|
333
|
+
// Solution: Find the relative path and the processed sub-item from there:
|
|
334
|
+
let { schemaComponent } = component
|
|
335
|
+
// Find the schema component that contains the desired data-path:
|
|
336
|
+
while (schemaComponent.dataPath.length > dataPath.length) {
|
|
337
|
+
schemaComponent = schemaComponent.parentSchemaComponent
|
|
338
|
+
}
|
|
339
|
+
return getItem(
|
|
340
|
+
schemaComponent.processedData,
|
|
341
|
+
// Get the dataPath relative to the schemaComponent's data:
|
|
342
|
+
dataPath.slice(schemaComponent.dataPath.length),
|
|
343
|
+
nested
|
|
344
|
+
)
|
|
345
|
+
}
|
|
@@ -22,7 +22,7 @@ export default DitoTypeComponent.register('component', {
|
|
|
22
22
|
// Override the standard `defaultValue: null` to not set any data for custom
|
|
23
23
|
// components, unless they provide a default value.
|
|
24
24
|
defaultValue: () => undefined, // Callback to override `defaultValue: null`
|
|
25
|
-
ignoreMissingValue: schema => !('default' in schema),
|
|
25
|
+
ignoreMissingValue: ({ schema }) => !('default' in schema),
|
|
26
26
|
|
|
27
27
|
async processSchema(api, schema) {
|
|
28
28
|
await resolveSchemaComponent(schema)
|