@ditojs/admin 2.75.1 → 2.77.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 +1776 -1730
- package/dist/dito-admin.umd.js +5 -5
- package/package.json +5 -5
- package/src/DitoContext.js +7 -4
- package/src/components/DitoAffixes.vue +6 -0
- package/src/components/DitoContainer.vue +1 -1
- package/src/components/DitoCreateButton.vue +6 -1
- package/src/components/DitoLabel.vue +2 -0
- package/src/components/DitoNotifications.vue +8 -3
- package/src/components/DitoPane.vue +4 -3
- package/src/components/DitoRoot.vue +2 -2
- package/src/components/DitoSchema.vue +7 -3
- package/src/components/DitoView.vue +1 -0
- package/src/mixins/SourceMixin.js +17 -3
- package/src/mixins/TypeMixin.js +11 -0
- package/src/types/DitoTypeButton.vue +0 -5
- package/src/types/DitoTypeColor.vue +1 -0
- package/src/types/DitoTypeDate.vue +1 -0
- package/src/types/DitoTypeList.vue +3 -3
- package/src/types/DitoTypeMultiselect.vue +4 -3
- package/src/types/DitoTypeNumber.vue +1 -0
- package/src/types/DitoTypeObject.vue +1 -1
- package/src/types/DitoTypeSelect.vue +1 -0
- package/src/types/DitoTypeText.vue +1 -0
- package/src/types/DitoTypeTreeList.vue +3 -2
- package/src/utils/schema.js +7 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ditojs/admin",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.77.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/master/packages/admin",
|
|
@@ -42,8 +42,8 @@
|
|
|
42
42
|
"not ie_mob > 0"
|
|
43
43
|
],
|
|
44
44
|
"dependencies": {
|
|
45
|
-
"@ditojs/ui": "^2.
|
|
46
|
-
"@ditojs/utils": "^2.
|
|
45
|
+
"@ditojs/ui": "^2.77.0",
|
|
46
|
+
"@ditojs/utils": "^2.77.0",
|
|
47
47
|
"@kyvg/vue3-notification": "^3.4.2",
|
|
48
48
|
"@lk77/vue3-color": "^3.0.6",
|
|
49
49
|
"@tiptap/core": "^3.15.3",
|
|
@@ -89,9 +89,9 @@
|
|
|
89
89
|
"vue-upload-component": "^3.1.17"
|
|
90
90
|
},
|
|
91
91
|
"devDependencies": {
|
|
92
|
-
"@ditojs/build": "^2.
|
|
92
|
+
"@ditojs/build": "^2.77.0",
|
|
93
93
|
"typescript": "^5.9.3",
|
|
94
94
|
"vite": "^7.3.1"
|
|
95
95
|
},
|
|
96
|
-
"gitHead": "
|
|
96
|
+
"gitHead": "d2cff77924d989aad5ab601cf08433a4e683ac6d"
|
|
97
97
|
}
|
package/src/DitoContext.js
CHANGED
|
@@ -260,10 +260,9 @@ export default class DitoContext {
|
|
|
260
260
|
return get(this, 'open', undefined)
|
|
261
261
|
}
|
|
262
262
|
|
|
263
|
-
//
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
return get(this, 'query', undefined)
|
|
263
|
+
// For search term in selects:
|
|
264
|
+
get searchTerm() {
|
|
265
|
+
return get(this, 'searchTerm', undefined)
|
|
267
266
|
}
|
|
268
267
|
|
|
269
268
|
// The error field is only populated in the context of buttons that send
|
|
@@ -284,6 +283,10 @@ export default class DitoContext {
|
|
|
284
283
|
set(this, 'isRunning', value)
|
|
285
284
|
}
|
|
286
285
|
|
|
286
|
+
get query() {
|
|
287
|
+
return this.component.$route.query
|
|
288
|
+
}
|
|
289
|
+
|
|
287
290
|
// Helper Methods
|
|
288
291
|
|
|
289
292
|
get request() {
|
|
@@ -21,6 +21,10 @@
|
|
|
21
21
|
@mousedown.stop
|
|
22
22
|
)
|
|
23
23
|
slot(name="append")
|
|
24
|
+
.dito-info(
|
|
25
|
+
v-if="inlineInfo"
|
|
26
|
+
:data-info="inlineInfo"
|
|
27
|
+
)
|
|
24
28
|
</template>
|
|
25
29
|
|
|
26
30
|
<script>
|
|
@@ -41,6 +45,7 @@ export default DitoComponent.component('DitoAffixes', {
|
|
|
41
45
|
absolute: { type: Boolean, default: false },
|
|
42
46
|
clearable: { type: Boolean, default: false },
|
|
43
47
|
disabled: { type: Boolean, default: false },
|
|
48
|
+
inlineInfo: { type: String, default: null },
|
|
44
49
|
parentContext: { type: Object, required: true }
|
|
45
50
|
},
|
|
46
51
|
|
|
@@ -85,6 +90,7 @@ export default DitoComponent.component('DitoAffixes', {
|
|
|
85
90
|
return (
|
|
86
91
|
this.visibleItems.length > 0 ||
|
|
87
92
|
this.clearable ||
|
|
93
|
+
this.inlineInfo ||
|
|
88
94
|
hasSlotContent(this.$slots.prepend) ||
|
|
89
95
|
hasSlotContent(this.$slots.append)
|
|
90
96
|
)
|
|
@@ -210,9 +210,9 @@ export default DitoComponent.component('DitoContainer', {
|
|
|
210
210
|
const { class: classes } = this.schema
|
|
211
211
|
const prefix = 'dito-container'
|
|
212
212
|
return {
|
|
213
|
-
[`${prefix}--single`]: this.single,
|
|
214
213
|
[`${prefix}--disabled`]: this.componentDisabled,
|
|
215
214
|
[`${prefix}--has-errors`]: !!this.errors,
|
|
215
|
+
[`${prefix}--single`]: this.single,
|
|
216
216
|
[`${prefix}--compact`]: this.compact,
|
|
217
217
|
[`${prefix}--label-vertical`]: this.verticalLabels,
|
|
218
218
|
[`${prefix}--omit-spacing`]: omitSpacing(this.schema),
|
|
@@ -105,9 +105,14 @@ export default DitoComponent.component('DitoCreateButton', {
|
|
|
105
105
|
if (this.isInlined) {
|
|
106
106
|
this.sourceComponent.createItem(form, type)
|
|
107
107
|
} else {
|
|
108
|
+
const { creatable } = this.schema
|
|
109
|
+
const query = {
|
|
110
|
+
...(type && { type }),
|
|
111
|
+
...creatable?.query?.(this.context)
|
|
112
|
+
}
|
|
108
113
|
this.$router.push({
|
|
109
114
|
path: `${this.path}/create`,
|
|
110
|
-
query
|
|
115
|
+
query
|
|
111
116
|
})
|
|
112
117
|
}
|
|
113
118
|
} else {
|
|
@@ -23,7 +23,7 @@ export default DitoComponent.component('DitoNotifications', {
|
|
|
23
23
|
},
|
|
24
24
|
|
|
25
25
|
methods: {
|
|
26
|
-
notify({ type = 'info', title, text, error } = {}) {
|
|
26
|
+
notify({ type = 'info', title, text, error, duration } = {}) {
|
|
27
27
|
title ||= (
|
|
28
28
|
{
|
|
29
29
|
warning: 'Warning',
|
|
@@ -59,8 +59,13 @@ export default DitoComponent.component('DitoNotifications', {
|
|
|
59
59
|
// amount of milliseconds multiplied with the amount of characters
|
|
60
60
|
// displayed in the notification, plus 40 (40 + title + message):
|
|
61
61
|
const { durationFactor = 20 } = notifications
|
|
62
|
-
|
|
63
|
-
this.$notify({
|
|
62
|
+
duration ??= (40 + text.length + title.length) * durationFactor
|
|
63
|
+
this.$notify({
|
|
64
|
+
type,
|
|
65
|
+
title,
|
|
66
|
+
text,
|
|
67
|
+
duration: duration === 0 ? -1 : duration // < 0 -> <= 0 = sticky
|
|
68
|
+
})
|
|
64
69
|
}
|
|
65
70
|
},
|
|
66
71
|
|
|
@@ -65,8 +65,8 @@ export default DitoComponent.component('DitoPane', {
|
|
|
65
65
|
meta: { type: Object, required: true },
|
|
66
66
|
store: { type: Object, required: true },
|
|
67
67
|
tab: { type: String, default: null },
|
|
68
|
-
padding: { type: String, default: null },
|
|
69
68
|
single: { type: Boolean, default: false },
|
|
69
|
+
padding: { type: String, default: null },
|
|
70
70
|
disabled: { type: Boolean, default: false },
|
|
71
71
|
compact: { type: Boolean, default: false },
|
|
72
72
|
generateLabels: { type: Boolean, default: false },
|
|
@@ -86,9 +86,10 @@ export default DitoComponent.component('DitoPane', {
|
|
|
86
86
|
},
|
|
87
87
|
|
|
88
88
|
classes() {
|
|
89
|
+
const prefix = 'dito-pane'
|
|
89
90
|
return {
|
|
90
|
-
|
|
91
|
-
[
|
|
91
|
+
[`${prefix}--single`]: this.isSingleComponent,
|
|
92
|
+
[`${prefix}--padding-${this.padding}`]: !!this.padding
|
|
92
93
|
}
|
|
93
94
|
},
|
|
94
95
|
|
|
@@ -231,8 +231,8 @@ export default DitoComponent.component('DitoRoot', {
|
|
|
231
231
|
})
|
|
232
232
|
},
|
|
233
233
|
|
|
234
|
-
notify({ type = 'info', title, text, error } = {}) {
|
|
235
|
-
this.notifications.notify({ type, title, text, error })
|
|
234
|
+
notify({ type = 'info', title, text, error, duration } = {}) {
|
|
235
|
+
this.notifications.notify({ type, title, text, error, duration })
|
|
236
236
|
},
|
|
237
237
|
|
|
238
238
|
closeNotifications() {
|
|
@@ -72,7 +72,7 @@ slot(name="prepend")
|
|
|
72
72
|
:meta="meta"
|
|
73
73
|
:store="store"
|
|
74
74
|
:padding="padding"
|
|
75
|
-
:single="!inlined && !hasMainPane"
|
|
75
|
+
:single="single && !inlined && !hasMainPane"
|
|
76
76
|
:disabled="disabled"
|
|
77
77
|
:compact="compact"
|
|
78
78
|
:generateLabels="generateLabels"
|
|
@@ -87,7 +87,7 @@ slot(name="prepend")
|
|
|
87
87
|
:meta="meta"
|
|
88
88
|
:store="store"
|
|
89
89
|
:padding="padding"
|
|
90
|
-
:single="!inlined && !hasTabs"
|
|
90
|
+
:single="single && !inlined && !hasTabs"
|
|
91
91
|
:disabled="disabled"
|
|
92
92
|
:compact="compact"
|
|
93
93
|
:generateLabels="generateLabels"
|
|
@@ -156,6 +156,7 @@ export default DitoComponent.component('DitoSchema', {
|
|
|
156
156
|
meta: { type: Object, default: () => ({}) },
|
|
157
157
|
store: { type: Object, default: () => ({}) },
|
|
158
158
|
label: { type: [String, Object], default: null },
|
|
159
|
+
single: { type: Boolean, default: false },
|
|
159
160
|
padding: { type: String, default: null },
|
|
160
161
|
active: { type: Boolean, default: true },
|
|
161
162
|
inlined: { type: Boolean, default: false },
|
|
@@ -395,7 +396,10 @@ export default DitoComponent.component('DitoSchema', {
|
|
|
395
396
|
const tab = this.shouldRenderSchema(this.tabs[newTab])
|
|
396
397
|
? newTab
|
|
397
398
|
: this.defaultTab
|
|
398
|
-
this.$router.replace({
|
|
399
|
+
this.$router.replace({
|
|
400
|
+
query: this.$route.query,
|
|
401
|
+
hash: tab ? `#${tab}` : null
|
|
402
|
+
})
|
|
399
403
|
}
|
|
400
404
|
if (this.hasErrors) {
|
|
401
405
|
this.repositionErrors()
|
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
hasFormSchema,
|
|
14
14
|
getFormSchemas,
|
|
15
15
|
getViewSchema,
|
|
16
|
+
getViewPath,
|
|
16
17
|
isCompact,
|
|
17
18
|
isInlined,
|
|
18
19
|
isObjectSource,
|
|
@@ -187,13 +188,16 @@ export default {
|
|
|
187
188
|
// the route query parameters to override them.
|
|
188
189
|
const {
|
|
189
190
|
scope = this.defaultScope?.name,
|
|
190
|
-
page = this.schema.page
|
|
191
|
+
page = this.schema.page,
|
|
192
|
+
type
|
|
191
193
|
} = this.query
|
|
192
|
-
// Preserve / merge currently stored values
|
|
194
|
+
// Preserve / merge currently stored values, including any custom query
|
|
195
|
+
// parameters added by creatable.query
|
|
193
196
|
query = {
|
|
194
197
|
...this.query,
|
|
195
198
|
...(scope != null && { scope }),
|
|
196
199
|
...(page != null && { page }),
|
|
200
|
+
...(type != null && { type }),
|
|
197
201
|
...query
|
|
198
202
|
}
|
|
199
203
|
if (!equals(query, this.$route.query)) {
|
|
@@ -337,7 +341,17 @@ export default {
|
|
|
337
341
|
maxDepth: getSchemaAccessor('maxDepth', {
|
|
338
342
|
type: Number,
|
|
339
343
|
default: 1
|
|
340
|
-
})
|
|
344
|
+
}),
|
|
345
|
+
|
|
346
|
+
createPath() {
|
|
347
|
+
if (this.creatable) {
|
|
348
|
+
return (
|
|
349
|
+
getViewPath(this.schema, this.context) ||
|
|
350
|
+
this.path
|
|
351
|
+
)
|
|
352
|
+
}
|
|
353
|
+
return null
|
|
354
|
+
}
|
|
341
355
|
},
|
|
342
356
|
|
|
343
357
|
watch: {
|
package/src/mixins/TypeMixin.js
CHANGED
|
@@ -101,6 +101,17 @@ export default {
|
|
|
101
101
|
type: String
|
|
102
102
|
}),
|
|
103
103
|
|
|
104
|
+
info: getSchemaAccessor('info', {
|
|
105
|
+
type: String,
|
|
106
|
+
default: null
|
|
107
|
+
}),
|
|
108
|
+
|
|
109
|
+
inlineInfo() {
|
|
110
|
+
// When a label is present, info is shown in the label component.
|
|
111
|
+
// Otherwise, we have to show it inline.
|
|
112
|
+
return !this.label ? this.info : null
|
|
113
|
+
},
|
|
114
|
+
|
|
104
115
|
events() {
|
|
105
116
|
const events = this.getEvents()
|
|
106
117
|
// Register callbacks for all provides non-recognized events,
|
|
@@ -107,6 +107,7 @@
|
|
|
107
107
|
v-if="hasCellEditButtons"
|
|
108
108
|
)
|
|
109
109
|
DitoEditButtons(
|
|
110
|
+
nested
|
|
110
111
|
:schema="getItemFormSchema(schema, item, context)"
|
|
111
112
|
:dataPath="getDataPath(index)"
|
|
112
113
|
:data="item"
|
|
@@ -132,10 +133,9 @@
|
|
|
132
133
|
:data="listData"
|
|
133
134
|
:meta="meta"
|
|
134
135
|
:store="store"
|
|
135
|
-
:nested="nested"
|
|
136
136
|
:disabled="disabled || isLoading"
|
|
137
137
|
:creatable="creatable"
|
|
138
|
-
:createPath="
|
|
138
|
+
:createPath="createPath"
|
|
139
139
|
)
|
|
140
140
|
//- Render create buttons outside table when in a single component view:
|
|
141
141
|
DitoEditButtons.dito-buttons--large.dito-buttons--main.dito-buttons--sticky(
|
|
@@ -148,7 +148,7 @@
|
|
|
148
148
|
:store="store"
|
|
149
149
|
:disabled="disabled || isLoading"
|
|
150
150
|
:creatable="creatable"
|
|
151
|
-
:createPath="
|
|
151
|
+
:createPath="createPath"
|
|
152
152
|
)
|
|
153
153
|
</template>
|
|
154
154
|
|
|
@@ -42,6 +42,7 @@
|
|
|
42
42
|
absolute
|
|
43
43
|
:clearable="showClearButton"
|
|
44
44
|
:disabled="disabled"
|
|
45
|
+
:inlineInfo="inlineInfo"
|
|
45
46
|
:parentContext="context"
|
|
46
47
|
@clear="clear"
|
|
47
48
|
)
|
|
@@ -221,14 +222,14 @@ export default DitoTypeComponent.register('multiselect', {
|
|
|
221
222
|
}
|
|
222
223
|
},
|
|
223
224
|
|
|
224
|
-
async onSearchChange(
|
|
225
|
+
async onSearchChange(searchTerm) {
|
|
225
226
|
if (this.searchFilter) {
|
|
226
|
-
if (
|
|
227
|
+
if (searchTerm) {
|
|
227
228
|
// Set `searchedOptions` to an empty array, before it will be
|
|
228
229
|
// populated asynchronously with the actual results.
|
|
229
230
|
this.searchedOptions = []
|
|
230
231
|
this.searchedOptions = await this.resolveData(
|
|
231
|
-
() => this.searchFilter(new DitoContext(this, {
|
|
232
|
+
() => this.searchFilter(new DitoContext(this, { searchTerm }))
|
|
232
233
|
)
|
|
233
234
|
} else {
|
|
234
235
|
// Clear `searchedOptions` when the query is cleared.
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
@update:data="data => (value = data)"
|
|
16
16
|
)
|
|
17
17
|
.dito-tree-form-container(
|
|
18
|
-
v-if="hasEditableForms"
|
|
18
|
+
v-if="editPath && hasEditableForms"
|
|
19
19
|
)
|
|
20
20
|
//- Include a router-view for the optional DitoFormInlined
|
|
21
21
|
RouterView
|
|
@@ -52,7 +52,8 @@ export default DitoTypeComponent.register(
|
|
|
52
52
|
|
|
53
53
|
editPath() {
|
|
54
54
|
// Accessed from DitoTreeItem through `container.editPath`:
|
|
55
|
-
|
|
55
|
+
const path = this.$route.path.slice(this.path?.length)
|
|
56
|
+
return path.startsWith(`/${this.schema.path}`) ? path : ''
|
|
56
57
|
},
|
|
57
58
|
|
|
58
59
|
treeData() {
|
package/src/utils/schema.js
CHANGED
|
@@ -491,17 +491,21 @@ export function hasViewSchema(schema, context) {
|
|
|
491
491
|
return !!getViewSchema(schema, context)
|
|
492
492
|
}
|
|
493
493
|
|
|
494
|
-
export function
|
|
494
|
+
export function getViewPath(schema, context) {
|
|
495
495
|
const view = getViewSchema(schema, context)
|
|
496
496
|
if (view) {
|
|
497
|
-
|
|
497
|
+
return isSingleComponentView(view)
|
|
498
498
|
? view.fullPath
|
|
499
499
|
: `${view.fullPath}/${view.path}`
|
|
500
|
-
return `${path}/${id}`
|
|
501
500
|
}
|
|
502
501
|
return null
|
|
503
502
|
}
|
|
504
503
|
|
|
504
|
+
export function getViewEditPath(schema, id, context) {
|
|
505
|
+
const path = getViewPath(schema, context)
|
|
506
|
+
return path ? `${path}/${id}` : null
|
|
507
|
+
}
|
|
508
|
+
|
|
505
509
|
export function getFormSchemas(schema, context, modifyForm) {
|
|
506
510
|
const viewSchema = context && getViewFormSchema(schema, context)
|
|
507
511
|
if (viewSchema) {
|