@ditojs/admin 2.3.1 → 2.3.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 +1394 -1313
- package/dist/dito-admin.umd.js +4 -4
- package/dist/style.css +1 -1
- package/package.json +3 -3
- package/src/components/DitoDialog.vue +1 -0
- package/src/components/DitoHeader.vue +5 -5
- package/src/components/DitoMenu.vue +172 -0
- package/src/components/DitoRoot.vue +4 -4
- package/src/components/DitoSchema.vue +7 -6
- package/src/components/DitoSidebar.vue +11 -49
- package/src/components/index.js +1 -0
- package/src/styles/_button.scss +1 -1
- package/src/styles/_scroll.scss +0 -1
- package/src/styles/_settings.scss +17 -10
- package/src/utils/schema.js +42 -16
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ditojs/admin",
|
|
3
|
-
"version": "2.3.
|
|
3
|
+
"version": "2.3.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",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"not ie_mob > 0"
|
|
34
34
|
],
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@ditojs/ui": "^2.3.
|
|
36
|
+
"@ditojs/ui": "^2.3.2",
|
|
37
37
|
"@ditojs/utils": "^2.3.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.1"
|
|
84
84
|
},
|
|
85
85
|
"types": "types",
|
|
86
|
-
"gitHead": "
|
|
86
|
+
"gitHead": "e8034d836e783c606746b8a51b20d8969f1472fc",
|
|
87
87
|
"scripts": {
|
|
88
88
|
"build": "vite build",
|
|
89
89
|
"watch": "yarn build --mode 'development' --watch",
|
|
@@ -20,7 +20,7 @@ nav.dito-header
|
|
|
20
20
|
v-if="isLoading"
|
|
21
21
|
)
|
|
22
22
|
//- Teleport target for `.dito-schema-header`:
|
|
23
|
-
.dito-
|
|
23
|
+
.dito-header__menu
|
|
24
24
|
slot
|
|
25
25
|
</template>
|
|
26
26
|
|
|
@@ -78,14 +78,14 @@ export default DitoComponent.component('DitoHeader', {
|
|
|
78
78
|
|
|
79
79
|
.dito-header {
|
|
80
80
|
background: $color-black;
|
|
81
|
-
font-size: $
|
|
82
|
-
line-height: $
|
|
83
|
-
z-index: $
|
|
81
|
+
font-size: $header-font-size;
|
|
82
|
+
line-height: $header-line-height;
|
|
83
|
+
z-index: $header-z-index;
|
|
84
84
|
@include user-select(none);
|
|
85
85
|
|
|
86
86
|
span {
|
|
87
87
|
display: inline-block;
|
|
88
|
-
padding: $
|
|
88
|
+
padding: $header-padding;
|
|
89
89
|
color: $color-white;
|
|
90
90
|
}
|
|
91
91
|
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
<template lang="pug">
|
|
2
|
+
ul.dito-menu(
|
|
3
|
+
v-resize="onResize"
|
|
4
|
+
:style="{ '--width': width ? `${width}px` : null }"
|
|
5
|
+
)
|
|
6
|
+
li(
|
|
7
|
+
v-for="item in items"
|
|
8
|
+
)
|
|
9
|
+
template(
|
|
10
|
+
v-if="shouldRenderSchema(item)"
|
|
11
|
+
)
|
|
12
|
+
a.dito-link(
|
|
13
|
+
:href="getItemHref(item)"
|
|
14
|
+
:class="getItemClass(item, 'dito-sub-menu-link')"
|
|
15
|
+
@click.prevent.stop="onClickItem(item)"
|
|
16
|
+
) {{ getLabel(item) }}
|
|
17
|
+
DitoMenu(
|
|
18
|
+
v-if="item.items"
|
|
19
|
+
:class="getItemClass(item, 'dito-sub-menu')"
|
|
20
|
+
:items="item.items"
|
|
21
|
+
)
|
|
22
|
+
</template>
|
|
23
|
+
|
|
24
|
+
<script>
|
|
25
|
+
import DitoComponent from '../DitoComponent.js'
|
|
26
|
+
|
|
27
|
+
// @vue/component
|
|
28
|
+
export default DitoComponent.component('DitoMenu', {
|
|
29
|
+
props: {
|
|
30
|
+
items: {
|
|
31
|
+
type: [Object, Array],
|
|
32
|
+
default: () => []
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
|
|
36
|
+
data() {
|
|
37
|
+
return {
|
|
38
|
+
width: 0
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
|
|
42
|
+
methods: {
|
|
43
|
+
onResize({ contentRect: { width } }) {
|
|
44
|
+
if (width) {
|
|
45
|
+
this.width = width
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
|
|
49
|
+
getItemClass(item, subMenuClass) {
|
|
50
|
+
return {
|
|
51
|
+
[subMenuClass]: !!item.items,
|
|
52
|
+
'dito-active': this.isActiveItem(item)
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
|
|
56
|
+
getItemHref(item) {
|
|
57
|
+
return item?.path
|
|
58
|
+
? `/${item.path}`
|
|
59
|
+
: item.items
|
|
60
|
+
? this.getItemHref(Object.values(item.items)[0])
|
|
61
|
+
: null
|
|
62
|
+
},
|
|
63
|
+
|
|
64
|
+
isActiveItem(item) {
|
|
65
|
+
return (
|
|
66
|
+
this.$route.path.startsWith(this.getItemHref(item)) ||
|
|
67
|
+
item.items && Object.values(item.items).some(this.isActiveItem)
|
|
68
|
+
)
|
|
69
|
+
},
|
|
70
|
+
|
|
71
|
+
onClickItem(item) {
|
|
72
|
+
const path = this.getItemHref(item)
|
|
73
|
+
if (path) {
|
|
74
|
+
this.$router.push({ path, force: true })
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
})
|
|
79
|
+
</script>
|
|
80
|
+
|
|
81
|
+
<style lang="scss">
|
|
82
|
+
@use 'sass:color';
|
|
83
|
+
@import '../styles/_imports';
|
|
84
|
+
|
|
85
|
+
.dito-menu {
|
|
86
|
+
$item-height: $menu-font-size + 2 * $menu-padding-ver;
|
|
87
|
+
|
|
88
|
+
border-right: $border-style;
|
|
89
|
+
padding: 0 $menu-spacing;
|
|
90
|
+
|
|
91
|
+
li {
|
|
92
|
+
&:has(.dito-sub-menu:not(.dito-active)) {
|
|
93
|
+
// Pop-out sub-menus on hover:
|
|
94
|
+
&:hover {
|
|
95
|
+
.dito-sub-menu-link {
|
|
96
|
+
background: $color-lightest;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.dito-sub-menu {
|
|
100
|
+
display: block;
|
|
101
|
+
position: absolute;
|
|
102
|
+
width: var(--width);
|
|
103
|
+
z-index: $header-z-index;
|
|
104
|
+
transform: translateX(calc(var(--width) + 2 * $menu-spacing))
|
|
105
|
+
translateY(-$item-height);
|
|
106
|
+
|
|
107
|
+
li:first-child {
|
|
108
|
+
.dito-link {
|
|
109
|
+
margin-top: 0;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
&::before {
|
|
114
|
+
// Fill the gap to not loose the hover when moving over it.
|
|
115
|
+
content: '';
|
|
116
|
+
position: absolute;
|
|
117
|
+
top: 0;
|
|
118
|
+
left: -2 * $menu-spacing;
|
|
119
|
+
width: 2 * $menu-spacing;
|
|
120
|
+
height: $item-height;
|
|
121
|
+
opacity: 0;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// .dito-sub-menu-link,
|
|
126
|
+
.dito-sub-menu {
|
|
127
|
+
box-shadow: $shadow-window;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
.dito-link {
|
|
134
|
+
display: block;
|
|
135
|
+
padding: $menu-padding;
|
|
136
|
+
line-height: $menu-line-height;
|
|
137
|
+
border-radius: $border-radius;
|
|
138
|
+
margin-top: $menu-spacing;
|
|
139
|
+
|
|
140
|
+
&:focus:not(:active, .dito-active) {
|
|
141
|
+
box-shadow: $shadow-focus;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
&:hover {
|
|
145
|
+
background: rgba(255, 255, 255, 0.5);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
&.dito-active {
|
|
149
|
+
color: $color-white;
|
|
150
|
+
background: $color-active;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
.dito-sub-menu-link {
|
|
155
|
+
&.dito-active {
|
|
156
|
+
background: color.adjust($color-active, $alpha: -0.3);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
.dito-sub-menu {
|
|
161
|
+
display: none;
|
|
162
|
+
border-right: 0;
|
|
163
|
+
padding: 0;
|
|
164
|
+
border-radius: $border-radius;
|
|
165
|
+
background: $color-lightest;
|
|
166
|
+
|
|
167
|
+
&.dito-active {
|
|
168
|
+
display: block;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
</style>
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
:settings="dialog.settings"
|
|
17
17
|
@remove="removeDialog(key)"
|
|
18
18
|
)
|
|
19
|
-
|
|
19
|
+
DitoSidebar
|
|
20
20
|
main.dito-page.dito-scroll-parent
|
|
21
21
|
DitoHeader(
|
|
22
22
|
:spinner="options.spinner"
|
|
@@ -43,7 +43,7 @@ import DitoDialog from './DitoDialog.vue'
|
|
|
43
43
|
import DomMixin from '../mixins/DomMixin.js'
|
|
44
44
|
import {
|
|
45
45
|
processView,
|
|
46
|
-
|
|
46
|
+
resolveViews,
|
|
47
47
|
processSchemaComponents
|
|
48
48
|
} from '../utils/schema.js'
|
|
49
49
|
|
|
@@ -328,7 +328,7 @@ export default DitoComponent.component('DitoRoot', {
|
|
|
328
328
|
|
|
329
329
|
async resolveViews() {
|
|
330
330
|
try {
|
|
331
|
-
this.resolvedViews = await
|
|
331
|
+
this.resolvedViews = await resolveViews(this.unresolvedViews)
|
|
332
332
|
} catch (error) {
|
|
333
333
|
if (!error.request) {
|
|
334
334
|
console.error(error)
|
|
@@ -350,7 +350,7 @@ export default DitoComponent.component('DitoRoot', {
|
|
|
350
350
|
path: '/',
|
|
351
351
|
components: {}
|
|
352
352
|
},
|
|
353
|
-
...routes
|
|
353
|
+
...routes.flat()
|
|
354
354
|
])
|
|
355
355
|
this.$router.replace(fullPath)
|
|
356
356
|
}
|
|
@@ -5,7 +5,7 @@ slot(name="before")
|
|
|
5
5
|
)
|
|
6
6
|
.dito-schema-content(:class="{ 'dito-scroll': scrollable }")
|
|
7
7
|
Teleport(
|
|
8
|
-
to=".dito-
|
|
8
|
+
to=".dito-header__menu"
|
|
9
9
|
:disabled="!headerInMenu"
|
|
10
10
|
)
|
|
11
11
|
.dito-schema-header(
|
|
@@ -118,6 +118,7 @@ import { getStoreAccessor } from '../utils/accessor.js'
|
|
|
118
118
|
export default DitoComponent.component('DitoSchema', {
|
|
119
119
|
mixins: [ItemMixin],
|
|
120
120
|
components: { TransitionHeight },
|
|
121
|
+
inheritAttrs: false,
|
|
121
122
|
|
|
122
123
|
provide() {
|
|
123
124
|
return {
|
|
@@ -787,13 +788,13 @@ export default DitoComponent.component('DitoSchema', {
|
|
|
787
788
|
&--menu {
|
|
788
789
|
// Align the tabs on top of to the header menu.
|
|
789
790
|
position: absolute;
|
|
790
|
-
height: $
|
|
791
|
-
padding: 0 $
|
|
791
|
+
height: $header-height;
|
|
792
|
+
padding: 0 $header-padding-hor;
|
|
792
793
|
max-width: $content-width;
|
|
793
794
|
top: 0;
|
|
794
795
|
left: 0;
|
|
795
796
|
right: 0;
|
|
796
|
-
z-index: $
|
|
797
|
+
z-index: $header-z-index;
|
|
797
798
|
// Turn off pointer events so that DitoTrail keeps receiving events...
|
|
798
799
|
pointer-events: none;
|
|
799
800
|
// ...but allow interaction with the tabs and buttons (e.g. clipboard)
|
|
@@ -801,8 +802,8 @@ export default DitoComponent.component('DitoSchema', {
|
|
|
801
802
|
.dito-tabs,
|
|
802
803
|
.dito-buttons {
|
|
803
804
|
pointer-events: auto;
|
|
804
|
-
line-height: $
|
|
805
|
-
font-size: $
|
|
805
|
+
line-height: $header-line-height;
|
|
806
|
+
font-size: $header-font-size;
|
|
806
807
|
}
|
|
807
808
|
}
|
|
808
809
|
}
|
|
@@ -1,78 +1,40 @@
|
|
|
1
1
|
<template lang="pug">
|
|
2
2
|
nav.dito-sidebar.dito-scroll-parent
|
|
3
|
-
h1
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
v-for="view in views"
|
|
7
|
-
)
|
|
8
|
-
RouterLink(
|
|
9
|
-
v-if="shouldRenderSchema(view)"
|
|
10
|
-
v-slot="{ isActive, href, route }"
|
|
11
|
-
custom
|
|
12
|
-
:to="`/${view.path}`"
|
|
13
|
-
)
|
|
14
|
-
a.dito-link(
|
|
15
|
-
:href="href"
|
|
16
|
-
:class="{ 'dito-active': isActive }"
|
|
17
|
-
@click.prevent="onClickLink(route)"
|
|
18
|
-
) {{ getLabel(view) }}
|
|
3
|
+
h1
|
|
4
|
+
RouterLink.dito-link(to="/") {{ appState.title }}
|
|
5
|
+
DitoMenu.dito-scroll(:items="views")
|
|
19
6
|
</template>
|
|
20
7
|
|
|
21
8
|
<script>
|
|
22
9
|
import DitoComponent from '../DitoComponent.js'
|
|
23
10
|
|
|
24
11
|
// @vue/component
|
|
25
|
-
export default DitoComponent.component('
|
|
26
|
-
methods: {
|
|
27
|
-
onClickLink(route) {
|
|
28
|
-
this.$router.push({ ...route, force: true })
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
})
|
|
12
|
+
export default DitoComponent.component('DitoSidebar', {})
|
|
32
13
|
</script>
|
|
33
14
|
|
|
34
15
|
<style lang="scss">
|
|
35
16
|
@import '../styles/_imports';
|
|
36
17
|
|
|
37
18
|
.dito-sidebar {
|
|
19
|
+
@include user-select(none);
|
|
20
|
+
|
|
38
21
|
flex: initial;
|
|
39
22
|
font-size: $menu-font-size;
|
|
40
23
|
white-space: nowrap;
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
ul {
|
|
44
|
-
background: $color-lighter;
|
|
45
|
-
border-right: $border-style;
|
|
46
|
-
}
|
|
24
|
+
background: $color-lighter;
|
|
47
25
|
|
|
48
|
-
a,
|
|
49
26
|
h1 {
|
|
50
27
|
display: block;
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
h1 {
|
|
54
|
-
padding: $menu-padding;
|
|
55
|
-
line-height: $menu-line-height;
|
|
28
|
+
line-height: $header-line-height;
|
|
56
29
|
font-weight: bold;
|
|
57
30
|
background: $color-darker;
|
|
58
31
|
border-right: $border-width solid $color-darkest;
|
|
59
32
|
color: $color-white;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
.dito-link {
|
|
63
|
-
padding: $menu-padding;
|
|
64
|
-
line-height: $menu-line-height;
|
|
65
33
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
34
|
+
.dito-link {
|
|
35
|
+
display: block;
|
|
36
|
+
padding: $header-padding;
|
|
69
37
|
}
|
|
70
38
|
}
|
|
71
39
|
}
|
|
72
|
-
|
|
73
|
-
.dito-link {
|
|
74
|
-
&:focus:not(:active, .dito-active) {
|
|
75
|
-
box-shadow: $shadow-focus;
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
40
|
</style>
|
package/src/components/index.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
// convention is in order of encountered hierarchy in the DOM.
|
|
5
5
|
|
|
6
6
|
export { default as DitoRoot } from './DitoRoot.vue'
|
|
7
|
+
export { default as DitoMenu } from './DitoMenu.vue'
|
|
7
8
|
export { default as DitoSidebar } from './DitoSidebar.vue'
|
|
8
9
|
export { default as DitoHeader } from './DitoHeader.vue'
|
|
9
10
|
export { default as DitoAccount } from './DitoAccount.vue'
|
package/src/styles/_button.scss
CHANGED
package/src/styles/_scroll.scss
CHANGED
|
@@ -43,21 +43,28 @@ $content-color-background: $color-lightest;
|
|
|
43
43
|
$form-spacing: $input-padding-hor;
|
|
44
44
|
$form-spacing-half: calc($form-spacing / 2);
|
|
45
45
|
|
|
46
|
-
//
|
|
47
|
-
$
|
|
48
|
-
$
|
|
49
|
-
$
|
|
50
|
-
$
|
|
51
|
-
$
|
|
52
|
-
$
|
|
53
|
-
$
|
|
46
|
+
// Header
|
|
47
|
+
$header-font-size: 14px;
|
|
48
|
+
$header-line-height: 1;
|
|
49
|
+
$header-z-index: 1000;
|
|
50
|
+
$header-padding-ver: $header-font-size;
|
|
51
|
+
$header-padding-hor: $content-padding;
|
|
52
|
+
$header-padding: $header-padding-ver $header-padding-hor;
|
|
53
|
+
$header-height: $header-font-size + 2 * $header-padding-ver;
|
|
54
54
|
|
|
55
55
|
// Tabs
|
|
56
56
|
$tab-margin: 6px;
|
|
57
57
|
$tab-padding-hor: 12px;
|
|
58
|
-
$tab-padding-ver: calc(($
|
|
58
|
+
$tab-padding-ver: calc(($header-padding-ver * 2 - $tab-margin) / 2);
|
|
59
59
|
$tab-radius: 4px;
|
|
60
|
-
|
|
60
|
+
|
|
61
|
+
// Menu
|
|
62
|
+
$menu-font-size: $header-font-size;
|
|
63
|
+
$menu-line-height: $header-line-height;
|
|
64
|
+
$menu-spacing: 4px;
|
|
65
|
+
$menu-padding-ver: $header-padding-ver - $menu-spacing;
|
|
66
|
+
$menu-padding-hor: $header-padding-hor - $menu-spacing;
|
|
67
|
+
$menu-padding: $menu-padding-ver $menu-padding-hor;
|
|
61
68
|
|
|
62
69
|
// Patterns
|
|
63
70
|
$pattern-transparency-size: ($font-size - $border-width) * $input-height-factor;
|
package/src/utils/schema.js
CHANGED
|
@@ -113,6 +113,10 @@ export function isPanel(schema) {
|
|
|
113
113
|
return isSchema(schema) && schema.type === 'panel'
|
|
114
114
|
}
|
|
115
115
|
|
|
116
|
+
export function isMenu(schema) {
|
|
117
|
+
return isSchema(schema) && schema.type === 'menu'
|
|
118
|
+
}
|
|
119
|
+
|
|
116
120
|
export function getSchemaIdentifier(schema) {
|
|
117
121
|
return JSON.stringify(schema)
|
|
118
122
|
}
|
|
@@ -176,6 +180,19 @@ export async function resolveSchemas(
|
|
|
176
180
|
return schemas
|
|
177
181
|
}
|
|
178
182
|
|
|
183
|
+
export async function resolveViews(unresolvedViews) {
|
|
184
|
+
return resolveSchemas(unresolvedViews, async (schema, unwrapModule) => {
|
|
185
|
+
schema = await resolveSchema(schema, unwrapModule)
|
|
186
|
+
if (!schema.name && isMenu(schema)) {
|
|
187
|
+
// Generate a name for sub-menus from their label if it's missing.
|
|
188
|
+
// NOTE: This is never actually referenced from anywhere, but they need
|
|
189
|
+
// a name by which they're stored in the parent object.
|
|
190
|
+
schema.name = camelize(schema.label)
|
|
191
|
+
}
|
|
192
|
+
return schema
|
|
193
|
+
})
|
|
194
|
+
}
|
|
195
|
+
|
|
179
196
|
export async function resolveSchemaComponent(schema) {
|
|
180
197
|
// Resolves async schema components and adds DitoMixin and TypeMixin to them.
|
|
181
198
|
let { component } = schema
|
|
@@ -250,22 +267,31 @@ export async function processSchemaComponent(
|
|
|
250
267
|
}
|
|
251
268
|
|
|
252
269
|
export async function processView(component, api, schema, name) {
|
|
253
|
-
if (!isView(schema)) {
|
|
254
|
-
throw new Error(`Invalid view schema: '${getSchemaIdentifier(schema)}'`)
|
|
255
|
-
}
|
|
256
|
-
processRouteSchema(api, schema, name)
|
|
257
270
|
processSchemaDefaults(api, schema)
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
271
|
+
if (isView(schema)) {
|
|
272
|
+
processRouteSchema(api, schema, name)
|
|
273
|
+
await processNestedSchemas(api, schema)
|
|
274
|
+
const children = []
|
|
275
|
+
await processSchemaComponents(api, schema, children, 0)
|
|
276
|
+
return {
|
|
277
|
+
path: `/${schema.path}`,
|
|
278
|
+
children,
|
|
279
|
+
component,
|
|
280
|
+
meta: {
|
|
281
|
+
api,
|
|
282
|
+
schema
|
|
283
|
+
}
|
|
268
284
|
}
|
|
285
|
+
} else if (isMenu(schema)) {
|
|
286
|
+
schema.items = await resolveSchemas(schema.items)
|
|
287
|
+
return Promise.all(
|
|
288
|
+
Object.entries(schema.items).map(async ([name, item]) =>
|
|
289
|
+
processView(component, api, item, name)
|
|
290
|
+
)
|
|
291
|
+
)
|
|
292
|
+
//
|
|
293
|
+
} else {
|
|
294
|
+
throw new Error(`Invalid view schema: '${getSchemaIdentifier(schema)}'`)
|
|
269
295
|
}
|
|
270
296
|
}
|
|
271
297
|
|
|
@@ -303,8 +329,8 @@ export function processNestedSchemaDefaults(api, schema) {
|
|
|
303
329
|
|
|
304
330
|
export function processRouteSchema(api, schema, name) {
|
|
305
331
|
// Used for view and source schemas, see SourceMixin.
|
|
306
|
-
schema.name
|
|
307
|
-
schema.path
|
|
332
|
+
schema.name ??= name
|
|
333
|
+
schema.path ??= api.normalizePath(name)
|
|
308
334
|
}
|
|
309
335
|
|
|
310
336
|
export async function processForms(api, schema, level) {
|