@ditojs/admin 2.6.5 → 2.6.7
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 +529 -503
- package/dist/dito-admin.umd.js +5 -5
- package/dist/style.css +1 -1
- package/package.json +2 -2
- package/src/components/DitoContainer.vue +29 -21
- package/src/components/DitoMenu.vue +13 -9
- package/src/components/DitoPane.vue +7 -6
- package/src/components/DitoRoot.vue +3 -2
- package/src/components/DitoSchema.vue +4 -1
- package/src/components/DitoSchemaInlined.vue +3 -1
- package/src/components/DitoSidebar.vue +1 -1
- package/src/mixins/RouteMixin.js +8 -5
- package/src/mixins/TypeMixin.js +2 -1
- package/src/styles/_layout.scss +1 -1
- package/src/types/DitoTypeButton.vue +1 -1
- package/src/types/DitoTypeCheckboxes.vue +1 -0
- package/src/types/DitoTypeMultiselect.vue +8 -4
- package/src/types/DitoTypeObject.vue +1 -0
- package/src/types/DitoTypeRadio.vue +2 -1
- package/src/utils/schema.js +15 -15
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ditojs/admin",
|
|
3
|
-
"version": "2.6.
|
|
3
|
+
"version": "2.6.7",
|
|
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": "^4.3.4"
|
|
84
84
|
},
|
|
85
85
|
"types": "types",
|
|
86
|
-
"gitHead": "
|
|
86
|
+
"gitHead": "b192b2ffad1ff1c9e2e228a7b4a0ca86c8184028",
|
|
87
87
|
"scripts": {
|
|
88
88
|
"build": "vite build",
|
|
89
89
|
"watch": "yarn build --mode 'development' --watch",
|
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
:single="single"
|
|
25
25
|
:nested="nested"
|
|
26
26
|
:disabled="componentDisabled"
|
|
27
|
+
:accumulatedBasis="combinedBasis"
|
|
27
28
|
@errors="onErrors"
|
|
28
29
|
)
|
|
29
30
|
DitoErrors(:errors="errors")
|
|
@@ -49,7 +50,8 @@ export default DitoComponent.component('DitoContainer', {
|
|
|
49
50
|
nested: { type: Boolean, default: true },
|
|
50
51
|
disabled: { type: Boolean, required: true },
|
|
51
52
|
generateLabels: { type: Boolean, default: false },
|
|
52
|
-
verticalLabels: { type: Boolean, default: false }
|
|
53
|
+
verticalLabels: { type: Boolean, default: false },
|
|
54
|
+
accumulatedBasis: { type: Number, default: null }
|
|
53
55
|
},
|
|
54
56
|
|
|
55
57
|
data() {
|
|
@@ -140,14 +142,20 @@ export default DitoComponent.component('DitoContainer', {
|
|
|
140
142
|
flexBasis() {
|
|
141
143
|
const width = this.width
|
|
142
144
|
// 'auto' = no fitting:
|
|
143
|
-
|
|
145
|
+
return [null, 'auto', 'fill'].includes(width)
|
|
144
146
|
? 'auto'
|
|
145
147
|
: /%$/.test(width)
|
|
146
|
-
? parseFloat(width) // percentage
|
|
148
|
+
? parseFloat(width) / 100 // percentage -> fraction
|
|
147
149
|
: /[a-z]/.test(width)
|
|
148
150
|
? width // native units
|
|
149
|
-
: parseFraction(width)
|
|
150
|
-
|
|
151
|
+
: parseFraction(width) // fraction
|
|
152
|
+
},
|
|
153
|
+
|
|
154
|
+
combinedBasis() {
|
|
155
|
+
const { accumulatedBasis, flexBasis } = this
|
|
156
|
+
return isNumber(accumulatedBasis) && isNumber(flexBasis)
|
|
157
|
+
? accumulatedBasis * flexBasis
|
|
158
|
+
: null
|
|
151
159
|
},
|
|
152
160
|
|
|
153
161
|
containerClass() {
|
|
@@ -166,10 +174,15 @@ export default DitoComponent.component('DitoContainer', {
|
|
|
166
174
|
},
|
|
167
175
|
|
|
168
176
|
containerStyle() {
|
|
177
|
+
const { flexBasis, combinedBasis } = this
|
|
169
178
|
return {
|
|
170
179
|
'--grow': this.flexGrow ? 1 : 0,
|
|
171
180
|
'--shrink': this.flexShrink ? 1 : 0,
|
|
172
|
-
'--basis':
|
|
181
|
+
'--basis': isNumber(flexBasis) ? `${flexBasis * 100}%` : flexBasis,
|
|
182
|
+
'--basis-mobile':
|
|
183
|
+
isNumber(combinedBasis) && combinedBasis <= 0.25
|
|
184
|
+
? `${flexBasis * 200}%`
|
|
185
|
+
: null
|
|
173
186
|
}
|
|
174
187
|
},
|
|
175
188
|
|
|
@@ -207,8 +220,6 @@ export default DitoComponent.component('DitoContainer', {
|
|
|
207
220
|
flex: var(--grow) var(--shrink) var(--basis);
|
|
208
221
|
flex-flow: column;
|
|
209
222
|
align-items: flex-start;
|
|
210
|
-
// Needed for better vertical alignment:
|
|
211
|
-
align-self: stretch;
|
|
212
223
|
box-sizing: border-box;
|
|
213
224
|
// To prevent list tables from blowing out of their flex box containers.
|
|
214
225
|
max-width: 100%;
|
|
@@ -216,31 +227,28 @@ export default DitoComponent.component('DitoContainer', {
|
|
|
216
227
|
// percentages in flex-basis to work.
|
|
217
228
|
padding: $form-spacing $form-spacing-half;
|
|
218
229
|
|
|
219
|
-
.dito-page & {
|
|
220
|
-
@container (width < #{$content-width}) {
|
|
221
|
-
flex-grow: 1;
|
|
222
|
-
}
|
|
223
|
-
|
|
230
|
+
.dito-page .dito-pane > & {
|
|
224
231
|
@container (width < #{calc($content-width * 0.8)}) {
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
232
|
+
flex-grow: 1;
|
|
233
|
+
flex-basis: var(--basis-mobile, var(--basis));
|
|
234
|
+
// DEBUG: background: yellow;
|
|
228
235
|
}
|
|
229
236
|
|
|
230
237
|
@container (width < #{calc($content-width * 0.6)}) {
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
}
|
|
238
|
+
flex-basis: calc(2 * var(--basis));
|
|
239
|
+
// DEBUG: background: orange;
|
|
234
240
|
}
|
|
235
241
|
}
|
|
236
242
|
|
|
237
|
-
.dito-sidebar & {
|
|
243
|
+
.dito-sidebar .dito-pane > & {
|
|
238
244
|
@container (width < #{$sidebar-max-width}) {
|
|
239
245
|
flex-grow: 1;
|
|
246
|
+
// DEBUG: background: yellow;
|
|
240
247
|
}
|
|
241
248
|
|
|
242
249
|
@container (width < #{calc($sidebar-max-width * 0.6)}) {
|
|
243
|
-
flex-basis: calc(var(--basis)
|
|
250
|
+
flex-basis: calc(2 * var(--basis));
|
|
251
|
+
// DEBUG: background: orange;
|
|
244
252
|
}
|
|
245
253
|
}
|
|
246
254
|
|
|
@@ -18,6 +18,7 @@ ul.dito-menu(
|
|
|
18
18
|
v-if="item.items"
|
|
19
19
|
:class="getItemClass(item, 'dito-sub-menu')"
|
|
20
20
|
:items="item.items"
|
|
21
|
+
:path="getItemPath(item, false)"
|
|
21
22
|
)
|
|
22
23
|
</template>
|
|
23
24
|
|
|
@@ -30,6 +31,10 @@ export default DitoComponent.component('DitoMenu', {
|
|
|
30
31
|
items: {
|
|
31
32
|
type: [Object, Array],
|
|
32
33
|
default: () => []
|
|
34
|
+
},
|
|
35
|
+
path: {
|
|
36
|
+
type: String,
|
|
37
|
+
default: ''
|
|
33
38
|
}
|
|
34
39
|
},
|
|
35
40
|
|
|
@@ -53,28 +58,27 @@ export default DitoComponent.component('DitoMenu', {
|
|
|
53
58
|
}
|
|
54
59
|
},
|
|
55
60
|
|
|
56
|
-
getItemPath(item) {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
: null
|
|
61
|
+
getItemPath(item, firstChild) {
|
|
62
|
+
const path = item.path ? `${this.path}/${item.path}` : null
|
|
63
|
+
return firstChild && path && item.items
|
|
64
|
+
? `${path}${this.getItemPath(Object.values(item.items)[0], false)}`
|
|
65
|
+
: path
|
|
62
66
|
},
|
|
63
67
|
|
|
64
68
|
getItemHref(item) {
|
|
65
|
-
const path = this.getItemPath(item)
|
|
69
|
+
const path = this.getItemPath(item, true)
|
|
66
70
|
return path ? this.$router.resolve(path).href : null
|
|
67
71
|
},
|
|
68
72
|
|
|
69
73
|
isActiveItem(item) {
|
|
70
74
|
return (
|
|
71
|
-
this.$route.path.startsWith(this.getItemPath(item)) ||
|
|
75
|
+
this.$route.path.startsWith(this.getItemPath(item, false)) ||
|
|
72
76
|
item.items && Object.values(item.items).some(this.isActiveItem)
|
|
73
77
|
)
|
|
74
78
|
},
|
|
75
79
|
|
|
76
80
|
onClickItem(item) {
|
|
77
|
-
const path = this.getItemPath(item)
|
|
81
|
+
const path = this.getItemPath(item, true)
|
|
78
82
|
if (path) {
|
|
79
83
|
this.$router.push({ path, force: true })
|
|
80
84
|
}
|
|
@@ -33,6 +33,7 @@
|
|
|
33
33
|
:disabled="disabled"
|
|
34
34
|
:generateLabels="generateLabels"
|
|
35
35
|
:verticalLabels="isInLabeledRow(index)"
|
|
36
|
+
:accumulatedBasis="accumulatedBasis"
|
|
36
37
|
)
|
|
37
38
|
.dito-break(
|
|
38
39
|
v-if="schema.break === 'after'"
|
|
@@ -62,7 +63,8 @@ export default DitoComponent.component('DitoPane', {
|
|
|
62
63
|
single: { type: Boolean, default: false },
|
|
63
64
|
visible: { type: Boolean, default: true },
|
|
64
65
|
disabled: { type: Boolean, default: false },
|
|
65
|
-
generateLabels: { type: Boolean, default: false }
|
|
66
|
+
generateLabels: { type: Boolean, default: false },
|
|
67
|
+
accumulatedBasis: { type: Number, default: null }
|
|
66
68
|
},
|
|
67
69
|
|
|
68
70
|
data() {
|
|
@@ -162,7 +164,7 @@ export default DitoComponent.component('DitoPane', {
|
|
|
162
164
|
for (const index of row) {
|
|
163
165
|
const position = this.positions[index]
|
|
164
166
|
if (
|
|
165
|
-
position?.height >
|
|
167
|
+
position?.height > 3 &&
|
|
166
168
|
position.node.querySelector(':scope > .dito-label')
|
|
167
169
|
) {
|
|
168
170
|
// TODO: Handle nested schemas, e.g. 'section' or 'object' and
|
|
@@ -205,12 +207,11 @@ export default DitoComponent.component('DitoPane', {
|
|
|
205
207
|
}
|
|
206
208
|
},
|
|
207
209
|
|
|
208
|
-
onResizeContainer(index, { target }) {
|
|
209
|
-
const { y, width, height } = target.getBoundingClientRect()
|
|
210
|
+
onResizeContainer(index, { target, contentRect: { width, height } }) {
|
|
210
211
|
this.positions[index] =
|
|
211
212
|
width > 0 && height > 0
|
|
212
213
|
? {
|
|
213
|
-
top: y,
|
|
214
|
+
top: target.getBoundingClientRect().y,
|
|
214
215
|
height: height / parseFloat(getComputedStyle(target).fontSize),
|
|
215
216
|
node: target
|
|
216
217
|
}
|
|
@@ -233,8 +234,8 @@ export default DitoComponent.component('DitoPane', {
|
|
|
233
234
|
display: flex;
|
|
234
235
|
position: relative;
|
|
235
236
|
flex-flow: row wrap;
|
|
237
|
+
align-items: flex-start;
|
|
236
238
|
align-content: flex-start;
|
|
237
|
-
align-items: baseline;
|
|
238
239
|
padding: $content-padding;
|
|
239
240
|
// Remove the padding added by `.dito-container` inside `.dito-pane`:
|
|
240
241
|
margin: (-$form-spacing) (-$form-spacing-half);
|
|
@@ -473,10 +473,11 @@ function addRoutes(router, routes) {
|
|
|
473
473
|
|
|
474
474
|
.dito-page {
|
|
475
475
|
--max-content-width: #{$content-width};
|
|
476
|
+
--max-page-width: calc(var(--max-content-width) + 2 * #{$content-padding});
|
|
476
477
|
|
|
477
|
-
flex:
|
|
478
|
+
flex: 0 1 var(--max-page-width);
|
|
478
479
|
background: $content-color-background;
|
|
479
|
-
max-width:
|
|
480
|
+
max-width: var(--max-page-width);
|
|
480
481
|
// For the `@container` rule in `.dito-container` to work:
|
|
481
482
|
container-type: inline-size;
|
|
482
483
|
|
|
@@ -56,6 +56,7 @@ slot(name="before")
|
|
|
56
56
|
:single="!inlined && !hasMainPane"
|
|
57
57
|
:disabled="disabled"
|
|
58
58
|
:generateLabels="generateLabels"
|
|
59
|
+
:accumulatedBasis="accumulatedBasis"
|
|
59
60
|
)
|
|
60
61
|
TransitionHeight(:enabled="inlined")
|
|
61
62
|
DitoPane.dito-pane-main(
|
|
@@ -69,6 +70,7 @@ slot(name="before")
|
|
|
69
70
|
:single="!inlined && !hasTabs"
|
|
70
71
|
:disabled="disabled"
|
|
71
72
|
:generateLabels="generateLabels"
|
|
73
|
+
:accumulatedBasis="accumulatedBasis"
|
|
72
74
|
)
|
|
73
75
|
slot(
|
|
74
76
|
v-if="!inlined && isPopulated"
|
|
@@ -149,7 +151,8 @@ export default DitoComponent.component('DitoSchema', {
|
|
|
149
151
|
scrollable: { type: Boolean, default: false },
|
|
150
152
|
hasOwnData: { type: Boolean, default: false },
|
|
151
153
|
headerInMenu: { type: Boolean, default: false },
|
|
152
|
-
generateLabels: { type: Boolean, default: false }
|
|
154
|
+
generateLabels: { type: Boolean, default: false },
|
|
155
|
+
accumulatedBasis: { type: Number, default: 1 }
|
|
153
156
|
},
|
|
154
157
|
|
|
155
158
|
data() {
|
|
@@ -12,6 +12,7 @@ DitoSchema.dito-schema-inlined(
|
|
|
12
12
|
:collapsed="collapsed"
|
|
13
13
|
:collapsible="collapsible"
|
|
14
14
|
:generateLabels="!isCompact"
|
|
15
|
+
:accumulatedBasis="accumulatedBasis"
|
|
15
16
|
)
|
|
16
17
|
//- Render dito-edit-buttons for inlined schemas separately from all
|
|
17
18
|
//- others in `TypeList` as a scope, for better handling of layout.
|
|
@@ -51,7 +52,8 @@ export default DitoComponent.component('DitoSchemaInlined', {
|
|
|
51
52
|
draggable: { type: Boolean, default: false },
|
|
52
53
|
editable: { type: Boolean, default: false },
|
|
53
54
|
deletable: { type: Boolean, default: false },
|
|
54
|
-
editPath: { type: String, default: null }
|
|
55
|
+
editPath: { type: String, default: null },
|
|
56
|
+
accumulatedBasis: { type: Number, default: null }
|
|
55
57
|
},
|
|
56
58
|
|
|
57
59
|
computed: {
|
|
@@ -15,7 +15,7 @@ export default DitoComponent.component('DitoSidebar', {})
|
|
|
15
15
|
@import '../styles/_imports';
|
|
16
16
|
|
|
17
17
|
.dito-sidebar {
|
|
18
|
-
flex: 0
|
|
18
|
+
flex: 0 1 $sidebar-max-width;
|
|
19
19
|
max-width: $sidebar-max-width;
|
|
20
20
|
min-width: $sidebar-min-width;
|
|
21
21
|
// For the `@container` rule in `.dito-container` to work:
|
package/src/mixins/RouteMixin.js
CHANGED
|
@@ -73,7 +73,7 @@ export default {
|
|
|
73
73
|
},
|
|
74
74
|
|
|
75
75
|
path() {
|
|
76
|
-
return this.getRoutePath(this.routeRecord
|
|
76
|
+
return this.getRoutePath(this.routeRecord?.path)
|
|
77
77
|
},
|
|
78
78
|
|
|
79
79
|
label() {
|
|
@@ -168,10 +168,13 @@ export default {
|
|
|
168
168
|
// Maps the route's actual path to the matched routes by counting its
|
|
169
169
|
// parts separated by '/', splitting the path into the mapped parts
|
|
170
170
|
// containing actual parameters.
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
171
|
+
const { path } = this.$route
|
|
172
|
+
return templatePath
|
|
173
|
+
? path
|
|
174
|
+
.split('/')
|
|
175
|
+
.slice(0, templatePath.split('/').length)
|
|
176
|
+
.join('/')
|
|
177
|
+
: path
|
|
175
178
|
},
|
|
176
179
|
|
|
177
180
|
getChildPath(path) {
|
package/src/mixins/TypeMixin.js
CHANGED
|
@@ -21,7 +21,8 @@ export default {
|
|
|
21
21
|
label: { type: String, default: null },
|
|
22
22
|
single: { type: Boolean, default: false },
|
|
23
23
|
nested: { type: Boolean, default: true },
|
|
24
|
-
disabled: { type: Boolean, default: false }
|
|
24
|
+
disabled: { type: Boolean, default: false },
|
|
25
|
+
accumulatedBasis: { type: Number, default: null }
|
|
25
26
|
},
|
|
26
27
|
|
|
27
28
|
data() {
|
package/src/styles/_layout.scss
CHANGED
|
@@ -316,9 +316,10 @@ $tag-line-height: 1em;
|
|
|
316
316
|
}
|
|
317
317
|
|
|
318
318
|
&__tags {
|
|
319
|
+
display: flex;
|
|
319
320
|
font-size: inherit;
|
|
320
|
-
overflow: auto;
|
|
321
321
|
min-height: inherit;
|
|
322
|
+
overflow: auto;
|
|
322
323
|
padding: 0 $spinner-width 0 0;
|
|
323
324
|
// So tags can float on multiple lines and have proper margins:
|
|
324
325
|
padding-bottom: $tag-margin;
|
|
@@ -341,11 +342,14 @@ $tag-line-height: 1em;
|
|
|
341
342
|
&__single,
|
|
342
343
|
&__placeholder,
|
|
343
344
|
&__input {
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
345
|
+
@include ellipsis;
|
|
346
|
+
|
|
347
|
+
flex: 1 0 0%;
|
|
348
|
+
width: 0;
|
|
347
349
|
min-height: 0;
|
|
348
350
|
margin: 0 0 1px 0;
|
|
351
|
+
font-size: inherit;
|
|
352
|
+
line-height: inherit;
|
|
349
353
|
// Sadly, vue-select sets style="padding: ...;" in addition to using
|
|
350
354
|
// classes, so `!important` is necessary:
|
|
351
355
|
padding: $input-padding !important;
|
package/src/utils/schema.js
CHANGED
|
@@ -283,32 +283,32 @@ export async function processSchemaComponent(
|
|
|
283
283
|
])
|
|
284
284
|
}
|
|
285
285
|
|
|
286
|
-
export async function processView(component, api, schema, name) {
|
|
286
|
+
export async function processView(component, api, schema, name, menuLevel = 0) {
|
|
287
287
|
processSchemaDefaults(api, schema)
|
|
288
|
+
let children = []
|
|
288
289
|
if (isView(schema)) {
|
|
289
290
|
processRouteSchema(api, schema, name)
|
|
290
291
|
await processNestedSchemas(api, schema)
|
|
291
|
-
|
|
292
|
-
await processSchemaComponents(api, schema, children, 0)
|
|
293
|
-
return {
|
|
294
|
-
path: `/${schema.path}`,
|
|
295
|
-
children,
|
|
296
|
-
component,
|
|
297
|
-
meta: {
|
|
298
|
-
api,
|
|
299
|
-
schema
|
|
300
|
-
}
|
|
301
|
-
}
|
|
292
|
+
await processSchemaComponents(api, schema, children)
|
|
302
293
|
} else if (isMenu(schema)) {
|
|
303
|
-
|
|
294
|
+
processRouteSchema(api, schema, name)
|
|
295
|
+
children = await Promise.all(
|
|
304
296
|
Object.entries(schema.items).map(async ([name, item]) =>
|
|
305
|
-
processView(component, api, item, name)
|
|
297
|
+
processView(component, api, item, name, menuLevel + 1)
|
|
306
298
|
)
|
|
307
299
|
)
|
|
308
|
-
//
|
|
309
300
|
} else {
|
|
310
301
|
throw new Error(`Invalid view schema: '${getSchemaIdentifier(schema)}'`)
|
|
311
302
|
}
|
|
303
|
+
return {
|
|
304
|
+
path: menuLevel === 0 ? `/${schema.path}` : schema.path,
|
|
305
|
+
children,
|
|
306
|
+
component,
|
|
307
|
+
meta: {
|
|
308
|
+
api,
|
|
309
|
+
schema
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
312
|
}
|
|
313
313
|
|
|
314
314
|
export function processSchemaDefaults(api, schema) {
|