@ditojs/admin 3.2.7 → 3.3.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.css +1 -1
- package/dist/dito-admin.es.js +6011 -5826
- package/dist/dito-admin.umd.js +3 -7
- package/package.json +18 -17
- package/src/DitoAdmin.js +44 -24
- package/src/DitoContext.js +28 -2
- package/src/DitoTypeComponent.js +1 -0
- package/src/appState.js +6 -3
- package/src/components/DitoAccount.vue +35 -27
- package/src/components/DitoAffixes.vue +9 -2
- package/src/components/DitoClipboard.vue +59 -93
- package/src/components/DitoConfirmMessage.vue +18 -0
- package/src/components/DitoContainer.vue +56 -18
- package/src/components/DitoCreateButton.vue +36 -84
- package/src/components/DitoDialog.vue +20 -15
- package/src/components/DitoDragHandle.vue +44 -0
- package/src/components/DitoDraggable.vue +43 -16
- package/src/components/DitoEditButtons.vue +48 -24
- package/src/components/DitoErrors.vue +9 -56
- package/src/components/DitoForm.vue +82 -42
- package/src/components/DitoInputAffixes.vue +50 -0
- package/src/components/DitoLabel.vue +1 -15
- package/src/components/DitoMenu.vue +45 -52
- package/src/components/DitoNotifications.vue +38 -14
- package/src/components/DitoOptionList.vue +81 -0
- package/src/components/DitoOptionsEditButtons.vue +57 -0
- package/src/components/DitoPagination.vue +1 -8
- package/src/components/DitoPane.vue +51 -39
- package/src/components/DitoPanel.vue +12 -26
- package/src/components/DitoPanels.vue +11 -5
- package/src/components/DitoResizeHandle.vue +47 -0
- package/src/components/DitoRoot.vue +113 -320
- package/src/components/DitoSchema.vue +72 -63
- package/src/components/DitoSchemaInlined.vue +8 -9
- package/src/components/DitoScopes.vue +14 -18
- package/src/components/DitoSidebar.vue +4 -29
- package/src/components/DitoSourceItem.vue +114 -0
- package/src/components/DitoTableCell.vue +4 -0
- package/src/components/DitoTableHead.vue +15 -17
- package/src/components/DitoTabs.vue +25 -0
- package/src/components/DitoTrail.vue +25 -25
- package/src/components/DitoTreeItem.vue +102 -141
- package/src/components/DitoUploadFile.vue +5 -2
- package/src/components/DitoView.vue +33 -24
- package/src/index.js +4 -1
- package/src/mixins/DitoMixin.js +77 -110
- package/src/mixins/DomMixin.js +12 -14
- package/src/mixins/EmitterMixin.js +3 -2
- package/src/mixins/ItemMixin.js +38 -94
- package/src/mixins/OptionsMixin.js +38 -25
- package/src/mixins/ResourceMixin.js +182 -111
- package/src/mixins/RouteMixin.js +61 -44
- package/src/mixins/SchemaParentMixin.js +4 -1
- package/src/mixins/SourceMixin.js +118 -100
- package/src/mixins/TypeMixin.js +42 -40
- package/src/mixins/ValidationMixin.js +16 -4
- package/src/mixins/ValidatorMixin.js +1 -1
- package/src/styles/_settings.scss +4 -0
- package/src/styles/_tippy.scss +0 -11
- package/src/styles/style.scss +0 -1
- package/src/types/DitoTypeButton.vue +11 -14
- package/src/types/DitoTypeCheckboxes.vue +35 -17
- package/src/types/DitoTypeCode.vue +19 -41
- package/src/types/DitoTypeColor.vue +67 -19
- package/src/types/DitoTypeDate.vue +11 -14
- package/src/types/DitoTypeList.vue +50 -62
- package/src/types/DitoTypeMarkup.vue +41 -54
- package/src/types/DitoTypeMultiselect.vue +82 -52
- package/src/types/DitoTypeNumber.vue +12 -15
- package/src/types/DitoTypeObject.vue +4 -38
- package/src/types/DitoTypeRadio.vue +19 -6
- package/src/types/DitoTypeSection.vue +23 -9
- package/src/types/DitoTypeSelect.vue +39 -23
- package/src/types/DitoTypeSlider.vue +9 -1
- package/src/types/DitoTypeSwitch.vue +1 -1
- package/src/types/DitoTypeText.vue +11 -14
- package/src/types/DitoTypeTreeList.vue +46 -8
- package/src/types/DitoTypeUpload.vue +190 -67
- package/src/utils/DataModel.js +368 -146
- package/src/utils/FileDropTargets.js +97 -0
- package/src/utils/ItemStores.js +31 -0
- package/src/utils/ListQuery.js +115 -0
- package/src/utils/LoadingTracker.js +76 -0
- package/src/utils/SchemaGraph.js +3 -2
- package/src/utils/Session.js +151 -0
- package/src/utils/ViewRegistry.js +85 -0
- package/src/utils/accessor.js +12 -4
- package/src/utils/affixes.js +33 -0
- package/src/utils/changeOnceEdited.js +33 -0
- package/src/utils/clipboard.js +55 -0
- package/src/utils/data.js +10 -5
- package/src/utils/dialogs.js +59 -0
- package/src/utils/dragResize.js +61 -0
- package/src/utils/filter.js +36 -2
- package/src/utils/html.js +9 -0
- package/src/utils/list.js +10 -0
- package/src/utils/options.js +4 -0
- package/src/utils/registration.js +18 -0
- package/src/utils/request.js +108 -13
- package/src/utils/route.js +6 -17
- package/src/utils/schema/data.js +24 -2
- package/src/utils/schema/events.js +19 -0
- package/src/utils/schema/item.js +114 -0
- package/src/utils/schema/lookup.js +39 -14
- package/src/utils/schema/setup.js +5 -5
- package/src/utils/schema/validation.js +16 -2
- package/src/utils/uid.js +105 -8
- package/src/validators/_decimals.js +16 -5
- package/types/index.d.ts +168 -41
- package/src/mixins/LoadingMixin.js +0 -23
- package/src/mixins/PulldownMixin.js +0 -72
- package/src/styles/_pulldown.scss +0 -38
|
@@ -12,7 +12,6 @@
|
|
|
12
12
|
:disabled="disabled"
|
|
13
13
|
:collapsed="collapsed"
|
|
14
14
|
:collapsible="collapsible"
|
|
15
|
-
:labelNode="labelNode"
|
|
16
15
|
)
|
|
17
16
|
</template>
|
|
18
17
|
|
|
@@ -23,7 +22,7 @@ import SchemaParentMixin from '../mixins/SchemaParentMixin.js'
|
|
|
23
22
|
import { getSchemaAccessor } from '../utils/accessor.js'
|
|
24
23
|
import { setupSchemaComponents } from '../utils/schema/setup.js'
|
|
25
24
|
import { getItemFormSchema } from '../utils/schema/lookup.js'
|
|
26
|
-
import { hasComponentNamed } from '../utils/schema/structure.js'
|
|
25
|
+
import { hasComponentNamed, isCompact } from '../utils/schema/structure.js'
|
|
27
26
|
|
|
28
27
|
// @vue/component
|
|
29
28
|
export default DitoTypeComponent.register('section', {
|
|
@@ -39,6 +38,17 @@ export default DitoTypeComponent.register('section', {
|
|
|
39
38
|
treatNullAsMissing: ({ schema }) => !!schema.nested,
|
|
40
39
|
defaultNested: false,
|
|
41
40
|
generateLabel: false,
|
|
41
|
+
// The header of the section's form displays the label, except in compact
|
|
42
|
+
// forms, which don't have labels in their header, see `DitoSchemaInlined`.
|
|
43
|
+
// The form can depend on the item, see `item`.
|
|
44
|
+
rendersOwnLabel: context =>
|
|
45
|
+
!isCompact(
|
|
46
|
+
getItemFormSchema(
|
|
47
|
+
context.schema,
|
|
48
|
+
context.nested ? context.value : context.item,
|
|
49
|
+
context
|
|
50
|
+
)
|
|
51
|
+
),
|
|
42
52
|
|
|
43
53
|
computed: {
|
|
44
54
|
item() {
|
|
@@ -94,14 +104,18 @@ export default DitoTypeComponent.register('section', {
|
|
|
94
104
|
@import '../styles/_imports';
|
|
95
105
|
|
|
96
106
|
.dito-section {
|
|
97
|
-
&--labelled {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
107
|
+
&--labelled > &__schema {
|
|
108
|
+
// Display the header with the label above the bordered content.
|
|
109
|
+
> .dito-schema-content {
|
|
110
|
+
border: $border-style;
|
|
111
|
+
border-radius: $border-radius;
|
|
112
|
+
margin-top: $form-spacing-half;
|
|
113
|
+
}
|
|
102
114
|
|
|
103
|
-
|
|
104
|
-
border
|
|
115
|
+
> .dito-schema-header + .dito-schema-content > .dito-pane {
|
|
116
|
+
// Inside the border, the content's margin replaces the spacing below the
|
|
117
|
+
// header, see `DitoSchema`.
|
|
118
|
+
margin-top: -$form-spacing-half;
|
|
105
119
|
}
|
|
106
120
|
}
|
|
107
121
|
}
|
|
@@ -2,13 +2,10 @@
|
|
|
2
2
|
//- Nesting is needed to make an arrow appear over the select item:
|
|
3
3
|
.dito-select
|
|
4
4
|
.dito-select__inner
|
|
5
|
-
|
|
6
|
-
:items="schema.prefix"
|
|
5
|
+
DitoInputAffixes(
|
|
7
6
|
position="prefix"
|
|
8
|
-
|
|
7
|
+
v-bind="inputAffixesProps.prefix"
|
|
9
8
|
absolute
|
|
10
|
-
:disabled="disabled"
|
|
11
|
-
:parentContext="context"
|
|
12
9
|
)
|
|
13
10
|
select(
|
|
14
11
|
:id="componentPath"
|
|
@@ -21,6 +18,13 @@
|
|
|
21
18
|
template(
|
|
22
19
|
v-if="populate"
|
|
23
20
|
)
|
|
21
|
+
//- Plain values whose option disappeared are kept and shown as
|
|
22
|
+
//- unavailable, rather than cleared without the user noticing:
|
|
23
|
+
option(
|
|
24
|
+
v-if="shouldShowUnavailableValue"
|
|
25
|
+
:value="selectedValue"
|
|
26
|
+
disabled
|
|
27
|
+
) {{ getLabelForOption(selectedValue) }} (unavailable)
|
|
24
28
|
template(
|
|
25
29
|
v-for="option in options"
|
|
26
30
|
)
|
|
@@ -40,40 +44,35 @@
|
|
|
40
44
|
v-else-if="selectedOption"
|
|
41
45
|
)
|
|
42
46
|
option(:value="selectedValue") {{ getLabelForOption(selectedOption) }}
|
|
43
|
-
|
|
44
|
-
:items="schema.suffix"
|
|
47
|
+
DitoInputAffixes(
|
|
45
48
|
position="suffix"
|
|
46
|
-
|
|
49
|
+
v-bind="inputAffixesProps.suffix"
|
|
47
50
|
absolute
|
|
48
|
-
:clearable="showClearButton"
|
|
49
|
-
:disabled="disabled"
|
|
50
|
-
:inlineInfo="inlineInfo"
|
|
51
|
-
:parentContext="context"
|
|
52
51
|
@clear="clear"
|
|
53
52
|
)
|
|
54
|
-
|
|
55
|
-
DitoEditButtons(
|
|
53
|
+
DitoOptionsEditButtons(
|
|
56
54
|
v-if="editable"
|
|
57
55
|
:schema="schema"
|
|
58
56
|
:dataPath="dataPath"
|
|
59
57
|
:data="data"
|
|
60
58
|
:meta="meta"
|
|
61
59
|
:store="store"
|
|
62
|
-
:
|
|
63
|
-
:
|
|
64
|
-
:editPath="editPath"
|
|
60
|
+
:parentContext="context"
|
|
61
|
+
:optionValue="selectedValue"
|
|
65
62
|
)
|
|
66
63
|
</template>
|
|
67
64
|
|
|
68
65
|
<script>
|
|
69
66
|
import DitoTypeComponent from '../DitoTypeComponent.js'
|
|
70
67
|
import OptionsMixin from '../mixins/OptionsMixin.js'
|
|
71
|
-
import
|
|
68
|
+
import DitoInputAffixes from '../components/DitoInputAffixes.vue'
|
|
69
|
+
import { getInputAffixesProps } from '../utils/affixes.js'
|
|
70
|
+
import DitoOptionsEditButtons from '../components/DitoOptionsEditButtons.vue'
|
|
72
71
|
|
|
73
72
|
// @vue/component
|
|
74
73
|
export default DitoTypeComponent.register('select', {
|
|
75
74
|
mixins: [OptionsMixin],
|
|
76
|
-
components: {
|
|
75
|
+
components: { DitoInputAffixes, DitoOptionsEditButtons },
|
|
77
76
|
|
|
78
77
|
nativeField: true,
|
|
79
78
|
|
|
@@ -83,6 +82,27 @@ export default DitoTypeComponent.register('select', {
|
|
|
83
82
|
// TODO: Set to `false` Once lineto e2e tests address their issues.
|
|
84
83
|
populate: true
|
|
85
84
|
}
|
|
85
|
+
},
|
|
86
|
+
|
|
87
|
+
computed: {
|
|
88
|
+
inputAffixesProps() {
|
|
89
|
+
return getInputAffixesProps(this)
|
|
90
|
+
},
|
|
91
|
+
|
|
92
|
+
// Whether the value is set but none of the loaded options has it. Values
|
|
93
|
+
// of option objects are replaced with `null` when their option disappears,
|
|
94
|
+
// see `OptionsMixin`, but plain values match any value, so they stay.
|
|
95
|
+
// Object values without `optionValue` are left to the select, which
|
|
96
|
+
// matches them to their options by deep equality.
|
|
97
|
+
shouldShowUnavailableValue() {
|
|
98
|
+
const { selectedValue } = this
|
|
99
|
+
return (
|
|
100
|
+
selectedValue != null &&
|
|
101
|
+
typeof selectedValue !== 'object' &&
|
|
102
|
+
this.hasOptions &&
|
|
103
|
+
!this.findOptionForValue(selectedValue)
|
|
104
|
+
)
|
|
105
|
+
}
|
|
86
106
|
}
|
|
87
107
|
})
|
|
88
108
|
</script>
|
|
@@ -119,10 +139,6 @@ export default DitoTypeComponent.register('select', {
|
|
|
119
139
|
}
|
|
120
140
|
}
|
|
121
141
|
|
|
122
|
-
.dito-edit-buttons {
|
|
123
|
-
margin-left: $form-spacing-half;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
142
|
// Handle width fill separately due to required nesting of select:
|
|
127
143
|
&.dito-component--fill {
|
|
128
144
|
select {
|
|
@@ -10,11 +10,15 @@
|
|
|
10
10
|
:max="max"
|
|
11
11
|
:step="stepValue"
|
|
12
12
|
)
|
|
13
|
+
//- The range input holds the name and the label of the field, the number
|
|
14
|
+
//- input gets a label of its own and no name, to not submit it twice:
|
|
13
15
|
DitoInput.dito-number(
|
|
14
16
|
v-if="input"
|
|
15
17
|
v-model="inputValue"
|
|
16
18
|
type="number"
|
|
17
19
|
v-bind="attributes"
|
|
20
|
+
:name="null"
|
|
21
|
+
:aria-label="numberInputLabel"
|
|
18
22
|
:min="min"
|
|
19
23
|
:max="max"
|
|
20
24
|
:step="stepValue"
|
|
@@ -38,7 +42,11 @@ export default DitoTypeComponent.register('slider', {
|
|
|
38
42
|
input: getSchemaAccessor('input', {
|
|
39
43
|
type: Boolean,
|
|
40
44
|
default: true
|
|
41
|
-
})
|
|
45
|
+
}),
|
|
46
|
+
|
|
47
|
+
numberInputLabel() {
|
|
48
|
+
return `${this.label || this.labelize(this.name)} Value`
|
|
49
|
+
}
|
|
42
50
|
}
|
|
43
51
|
})
|
|
44
52
|
</script>
|
|
@@ -7,22 +7,14 @@ DitoInput.dito-text(
|
|
|
7
7
|
v-bind="attributes"
|
|
8
8
|
)
|
|
9
9
|
template(#prefix)
|
|
10
|
-
|
|
11
|
-
:items="schema.prefix"
|
|
10
|
+
DitoInputAffixes(
|
|
12
11
|
position="prefix"
|
|
13
|
-
|
|
14
|
-
:disabled="disabled"
|
|
15
|
-
:parentContext="context"
|
|
12
|
+
v-bind="inputAffixesProps.prefix"
|
|
16
13
|
)
|
|
17
14
|
template(#suffix)
|
|
18
|
-
|
|
19
|
-
:items="schema.suffix"
|
|
15
|
+
DitoInputAffixes(
|
|
20
16
|
position="suffix"
|
|
21
|
-
|
|
22
|
-
:clearable="showClearButton"
|
|
23
|
-
:disabled="disabled"
|
|
24
|
-
:inlineInfo="inlineInfo"
|
|
25
|
-
:parentContext="context"
|
|
17
|
+
v-bind="inputAffixesProps.suffix"
|
|
26
18
|
@clear="clear"
|
|
27
19
|
)
|
|
28
20
|
</template>
|
|
@@ -30,7 +22,8 @@ DitoInput.dito-text(
|
|
|
30
22
|
<script>
|
|
31
23
|
import DitoTypeComponent from '../DitoTypeComponent.js'
|
|
32
24
|
import TextMixin from '../mixins/TextMixin'
|
|
33
|
-
import
|
|
25
|
+
import DitoInputAffixes from '../components/DitoInputAffixes.vue'
|
|
26
|
+
import { getInputAffixesProps } from '../utils/affixes.js'
|
|
34
27
|
import { DitoInput } from '@ditojs/ui/src'
|
|
35
28
|
|
|
36
29
|
const maskedPassword = '****************'
|
|
@@ -49,7 +42,7 @@ export default DitoTypeComponent.register(
|
|
|
49
42
|
// @vue/component
|
|
50
43
|
{
|
|
51
44
|
mixins: [TextMixin],
|
|
52
|
-
components: { DitoInput,
|
|
45
|
+
components: { DitoInput, DitoInputAffixes },
|
|
53
46
|
nativeField: true,
|
|
54
47
|
textField: true,
|
|
55
48
|
ignoreMissingValue: ({ schema }) => schema.type === 'password',
|
|
@@ -67,6 +60,10 @@ export default DitoTypeComponent.register(
|
|
|
67
60
|
},
|
|
68
61
|
|
|
69
62
|
computed: {
|
|
63
|
+
inputAffixesProps() {
|
|
64
|
+
return getInputAffixesProps(this)
|
|
65
|
+
},
|
|
66
|
+
|
|
70
67
|
inputType() {
|
|
71
68
|
return (
|
|
72
69
|
{
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
:data="treeData"
|
|
15
15
|
:draggable="draggable"
|
|
16
16
|
:open="true"
|
|
17
|
-
@
|
|
17
|
+
@change-children="changeChildren"
|
|
18
18
|
)
|
|
19
19
|
.dito-tree-form-container(
|
|
20
20
|
v-if="editPath && hasEditableForms"
|
|
@@ -28,7 +28,9 @@ import DitoTypeComponent from '../DitoTypeComponent.js'
|
|
|
28
28
|
import SourceMixin from '../mixins/SourceMixin.js'
|
|
29
29
|
import { resolveSchemaComponents } from '../utils/schema/setup.js'
|
|
30
30
|
import { hasFormSchema, getFormSchemas } from '../utils/schema/lookup.js'
|
|
31
|
+
import { updateOrder } from '../utils/schema/data.js'
|
|
31
32
|
import { getParentDataPath } from '../utils/data.js'
|
|
33
|
+
import { isPathWithin } from '../utils/route.js'
|
|
32
34
|
|
|
33
35
|
export default DitoTypeComponent.register(
|
|
34
36
|
['tree-list', 'tree-object'],
|
|
@@ -36,24 +38,20 @@ export default DitoTypeComponent.register(
|
|
|
36
38
|
{
|
|
37
39
|
mixins: [SourceMixin],
|
|
38
40
|
|
|
39
|
-
provide() {
|
|
40
|
-
return { container: this }
|
|
41
|
-
},
|
|
42
|
-
|
|
43
41
|
getSourceType(type) {
|
|
44
42
|
return type === 'tree-object' ? 'object' : 'list'
|
|
45
43
|
},
|
|
46
44
|
|
|
47
45
|
computed: {
|
|
48
46
|
path() {
|
|
49
|
-
// Accessed from DitoTreeItem through `
|
|
47
|
+
// Accessed from DitoTreeItem through `sourceComponent.path`:
|
|
50
48
|
return this.formComponent?.path
|
|
51
49
|
},
|
|
52
50
|
|
|
53
51
|
editPath() {
|
|
54
|
-
// Accessed from DitoTreeItem through `
|
|
52
|
+
// Accessed from DitoTreeItem through `sourceComponent.editPath`:
|
|
55
53
|
const path = this.$route.path.slice(this.path?.length)
|
|
56
|
-
return path
|
|
54
|
+
return isPathWithin(path, `/${this.schema.path}`) ? path : ''
|
|
57
55
|
},
|
|
58
56
|
|
|
59
57
|
treeData() {
|
|
@@ -100,6 +98,46 @@ export default DitoTypeComponent.register(
|
|
|
100
98
|
}
|
|
101
99
|
},
|
|
102
100
|
|
|
101
|
+
methods: {
|
|
102
|
+
// Replaces the children of the tree item that holds them in `data`, as
|
|
103
|
+
// the only writer of the tree, see `DitoTreeItem.changeChildren()`.
|
|
104
|
+
changeChildren({ data, childrenSchema, path, children }) {
|
|
105
|
+
const previousChildren = data[childrenSchema.name]
|
|
106
|
+
updateOrder(childrenSchema, children)
|
|
107
|
+
if (data === this.treeData && this.isListSource) {
|
|
108
|
+
// The root item of tree lists holds the list in a wrapper object,
|
|
109
|
+
// see `treeData`.
|
|
110
|
+
this.value = children
|
|
111
|
+
} else {
|
|
112
|
+
data[childrenSchema.name] = children
|
|
113
|
+
}
|
|
114
|
+
this.followEditedChild({
|
|
115
|
+
childrenPath: childrenSchema.path && `${path}/${childrenSchema.path}`,
|
|
116
|
+
previousChildren,
|
|
117
|
+
children
|
|
118
|
+
})
|
|
119
|
+
this.onChange()
|
|
120
|
+
},
|
|
121
|
+
|
|
122
|
+
// Keeps the form of an edited child or of one of its descendants open
|
|
123
|
+
// at the child's new index, or closes it if the child was removed.
|
|
124
|
+
followEditedChild({ childrenPath, previousChildren, children }) {
|
|
125
|
+
const prefix = `${childrenPath}/`
|
|
126
|
+
const { editPath } = this
|
|
127
|
+
if (childrenPath && editPath.startsWith(prefix)) {
|
|
128
|
+
const [index, ...rest] = editPath.slice(prefix.length).split('/')
|
|
129
|
+
const newIndex = children.indexOf(previousChildren?.[index])
|
|
130
|
+
if (newIndex !== +index) {
|
|
131
|
+
const path =
|
|
132
|
+
newIndex >= 0
|
|
133
|
+
? [`${this.path}${prefix}${newIndex}`, ...rest].join('/')
|
|
134
|
+
: this.path
|
|
135
|
+
this.$router.push({ path, query: this.$route.query })
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
},
|
|
140
|
+
|
|
103
141
|
async processSchema(
|
|
104
142
|
api,
|
|
105
143
|
schema,
|