@ditojs/admin 2.0.4 → 2.1.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.es.js +2065 -1969
- package/dist/dito-admin.umd.js +4 -4
- package/dist/style.css +1 -1
- package/package.json +32 -31
- package/src/DitoAdmin.js +66 -31
- package/src/DitoComponent.js +4 -1
- package/src/DitoContext.js +13 -5
- package/src/{TypeComponent.js → DitoTypeComponent.js} +8 -5
- package/src/components/DitoAccount.vue +20 -19
- package/src/components/DitoButtons.vue +14 -12
- package/src/components/DitoClipboard.vue +16 -8
- package/src/components/DitoContainer.vue +56 -43
- package/src/components/DitoCreateButton.vue +20 -15
- package/src/components/DitoDialog.vue +78 -53
- package/src/components/DitoEditButtons.vue +16 -14
- package/src/components/DitoElement.vue +2 -3
- package/src/components/DitoErrors.vue +18 -13
- package/src/components/DitoForm.vue +41 -24
- package/src/components/DitoFormNested.vue +12 -10
- package/src/components/DitoHeader.vue +103 -69
- package/src/components/DitoLabel.vue +108 -81
- package/src/components/DitoMenu.vue +52 -36
- package/src/components/DitoPagination.vue +9 -7
- package/src/components/DitoPane.vue +53 -45
- package/src/components/DitoPanel.vue +62 -42
- package/src/components/DitoPanels.vue +11 -10
- package/src/components/DitoRoot.vue +57 -46
- package/src/components/DitoSchema.vue +179 -131
- package/src/components/DitoSchemaInlined.vue +39 -28
- package/src/components/DitoScopes.vue +41 -31
- package/src/components/DitoSpinner.vue +31 -40
- package/src/components/DitoTableCell.vue +9 -9
- package/src/components/DitoTableHead.vue +52 -37
- package/src/components/DitoTabs.vue +39 -29
- package/src/components/DitoTreeItem.vue +140 -86
- package/src/components/DitoVNode.vue +1 -1
- package/src/components/DitoView.vue +13 -11
- package/src/mixins/DataMixin.js +11 -9
- package/src/mixins/DitoMixin.js +47 -25
- package/src/mixins/EmitterMixin.js +2 -1
- package/src/mixins/ItemMixin.js +15 -10
- package/src/mixins/LoadingMixin.js +2 -1
- package/src/mixins/NumberMixin.js +15 -10
- package/src/mixins/OptionsMixin.js +24 -12
- package/src/mixins/ResourceMixin.js +42 -34
- package/src/mixins/RouteMixin.js +8 -8
- package/src/mixins/SortableMixin.js +1 -1
- package/src/mixins/SourceMixin.js +68 -34
- package/src/mixins/TypeMixin.js +5 -4
- package/src/mixins/ValidationMixin.js +3 -0
- package/src/styles/_base.scss +17 -0
- package/src/styles/_button.scss +212 -0
- package/src/styles/_imports.scss +2 -0
- package/src/styles/_layout.scss +22 -0
- package/src/styles/_notifications.scss +54 -0
- package/src/styles/_pulldown.scss +39 -0
- package/src/styles/_scroll.scss +15 -0
- package/src/styles/_settings.scss +68 -0
- package/src/styles/_sortable.scss +13 -0
- package/src/styles/_table.scss +224 -0
- package/src/styles/style.scss +9 -0
- package/src/types/DitoTypeButton.vue +72 -0
- package/src/types/{TypeCheckbox.vue → DitoTypeCheckbox.vue} +12 -11
- package/src/types/{TypeCheckboxes.vue → DitoTypeCheckboxes.vue} +21 -15
- package/src/types/{TypeCode.vue → DitoTypeCode.vue} +46 -34
- package/src/types/{TypeColor.vue → DitoTypeColor.vue} +71 -52
- package/src/types/{TypeComponent.vue → DitoTypeComponent.vue} +2 -2
- package/src/types/DitoTypeComputed.vue +54 -0
- package/src/types/DitoTypeDate.vue +64 -0
- package/src/types/DitoTypeLabel.vue +23 -0
- package/src/types/{TypeList.vue → DitoTypeList.vue} +83 -61
- package/src/types/{TypeMarkup.vue → DitoTypeMarkup.vue} +172 -122
- package/src/types/DitoTypeMultiselect.vue +434 -0
- package/src/types/DitoTypeNumber.vue +46 -0
- package/src/types/{TypeObject.vue → DitoTypeObject.vue} +41 -26
- package/src/types/{TypePanel.vue → DitoTypePanel.vue} +2 -2
- package/src/types/{TypeProgress.vue → DitoTypeProgress.vue} +4 -6
- package/src/types/{TypeRadio.vue → DitoTypeRadio.vue} +17 -13
- package/src/types/{TypeSection.vue → DitoTypeSection.vue} +17 -17
- package/src/types/{TypeSelect.vue → DitoTypeSelect.vue} +39 -35
- package/src/types/{TypeSlider.vue → DitoTypeSlider.vue} +29 -23
- package/src/types/{TypeSwitch.vue → DitoTypeSwitch.vue} +15 -13
- package/src/types/DitoTypeText.vue +77 -0
- package/src/types/{TypeTextarea.vue → DitoTypeTextarea.vue} +17 -14
- package/src/types/DitoTypeTreeList.vue +191 -0
- package/src/types/{TypeUpload.vue → DitoTypeUpload.vue} +92 -65
- package/src/types/index.js +26 -26
- package/src/utils/SchemaGraph.js +21 -13
- package/src/utils/accessor.js +17 -9
- package/src/utils/data.js +4 -1
- package/src/utils/filter.js +8 -10
- package/src/utils/options.js +3 -3
- package/src/utils/resource.js +12 -10
- package/src/utils/schema.js +190 -125
- package/src/utils/type.js +31 -20
- package/src/validations/_decimals.js +1 -2
- package/types/index.d.ts +27 -23
- package/src/styles/_base.sass +0 -15
- package/src/styles/_button.sass +0 -127
- package/src/styles/_imports.sass +0 -2
- package/src/styles/_layout.sass +0 -13
- package/src/styles/_notifications.sass +0 -33
- package/src/styles/_pulldown.sass +0 -26
- package/src/styles/_scroll.sass +0 -13
- package/src/styles/_settings.sass +0 -55
- package/src/styles/_sortable.sass +0 -9
- package/src/styles/_table.sass +0 -153
- package/src/styles/style.sass +0 -10
- package/src/types/TypeButton.vue +0 -73
- package/src/types/TypeComputed.vue +0 -53
- package/src/types/TypeDate.vue +0 -64
- package/src/types/TypeLabel.vue +0 -19
- package/src/types/TypeMultiselect.vue +0 -376
- package/src/types/TypeNumber.vue +0 -44
- package/src/types/TypeText.vue +0 -67
- package/src/types/TypeTreeList.vue +0 -164
package/src/mixins/DitoMixin.js
CHANGED
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
import {
|
|
2
|
-
isObject,
|
|
3
|
-
|
|
2
|
+
isObject,
|
|
3
|
+
isArray,
|
|
4
|
+
isString,
|
|
5
|
+
isFunction,
|
|
6
|
+
asArray,
|
|
7
|
+
equals,
|
|
8
|
+
getValueAtDataPath,
|
|
9
|
+
labelize,
|
|
10
|
+
hyphenate,
|
|
11
|
+
format
|
|
4
12
|
} from '@ditojs/utils'
|
|
5
13
|
import appState from '../appState.js'
|
|
6
14
|
import DitoContext from '../DitoContext.js'
|
|
@@ -32,12 +40,12 @@ export default {
|
|
|
32
40
|
provide() {
|
|
33
41
|
return this.providesData
|
|
34
42
|
? {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
43
|
+
$parentComponent: () => this,
|
|
44
|
+
$dataComponent: () => this
|
|
45
|
+
}
|
|
38
46
|
: {
|
|
39
|
-
|
|
40
|
-
|
|
47
|
+
$parentComponent: () => this
|
|
48
|
+
}
|
|
41
49
|
},
|
|
42
50
|
|
|
43
51
|
data() {
|
|
@@ -161,7 +169,9 @@ export default {
|
|
|
161
169
|
beforeCreate() {
|
|
162
170
|
const uid = nextUid++
|
|
163
171
|
Object.defineProperty(this, '$uid', {
|
|
164
|
-
get() {
|
|
172
|
+
get() {
|
|
173
|
+
return uid
|
|
174
|
+
}
|
|
165
175
|
})
|
|
166
176
|
},
|
|
167
177
|
|
|
@@ -255,11 +265,14 @@ export default {
|
|
|
255
265
|
},
|
|
256
266
|
|
|
257
267
|
shouldRender(schema = null) {
|
|
258
|
-
return
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
268
|
+
return (
|
|
269
|
+
!!schema &&
|
|
270
|
+
this.getSchemaValue('if', {
|
|
271
|
+
type: Boolean,
|
|
272
|
+
default: true,
|
|
273
|
+
schema
|
|
274
|
+
})
|
|
275
|
+
)
|
|
263
276
|
},
|
|
264
277
|
|
|
265
278
|
getResourcePath(resource) {
|
|
@@ -310,20 +323,29 @@ export default {
|
|
|
310
323
|
// - 'global': cache globally, for the entire admin session
|
|
311
324
|
// - 'local': cache locally within the closest route component that is
|
|
312
325
|
// associated with a resource and loads its own data.
|
|
313
|
-
const cacheParent =
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
326
|
+
const cacheParent = (
|
|
327
|
+
cache &&
|
|
328
|
+
{
|
|
329
|
+
global: this.appState,
|
|
330
|
+
local: this.dataComponent
|
|
331
|
+
}[cache]
|
|
332
|
+
)
|
|
317
333
|
const loadCache = cacheParent?.loadCache
|
|
318
334
|
// Build a cache key from the config:
|
|
319
|
-
const cacheKey =
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
335
|
+
const cacheKey = (
|
|
336
|
+
loadCache &&
|
|
337
|
+
`${
|
|
338
|
+
options.method || 'get'
|
|
339
|
+
} ${
|
|
340
|
+
options.url
|
|
341
|
+
} ${
|
|
342
|
+
// TODO: `request.params` was deprecated in favour of `query` on
|
|
343
|
+
// 2022-11-01, remove once not in use anywhere any more.
|
|
344
|
+
JSON.stringify(options.query || options.params || '')
|
|
345
|
+
} ${
|
|
346
|
+
JSON.stringify(options.data || '')
|
|
347
|
+
}`
|
|
348
|
+
)
|
|
327
349
|
if (loadCache && (cacheKey in loadCache)) {
|
|
328
350
|
return loadCache[cacheKey]
|
|
329
351
|
}
|
package/src/mixins/ItemMixin.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import DitoContext from '../DitoContext.js'
|
|
2
2
|
import {
|
|
3
|
-
getItemFormSchema,
|
|
3
|
+
getItemFormSchema,
|
|
4
|
+
getItemId,
|
|
5
|
+
getItemUid,
|
|
6
|
+
isListSource
|
|
4
7
|
} from '../utils/schema.js'
|
|
5
8
|
import { appendDataPath } from '../utils/data.js'
|
|
6
9
|
import { isObject, isString, isFunction } from '@ditojs/utils'
|
|
@@ -31,12 +34,13 @@ export default {
|
|
|
31
34
|
|
|
32
35
|
findItemIdIndex(sourceSchema, data, itemId) {
|
|
33
36
|
const index = this.isTransient
|
|
34
|
-
// For transient data, the index is used as the id
|
|
35
|
-
|
|
37
|
+
? // For transient data, the index is used as the id
|
|
38
|
+
itemId
|
|
36
39
|
: data?.findIndex(
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
+
(item, index) => (
|
|
41
|
+
this.getItemId(sourceSchema, item, index) === itemId
|
|
42
|
+
)
|
|
43
|
+
)
|
|
40
44
|
return index !== -1 ? index : null
|
|
41
45
|
},
|
|
42
46
|
|
|
@@ -82,7 +86,7 @@ export default {
|
|
|
82
86
|
})
|
|
83
87
|
)
|
|
84
88
|
if (isObject(label)) {
|
|
85
|
-
({ text, prefix, suffix } = label)
|
|
89
|
+
;({ text, prefix, suffix } = label)
|
|
86
90
|
} else {
|
|
87
91
|
text = label
|
|
88
92
|
}
|
|
@@ -109,9 +113,10 @@ export default {
|
|
|
109
113
|
if (text == null) {
|
|
110
114
|
// Always use extended style when auto-generating labels from index/id:
|
|
111
115
|
extended = true
|
|
112
|
-
text =
|
|
113
|
-
|
|
114
|
-
|
|
116
|
+
text =
|
|
117
|
+
isListSource(sourceSchema) && index !== null
|
|
118
|
+
? (text = `${index + 1}`)
|
|
119
|
+
: ''
|
|
115
120
|
}
|
|
116
121
|
if (extended) {
|
|
117
122
|
const formLabel = getFormLabel()
|
|
@@ -8,7 +8,8 @@ export default {
|
|
|
8
8
|
|
|
9
9
|
methods: {
|
|
10
10
|
setLoading(isLoading, { updateRoot = false, updateView = false } = {}) {
|
|
11
|
-
if (!this.isLoading ^ !isLoading) {
|
|
11
|
+
if (!this.isLoading ^ !isLoading) {
|
|
12
|
+
// Boolean xor
|
|
12
13
|
this.isLoading = !!isLoading
|
|
13
14
|
if (updateRoot) {
|
|
14
15
|
this.rootComponent.registerLoading(isLoading)
|
|
@@ -10,9 +10,12 @@ export default {
|
|
|
10
10
|
},
|
|
11
11
|
|
|
12
12
|
set(value) {
|
|
13
|
-
this.value =
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
this.value =
|
|
14
|
+
value !== ''
|
|
15
|
+
? this.isInteger
|
|
16
|
+
? parseInt(value, 10)
|
|
17
|
+
: parseFloat(value)
|
|
18
|
+
: null
|
|
16
19
|
}
|
|
17
20
|
},
|
|
18
21
|
|
|
@@ -40,9 +43,10 @@ export default {
|
|
|
40
43
|
min: getSchemaAccessor('min', {
|
|
41
44
|
type: Number,
|
|
42
45
|
get(min) {
|
|
43
|
-
min =
|
|
44
|
-
|
|
45
|
-
|
|
46
|
+
min =
|
|
47
|
+
min === undefined
|
|
48
|
+
? this.getSchemaValue('range', { type: Array })?.[0]
|
|
49
|
+
: min
|
|
46
50
|
return this.isInteger && min != null ? Math.floor(min) : min
|
|
47
51
|
}
|
|
48
52
|
}),
|
|
@@ -50,9 +54,10 @@ export default {
|
|
|
50
54
|
max: getSchemaAccessor('max', {
|
|
51
55
|
type: Number,
|
|
52
56
|
get(max) {
|
|
53
|
-
max =
|
|
54
|
-
|
|
55
|
-
|
|
57
|
+
max =
|
|
58
|
+
max === undefined
|
|
59
|
+
? this.getSchemaValue('range', { type: Array })?.[1]
|
|
60
|
+
: max
|
|
56
61
|
return this.isInteger && max != null ? Math.ceil(max) : max
|
|
57
62
|
}
|
|
58
63
|
}),
|
|
@@ -70,7 +75,7 @@ export default {
|
|
|
70
75
|
// Provide a setter that delegates to `[this.min, this.max]`,
|
|
71
76
|
// since those already handle `schema.range`.
|
|
72
77
|
if (isArray(range)) {
|
|
73
|
-
[this.min, this.max] = range
|
|
78
|
+
;[this.min, this.max] = range
|
|
74
79
|
}
|
|
75
80
|
}
|
|
76
81
|
})
|
|
@@ -3,8 +3,13 @@ import DataMixin from './DataMixin.js'
|
|
|
3
3
|
import { getSchemaAccessor } from '../utils/accessor.js'
|
|
4
4
|
import { setTemporaryId, isReference } from '../utils/data.js'
|
|
5
5
|
import {
|
|
6
|
-
isObject,
|
|
7
|
-
|
|
6
|
+
isObject,
|
|
7
|
+
isArray,
|
|
8
|
+
isString,
|
|
9
|
+
isFunction,
|
|
10
|
+
normalizeDataPath,
|
|
11
|
+
labelize,
|
|
12
|
+
debounceAsync
|
|
8
13
|
} from '@ditojs/utils'
|
|
9
14
|
|
|
10
15
|
// @vue/component
|
|
@@ -20,17 +25,19 @@ export default {
|
|
|
20
25
|
computed: {
|
|
21
26
|
selectedValue: {
|
|
22
27
|
get() {
|
|
23
|
-
const convertValue = value =>
|
|
24
|
-
|
|
25
|
-
? this.
|
|
26
|
-
|
|
27
|
-
|
|
28
|
+
const convertValue = value =>
|
|
29
|
+
this.relate
|
|
30
|
+
? this.hasOption(value)
|
|
31
|
+
? this.getValueForOption(value)
|
|
32
|
+
: null
|
|
33
|
+
: value
|
|
28
34
|
const value = isArray(this.value)
|
|
29
35
|
? this.value.map(convertValue).filter(value => value !== null)
|
|
30
36
|
: convertValue(this.value)
|
|
31
37
|
if (
|
|
32
38
|
// When relating and as soon as the options are available...
|
|
33
|
-
this.relate &&
|
|
39
|
+
this.relate &&
|
|
40
|
+
this.hasOptions && (
|
|
34
41
|
// ...if the value is forced to null because a disappeared option...
|
|
35
42
|
value === null && this.value !== null ||
|
|
36
43
|
// ...or if the value is a reference, replace it with its option
|
|
@@ -38,15 +45,18 @@ export default {
|
|
|
38
45
|
isReference(this.value)
|
|
39
46
|
)
|
|
40
47
|
) {
|
|
48
|
+
// TODO: Fix side-effects
|
|
49
|
+
// eslint-disable-next-line vue/no-side-effects-in-computed-properties
|
|
41
50
|
this.selectedValue = value
|
|
42
51
|
}
|
|
43
52
|
return value
|
|
44
53
|
},
|
|
45
54
|
|
|
46
55
|
set(value) {
|
|
47
|
-
const convert = value =>
|
|
48
|
-
|
|
49
|
-
|
|
56
|
+
const convert = value =>
|
|
57
|
+
this.relate
|
|
58
|
+
? this.getOptionForValue(value)
|
|
59
|
+
: value
|
|
50
60
|
this.value = isArray(value)
|
|
51
61
|
? value.map(convert)
|
|
52
62
|
: convert(value)
|
|
@@ -64,6 +74,8 @@ export default {
|
|
|
64
74
|
if (!isArray(data)) {
|
|
65
75
|
throw new Error(`Invalid options data, should be array: ${data}`)
|
|
66
76
|
}
|
|
77
|
+
// TODO: Fix side-effects
|
|
78
|
+
// eslint-disable-next-line vue/no-side-effects-in-computed-properties
|
|
67
79
|
this.hasOptions = data.length > 0
|
|
68
80
|
return this.processOptions(data)
|
|
69
81
|
},
|
|
@@ -242,7 +254,7 @@ export default {
|
|
|
242
254
|
}
|
|
243
255
|
// Convert relating objects to a shallow copy with only the id left.
|
|
244
256
|
// TODO: Convert to using `relateBy`:
|
|
245
|
-
const processRelate = value => value ? { id: value.id } : value
|
|
257
|
+
const processRelate = value => (value ? { id: value.id } : value)
|
|
246
258
|
// Selected options can be both objects & arrays, e.g. 'checkboxes':
|
|
247
259
|
value = isArray(value)
|
|
248
260
|
? value.map(processRelate)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import ItemMixin from './ItemMixin.js'
|
|
2
2
|
import LoadingMixin from './LoadingMixin.js'
|
|
3
|
-
import {
|
|
3
|
+
import { setDefaultValues } from '../utils/schema.js'
|
|
4
4
|
import { isObject, isString, labelize } from '@ditojs/utils'
|
|
5
5
|
import { getResource } from '../utils/resource.js'
|
|
6
6
|
import DitoContext from '../DitoContext.js'
|
|
@@ -66,9 +66,10 @@ export default {
|
|
|
66
66
|
|
|
67
67
|
transientNote() {
|
|
68
68
|
return (
|
|
69
|
-
this.isTransient &&
|
|
70
|
-
|
|
71
|
-
|
|
69
|
+
this.isTransient && (
|
|
70
|
+
'<b>Note</b>: the parent still needs to be saved ' +
|
|
71
|
+
'in order to persist this change.'
|
|
72
|
+
)
|
|
72
73
|
)
|
|
73
74
|
},
|
|
74
75
|
|
|
@@ -99,6 +100,7 @@ export default {
|
|
|
99
100
|
const start = page * amount
|
|
100
101
|
return [start, start + amount - 1]
|
|
101
102
|
}
|
|
103
|
+
return null
|
|
102
104
|
},
|
|
103
105
|
|
|
104
106
|
queryParams() {
|
|
@@ -136,15 +138,15 @@ export default {
|
|
|
136
138
|
const verbs = this.$verbs()
|
|
137
139
|
return this.isTransient
|
|
138
140
|
? {
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
141
|
+
...verbs,
|
|
142
|
+
// Override default verbs with their transient versions:
|
|
143
|
+
create: 'add',
|
|
144
|
+
created: 'added',
|
|
145
|
+
save: 'apply',
|
|
146
|
+
saved: 'applied',
|
|
147
|
+
delete: 'remove',
|
|
148
|
+
deleted: 'removed'
|
|
149
|
+
}
|
|
148
150
|
: verbs
|
|
149
151
|
},
|
|
150
152
|
|
|
@@ -189,7 +191,7 @@ export default {
|
|
|
189
191
|
},
|
|
190
192
|
|
|
191
193
|
createData(schema, type) {
|
|
192
|
-
return
|
|
194
|
+
return setDefaultValues(schema, type ? { type } : {}, this)
|
|
193
195
|
},
|
|
194
196
|
|
|
195
197
|
requestData() {
|
|
@@ -200,7 +202,8 @@ export default {
|
|
|
200
202
|
const { data } = response
|
|
201
203
|
if (
|
|
202
204
|
data?.type === 'FilterValidation' &&
|
|
203
|
-
this.onFilterErrors?.(data.errors)
|
|
205
|
+
this.onFilterErrors?.(data.errors)
|
|
206
|
+
) {
|
|
204
207
|
return true
|
|
205
208
|
} else if (this.isUnauthorizedError(response)) {
|
|
206
209
|
// TODO: Can we really swallow these errors?
|
|
@@ -223,12 +226,15 @@ export default {
|
|
|
223
226
|
return response?.status === 401
|
|
224
227
|
},
|
|
225
228
|
|
|
226
|
-
async handleRequest(
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
229
|
+
async handleRequest(
|
|
230
|
+
{
|
|
231
|
+
method,
|
|
232
|
+
resource = this.resource,
|
|
233
|
+
query,
|
|
234
|
+
data
|
|
235
|
+
},
|
|
236
|
+
callback
|
|
237
|
+
) {
|
|
232
238
|
const loadingOptions = {
|
|
233
239
|
updateRoot: true, // Display spinner in header when loading in resources
|
|
234
240
|
updateView: this.isInView // Notify view of loading for view components
|
|
@@ -283,19 +289,21 @@ export default {
|
|
|
283
289
|
setData = false,
|
|
284
290
|
onSuccess,
|
|
285
291
|
onError,
|
|
286
|
-
notifySuccess = () =>
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
292
|
+
notifySuccess = () =>
|
|
293
|
+
this.notify({
|
|
294
|
+
type: 'success',
|
|
295
|
+
title: 'Request Successful',
|
|
296
|
+
text: 'Request was successfully sent.'
|
|
297
|
+
}),
|
|
298
|
+
notifyError = error =>
|
|
299
|
+
this.notify({
|
|
300
|
+
type: 'error',
|
|
301
|
+
title: 'Request Error',
|
|
302
|
+
text: [
|
|
303
|
+
`Unable to send request${error ? ':' : ''}`,
|
|
304
|
+
error?.message || error
|
|
305
|
+
]
|
|
306
|
+
})
|
|
299
307
|
} = {}) {
|
|
300
308
|
return new Promise(resolve => {
|
|
301
309
|
this.handleRequest(
|
package/src/mixins/RouteMixin.js
CHANGED
|
@@ -11,14 +11,6 @@ export default {
|
|
|
11
11
|
}
|
|
12
12
|
},
|
|
13
13
|
|
|
14
|
-
beforeRouteUpdate(to, from, next) {
|
|
15
|
-
this?.beforeRouteChange(to, from, next)
|
|
16
|
-
},
|
|
17
|
-
|
|
18
|
-
beforeRouteLeave(to, from, next) {
|
|
19
|
-
this?.beforeRouteChange(to, from, next)
|
|
20
|
-
},
|
|
21
|
-
|
|
22
14
|
data() {
|
|
23
15
|
return {
|
|
24
16
|
reload: false,
|
|
@@ -110,6 +102,14 @@ export default {
|
|
|
110
102
|
}
|
|
111
103
|
},
|
|
112
104
|
|
|
105
|
+
beforeRouteUpdate(to, from, next) {
|
|
106
|
+
this?.beforeRouteChange(to, from, next)
|
|
107
|
+
},
|
|
108
|
+
|
|
109
|
+
beforeRouteLeave(to, from, next) {
|
|
110
|
+
this?.beforeRouteChange(to, from, next)
|
|
111
|
+
},
|
|
112
|
+
|
|
113
113
|
created() {
|
|
114
114
|
// Keep a shared stack of root components for DitoTrail to use to render
|
|
115
115
|
// labels. Can't rely on $route.matched[i].instances.default unfortunately,
|
|
@@ -4,14 +4,27 @@ import SchemaParentMixin from '../mixins/SchemaParentMixin.js'
|
|
|
4
4
|
import { getSchemaAccessor, getStoreAccessor } from '../utils/accessor.js'
|
|
5
5
|
import { getMemberResource } from '../utils/resource.js'
|
|
6
6
|
import {
|
|
7
|
-
processRouteSchema,
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
processRouteSchema,
|
|
8
|
+
processForms,
|
|
9
|
+
getNamedSchemas,
|
|
10
|
+
getButtonSchemas,
|
|
11
|
+
hasFormSchema,
|
|
12
|
+
getFormSchemas,
|
|
13
|
+
getViewSchema,
|
|
14
|
+
hasLabels,
|
|
15
|
+
isCompact,
|
|
16
|
+
isInlined,
|
|
17
|
+
isObjectSource,
|
|
18
|
+
isListSource
|
|
11
19
|
} from '../utils/schema.js'
|
|
12
20
|
import {
|
|
13
|
-
isObject,
|
|
14
|
-
|
|
21
|
+
isObject,
|
|
22
|
+
isString,
|
|
23
|
+
isArray,
|
|
24
|
+
isNumber,
|
|
25
|
+
equals,
|
|
26
|
+
parseDataPath,
|
|
27
|
+
normalizeDataPath
|
|
15
28
|
} from '@ditojs/utils'
|
|
16
29
|
|
|
17
30
|
// @vue/component
|
|
@@ -85,9 +98,13 @@ export default {
|
|
|
85
98
|
if (this.unwrappingPrimitives) {
|
|
86
99
|
// We're done unwrapping once `listData` is reevaluated, so set
|
|
87
100
|
// this to `false` again. See `wrappedPrimitives` watcher above.
|
|
101
|
+
// TODO: Fix side-effects
|
|
102
|
+
// eslint-disable-next-line
|
|
88
103
|
this.unwrappingPrimitives = false
|
|
89
104
|
} else {
|
|
90
105
|
// Convert data to a list of wrapped primitives, and return it.
|
|
106
|
+
// TODO: Fix side-effects
|
|
107
|
+
// eslint-disable-next-line
|
|
91
108
|
this.wrappedPrimitives = data.map(value => ({
|
|
92
109
|
[wrapPrimitives]: value
|
|
93
110
|
}))
|
|
@@ -102,7 +119,9 @@ export default {
|
|
|
102
119
|
this.wrappedPrimitives = data
|
|
103
120
|
} else {
|
|
104
121
|
this.value = this.isObjectSource
|
|
105
|
-
?
|
|
122
|
+
? data && data.length > 0
|
|
123
|
+
? data[0]
|
|
124
|
+
: null
|
|
106
125
|
: data
|
|
107
126
|
}
|
|
108
127
|
}
|
|
@@ -178,8 +197,8 @@ export default {
|
|
|
178
197
|
},
|
|
179
198
|
|
|
180
199
|
defaultScope() {
|
|
200
|
+
let first = null
|
|
181
201
|
if (this.scopes) {
|
|
182
|
-
let first = null
|
|
183
202
|
for (const scope of Object.values(this.scopes)) {
|
|
184
203
|
if (scope.defaultScope) {
|
|
185
204
|
return scope
|
|
@@ -188,8 +207,8 @@ export default {
|
|
|
188
207
|
first = scope
|
|
189
208
|
}
|
|
190
209
|
}
|
|
191
|
-
return first
|
|
192
210
|
}
|
|
211
|
+
return first
|
|
193
212
|
},
|
|
194
213
|
|
|
195
214
|
defaultOrder() {
|
|
@@ -202,6 +221,7 @@ export default {
|
|
|
202
221
|
}
|
|
203
222
|
}
|
|
204
223
|
}
|
|
224
|
+
return null
|
|
205
225
|
},
|
|
206
226
|
|
|
207
227
|
nestedMeta() {
|
|
@@ -408,22 +428,29 @@ export default {
|
|
|
408
428
|
},
|
|
409
429
|
|
|
410
430
|
deleteItem(item, index) {
|
|
411
|
-
const label =
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
431
|
+
const label = (
|
|
432
|
+
item &&
|
|
433
|
+
this.getItemLabel(this.schema, item, {
|
|
434
|
+
index,
|
|
435
|
+
extended: true
|
|
436
|
+
})
|
|
437
|
+
)
|
|
415
438
|
|
|
416
|
-
const notify = () =>
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
439
|
+
const notify = () =>
|
|
440
|
+
this.notify({
|
|
441
|
+
type: this.isTransient ? 'info' : 'success',
|
|
442
|
+
title: 'Successfully Removed',
|
|
443
|
+
text: [
|
|
444
|
+
`${label} was ${this.verbs.deleted}.`,
|
|
445
|
+
this.transientNote
|
|
446
|
+
]
|
|
447
|
+
})
|
|
424
448
|
|
|
425
|
-
if (
|
|
426
|
-
|
|
449
|
+
if (
|
|
450
|
+
item &&
|
|
451
|
+
window.confirm(
|
|
452
|
+
`Do you really want to ${this.verbs.delete} ${label}?`
|
|
453
|
+
)
|
|
427
454
|
) {
|
|
428
455
|
if (this.isTransient) {
|
|
429
456
|
this.removeItem(item)
|
|
@@ -505,11 +532,12 @@ export default {
|
|
|
505
532
|
const { matched } = this.$router.match(path)
|
|
506
533
|
if (matched.length) {
|
|
507
534
|
if (this.$route.path === path) {
|
|
508
|
-
|
|
535
|
+
// We're already there, so just call `onComplete()`:
|
|
509
536
|
callOnComplete()
|
|
510
537
|
} else {
|
|
511
|
-
|
|
512
|
-
this.$router
|
|
538
|
+
// Navigate to the component's path, then call `onComplete()`_:
|
|
539
|
+
this.$router
|
|
540
|
+
.push({ path })
|
|
513
541
|
.catch(reject)
|
|
514
542
|
// Wait for the last route component to be mounted in the next
|
|
515
543
|
// tick before calling `onComplete()`
|
|
@@ -527,8 +555,13 @@ export default {
|
|
|
527
555
|
}, // end of `methods`
|
|
528
556
|
|
|
529
557
|
async processSchema(
|
|
530
|
-
api,
|
|
531
|
-
|
|
558
|
+
api,
|
|
559
|
+
schema,
|
|
560
|
+
name,
|
|
561
|
+
routes,
|
|
562
|
+
level,
|
|
563
|
+
nested = false,
|
|
564
|
+
flatten = false,
|
|
532
565
|
process = null
|
|
533
566
|
) {
|
|
534
567
|
processRouteSchema(api, schema, name)
|
|
@@ -560,11 +593,12 @@ export default {
|
|
|
560
593
|
}
|
|
561
594
|
// Inlined forms don't need to actually add routes.
|
|
562
595
|
if (hasFormSchema(schema) && !inlined) {
|
|
563
|
-
const getPathWithParam = (path, param) =>
|
|
564
|
-
|
|
565
|
-
?
|
|
566
|
-
|
|
567
|
-
|
|
596
|
+
const getPathWithParam = (path, param) =>
|
|
597
|
+
param
|
|
598
|
+
? path
|
|
599
|
+
? `${path}/:${param}`
|
|
600
|
+
: `:${param}`
|
|
601
|
+
: path
|
|
568
602
|
|
|
569
603
|
// Lists in single-component-views (level === 0) use their view's path,
|
|
570
604
|
// while all others need their path prefixed with the parent's path:
|
|
@@ -574,7 +608,7 @@ export default {
|
|
|
574
608
|
// directly edit one object.
|
|
575
609
|
path: getPathWithParam(sourcePath, isListSource(schema) && param),
|
|
576
610
|
component: DitoComponent.component(
|
|
577
|
-
nested ? '
|
|
611
|
+
nested ? 'DitoFormNested' : 'DitoForm'
|
|
578
612
|
),
|
|
579
613
|
meta: formMeta
|
|
580
614
|
}
|