@live-change/frontend-auto-form 0.9.11 → 0.9.13
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/ModelList.vue +37 -9
- package/front/src/components/crud/ModelView.vue +105 -0
- package/front/src/components/form/AutoField.vue +4 -3
- package/front/src/components/form/AutoInput.vue +2 -0
- package/front/src/components/view/AutoView.vue +113 -0
- package/front/src/components/view/AutoViewField.vue +120 -0
- package/front/src/components/view/DefaultFieldView.vue +82 -0
- package/front/src/components/view/JsonView.vue +39 -0
- package/front/src/components/view/ObjectView.vue +60 -0
- package/front/src/logic/viewData.js +34 -0
- package/front/src/pages/Editor.vue +0 -2
- package/front/src/pages/View.vue +62 -0
- package/front/src/router.js +6 -1
- package/index.js +9 -0
- package/package.json +13 -13
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
</div>
|
|
14
14
|
</div>
|
|
15
15
|
|
|
16
|
-
<div class="surface-card p-3 shadow-1 border-round">
|
|
16
|
+
<div class="surface-card p-3 shadow-1 border-round" v-if="modelsPathRangeFunction">
|
|
17
17
|
<range-viewer :key="JSON.stringify(modelsPathRangeConfig)"
|
|
18
18
|
:pathFunction="modelsPathRangeFunction"
|
|
19
19
|
:canLoadTop="false" canDropBottom
|
|
@@ -24,13 +24,20 @@
|
|
|
24
24
|
</div>
|
|
25
25
|
</template>
|
|
26
26
|
<template #default="{ item: object }">
|
|
27
|
-
<div class="flex flex-row align-items-center justify-content-between">
|
|
28
|
-
<
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
27
|
+
<div class="flex flex-row align-items-center justify-content-between my-3">
|
|
28
|
+
<router-link :to="viewRoute(object)" class="no-underline text-color">
|
|
29
|
+
<ObjectIdentification
|
|
30
|
+
:objectType="service + '_' + model"
|
|
31
|
+
:object="object.to ?? object.id"
|
|
32
|
+
:data="object"
|
|
33
|
+
class="text-xl"
|
|
34
|
+
/>
|
|
35
|
+
</router-link>
|
|
33
36
|
<div class="flex flex-row">
|
|
37
|
+
<router-link :to="viewRoute(object)" class="no-underline">
|
|
38
|
+
<Button icon="pi pi-eye" severity="primary" label="View" class="mr-2" />
|
|
39
|
+
</router-link>
|
|
40
|
+
|
|
34
41
|
<router-link :to="editRoute(object)" class="no-underline">
|
|
35
42
|
<Button icon="pi pi-pencil" severity="primary" label="Edit" class="mr-2" />
|
|
36
43
|
</router-link>
|
|
@@ -41,6 +48,15 @@
|
|
|
41
48
|
</template>
|
|
42
49
|
</range-viewer>
|
|
43
50
|
</div>
|
|
51
|
+
<div v-else class="flex align-items-start p-4 bg-pink-100 border-round border-1 border-pink-300 mb-4">
|
|
52
|
+
<i class="pi pi-times-circle text-pink-900 text-2xl mr-3" />
|
|
53
|
+
<div class="mr-3">
|
|
54
|
+
<div class="text-pink-900 font-medium text-xl mb-3 line-height-1">Not authorized</div>
|
|
55
|
+
<p class="m-0 p-0 text-pink-700">
|
|
56
|
+
You do not have sufficient privileges to use this feature of this object.
|
|
57
|
+
</p>
|
|
58
|
+
</div>
|
|
59
|
+
</div>
|
|
44
60
|
|
|
45
61
|
<div class="mt-3 flex flex-row justify-content-end mr-2">
|
|
46
62
|
<router-link :to="createRoute" class="no-underline2">
|
|
@@ -48,7 +64,6 @@
|
|
|
48
64
|
</router-link>
|
|
49
65
|
</div>
|
|
50
66
|
|
|
51
|
-
|
|
52
67
|
</div>
|
|
53
68
|
</template>
|
|
54
69
|
|
|
@@ -100,7 +115,9 @@
|
|
|
100
115
|
const modelsPathRangeFunction = computed(() => {
|
|
101
116
|
const config = modelsPathRangeConfig.value
|
|
102
117
|
const rangeView = config.definition?.crud?.range
|
|
103
|
-
|
|
118
|
+
if(!path[config.service]) return null
|
|
119
|
+
if(!path[config.service][rangeView]) return null
|
|
120
|
+
return (range) => path[config.service][rangeView]({
|
|
104
121
|
...(config.reverse ? reverseRange(range) : range),
|
|
105
122
|
})
|
|
106
123
|
})
|
|
@@ -132,6 +149,17 @@
|
|
|
132
149
|
}
|
|
133
150
|
}
|
|
134
151
|
|
|
152
|
+
function viewRoute(object) {
|
|
153
|
+
return {
|
|
154
|
+
name: 'auto-form:view',
|
|
155
|
+
params: {
|
|
156
|
+
serviceName: service.value,
|
|
157
|
+
modelName: model.value,
|
|
158
|
+
identifiers: Object.values(objectIdentifiers(object))
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
135
163
|
const createRoute = computed(() => ({
|
|
136
164
|
name: 'auto-form:editor',
|
|
137
165
|
params: {
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div>
|
|
3
|
+
|
|
4
|
+
<!-- <h4>identifiers</h4>
|
|
5
|
+
<pre>{{ identifiers }}</pre>
|
|
6
|
+
|
|
7
|
+
<h4>definition</h4>
|
|
8
|
+
<pre>{{ modelDefinition }}</pre>
|
|
9
|
+
|
|
10
|
+
<h4>object</h4>
|
|
11
|
+
<pre>{{ object }}</pre>-->
|
|
12
|
+
|
|
13
|
+
<div class="">
|
|
14
|
+
Service <strong>{{ service }}</strong>
|
|
15
|
+
</div>
|
|
16
|
+
<div class="text-2xl mb-4">
|
|
17
|
+
<strong>{{ model }}</strong>
|
|
18
|
+
<ObjectIdentification
|
|
19
|
+
:objectType="service + '_' + model"
|
|
20
|
+
:object="object.to ?? object.id"
|
|
21
|
+
:data="object"
|
|
22
|
+
class="ml-2"
|
|
23
|
+
/>
|
|
24
|
+
</div>
|
|
25
|
+
|
|
26
|
+
<AutoView :value="object" :root-value="object" :i18n="i18n" :attributes="attributes"
|
|
27
|
+
:definition="modelDefinition" />
|
|
28
|
+
|
|
29
|
+
</div>
|
|
30
|
+
</template>
|
|
31
|
+
|
|
32
|
+
<script setup>
|
|
33
|
+
|
|
34
|
+
import AutoView from '../view/AutoView.vue'
|
|
35
|
+
|
|
36
|
+
import { ref, computed, onMounted, defineProps, defineEmits, toRefs } from 'vue'
|
|
37
|
+
import { RangeViewer, injectComponent } from "@live-change/vue3-components"
|
|
38
|
+
|
|
39
|
+
const props = defineProps({
|
|
40
|
+
service: {
|
|
41
|
+
type: String,
|
|
42
|
+
required: true,
|
|
43
|
+
},
|
|
44
|
+
model: {
|
|
45
|
+
type: String,
|
|
46
|
+
required: true,
|
|
47
|
+
},
|
|
48
|
+
identifiers: {
|
|
49
|
+
type: Object,
|
|
50
|
+
default: []
|
|
51
|
+
},
|
|
52
|
+
draft: {
|
|
53
|
+
type: Boolean,
|
|
54
|
+
default: false
|
|
55
|
+
},
|
|
56
|
+
attributes: {
|
|
57
|
+
type: Object,
|
|
58
|
+
default: () => ({})
|
|
59
|
+
},
|
|
60
|
+
i18n: {
|
|
61
|
+
type: String,
|
|
62
|
+
default: ''
|
|
63
|
+
}
|
|
64
|
+
})
|
|
65
|
+
const { service, model, identifiers, draft, attributes, i18n } = toRefs(props)
|
|
66
|
+
|
|
67
|
+
const emit = defineEmits(['saved', 'draftSaved', 'draftDiscarded', 'saveError', 'created' ])
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
import AutoObjectIdentification from './AutoObjectIdentification.vue'
|
|
71
|
+
const ObjectIdentification = computed(() =>
|
|
72
|
+
injectComponent({
|
|
73
|
+
name: 'ObjectIdentification',
|
|
74
|
+
type: service.value + '_' + model.value,
|
|
75
|
+
service: service.value,
|
|
76
|
+
model: model.value
|
|
77
|
+
}, AutoObjectIdentification)
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
import { useApi, usePath, live } from '@live-change/vue3-ssr'
|
|
81
|
+
const api = useApi()
|
|
82
|
+
const path = usePath()
|
|
83
|
+
|
|
84
|
+
const modelDefinition = computed(() => {
|
|
85
|
+
return api.services?.[service.value]?.models?.[model.value]
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
import viewData from '../../logic/viewData.js'
|
|
89
|
+
|
|
90
|
+
const viewDataPromise = viewData({
|
|
91
|
+
service: service.value,
|
|
92
|
+
model: model.value,
|
|
93
|
+
identifiers: identifiers.value,
|
|
94
|
+
path, api
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
const [object] = await Promise.all([
|
|
98
|
+
viewDataPromise
|
|
99
|
+
])
|
|
100
|
+
|
|
101
|
+
</script>
|
|
102
|
+
|
|
103
|
+
<style scoped>
|
|
104
|
+
|
|
105
|
+
</style>
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
import AutoInput from "./AutoInput.vue"
|
|
43
43
|
|
|
44
44
|
import { inputs, types } from '../../config.js'
|
|
45
|
-
import { computed, getCurrentInstance, inject, toRefs, onMounted, ref } from 'vue'
|
|
45
|
+
import { computed, getCurrentInstance, inject, toRefs, onMounted, ref, useId } from 'vue'
|
|
46
46
|
|
|
47
47
|
const isMounted = ref(false)
|
|
48
48
|
onMounted(() => isMounted.value = true)
|
|
@@ -94,8 +94,7 @@
|
|
|
94
94
|
}
|
|
95
95
|
})
|
|
96
96
|
|
|
97
|
-
const
|
|
98
|
-
const uid = computed(() => isMounted.value ? 'field_'+instanceUid.toFixed().padStart(6, '0') : undefined)
|
|
97
|
+
const uid = useId()
|
|
99
98
|
|
|
100
99
|
const emit = defineEmits(['update:modelValue'])
|
|
101
100
|
|
|
@@ -105,6 +104,8 @@
|
|
|
105
104
|
if(definition.value?.if) {
|
|
106
105
|
if(definition.value?.if.function) {
|
|
107
106
|
return eval(`(${definition.value.if.function})`)
|
|
107
|
+
} else {
|
|
108
|
+
throw new Error('Unknown if type' + JSON.stringify(definition.value.if))
|
|
108
109
|
}
|
|
109
110
|
}
|
|
110
111
|
return false
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<component v-if="viewComponent && visible" :is="viewComponent" v-bind="attributes" :i18n="i18n" />
|
|
3
|
+
</template>
|
|
4
|
+
|
|
5
|
+
<script setup>
|
|
6
|
+
import { injectComponent } from '@live-change/vue3-components'
|
|
7
|
+
|
|
8
|
+
import { computed, inject, getCurrentInstance, toRefs, defineAsyncComponent } from 'vue'
|
|
9
|
+
|
|
10
|
+
const props = defineProps({
|
|
11
|
+
value: {},
|
|
12
|
+
definition: {
|
|
13
|
+
type: Object
|
|
14
|
+
},
|
|
15
|
+
rootValue: {
|
|
16
|
+
type: Object,
|
|
17
|
+
default: () => ({})
|
|
18
|
+
},
|
|
19
|
+
propName: {
|
|
20
|
+
type: String,
|
|
21
|
+
default: ''
|
|
22
|
+
},
|
|
23
|
+
i18n: {
|
|
24
|
+
type: String,
|
|
25
|
+
default: ''
|
|
26
|
+
},
|
|
27
|
+
visibleProperties: {
|
|
28
|
+
type: Array,
|
|
29
|
+
items: {
|
|
30
|
+
type: String
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
class: {},
|
|
34
|
+
style: {},
|
|
35
|
+
attributes: {
|
|
36
|
+
type: Object,
|
|
37
|
+
default: () => ({})
|
|
38
|
+
}
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
const { value, definition, propName, rootValue, visibleProperties } = toRefs(props)
|
|
42
|
+
|
|
43
|
+
const definitionIf = computed(() => {
|
|
44
|
+
if(definition.value?.if) {
|
|
45
|
+
if(definition.value?.if.function) {
|
|
46
|
+
return eval(`(${definition.value.if.function})`)
|
|
47
|
+
} else {
|
|
48
|
+
throw new Error('Unknown if type' + JSON.stringify(definition.value.if))
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return false
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
const visible = computed(() => {
|
|
55
|
+
if(!definition.value) return false
|
|
56
|
+
if(definitionIf.value) {
|
|
57
|
+
//console.log("DIF", propName.value, definitionIf.value, 'IN', props.rootValue)
|
|
58
|
+
return definitionIf.value({
|
|
59
|
+
source: definition.value,
|
|
60
|
+
props: props.rootValue,
|
|
61
|
+
propName: props.propName
|
|
62
|
+
})
|
|
63
|
+
}
|
|
64
|
+
return true
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
const viewFilter = computed(() => {
|
|
68
|
+
const filter = definition?.view?.componentFilter
|
|
69
|
+
if(filter) {
|
|
70
|
+
if(filter.function) {
|
|
71
|
+
return eval(`(${filter.function})`)
|
|
72
|
+
} else {
|
|
73
|
+
throw new Error('Unknown filter type' + JSON.stringify(filter))
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return undefined
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
const viewComponent = computed(() => {
|
|
80
|
+
const type = definition.value.type ?? 'Object'
|
|
81
|
+
const defaultComponent = (type === 'Object')
|
|
82
|
+
? defineAsyncComponent(() => import('./ObjectView.vue'))
|
|
83
|
+
: defineAsyncComponent(() => import('./JsonView.vue'))
|
|
84
|
+
return injectComponent(definition.value?.view?.componentRequest ?? {
|
|
85
|
+
...(definition.value?.view?.componentRequestProperties),
|
|
86
|
+
name: 'AutoView',
|
|
87
|
+
type,
|
|
88
|
+
view: definition?.view?.name ?? definition?.view,
|
|
89
|
+
filter: viewFilter.value
|
|
90
|
+
}, defaultComponent)
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
const viewClass = computed(() => [definition.value?.view?.class, props.class])
|
|
94
|
+
const viewStyle = computed(() => [definition.value?.view?.style, props.style])
|
|
95
|
+
|
|
96
|
+
const attributes = computed(() => ({
|
|
97
|
+
visibleProperties: visibleProperties.value,
|
|
98
|
+
i18n: i18n.value,
|
|
99
|
+
...(definition.value?.view?.attributes),
|
|
100
|
+
...(props.attributes),
|
|
101
|
+
value: value.value,
|
|
102
|
+
definition: definition.value,
|
|
103
|
+
class: viewClass.value,
|
|
104
|
+
style: viewStyle.value,
|
|
105
|
+
rootValue: rootValue.value,
|
|
106
|
+
propName: propName.value,
|
|
107
|
+
}))
|
|
108
|
+
|
|
109
|
+
</script>
|
|
110
|
+
|
|
111
|
+
<style scoped>
|
|
112
|
+
|
|
113
|
+
</style>
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<component v-if="fieldComponent && visible" :is="fieldComponent" v-bind="attributes" :i18n="i18n" />
|
|
3
|
+
</template>
|
|
4
|
+
|
|
5
|
+
<script setup>
|
|
6
|
+
import { injectComponent } from '@live-change/vue3-components'
|
|
7
|
+
|
|
8
|
+
import { computed, inject, getCurrentInstance, toRefs } from 'vue'
|
|
9
|
+
import DefaultFieldView from './DefaultFieldView.vue'
|
|
10
|
+
|
|
11
|
+
const props = defineProps({
|
|
12
|
+
name: {
|
|
13
|
+
type: String
|
|
14
|
+
},
|
|
15
|
+
label: {
|
|
16
|
+
type: String
|
|
17
|
+
},
|
|
18
|
+
value: {},
|
|
19
|
+
definition: {
|
|
20
|
+
type: Object
|
|
21
|
+
},
|
|
22
|
+
rootValue: {
|
|
23
|
+
type: Object,
|
|
24
|
+
default: () => ({})
|
|
25
|
+
},
|
|
26
|
+
propName: {
|
|
27
|
+
type: String,
|
|
28
|
+
default: ''
|
|
29
|
+
},
|
|
30
|
+
i18n: {
|
|
31
|
+
type: String,
|
|
32
|
+
default: ''
|
|
33
|
+
},
|
|
34
|
+
visibleProperties: {
|
|
35
|
+
type: Array,
|
|
36
|
+
items: {
|
|
37
|
+
type: String
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
class: {},
|
|
41
|
+
style: {},
|
|
42
|
+
attributes: {
|
|
43
|
+
type: Object,
|
|
44
|
+
default: () => ({})
|
|
45
|
+
}
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
const { value, definition, propName, rootValue, label, name } = toRefs(props)
|
|
49
|
+
|
|
50
|
+
const definitionIf = computed(() => {
|
|
51
|
+
if(definition.value?.if) {
|
|
52
|
+
if(definition.value?.if.function) {
|
|
53
|
+
return eval(`(${definition.value.if.function})`)
|
|
54
|
+
} else {
|
|
55
|
+
throw new Error('Unknown if type' + JSON.stringify(definition.value.if))
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return false
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
const visible = computed(() => {
|
|
62
|
+
if(!definition.value) return false
|
|
63
|
+
if(definitionIf.value) {
|
|
64
|
+
//console.log("DIF", propName.value, definitionIf.value, 'IN', props.rootValue)
|
|
65
|
+
return definitionIf.value({
|
|
66
|
+
source: definition.value,
|
|
67
|
+
props: props.rootValue,
|
|
68
|
+
propName: props.propName
|
|
69
|
+
})
|
|
70
|
+
}
|
|
71
|
+
return true
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
const fieldFilter = computed(() => {
|
|
75
|
+
const filter = definition?.view?.fieldComponentFilter
|
|
76
|
+
if(filter) {
|
|
77
|
+
if(filter.function) {
|
|
78
|
+
return eval(`(${filter.function})`)
|
|
79
|
+
} else {
|
|
80
|
+
throw new Error('Unknown filter type' + JSON.stringify(filter))
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return undefined
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
const fieldComponent = computed(() => injectComponent(definition.value?.view?.fieldComponentRequest ?? {
|
|
87
|
+
...(definition.value?.view?.fieldComponentRequestProperties),
|
|
88
|
+
name: 'AutoFieldView',
|
|
89
|
+
type: definition.type ?? 'Object',
|
|
90
|
+
view: definition?.view?.name ?? definition?.view,
|
|
91
|
+
filter: fieldFilter.value
|
|
92
|
+
}, DefaultFieldView))
|
|
93
|
+
|
|
94
|
+
const fieldClass = computed(() => [definition.value?.view?.fieldClass, props.class])
|
|
95
|
+
const fieldStyle = computed(() => [definition.value?.view?.fieldStyle, props.style])
|
|
96
|
+
|
|
97
|
+
const viewClass = computed(() => [definition.value?.view?.class, props.viewClass])
|
|
98
|
+
const viewStyle = computed(() => [definition.value?.view?.style, props.viewStyle])
|
|
99
|
+
|
|
100
|
+
const attributes = computed(() => ({
|
|
101
|
+
i18n: i18n.value,
|
|
102
|
+
name: name.value,
|
|
103
|
+
label: label.value,
|
|
104
|
+
...(definition.value?.view?.attributes),
|
|
105
|
+
...(props.attributes),
|
|
106
|
+
value: value.value,
|
|
107
|
+
definition: definition.value,
|
|
108
|
+
class: fieldClass.value,
|
|
109
|
+
style: fieldStyle.value,
|
|
110
|
+
viewClass: viewClass.value,
|
|
111
|
+
viewStyle: viewStyle.value,
|
|
112
|
+
rootValue: rootValue.value,
|
|
113
|
+
propName: propName.value,
|
|
114
|
+
}))
|
|
115
|
+
|
|
116
|
+
</script>
|
|
117
|
+
|
|
118
|
+
<style scoped>
|
|
119
|
+
|
|
120
|
+
</style>
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="field" :class="fieldClass" :style="fieldStyle">
|
|
3
|
+
<slot name="label"
|
|
4
|
+
v-bind="{ uid, value, definition, viewClass, viewStyle, attributes, propName, rootValue, i18n }">
|
|
5
|
+
<label :for="uid">{{ t( label ) }}</label>
|
|
6
|
+
</slot>
|
|
7
|
+
<slot v-bind="{ uid, value, definition, viewClass, viewStyle, attributes, propName, rootValue, i18n }">
|
|
8
|
+
<AutoView :value="value" :definition="definition"
|
|
9
|
+
:class="viewClass" :style="viewStyle"
|
|
10
|
+
:attributes="attributes"
|
|
11
|
+
:propName="propName"
|
|
12
|
+
:rootValue="rootValue"
|
|
13
|
+
:id="uid"
|
|
14
|
+
:i18n="i18n" />
|
|
15
|
+
</slot>
|
|
16
|
+
</div>
|
|
17
|
+
</template>
|
|
18
|
+
|
|
19
|
+
<script setup>
|
|
20
|
+
|
|
21
|
+
import AutoView from "./AutoView.vue"
|
|
22
|
+
|
|
23
|
+
import { computed, getCurrentInstance, inject, toRefs, onMounted, ref, useId } from 'vue'
|
|
24
|
+
|
|
25
|
+
const isMounted = ref(false)
|
|
26
|
+
onMounted(() => isMounted.value = true)
|
|
27
|
+
|
|
28
|
+
import { useI18n } from 'vue-i18n'
|
|
29
|
+
const { t, rt } = useI18n()
|
|
30
|
+
|
|
31
|
+
const props = defineProps({
|
|
32
|
+
value: {},
|
|
33
|
+
definition: {
|
|
34
|
+
type: Object
|
|
35
|
+
},
|
|
36
|
+
name: {
|
|
37
|
+
type: String
|
|
38
|
+
},
|
|
39
|
+
label: {
|
|
40
|
+
type: String
|
|
41
|
+
},
|
|
42
|
+
class: {},
|
|
43
|
+
style: {},
|
|
44
|
+
viewClass: {},
|
|
45
|
+
viewStyle: {},
|
|
46
|
+
attributes: {
|
|
47
|
+
type: Object,
|
|
48
|
+
default: () => ({})
|
|
49
|
+
},
|
|
50
|
+
rootValue: {
|
|
51
|
+
type: Object,
|
|
52
|
+
default: () => ({})
|
|
53
|
+
},
|
|
54
|
+
propName: {
|
|
55
|
+
type: String,
|
|
56
|
+
default: ''
|
|
57
|
+
},
|
|
58
|
+
i18n: {
|
|
59
|
+
type: String,
|
|
60
|
+
default: ''
|
|
61
|
+
},
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
const instanceUid = getCurrentInstance().uid
|
|
65
|
+
const uid = useId()
|
|
66
|
+
|
|
67
|
+
const emit = defineEmits(['update:modelValue'])
|
|
68
|
+
|
|
69
|
+
const { error, definition, value } = toRefs(props)
|
|
70
|
+
|
|
71
|
+
const label = computed(() => props.i18n + (props.label || definition.value.label || props.name))
|
|
72
|
+
|
|
73
|
+
const viewClass = computed(() => [definition.value?.view?.class, props.viewClass])
|
|
74
|
+
const viewStyle = computed(() => [definition.value?.view?.style, props.viewStyle])
|
|
75
|
+
const fieldClass = computed(() => [definition.value?.view?.class, props.class])
|
|
76
|
+
const fieldStyle = computed(() => [definition.value?.view?.style, props.style])
|
|
77
|
+
|
|
78
|
+
</script>
|
|
79
|
+
|
|
80
|
+
<style scoped>
|
|
81
|
+
|
|
82
|
+
</style>
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div>
|
|
3
|
+
<pre>{{ JSON.stringify(value, null, 2) }}</pre>
|
|
4
|
+
</div>
|
|
5
|
+
</template>
|
|
6
|
+
|
|
7
|
+
<script setup>
|
|
8
|
+
import AutoViewField from "./AutoViewField.vue"
|
|
9
|
+
|
|
10
|
+
import { computed, inject, getCurrentInstance, toRefs } from 'vue'
|
|
11
|
+
|
|
12
|
+
const props = defineProps({
|
|
13
|
+
value: {},
|
|
14
|
+
definition: {
|
|
15
|
+
type: Object
|
|
16
|
+
},
|
|
17
|
+
rootValue: {
|
|
18
|
+
type: Object,
|
|
19
|
+
default: () => ({})
|
|
20
|
+
},
|
|
21
|
+
propName: {
|
|
22
|
+
type: String,
|
|
23
|
+
default: ''
|
|
24
|
+
},
|
|
25
|
+
class: {},
|
|
26
|
+
style: {},
|
|
27
|
+
i18n: {
|
|
28
|
+
type: String,
|
|
29
|
+
default: ''
|
|
30
|
+
},
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
const { value, definition, propName } = toRefs(props)
|
|
34
|
+
|
|
35
|
+
</script>
|
|
36
|
+
|
|
37
|
+
<style scoped>
|
|
38
|
+
|
|
39
|
+
</style>
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div v-if="definition" class="grid formgrid p-fluid mt-2 mb-2">
|
|
3
|
+
<AutoViewField v-for="property in propertiesList" :key="property"
|
|
4
|
+
:value="value?.[property]"
|
|
5
|
+
:definition="definition.properties[property]"
|
|
6
|
+
:label="property"
|
|
7
|
+
:name="property"
|
|
8
|
+
:rootValue="props.rootValue" :propName="(propName ? propName + '.' : '') + property"
|
|
9
|
+
:i18n="i18n"
|
|
10
|
+
class="col-12" />
|
|
11
|
+
</div>
|
|
12
|
+
</template>
|
|
13
|
+
|
|
14
|
+
<script setup>
|
|
15
|
+
import AutoViewField from "./AutoViewField.vue"
|
|
16
|
+
|
|
17
|
+
import { computed, inject, getCurrentInstance, toRefs } from 'vue'
|
|
18
|
+
|
|
19
|
+
const props = defineProps({
|
|
20
|
+
value: {},
|
|
21
|
+
definition: {
|
|
22
|
+
type: Object
|
|
23
|
+
},
|
|
24
|
+
rootValue: {
|
|
25
|
+
type: Object,
|
|
26
|
+
default: () => ({})
|
|
27
|
+
},
|
|
28
|
+
propName: {
|
|
29
|
+
type: String,
|
|
30
|
+
default: ''
|
|
31
|
+
},
|
|
32
|
+
class: {},
|
|
33
|
+
style: {},
|
|
34
|
+
i18n: {
|
|
35
|
+
type: String,
|
|
36
|
+
default: ''
|
|
37
|
+
},
|
|
38
|
+
visibleProperties: {
|
|
39
|
+
type: Array,
|
|
40
|
+
items: {
|
|
41
|
+
type: String
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
const { value, definition, propName, visibleProperties } = toRefs(props)
|
|
47
|
+
|
|
48
|
+
const propertiesList = computed(() =>
|
|
49
|
+
visibleProperties.value ??
|
|
50
|
+
props.definition.visibleProperties ??
|
|
51
|
+
(definition.value.properties
|
|
52
|
+
? Object.keys(definition.value.properties).filter(key => props.definition.properties[key])
|
|
53
|
+
: [])
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
</script>
|
|
57
|
+
|
|
58
|
+
<style scoped>
|
|
59
|
+
|
|
60
|
+
</style>
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { usePath, live, useApi } from '@live-change/vue3-ssr'
|
|
2
|
+
|
|
3
|
+
export default function viewData(options) {
|
|
4
|
+
if(!options) throw new Error('options must be provided')
|
|
5
|
+
|
|
6
|
+
const {
|
|
7
|
+
identifiers,
|
|
8
|
+
service: serviceName,
|
|
9
|
+
model: modelName,
|
|
10
|
+
|
|
11
|
+
path = usePath(),
|
|
12
|
+
api = useApi(),
|
|
13
|
+
} = options
|
|
14
|
+
|
|
15
|
+
if(!identifiers) throw new Error('identifiers must be defined')
|
|
16
|
+
if(!serviceName || !modelName) throw new Error('service and model must be defined')
|
|
17
|
+
|
|
18
|
+
const service = api.services[serviceName]
|
|
19
|
+
const model = service.models[modelName]
|
|
20
|
+
const {
|
|
21
|
+
crudMethods = model.crud,
|
|
22
|
+
identifiersNames = model.identifiers,
|
|
23
|
+
//editableProperties = model.editableProperties ?? Object.keys(model.properties)
|
|
24
|
+
} = options
|
|
25
|
+
|
|
26
|
+
if(!crudMethods) throw new Error('crud methods must be defined in model or options')
|
|
27
|
+
if(!identifiersNames) throw new Error('identifiers names must be defined in model or options')
|
|
28
|
+
// if(!editableProperties) throw new Error('editableProperties must be defined in model or options')
|
|
29
|
+
|
|
30
|
+
const savedDataPath = path[serviceName][crudMethods.read](identifiers)
|
|
31
|
+
|
|
32
|
+
return live(savedDataPath)
|
|
33
|
+
|
|
34
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="w-full lg:w-8 md:w-11">
|
|
3
|
+
<div class="surface-card p-3 shadow-1 border-round">
|
|
4
|
+
|
|
5
|
+
<ModelView :service="serviceName" :model="modelName" :identifiers="identifiersObject" />
|
|
6
|
+
|
|
7
|
+
</div>
|
|
8
|
+
</div>
|
|
9
|
+
</template>
|
|
10
|
+
|
|
11
|
+
<script setup>
|
|
12
|
+
|
|
13
|
+
import ModelView from "../components/crud/ModelView.vue"
|
|
14
|
+
|
|
15
|
+
import { ref, computed, onMounted, defineProps, toRefs } from 'vue'
|
|
16
|
+
|
|
17
|
+
const props = defineProps({
|
|
18
|
+
serviceName: {
|
|
19
|
+
type: String,
|
|
20
|
+
required: true,
|
|
21
|
+
},
|
|
22
|
+
modelName: {
|
|
23
|
+
type: String,
|
|
24
|
+
required: true,
|
|
25
|
+
},
|
|
26
|
+
identifiers: {
|
|
27
|
+
type: Array,
|
|
28
|
+
default: []
|
|
29
|
+
}
|
|
30
|
+
})
|
|
31
|
+
const { serviceName, modelName, identifiers } = toRefs(props)
|
|
32
|
+
|
|
33
|
+
import { useApi, usePath, live } from '@live-change/vue3-ssr'
|
|
34
|
+
const api = useApi()
|
|
35
|
+
const path = usePath()
|
|
36
|
+
|
|
37
|
+
const modelDefinition = computed(() => {
|
|
38
|
+
const service = api.services[serviceName.value]
|
|
39
|
+
if(!service) return null
|
|
40
|
+
const model = service.models[modelName.value]
|
|
41
|
+
if(!model) return null
|
|
42
|
+
return model
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
const identifiersObject = computed(() => {
|
|
46
|
+
const result = {}
|
|
47
|
+
for(const [i, identifier] of Object.entries(identifiers.value)) {
|
|
48
|
+
const identifierDefinition = modelDefinition.value.identifiers[i]
|
|
49
|
+
if(typeof identifierDefinition === 'string') {
|
|
50
|
+
result[identifierDefinition] = identifier
|
|
51
|
+
} else {
|
|
52
|
+
result[identifierDefinition.name] = identifier
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return result
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
</script>
|
|
59
|
+
|
|
60
|
+
<style scoped>
|
|
61
|
+
|
|
62
|
+
</style>
|
package/front/src/router.js
CHANGED
|
@@ -14,13 +14,18 @@ export function autoFormRoutes(config = {}) {
|
|
|
14
14
|
props: true
|
|
15
15
|
}),
|
|
16
16
|
|
|
17
|
+
route({
|
|
18
|
+
name: 'auto-form:view', path: prefix + '/view/:serviceName/:modelName/:identifiers*', meta: { },
|
|
19
|
+
component: () => import("./pages/View.vue"),
|
|
20
|
+
props: true
|
|
21
|
+
}),
|
|
22
|
+
|
|
17
23
|
route({
|
|
18
24
|
name: 'auto-form:list', path: prefix + '/models/:serviceName/:modelName', meta: { },
|
|
19
25
|
component: () => import("./pages/List.vue"),
|
|
20
26
|
props: true
|
|
21
27
|
}),
|
|
22
28
|
|
|
23
|
-
|
|
24
29
|
]
|
|
25
30
|
}
|
|
26
31
|
|
package/index.js
CHANGED
|
@@ -9,11 +9,20 @@ export { inputConfig }
|
|
|
9
9
|
|
|
10
10
|
import editorData from './front/src/logic/editorData.js'
|
|
11
11
|
export { editorData }
|
|
12
|
+
import viewData from './front/src/logic/viewData.js'
|
|
12
13
|
|
|
13
14
|
export * from './front/src/logic/relations.js'
|
|
14
15
|
|
|
15
16
|
import ModelEditor from './front/src/components/crud/ModelEditor.vue'
|
|
16
17
|
export { ModelEditor }
|
|
18
|
+
import ModelView from './front/src/components/crud/ModelView.vue'
|
|
19
|
+
export { ModelView }
|
|
20
|
+
import ModelList from './front/src/components/crud/ModelList.vue'
|
|
21
|
+
export { ModelList }
|
|
22
|
+
import EditorButtons from './front/src/components/crud/EditorButtons.vue'
|
|
23
|
+
export { EditorButtons }
|
|
24
|
+
import AutoObjectIdentification from './front/src/components/crud/AutoObjectIdentification.vue'
|
|
25
|
+
export { AutoObjectIdentification }
|
|
17
26
|
|
|
18
27
|
export * from './front/src/router.js'
|
|
19
28
|
|
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.13",
|
|
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.5.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.13",
|
|
26
|
+
"@live-change/dao": "^0.9.13",
|
|
27
|
+
"@live-change/dao-vue3": "^0.9.13",
|
|
28
|
+
"@live-change/dao-websocket": "^0.9.13",
|
|
29
|
+
"@live-change/framework": "^0.9.13",
|
|
30
|
+
"@live-change/image-frontend": "^0.9.13",
|
|
31
|
+
"@live-change/image-service": "^0.9.13",
|
|
32
|
+
"@live-change/session-service": "^0.9.13",
|
|
33
|
+
"@live-change/vue3-components": "^0.9.13",
|
|
34
|
+
"@live-change/vue3-ssr": "^0.9.13",
|
|
35
35
|
"@vueuse/core": "^10.11.0",
|
|
36
36
|
"codeceptjs-assert": "^0.0.5",
|
|
37
37
|
"compression": "^1.7.4",
|
|
@@ -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.13",
|
|
56
56
|
"codeceptjs": "^3.6.5",
|
|
57
57
|
"generate-password": "1.7.1",
|
|
58
58
|
"playwright": "1.48.1",
|
|
@@ -63,5 +63,5 @@
|
|
|
63
63
|
"author": "Michał Łaszczewski <michal@laszczewski.pl>",
|
|
64
64
|
"license": "ISC",
|
|
65
65
|
"description": "",
|
|
66
|
-
"gitHead": "
|
|
66
|
+
"gitHead": "b0b18e7a8e253195c6df4b25c6bb5c407b1a2450"
|
|
67
67
|
}
|