@ditojs/admin 2.27.0 → 2.27.2
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 +1307 -1279
- package/dist/dito-admin.umd.js +5 -5
- package/dist/style.css +1 -1
- package/package.json +2 -2
- package/src/DitoContext.js +4 -0
- package/src/components/DitoContainer.vue +6 -0
- package/src/mixins/RouteMixin.js +1 -1
- package/src/mixins/SourceMixin.js +22 -1
- package/src/mixins/TypeMixin.js +26 -10
- package/src/mixins/ValidationMixin.js +8 -4
- package/src/utils/schema.js +48 -38
- package/src/{validations → validators}/_required.js +1 -2
- /package/src/{validations → validators}/_creditcard.js +0 -0
- /package/src/{validations → validators}/_decimals.js +0 -0
- /package/src/{validations → validators}/_domain.js +0 -0
- /package/src/{validations → validators}/_email.js +0 -0
- /package/src/{validations → validators}/_hostname.js +0 -0
- /package/src/{validations → validators}/_integer.js +0 -0
- /package/src/{validations → validators}/_max.js +0 -0
- /package/src/{validations → validators}/_min.js +0 -0
- /package/src/{validations → validators}/_password.js +0 -0
- /package/src/{validations → validators}/_range.js +0 -0
- /package/src/{validations → validators}/_url.js +0 -0
- /package/src/{validations → validators}/index.js +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ditojs/admin",
|
|
3
|
-
"version": "2.27.
|
|
3
|
+
"version": "2.27.2",
|
|
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",
|
|
@@ -83,7 +83,7 @@
|
|
|
83
83
|
"vite": "^5.2.8"
|
|
84
84
|
},
|
|
85
85
|
"types": "types",
|
|
86
|
-
"gitHead": "
|
|
86
|
+
"gitHead": "d15a80e1ecdf916fd087ad7c5b21eee0b2ee9daf",
|
|
87
87
|
"scripts": {
|
|
88
88
|
"build": "vite build",
|
|
89
89
|
"watch": "yarn build --mode 'development' --watch",
|
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;
|
package/src/mixins/RouteMixin.js
CHANGED
|
@@ -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
|
|
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
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { isFunction } from '@ditojs/utils'
|
|
2
|
-
import * as
|
|
2
|
+
import * as validators from '../validators/index.js'
|
|
3
3
|
|
|
4
4
|
// @vue/component
|
|
5
5
|
export default {
|
|
@@ -36,11 +36,15 @@ export default {
|
|
|
36
36
|
this.clearErrors()
|
|
37
37
|
}
|
|
38
38
|
const { value } = this
|
|
39
|
-
// console.log('validate', this.dataPath, value, this.validations)
|
|
40
39
|
for (const [rule, setting] of Object.entries(this.validations)) {
|
|
41
40
|
// eslint-disable-next-line import/namespace
|
|
42
|
-
const validator =
|
|
43
|
-
if (
|
|
41
|
+
const validator = validators[rule]
|
|
42
|
+
if (
|
|
43
|
+
validator &&
|
|
44
|
+
// Only apply 'required' validator to empty values.
|
|
45
|
+
// Apply all other validators only to non-empty values.
|
|
46
|
+
(rule === 'required' || value != null && value !== '')
|
|
47
|
+
) {
|
|
44
48
|
const { validate, message } = validator
|
|
45
49
|
if (!validate(value, setting, this.validations)) {
|
|
46
50
|
isValid = false
|
package/src/utils/schema.js
CHANGED
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
mapConcurrently,
|
|
20
20
|
getValueAtDataPath
|
|
21
21
|
} from '@ditojs/utils'
|
|
22
|
-
import { markRaw } from 'vue'
|
|
22
|
+
import { markRaw, reactive } from 'vue'
|
|
23
23
|
|
|
24
24
|
const typeComponents = {}
|
|
25
25
|
const unknownTypeReported = {}
|
|
@@ -242,37 +242,40 @@ export async function resolveSchemaComponents(schemas) {
|
|
|
242
242
|
await mapConcurrently(Object.values(schemas || {}), resolveSchemaComponent)
|
|
243
243
|
}
|
|
244
244
|
|
|
245
|
-
const
|
|
246
|
-
export
|
|
245
|
+
const processedSchemaDepths = new WeakMap()
|
|
246
|
+
export function processSchemaComponents(
|
|
247
247
|
api,
|
|
248
248
|
schema,
|
|
249
249
|
routes = null,
|
|
250
|
-
level = 0
|
|
250
|
+
level = 0,
|
|
251
|
+
maxDepth = 1
|
|
251
252
|
) {
|
|
252
|
-
if (schema
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
253
|
+
if (schema) {
|
|
254
|
+
const depth = processedSchemaDepths.get(schema) ?? 0
|
|
255
|
+
if (depth < maxDepth) {
|
|
256
|
+
processedSchemaDepths.set(schema, depth + 1)
|
|
257
|
+
const promises = []
|
|
258
|
+
const process = (component, name, relativeLevel) => {
|
|
259
|
+
promises.push(
|
|
260
|
+
processSchemaComponent(
|
|
261
|
+
api,
|
|
262
|
+
component,
|
|
263
|
+
name,
|
|
264
|
+
routes,
|
|
265
|
+
level + relativeLevel
|
|
266
|
+
)
|
|
264
267
|
)
|
|
265
|
-
|
|
266
|
-
}
|
|
268
|
+
}
|
|
267
269
|
|
|
268
|
-
|
|
269
|
-
|
|
270
|
+
iterateNestedSchemaComponents(schema, process)
|
|
271
|
+
iterateSchemaComponents(getPanelSchemas(schema), process)
|
|
270
272
|
|
|
271
|
-
|
|
273
|
+
return Promise.all(promises)
|
|
274
|
+
}
|
|
272
275
|
}
|
|
273
276
|
}
|
|
274
277
|
|
|
275
|
-
export
|
|
278
|
+
export function processSchemaComponent(
|
|
276
279
|
api,
|
|
277
280
|
schema,
|
|
278
281
|
name,
|
|
@@ -281,7 +284,7 @@ export async function processSchemaComponent(
|
|
|
281
284
|
) {
|
|
282
285
|
processSchemaDefaults(api, schema)
|
|
283
286
|
|
|
284
|
-
|
|
287
|
+
return Promise.all([
|
|
285
288
|
// Also process nested panel schemas.
|
|
286
289
|
mapConcurrently(
|
|
287
290
|
getPanelSchemas(schema),
|
|
@@ -367,38 +370,41 @@ export function processRouteSchema(api, schema, name, fullPath = null) {
|
|
|
367
370
|
}
|
|
368
371
|
|
|
369
372
|
export async function processForms(api, schema, level) {
|
|
373
|
+
const routes = []
|
|
370
374
|
// First resolve the forms and store the results back on the schema.
|
|
371
|
-
|
|
375
|
+
const { form, forms, components, maxDepth = 1 } = schema
|
|
372
376
|
if (forms) {
|
|
373
|
-
|
|
374
|
-
processForm(api, form)
|
|
377
|
+
schema.forms = await resolveSchemas(forms, form =>
|
|
378
|
+
processForm(api, form, routes, level, maxDepth)
|
|
375
379
|
)
|
|
376
380
|
} else if (form) {
|
|
377
|
-
|
|
381
|
+
schema.form = await processForm(api, form, routes, level, maxDepth)
|
|
378
382
|
} else if (isObject(components)) {
|
|
379
383
|
// NOTE: Processing forms in computed components is not supported, since it
|
|
380
384
|
// only can be computed in conjunction with actual data.
|
|
381
|
-
form = {
|
|
385
|
+
const form = {
|
|
382
386
|
type: 'form',
|
|
383
387
|
components
|
|
384
388
|
}
|
|
389
|
+
await processForm(api, form, routes, level, maxDepth)
|
|
385
390
|
}
|
|
386
|
-
|
|
387
|
-
forms ||= { default: form } // Only used for process loop below.
|
|
388
|
-
const children = []
|
|
389
|
-
for (const form of Object.values(forms)) {
|
|
390
|
-
await processSchemaComponents(api, form, children, level)
|
|
391
|
-
}
|
|
392
|
-
return children
|
|
391
|
+
return routes
|
|
393
392
|
}
|
|
394
393
|
|
|
395
|
-
export async function processForm(
|
|
394
|
+
export async function processForm(
|
|
395
|
+
api,
|
|
396
|
+
schema,
|
|
397
|
+
routes = null,
|
|
398
|
+
level = 0,
|
|
399
|
+
maxDepth = 1
|
|
400
|
+
) {
|
|
396
401
|
schema = await resolveSchema(schema, true)
|
|
397
402
|
if (!isForm(schema)) {
|
|
398
403
|
throw new Error(`Invalid form schema: '${getSchemaIdentifier(schema)}'`)
|
|
399
404
|
}
|
|
400
405
|
processSchemaDefaults(api, schema)
|
|
401
406
|
await processNestedSchemas(api, schema)
|
|
407
|
+
await processSchemaComponents(api, schema, routes, level, maxDepth)
|
|
402
408
|
return schema
|
|
403
409
|
}
|
|
404
410
|
|
|
@@ -515,10 +521,14 @@ export function getFormSchemas(schema, context, modifyForm) {
|
|
|
515
521
|
Object.entries(forms).map(([type, form]) => {
|
|
516
522
|
// Support `schema.components` callbacks to create components on the fly.
|
|
517
523
|
if (context && isFunction(form.components)) {
|
|
518
|
-
form
|
|
524
|
+
// Make the form schema reactive since `processForm()` is async, so that
|
|
525
|
+
// the setting of defaults will be picked up by downstream code.
|
|
526
|
+
form = reactive({
|
|
519
527
|
...form,
|
|
520
528
|
components: form.components(context)
|
|
521
|
-
}
|
|
529
|
+
})
|
|
530
|
+
// Process the form again, now that we have the components.
|
|
531
|
+
processForm(context.api, form).catch(console.error)
|
|
522
532
|
}
|
|
523
533
|
return [type, modifyForm?.(form) ?? form]
|
|
524
534
|
})
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|