@live-change/frontend-auto-form 0.9.42 → 0.9.44
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/front/src/components/crud/InjectedObjectIndentification.vue +123 -0
- package/front/src/components/crud/ModelEditor.vue +28 -4
- package/front/src/components/form/ArrayInput.vue +0 -1
- package/front/src/components/form/AutoField.vue +2 -13
- package/front/src/components/form/AutoInput.vue +2 -15
- package/front/src/components/form/GroupField.vue +3 -7
- package/front/src/components/form/ObjectInput.vue +49 -4
- package/front/src/components/form/ObjectPicker.vue +12 -0
- package/front/src/components/form/inputConfigInjection.js +68 -0
- package/front/src/components/form/provideAutoInputConfiguration.js +103 -0
- package/front/src/logic/editorData.js +1 -1
- package/index.js +2 -2
- package/package.json +13 -13
- package/front/src/config.js +0 -82
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<router-link v-if="link" :to="linkPath">
|
|
3
|
+
<ObjectIdentification
|
|
4
|
+
:objectType="type"
|
|
5
|
+
:object="object"
|
|
6
|
+
:data="objectData"
|
|
7
|
+
:inline="inline"
|
|
8
|
+
/>
|
|
9
|
+
</router-link>
|
|
10
|
+
<ObjectIdentification
|
|
11
|
+
v-else
|
|
12
|
+
:objectType="type"
|
|
13
|
+
:object="object"
|
|
14
|
+
:data="objectData"
|
|
15
|
+
:inline="inline"
|
|
16
|
+
/>
|
|
17
|
+
</template>
|
|
18
|
+
|
|
19
|
+
<script setup>
|
|
20
|
+
|
|
21
|
+
import { computed, defineProps, toRefs } from 'vue'
|
|
22
|
+
import { injectComponent } from '@live-change/vue3-components'
|
|
23
|
+
|
|
24
|
+
const props = defineProps({
|
|
25
|
+
type: {
|
|
26
|
+
type: String,
|
|
27
|
+
required: true
|
|
28
|
+
},
|
|
29
|
+
object: {
|
|
30
|
+
type: String,
|
|
31
|
+
required: true
|
|
32
|
+
},
|
|
33
|
+
data: {
|
|
34
|
+
type: Object,
|
|
35
|
+
default: () => null
|
|
36
|
+
},
|
|
37
|
+
link: {
|
|
38
|
+
type: String,
|
|
39
|
+
default: 'view'
|
|
40
|
+
},
|
|
41
|
+
inline: {
|
|
42
|
+
type: Boolean,
|
|
43
|
+
default: false
|
|
44
|
+
}
|
|
45
|
+
})
|
|
46
|
+
const { type, object, data, link, inline } = toRefs(props)
|
|
47
|
+
|
|
48
|
+
import AutoObjectIdentification from './AutoObjectIdentification.vue'
|
|
49
|
+
|
|
50
|
+
import { useApi, usePath, live } from '@live-change/vue3-ssr'
|
|
51
|
+
const api = useApi()
|
|
52
|
+
const path = usePath()
|
|
53
|
+
|
|
54
|
+
const serviceAndModel = computed(() => {
|
|
55
|
+
const [service, model] = type.value.split('_')
|
|
56
|
+
return { service, model }
|
|
57
|
+
})
|
|
58
|
+
const service = computed(() => serviceAndModel.value.service)
|
|
59
|
+
const model = computed(() => serviceAndModel.value.model)
|
|
60
|
+
|
|
61
|
+
const ObjectIdentification = computed(() =>
|
|
62
|
+
injectComponent({
|
|
63
|
+
name: 'ObjectIdentification',
|
|
64
|
+
type: type.value,
|
|
65
|
+
service: service.value,
|
|
66
|
+
model: model.value
|
|
67
|
+
}, AutoObjectIdentification)
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
const modelDefinition = computed(() => {
|
|
71
|
+
return api.services?.[service.value]?.models?.[model.value]
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
const identificationViewName = computed(() => {
|
|
75
|
+
return modelDefinition.value?.crud?.identification || modelDefinition.value?.crud?.read
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
const identificationConfig = computed(() => {
|
|
79
|
+
return modelDefinition.value?.identification
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
const objectDataPath = computed(() => {
|
|
83
|
+
if(data.value) return null
|
|
84
|
+
if(!identificationConfig.value) return null
|
|
85
|
+
const viewName = identificationViewName.value
|
|
86
|
+
if(!viewName) return null
|
|
87
|
+
const modelName = model.value
|
|
88
|
+
return path[service.value][viewName]({
|
|
89
|
+
[modelName[0].toLowerCase() + modelName.slice(1)]: object.value
|
|
90
|
+
})
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
const loadedObjectData = await live(objectDataPath)
|
|
94
|
+
const objectData = computed(() => data.value || loadedObjectData.value)
|
|
95
|
+
|
|
96
|
+
function objectIdentifiers(object) {
|
|
97
|
+
const identifiers = {}
|
|
98
|
+
for(const identifierDefinition of modelDefinition.value.identifiers) {
|
|
99
|
+
if(typeof identifierDefinition === 'string') {
|
|
100
|
+
identifiers[identifierDefinition] = object[identifierDefinition]
|
|
101
|
+
} else {
|
|
102
|
+
if(identifierDefinition.field === 'id') {
|
|
103
|
+
identifiers[identifierDefinition.name] = object?.to ?? object.id
|
|
104
|
+
} else {
|
|
105
|
+
identifiers[identifierDefinition.name] = object[identifierDefinition.field]
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return identifiers
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const linkPath = computed(() => {
|
|
113
|
+
return {
|
|
114
|
+
name: 'auto-form:view',
|
|
115
|
+
params: {
|
|
116
|
+
serviceName: service.value,
|
|
117
|
+
modelName: model.value,
|
|
118
|
+
identifiers: Object.values(objectIdentifiers(objectData.value))
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
})
|
|
122
|
+
|
|
123
|
+
</script>
|
|
@@ -16,11 +16,33 @@
|
|
|
16
16
|
</div>
|
|
17
17
|
|
|
18
18
|
<form v-if="editor" @submit="handleSave" @reset="handleReset">
|
|
19
|
+
<div v-for="identifier in modelDefinition.identifiers">
|
|
20
|
+
<template v-if="identifier.slice(-4) !== 'Type'">
|
|
21
|
+
<div v-if="identifiers[identifier]" class="flex flex-col mb-3">
|
|
22
|
+
<div class="min-w-[8rem] font-medium">{{ identifier }}</div>
|
|
23
|
+
<div class="">
|
|
24
|
+
<InjectedObjectIndentification
|
|
25
|
+
:type="identifiers[identifier+'Type'] ?? modelDefinition.properties[identifier].type"
|
|
26
|
+
:object="identifiers[identifier]"
|
|
27
|
+
/>
|
|
28
|
+
</div>
|
|
29
|
+
</div>
|
|
30
|
+
<div v-else class="flex flex-col mb-3">
|
|
31
|
+
<auto-field :key="identifier"
|
|
32
|
+
v-model="editor.value.value[identifier]"
|
|
33
|
+
:definition="modelDefinition.properties[identifier]"
|
|
34
|
+
:label="identifier"
|
|
35
|
+
:rootValue="props.rootValue" :propName="identifier"
|
|
36
|
+
:i18n="i18n"
|
|
37
|
+
class="col-span-12" />
|
|
38
|
+
</div>
|
|
39
|
+
</template>
|
|
40
|
+
</div>
|
|
19
41
|
<auto-editor
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
42
|
+
:definition="modelDefinition"
|
|
43
|
+
v-model="editor.value.value"
|
|
44
|
+
:rootValue="editor.value.value"
|
|
45
|
+
:i18n="i18n" />
|
|
24
46
|
<EditorButtons :editor="editor" reset-button />
|
|
25
47
|
</form>
|
|
26
48
|
</div>
|
|
@@ -30,6 +52,7 @@
|
|
|
30
52
|
|
|
31
53
|
import AutoEditor from '../form/AutoEditor.vue'
|
|
32
54
|
import EditorButtons from './EditorButtons.vue'
|
|
55
|
+
import AutoField from "../form/AutoField.vue"
|
|
33
56
|
|
|
34
57
|
import { ref, computed, onMounted, defineProps, defineEmits, toRefs } from 'vue'
|
|
35
58
|
|
|
@@ -73,6 +96,7 @@
|
|
|
73
96
|
|
|
74
97
|
import { editorData } from "@live-change/frontend-auto-form"
|
|
75
98
|
import { computedAsync } from "@vueuse/core"
|
|
99
|
+
import InjectedObjectIndentification from './InjectedObjectIndentification.vue'
|
|
76
100
|
|
|
77
101
|
const editor = computedAsync(async () => {
|
|
78
102
|
try {
|
|
@@ -43,7 +43,6 @@
|
|
|
43
43
|
|
|
44
44
|
import AutoInput from "./AutoInput.vue"
|
|
45
45
|
|
|
46
|
-
import { inputs, types } from '../../config.js'
|
|
47
46
|
import { computed, getCurrentInstance, inject, toRefs, onMounted, ref, useId } from 'vue'
|
|
48
47
|
|
|
49
48
|
const isMounted = ref(false)
|
|
@@ -159,18 +158,8 @@
|
|
|
159
158
|
&& props.modelValue?.length < minLengthValidation.value.length
|
|
160
159
|
)
|
|
161
160
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
types: {}
|
|
165
|
-
})
|
|
166
|
-
const inputConfig = computed(() => {
|
|
167
|
-
if(definition.value.input) return config.inputs?.[definition.value.input] ?? inputs[definition.value.input]
|
|
168
|
-
if(definition.value.type) return config.types?.[definition.value.type] ?? types[definition.value.type]
|
|
169
|
-
return {
|
|
170
|
-
...(config.inputs?.default ?? inputs.default),
|
|
171
|
-
...definition?.autoForm?.config, // possible to modify config per input
|
|
172
|
-
}
|
|
173
|
-
})
|
|
161
|
+
import { provideInputConfigByDefinition } from './inputConfigInjection.js'
|
|
162
|
+
const inputConfig = computed(() => provideInputConfigByDefinition(definition.value))
|
|
174
163
|
|
|
175
164
|
const label = computed(() => props.i18n + (props.label || definition.value.label || props.name))
|
|
176
165
|
|
|
@@ -9,9 +9,7 @@
|
|
|
9
9
|
</template>
|
|
10
10
|
|
|
11
11
|
<script setup>
|
|
12
|
-
import { inputs, types } from '../../config.js'
|
|
13
12
|
import { computed, inject, toRefs } from 'vue'
|
|
14
|
-
import deepmerge from 'deepmerge';
|
|
15
13
|
|
|
16
14
|
const props = defineProps({
|
|
17
15
|
modelValue: {
|
|
@@ -43,19 +41,8 @@
|
|
|
43
41
|
|
|
44
42
|
const { definition, modelValue, propName } = toRefs(props)
|
|
45
43
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
types: {}
|
|
49
|
-
})
|
|
50
|
-
const inputConfig = computed(() => {
|
|
51
|
-
let baseConfig
|
|
52
|
-
if(definition.value.input && !baseConfig) baseConfig =
|
|
53
|
-
config.inputs?.[definition.value.input] ?? inputs[definition.value.input]
|
|
54
|
-
if(definition.value.type && !baseConfig) baseConfig =
|
|
55
|
-
config.types?.[definition.value.type] ?? types[definition.value.type]
|
|
56
|
-
if(!baseConfig) baseConfig = config.inputs?.default ?? inputs.default
|
|
57
|
-
return deepmerge(baseConfig, definition.value?.inputConfig ?? {}) // possible to modify config per input
|
|
58
|
-
})
|
|
44
|
+
import { provideInputConfigByDefinition } from './inputConfigInjection.js'
|
|
45
|
+
const inputConfig = computed(() => provideInputConfigByDefinition(definition.value))
|
|
59
46
|
|
|
60
47
|
const definitionIf = computed(() => {
|
|
61
48
|
if(definition.value?.if) {
|
|
@@ -15,8 +15,7 @@
|
|
|
15
15
|
|
|
16
16
|
<script setup>
|
|
17
17
|
import AutoInput from "./AutoInput.vue"
|
|
18
|
-
import {
|
|
19
|
-
import { computed, inject, toRefs, getCurrentInstance } from 'vue'
|
|
18
|
+
import { computed, toRefs, getCurrentInstance } from 'vue'
|
|
20
19
|
import Message from 'primevue/message'
|
|
21
20
|
|
|
22
21
|
import { useI18n } from 'vue-i18n'
|
|
@@ -87,11 +86,8 @@
|
|
|
87
86
|
return true
|
|
88
87
|
})
|
|
89
88
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
if(definition.value?.type) return types[definition.value.type]
|
|
93
|
-
return inputs.default
|
|
94
|
-
})
|
|
89
|
+
import { provideInputConfigByDefinition } from './inputConfigInjection.js'
|
|
90
|
+
const inputConfig = computed(() => provideInputConfigByDefinition(definition.value))
|
|
95
91
|
|
|
96
92
|
import { validateData } from "@live-change/vue3-components"
|
|
97
93
|
|
|
@@ -1,15 +1,41 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div>
|
|
3
|
+
<div ref="selectElement" class="p-select p-component p-inputwrapper w-full" @click="toggleObjectPicker">
|
|
4
|
+
<span class="p-select-label p-placeholder" tabindex="0" role="combobox">
|
|
5
|
+
Select object
|
|
6
|
+
</span>
|
|
7
|
+
<div class="p-select-dropdown" data-pc-section="dropdown">
|
|
8
|
+
<ChevronDownIcon />
|
|
9
|
+
</div>
|
|
10
|
+
</div>
|
|
3
11
|
|
|
12
|
+
<Popover ref="objectPickerPopover" :pt="{
|
|
13
|
+
root: {
|
|
14
|
+
class: 'object-picker-popover overflow-y-auto',
|
|
15
|
+
style: {
|
|
16
|
+
minWidth: `${width}px`,
|
|
17
|
+
maxHeight: `calc(50vh - 30px)`
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}">
|
|
21
|
+
<ObjectPicker />
|
|
22
|
+
</Popover>
|
|
23
|
+
|
|
24
|
+
<!-- needed to autoload styles: -->
|
|
25
|
+
<Select class="hidden" />
|
|
4
26
|
</div>
|
|
5
27
|
</template>
|
|
6
28
|
|
|
7
29
|
<script setup>
|
|
30
|
+
import ChevronDownIcon from '@primevue/icons/chevrondown'
|
|
31
|
+
import Select from 'primevue/select'
|
|
32
|
+
import Popover from 'primevue/popover'
|
|
33
|
+
import ObjectPicker from './ObjectPicker.vue'
|
|
8
34
|
|
|
35
|
+
import { defineProps, defineEmits, toRefs, ref, defineModel } from 'vue'
|
|
36
|
+
import { useElementSize } from '@vueuse/core'
|
|
9
37
|
|
|
10
38
|
const props = defineProps({
|
|
11
|
-
modelValue: {
|
|
12
|
-
},
|
|
13
39
|
definition: {
|
|
14
40
|
type: Object
|
|
15
41
|
},
|
|
@@ -19,12 +45,31 @@
|
|
|
19
45
|
}
|
|
20
46
|
})
|
|
21
47
|
|
|
22
|
-
const
|
|
48
|
+
const model = defineModel({
|
|
49
|
+
required: true
|
|
50
|
+
})
|
|
23
51
|
|
|
24
52
|
const { value, definition, modelValue } = toRefs(props)
|
|
25
53
|
|
|
54
|
+
const objectPickerPopover = ref()
|
|
55
|
+
const selectElement = ref()
|
|
56
|
+
const { width } = useElementSize(selectElement)
|
|
57
|
+
|
|
58
|
+
const toggleObjectPicker = (event) => {
|
|
59
|
+
objectPickerPopover.value.toggle(event)
|
|
60
|
+
}
|
|
61
|
+
|
|
26
62
|
</script>
|
|
27
63
|
|
|
28
|
-
<style
|
|
64
|
+
<style>
|
|
65
|
+
.object-picker-popover {
|
|
66
|
+
margin-top: 1px;
|
|
67
|
+
}
|
|
68
|
+
.object-picker-popover:before {
|
|
69
|
+
display: none;
|
|
70
|
+
}
|
|
29
71
|
|
|
72
|
+
.object-picker-popover:after {
|
|
73
|
+
display: none;
|
|
74
|
+
}
|
|
30
75
|
</style>
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { provide, inject, h } from 'vue'
|
|
2
|
+
|
|
3
|
+
export function provideInputConfig(description, inputConfig) {
|
|
4
|
+
if(!description) throw new Error("provideInputConfig: description is required")
|
|
5
|
+
if(!inputConfig) throw new Error("provideInputConfig: inputConfig is required")
|
|
6
|
+
if(typeof description === 'string') description = { name: description }
|
|
7
|
+
|
|
8
|
+
for(let key in description) {
|
|
9
|
+
for(let value of (description[key] instanceof Array ? description[key] : [description[key]])) {
|
|
10
|
+
const provideKey = `input:${key}=${value}`
|
|
11
|
+
console.log("PROVIDE COMPONENT", provideKey)
|
|
12
|
+
provide(provideKey, {
|
|
13
|
+
inputConfig,
|
|
14
|
+
description
|
|
15
|
+
})
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function injectInputConfig(request, defaultInputConfig, factory) {
|
|
21
|
+
if(!request) throw new Error("injectInputConfig: request is required")
|
|
22
|
+
if(typeof request === 'string') request = { name: request }
|
|
23
|
+
//console.log("INJECT INPUT CONFIG", request)
|
|
24
|
+
const filter = request.filter || (() => true)
|
|
25
|
+
delete request.filter
|
|
26
|
+
|
|
27
|
+
for(let key in request) {
|
|
28
|
+
const provideKey = `input:${key}=${request[key]}`
|
|
29
|
+
console.log("INJECT INPUT CONFIG PROVIDE KEY", provideKey)
|
|
30
|
+
const entry = inject(provideKey, null)
|
|
31
|
+
console.log("RESOLVED INPUT CONFIG", entry)
|
|
32
|
+
if(!entry) continue
|
|
33
|
+
let isValid = true
|
|
34
|
+
for(let key in entry.description) {
|
|
35
|
+
const value = request[key]
|
|
36
|
+
if(Array.isArray(value)) {
|
|
37
|
+
if(!value.includes(entry.description[key])) isValid = false
|
|
38
|
+
} else if(value !== entry.description[key]) isValid = false
|
|
39
|
+
}
|
|
40
|
+
console.log("RESOLVED COMPONENT VALID", isValid, filter(entry))
|
|
41
|
+
if(isValid && filter(entry)) return entry.inputConfig
|
|
42
|
+
}
|
|
43
|
+
return factory ? defaultInputConfig() : defaultInputConfig
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
import { defineAsyncComponent } from 'vue'
|
|
47
|
+
export function inputConfig(src, config) {
|
|
48
|
+
return {
|
|
49
|
+
component: src && defineAsyncComponent(src),
|
|
50
|
+
...config,
|
|
51
|
+
with(config) {
|
|
52
|
+
return { component: this.component, ...config }
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
import deepmerge from 'deepmerge'
|
|
58
|
+
export function provideInputConfigByDefinition(definition) {
|
|
59
|
+
let baseConfig
|
|
60
|
+
if(definition?.input && !baseConfig) baseConfig =
|
|
61
|
+
injectInputConfig({ name: definition.input }, null)
|
|
62
|
+
if(definition?.type && !baseConfig) baseConfig =
|
|
63
|
+
injectInputConfig({ type: definition.type }, null)
|
|
64
|
+
if(!baseConfig) baseConfig = injectInputConfig({ name: 'default' }, null)
|
|
65
|
+
const config = deepmerge(baseConfig, definition?.inputConfig ?? {}) // possible to modify config per input
|
|
66
|
+
if(Object.keys(config).length === 0) return null
|
|
67
|
+
return config
|
|
68
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { defineAsyncComponent } from 'vue'
|
|
2
|
+
import { provideInputConfig, inputConfig } from './inputConfigInjection'
|
|
3
|
+
|
|
4
|
+
export const inputs = {
|
|
5
|
+
}
|
|
6
|
+
export const types = {
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
types.String = inputs.text = inputConfig( () => import('primevue/inputtext'))
|
|
10
|
+
inputs.textarea = inputConfig(() => import('primevue/textarea'), { attributes: { autoResize: true } })
|
|
11
|
+
|
|
12
|
+
inputs.password = inputConfig(() => import('primevue/password'))
|
|
13
|
+
|
|
14
|
+
const number = inputConfig(() => import('primevue/inputnumber'))
|
|
15
|
+
inputs.integer = number
|
|
16
|
+
types.Number = inputs.decimal = number.with({ attributes: { mode: 'decimal' } })
|
|
17
|
+
|
|
18
|
+
types.Object = inputs.object = inputConfig(() => import('./AutoEditor.vue'), {
|
|
19
|
+
fieldComponent: defineAsyncComponent(() => import('./GroupField.vue'))
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
types.Array = inputs.list = inputConfig(() => import('./ArrayInput.vue'), {
|
|
23
|
+
fieldComponent: defineAsyncComponent(() => import('./GroupField.vue'))
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
types.Date = inputs.datetime = inputConfig(() => import('./Calendar.vue'), { attributes: { showTime: true } })
|
|
27
|
+
|
|
28
|
+
inputs.select = inputConfig(() => import('primevue/dropdown'), {
|
|
29
|
+
attributes: (config) => {
|
|
30
|
+
const { definition, i18n, t, te } = config
|
|
31
|
+
// console.log("SELECT", config)
|
|
32
|
+
return {
|
|
33
|
+
options: definition.options ?? definition.enum,
|
|
34
|
+
optionLabel: option => {
|
|
35
|
+
const i18nId = (definition.i18n ?? i18n + ':options') + '.' + option
|
|
36
|
+
if(te(i18nId)) return t(i18nId)
|
|
37
|
+
return t(option)
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
inputs.multiselect = inputConfig(() => import('primevue/multiselect'), {
|
|
44
|
+
attributes: (config) => {
|
|
45
|
+
const { definition, i18n, t, te } = config
|
|
46
|
+
return {
|
|
47
|
+
options: definition.of.options ?? definition.of.enum ?? definition.options ?? definition.enum,
|
|
48
|
+
optionLabel: option => {
|
|
49
|
+
const i18nId = (definition.i18n ?? i18n + ':options') + '.' + option
|
|
50
|
+
if(te(i18nId)) return t(i18nId)
|
|
51
|
+
return t(option)
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
inputs.duration = inputConfig(() => import('primevue/inputmask'), {
|
|
58
|
+
attributes: { mask: '99:99:99' }
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
types.Image = inputs.image = inputConfig(
|
|
62
|
+
async () => (await import('@live-change/image-frontend')).ImageInput
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
types.Boolean = inputs.switch = inputConfig(
|
|
66
|
+
async () => (await import('primevue/inputswitch'))
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
/*
|
|
70
|
+
types.Boolean = inputs.switch = {
|
|
71
|
+
fieldComponent: defineAsyncComponent(() => import('./SwitchField.vue')),
|
|
72
|
+
}*/
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
export function provideAutoInputConfiguration() {
|
|
76
|
+
for(let type in types) {
|
|
77
|
+
provideInputConfig({
|
|
78
|
+
type: type
|
|
79
|
+
}, types[type])
|
|
80
|
+
}
|
|
81
|
+
for(let input in inputs) {
|
|
82
|
+
provideInputConfig({
|
|
83
|
+
name: input
|
|
84
|
+
}, inputs[input])
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
import { useApi } from '@live-change/vue3-ssr'
|
|
89
|
+
|
|
90
|
+
export function provideMetadataBasedAutoInputConfiguration() {
|
|
91
|
+
const objectInputConfig = inputConfig(() => import('./ObjectInput.vue'))
|
|
92
|
+
provideInputConfig({
|
|
93
|
+
name: 'object'
|
|
94
|
+
}, objectInputConfig)
|
|
95
|
+
const api = useApi()
|
|
96
|
+
for(const service of api.metadata.api.value.services) {
|
|
97
|
+
for(const modelName in service.models) {
|
|
98
|
+
provideInputConfig({
|
|
99
|
+
type: service.name + '_' + modelName
|
|
100
|
+
}, objectInputConfig)
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
@@ -65,7 +65,7 @@ export default function editorData(options) {
|
|
|
65
65
|
draftIdParts.push(identifier)
|
|
66
66
|
}
|
|
67
67
|
}
|
|
68
|
-
const isNew = (idKey ? (!identifiers[idKey]) : (!draftIdParts.
|
|
68
|
+
const isNew = (idKey ? (!identifiers[idKey]) : (!draftIdParts.every(key => identifiers[key])))
|
|
69
69
|
const draftId = (idKey ? identifiers[idKey]
|
|
70
70
|
: draftIdParts.map(key => JSON.stringify(identifiers[key])).join('_')) ?? 'new'
|
|
71
71
|
const draftIdentifiers = {
|
package/index.js
CHANGED
|
@@ -4,8 +4,8 @@ import AutoEditor from './front/src/components/form/AutoEditor.vue'
|
|
|
4
4
|
|
|
5
5
|
export { AutoInput, AutoField, AutoEditor }
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
export
|
|
7
|
+
export * from './front/src/components/form/provideAutoInputConfiguration.js'
|
|
8
|
+
export * from './front/src/components/form/inputConfigInjection.js'
|
|
9
9
|
|
|
10
10
|
import editorData from './front/src/logic/editorData.js'
|
|
11
11
|
export { editorData }
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@live-change/frontend-auto-form",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.44",
|
|
4
4
|
"scripts": {
|
|
5
5
|
"memDev": "node server/start.js memDev --enableSessions --initScript ./init.js --dbAccess",
|
|
6
6
|
"localDevInit": "rm tmp.db; lcli localDev --enableSessions --initScript ./init.js",
|
|
@@ -22,16 +22,16 @@
|
|
|
22
22
|
"type": "module",
|
|
23
23
|
"dependencies": {
|
|
24
24
|
"@fortawesome/fontawesome-free": "^6.7.2",
|
|
25
|
-
"@live-change/cli": "^0.9.
|
|
26
|
-
"@live-change/dao": "^0.9.
|
|
27
|
-
"@live-change/dao-vue3": "^0.9.
|
|
28
|
-
"@live-change/dao-websocket": "^0.9.
|
|
29
|
-
"@live-change/framework": "^0.9.
|
|
30
|
-
"@live-change/image-frontend": "^0.9.
|
|
31
|
-
"@live-change/image-service": "^0.9.
|
|
32
|
-
"@live-change/session-service": "^0.9.
|
|
33
|
-
"@live-change/vue3-components": "^0.9.
|
|
34
|
-
"@live-change/vue3-ssr": "^0.9.
|
|
25
|
+
"@live-change/cli": "^0.9.44",
|
|
26
|
+
"@live-change/dao": "^0.9.44",
|
|
27
|
+
"@live-change/dao-vue3": "^0.9.44",
|
|
28
|
+
"@live-change/dao-websocket": "^0.9.44",
|
|
29
|
+
"@live-change/framework": "^0.9.44",
|
|
30
|
+
"@live-change/image-frontend": "^0.9.44",
|
|
31
|
+
"@live-change/image-service": "^0.9.44",
|
|
32
|
+
"@live-change/session-service": "^0.9.44",
|
|
33
|
+
"@live-change/vue3-components": "^0.9.44",
|
|
34
|
+
"@live-change/vue3-ssr": "^0.9.44",
|
|
35
35
|
"@vueuse/core": "^12.3.0",
|
|
36
36
|
"codeceptjs-assert": "^0.0.5",
|
|
37
37
|
"compression": "^1.7.5",
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
"vue3-scroll-border": "0.1.6"
|
|
53
53
|
},
|
|
54
54
|
"devDependencies": {
|
|
55
|
-
"@live-change/codeceptjs-helper": "^0.9.
|
|
55
|
+
"@live-change/codeceptjs-helper": "^0.9.44",
|
|
56
56
|
"codeceptjs": "^3.6.10",
|
|
57
57
|
"generate-password": "1.7.1",
|
|
58
58
|
"playwright": "1.49.1",
|
|
@@ -63,5 +63,5 @@
|
|
|
63
63
|
"author": "Michał Łaszczewski <michal@laszczewski.pl>",
|
|
64
64
|
"license": "ISC",
|
|
65
65
|
"description": "",
|
|
66
|
-
"gitHead": "
|
|
66
|
+
"gitHead": "6e9cf980b2ac6e4e7d78955cbf97ae1c2963bcab"
|
|
67
67
|
}
|
package/front/src/config.js
DELETED
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
import { defineAsyncComponent } from 'vue'
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
export const inputs = {
|
|
5
|
-
}
|
|
6
|
-
export const types = {
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export function input(src, config) {
|
|
10
|
-
return {
|
|
11
|
-
component: src && defineAsyncComponent(src),
|
|
12
|
-
...config,
|
|
13
|
-
with(config) {
|
|
14
|
-
return { component: this.component, ...config }
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
types.String = inputs.text = input( () => import('primevue/inputtext'))
|
|
20
|
-
inputs.textarea = input(() => import('primevue/textarea'), { attributes: { autoResize: true } })
|
|
21
|
-
|
|
22
|
-
inputs.password = input(() => import('primevue/password'))
|
|
23
|
-
|
|
24
|
-
const number = input(() => import('primevue/inputnumber'))
|
|
25
|
-
inputs.integer = number
|
|
26
|
-
types.Number = inputs.decimal = number.with({ attributes: { mode: 'decimal' } })
|
|
27
|
-
|
|
28
|
-
types.Object = inputs.object = input(() => import('./components/form/AutoEditor.vue'), {
|
|
29
|
-
fieldComponent: defineAsyncComponent(() => import('./components/form/GroupField.vue'))
|
|
30
|
-
})
|
|
31
|
-
|
|
32
|
-
types.Array = inputs.list = input(() => import('./components/form/ArrayInput.vue'), {
|
|
33
|
-
fieldComponent: defineAsyncComponent(() => import('./components/form/GroupField.vue'))
|
|
34
|
-
})
|
|
35
|
-
|
|
36
|
-
types.Date = inputs.datetime = input(() => import('./components/form/Calendar.vue'), { attributes: { showTime: true } })
|
|
37
|
-
|
|
38
|
-
inputs.select = input(() => import('primevue/dropdown'), {
|
|
39
|
-
attributes: (config) => {
|
|
40
|
-
const { definition, i18n, t, te } = config
|
|
41
|
-
// console.log("SELECT", config)
|
|
42
|
-
return {
|
|
43
|
-
options: definition.options ?? definition.enum,
|
|
44
|
-
optionLabel: option => {
|
|
45
|
-
const i18nId = (definition.i18n ?? i18n + ':options') + '.' + option
|
|
46
|
-
if(te(i18nId)) return t(i18nId)
|
|
47
|
-
return t(option)
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
})
|
|
52
|
-
|
|
53
|
-
inputs.multiselect = input(() => import('primevue/multiselect'), {
|
|
54
|
-
attributes: (config) => {
|
|
55
|
-
const { definition, i18n, t, te } = config
|
|
56
|
-
return {
|
|
57
|
-
options: definition.of.options ?? definition.of.enum ?? definition.options ?? definition.enum,
|
|
58
|
-
optionLabel: option => {
|
|
59
|
-
const i18nId = (definition.i18n ?? i18n + ':options') + '.' + option
|
|
60
|
-
if(te(i18nId)) return t(i18nId)
|
|
61
|
-
return t(option)
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
})
|
|
66
|
-
|
|
67
|
-
inputs.duration = input(() => import('primevue/inputmask'), {
|
|
68
|
-
attributes: { mask: '99:99:99' }
|
|
69
|
-
})
|
|
70
|
-
|
|
71
|
-
types.Image = inputs.image = input(
|
|
72
|
-
async () => (await import('@live-change/image-frontend')).ImageInput
|
|
73
|
-
)
|
|
74
|
-
|
|
75
|
-
types.Boolean = inputs.switch = input(
|
|
76
|
-
async () => (await import('primevue/inputswitch'))
|
|
77
|
-
)
|
|
78
|
-
|
|
79
|
-
/*
|
|
80
|
-
types.Boolean = inputs.switch = {
|
|
81
|
-
fieldComponent: defineAsyncComponent(() => import('./SwitchField.vue')),
|
|
82
|
-
}*/
|