@ditojs/admin 2.6.0 → 2.6.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 +1063 -1048
- package/dist/dito-admin.umd.js +5 -5
- package/dist/style.css +1 -1
- package/package.json +3 -3
- package/src/DitoContext.js +4 -0
- package/src/components/DitoContainer.vue +4 -5
- package/src/components/DitoLabel.vue +7 -3
- package/src/components/DitoPane.vue +28 -17
- package/src/components/DitoPanel.vue +0 -2
- package/src/components/DitoPanels.vue +1 -0
- package/src/components/DitoRoot.vue +5 -3
- package/src/components/DitoSchema.vue +2 -1
- package/src/mixins/DitoMixin.js +9 -1
- package/src/types/DitoTypeList.vue +5 -5
- package/src/types/DitoTypeObject.vue +5 -5
- package/src/utils/schema.js +19 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ditojs/admin",
|
|
3
|
-
"version": "2.6.
|
|
3
|
+
"version": "2.6.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,7 +33,7 @@
|
|
|
33
33
|
"not ie_mob > 0"
|
|
34
34
|
],
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@ditojs/ui": "^2.6.
|
|
36
|
+
"@ditojs/ui": "^2.6.1",
|
|
37
37
|
"@ditojs/utils": "^2.6.0",
|
|
38
38
|
"@kyvg/vue3-notification": "^2.9.0",
|
|
39
39
|
"@lk77/vue3-color": "^3.0.6",
|
|
@@ -83,7 +83,7 @@
|
|
|
83
83
|
"vite": "^4.3.4"
|
|
84
84
|
},
|
|
85
85
|
"types": "types",
|
|
86
|
-
"gitHead": "
|
|
86
|
+
"gitHead": "a95912074661c314de4a56debf68950e12590dbd",
|
|
87
87
|
"scripts": {
|
|
88
88
|
"build": "vite build",
|
|
89
89
|
"watch": "yarn build --mode 'development' --watch",
|
package/src/DitoContext.js
CHANGED
|
@@ -49,7 +49,7 @@ export default DitoComponent.component('DitoContainer', {
|
|
|
49
49
|
nested: { type: Boolean, default: true },
|
|
50
50
|
disabled: { type: Boolean, required: true },
|
|
51
51
|
generateLabels: { type: Boolean, default: false },
|
|
52
|
-
|
|
52
|
+
verticalLabels: { type: Boolean, default: false }
|
|
53
53
|
},
|
|
54
54
|
|
|
55
55
|
data() {
|
|
@@ -155,7 +155,7 @@ export default DitoComponent.component('DitoContainer', {
|
|
|
155
155
|
const prefix = 'dito-container'
|
|
156
156
|
return {
|
|
157
157
|
[`${prefix}--single`]: this.single,
|
|
158
|
-
[`${prefix}--
|
|
158
|
+
[`${prefix}--label-vertical`]: this.verticalLabels,
|
|
159
159
|
[`${prefix}--omit-padding`]: omitPadding(this.schema),
|
|
160
160
|
...(
|
|
161
161
|
isString(containerClass)
|
|
@@ -178,12 +178,11 @@ export default DitoComponent.component('DitoContainer', {
|
|
|
178
178
|
},
|
|
179
179
|
|
|
180
180
|
componentClass() {
|
|
181
|
-
const basisIsAuto = this.flexBasis === 'auto'
|
|
182
181
|
return {
|
|
183
182
|
// TODO: BEM?
|
|
184
183
|
'dito-single': this.single,
|
|
185
184
|
'dito-disabled': this.componentDisabled,
|
|
186
|
-
'dito-width-fill':
|
|
185
|
+
'dito-width-fill': this.width === 'fill' || this.flexBasis !== 'auto',
|
|
187
186
|
'dito-width-grow': this.flexGrow,
|
|
188
187
|
'dito-width-shrink': this.flexShrink,
|
|
189
188
|
'dito-has-errors': !!this.errors
|
|
@@ -232,7 +231,7 @@ export default DitoComponent.component('DitoContainer', {
|
|
|
232
231
|
padding: 0;
|
|
233
232
|
}
|
|
234
233
|
|
|
235
|
-
&--
|
|
234
|
+
&--label-vertical {
|
|
236
235
|
// For components without labels in rows with other components that have
|
|
237
236
|
// labels, add some spacing to the top to align with the other components:
|
|
238
237
|
> .dito-component:first-child {
|
|
@@ -98,7 +98,11 @@ export default DitoComponent.component('DitoLabel', {
|
|
|
98
98
|
// Vertically center all items in the label, e.g. chevron, edit-buttons.
|
|
99
99
|
align-items: center;
|
|
100
100
|
padding: var(--label-padding);
|
|
101
|
-
margin: 0
|
|
101
|
+
margin: 0 $form-spacing-half $form-spacing-half 0;
|
|
102
|
+
|
|
103
|
+
.dito-container:not(.dito-container--label-vertical) > & {
|
|
104
|
+
margin-bottom: 0;
|
|
105
|
+
}
|
|
102
106
|
|
|
103
107
|
&__inner {
|
|
104
108
|
display: flex;
|
|
@@ -175,10 +179,10 @@ a.dito-label {
|
|
|
175
179
|
.dito-schema-compact {
|
|
176
180
|
> .dito-schema-content {
|
|
177
181
|
> .dito-pane {
|
|
178
|
-
> .dito-container {
|
|
182
|
+
> .dito-container:not(.dito-container--label-vertical) {
|
|
179
183
|
display: flex;
|
|
180
184
|
flex-flow: row wrap;
|
|
181
|
-
align-items:
|
|
185
|
+
align-items: center;
|
|
182
186
|
}
|
|
183
187
|
}
|
|
184
188
|
}
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
:nested="nested"
|
|
33
33
|
:disabled="disabled"
|
|
34
34
|
:generateLabels="generateLabels"
|
|
35
|
-
:
|
|
35
|
+
:verticalLabels="isInLabeledRow(index)"
|
|
36
36
|
)
|
|
37
37
|
.dito-break(
|
|
38
38
|
v-if="schema.break === 'after'"
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
<script>
|
|
43
43
|
import DitoComponent from '../DitoComponent.js'
|
|
44
44
|
import { appendDataPath } from '../utils/data.js'
|
|
45
|
-
import { getAllPanelEntries,
|
|
45
|
+
import { getAllPanelEntries, isNested } from '../utils/schema.js'
|
|
46
46
|
|
|
47
47
|
// @vue/component
|
|
48
48
|
export default DitoComponent.component('DitoPane', {
|
|
@@ -125,13 +125,13 @@ export default DitoComponent.component('DitoPane', {
|
|
|
125
125
|
return this.single && this.componentSchemas.length === 1
|
|
126
126
|
},
|
|
127
127
|
|
|
128
|
-
|
|
128
|
+
verticalLabelsByIndices() {
|
|
129
129
|
const { positions } = this
|
|
130
130
|
|
|
131
131
|
const isLastInRow = index => (
|
|
132
|
-
positions[index]
|
|
132
|
+
positions[index] && (
|
|
133
133
|
index === positions.length - 1 ||
|
|
134
|
-
findNextPosition(index) > positions[index]
|
|
134
|
+
findNextPosition(index).top > positions[index].top
|
|
135
135
|
)
|
|
136
136
|
)
|
|
137
137
|
|
|
@@ -155,25 +155,28 @@ export default DitoComponent.component('DitoPane', {
|
|
|
155
155
|
rows.push(row)
|
|
156
156
|
}
|
|
157
157
|
|
|
158
|
-
const
|
|
158
|
+
const verticalLabelsByIndices = []
|
|
159
159
|
|
|
160
160
|
for (const row of rows) {
|
|
161
161
|
let hasLabelsInRow = false
|
|
162
162
|
for (const index of row) {
|
|
163
|
-
const
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
163
|
+
const position = this.positions[index]
|
|
164
|
+
if (
|
|
165
|
+
position?.height > 4 &&
|
|
166
|
+
position.node.querySelector(':scope > .dito-label')
|
|
167
|
+
) {
|
|
168
|
+
// TODO: Handle nested schemas, e.g. 'section' or 'object' and
|
|
169
|
+
// detect labels there too.
|
|
167
170
|
hasLabelsInRow = true
|
|
168
171
|
break
|
|
169
172
|
}
|
|
170
173
|
}
|
|
171
174
|
for (const index of row) {
|
|
172
|
-
|
|
175
|
+
verticalLabelsByIndices[index] = hasLabelsInRow
|
|
173
176
|
}
|
|
174
177
|
}
|
|
175
178
|
|
|
176
|
-
return
|
|
179
|
+
return verticalLabelsByIndices
|
|
177
180
|
}
|
|
178
181
|
},
|
|
179
182
|
|
|
@@ -204,11 +207,18 @@ export default DitoComponent.component('DitoPane', {
|
|
|
204
207
|
|
|
205
208
|
onResizeContainer(index, { target }) {
|
|
206
209
|
const { y, width, height } = target.getBoundingClientRect()
|
|
207
|
-
this.positions[index] =
|
|
210
|
+
this.positions[index] =
|
|
211
|
+
width > 0 && height > 0
|
|
212
|
+
? {
|
|
213
|
+
top: y,
|
|
214
|
+
height: height / parseFloat(getComputedStyle(target).fontSize),
|
|
215
|
+
node: target
|
|
216
|
+
}
|
|
217
|
+
: null
|
|
208
218
|
},
|
|
209
219
|
|
|
210
220
|
isInLabeledRow(index) {
|
|
211
|
-
return this.
|
|
221
|
+
return !!this.verticalLabelsByIndices[index]
|
|
212
222
|
}
|
|
213
223
|
}
|
|
214
224
|
})
|
|
@@ -223,16 +233,17 @@ export default DitoComponent.component('DitoPane', {
|
|
|
223
233
|
flex-flow: row wrap;
|
|
224
234
|
align-content: flex-start;
|
|
225
235
|
align-items: baseline;
|
|
226
|
-
padding: $content-padding;
|
|
227
236
|
// Remove the padding added by `.dito-container` inside `.dito-pane`:
|
|
228
|
-
|
|
237
|
+
padding: ($content-padding - $form-spacing)
|
|
238
|
+
($content-padding - $form-spacing-half);
|
|
239
|
+
max-width: calc(var(--max-content-width) + $form-spacing);
|
|
229
240
|
// Use `flex: 0%` for all `.dito-pane` except `.dito-pane-main`,
|
|
230
241
|
// so that the `.dito-buttons-main` can be moved all the way to the bottom.
|
|
231
242
|
flex: 0%;
|
|
232
243
|
|
|
233
244
|
&--single {
|
|
234
245
|
// Clear margin from above.
|
|
235
|
-
|
|
246
|
+
padding: $content-padding;
|
|
236
247
|
}
|
|
237
248
|
|
|
238
249
|
&.dito-pane-main {
|
|
@@ -472,12 +472,14 @@ function addRoutes(router, routes) {
|
|
|
472
472
|
}
|
|
473
473
|
|
|
474
474
|
.dito-page {
|
|
475
|
-
|
|
475
|
+
--max-content-width: #{$content-width};
|
|
476
|
+
|
|
477
|
+
flex: 1 1 var(--max-content-width);
|
|
476
478
|
background: $content-color-background;
|
|
477
|
-
max-width: $content-
|
|
479
|
+
max-width: calc(var(--max-content-width) + 2 * #{$content-padding});
|
|
478
480
|
|
|
479
481
|
&--wide {
|
|
480
|
-
max-width: $content-width-wide;
|
|
482
|
+
--max-content-width: #{$content-width-wide};
|
|
481
483
|
}
|
|
482
484
|
}
|
|
483
485
|
|
|
@@ -757,8 +757,9 @@ export default DitoComponent.component('DitoSchema', {
|
|
|
757
757
|
|
|
758
758
|
.dito-schema {
|
|
759
759
|
box-sizing: border-box;
|
|
760
|
-
// To display schema next to
|
|
760
|
+
// To display schema next to buttons:
|
|
761
761
|
display: flex;
|
|
762
|
+
align-items: flex-start;
|
|
762
763
|
min-height: 100%;
|
|
763
764
|
|
|
764
765
|
> .dito-schema-content {
|
package/src/mixins/DitoMixin.js
CHANGED
|
@@ -10,7 +10,11 @@ import {
|
|
|
10
10
|
import appState from '../appState.js'
|
|
11
11
|
import DitoContext from '../DitoContext.js'
|
|
12
12
|
import EmitterMixin from './EmitterMixin.js'
|
|
13
|
-
import {
|
|
13
|
+
import {
|
|
14
|
+
flattenViews,
|
|
15
|
+
getSchemaValue,
|
|
16
|
+
shouldRenderSchema
|
|
17
|
+
} from '../utils/schema.js'
|
|
14
18
|
import { getResource, getMemberResource } from '../utils/resource.js'
|
|
15
19
|
import { computed, reactive } from 'vue'
|
|
16
20
|
|
|
@@ -77,6 +81,10 @@ export default {
|
|
|
77
81
|
return this.$views()
|
|
78
82
|
},
|
|
79
83
|
|
|
84
|
+
flattenedViews() {
|
|
85
|
+
return flattenViews(this.views)
|
|
86
|
+
},
|
|
87
|
+
|
|
80
88
|
isPopulated() {
|
|
81
89
|
return this.$isPopulated()
|
|
82
90
|
},
|
|
@@ -2,10 +2,8 @@
|
|
|
2
2
|
.dito-list(
|
|
3
3
|
v-if="isReady"
|
|
4
4
|
:id="dataPath"
|
|
5
|
-
:class="schema.class"
|
|
6
|
-
:style="schema.style"
|
|
7
5
|
)
|
|
8
|
-
.dito-
|
|
6
|
+
.dito-list__header(
|
|
9
7
|
v-if="scopes || hasPagination"
|
|
10
8
|
)
|
|
11
9
|
DitoScopes(
|
|
@@ -314,9 +312,11 @@ export default DitoTypeComponent.register('list', {
|
|
|
314
312
|
@import '../styles/_imports';
|
|
315
313
|
|
|
316
314
|
.dito-list {
|
|
315
|
+
$self: &;
|
|
316
|
+
|
|
317
317
|
position: relative;
|
|
318
318
|
|
|
319
|
-
|
|
319
|
+
&__header {
|
|
320
320
|
display: flex;
|
|
321
321
|
justify-content: space-between;
|
|
322
322
|
padding-bottom: $content-padding-half;
|
|
@@ -342,7 +342,7 @@ export default DitoTypeComponent.register('list', {
|
|
|
342
342
|
|
|
343
343
|
// Make single list header, navigation and buttons sticky to the top and
|
|
344
344
|
// bottom:
|
|
345
|
-
|
|
345
|
+
#{$self}__header {
|
|
346
346
|
position: sticky;
|
|
347
347
|
top: 0;
|
|
348
348
|
margin-top: -$content-padding;
|
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
.dito-object(
|
|
3
3
|
v-if="isReady"
|
|
4
4
|
:id="dataPath"
|
|
5
|
-
:class="schema.class"
|
|
6
|
-
:style="schema.style"
|
|
7
5
|
)
|
|
8
6
|
.dito-object-content(
|
|
9
7
|
v-if="objectData"
|
|
@@ -118,16 +116,18 @@ export default DitoTypeComponent.register('object', {
|
|
|
118
116
|
border: $border-style;
|
|
119
117
|
border-radius: $border-radius;
|
|
120
118
|
margin: 0;
|
|
121
|
-
|
|
119
|
+
// Only add what's not already added by the nested '.dito-pane' as padding,
|
|
120
|
+
// in order to have `$form-spacing` all around.
|
|
121
|
+
padding: 0 $form-spacing-half;
|
|
122
122
|
box-sizing: border-box;
|
|
123
123
|
|
|
124
124
|
.dito-object-content {
|
|
125
125
|
flex: 0 1 100%;
|
|
126
126
|
}
|
|
127
127
|
|
|
128
|
-
> .dito-buttons {
|
|
128
|
+
> .dito-edit-buttons {
|
|
129
129
|
flex: 1 0 0%;
|
|
130
|
-
|
|
130
|
+
padding: $form-spacing;
|
|
131
131
|
}
|
|
132
132
|
}
|
|
133
133
|
</style>
|
package/src/utils/schema.js
CHANGED
|
@@ -188,11 +188,28 @@ export async function resolveViews(unresolvedViews) {
|
|
|
188
188
|
// NOTE: This is never actually referenced from anywhere, but they need
|
|
189
189
|
// a name by which they're stored in the parent object.
|
|
190
190
|
schema.name = camelize(schema.label)
|
|
191
|
+
schema.items = await resolveSchemas(schema.items)
|
|
191
192
|
}
|
|
192
193
|
return schema
|
|
193
194
|
})
|
|
194
195
|
}
|
|
195
196
|
|
|
197
|
+
export function flattenViews(views) {
|
|
198
|
+
return Object.fromEntries(
|
|
199
|
+
Object.entries(views).reduce(
|
|
200
|
+
(entries, [key, schema]) => {
|
|
201
|
+
if (isMenu(schema)) {
|
|
202
|
+
entries.push(...Object.entries(schema.items))
|
|
203
|
+
} else {
|
|
204
|
+
entries.push([key, schema])
|
|
205
|
+
}
|
|
206
|
+
return entries
|
|
207
|
+
},
|
|
208
|
+
[]
|
|
209
|
+
)
|
|
210
|
+
)
|
|
211
|
+
}
|
|
212
|
+
|
|
196
213
|
export async function resolveSchemaComponent(schema) {
|
|
197
214
|
// Resolves async schema components and adds DitoMixin and TypeMixin to them.
|
|
198
215
|
let { component } = schema
|
|
@@ -283,7 +300,6 @@ export async function processView(component, api, schema, name) {
|
|
|
283
300
|
}
|
|
284
301
|
}
|
|
285
302
|
} else if (isMenu(schema)) {
|
|
286
|
-
schema.items = await resolveSchemas(schema.items)
|
|
287
303
|
return Promise.all(
|
|
288
304
|
Object.entries(schema.items).map(async ([name, item]) =>
|
|
289
305
|
processView(component, api, item, name)
|
|
@@ -428,7 +444,7 @@ export function isSingleComponentView(schema) {
|
|
|
428
444
|
|
|
429
445
|
export function getViewFormSchema(schema, context) {
|
|
430
446
|
const { view } = schema
|
|
431
|
-
const viewSchema = view && context.
|
|
447
|
+
const viewSchema = view && context.flattenedViews[view]
|
|
432
448
|
return viewSchema
|
|
433
449
|
? // NOTE: Views can have tabs, in which case the view component is nested
|
|
434
450
|
// in one of the tabs, go find it.
|
|
@@ -438,7 +454,7 @@ export function getViewFormSchema(schema, context) {
|
|
|
438
454
|
|
|
439
455
|
export function getViewSchema(schema, context) {
|
|
440
456
|
return getViewFormSchema(schema, context)
|
|
441
|
-
? context.
|
|
457
|
+
? context.flattenedViews[schema.view]
|
|
442
458
|
: null
|
|
443
459
|
}
|
|
444
460
|
|