@live-change/frontend-auto-form 0.9.85 → 0.9.87
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/ActionButtons.vue +80 -0
- package/front/src/components/crud/ActionForm.vue +137 -8
- package/front/src/components/crud/AutoObjectIdentification.vue +1 -1
- package/front/src/components/crud/DefaultObjectIdentification.vue +72 -4
- package/front/src/components/crud/InjectedObjectIndentification.vue +3 -3
- package/front/src/components/crud/ModelEditor.vue +25 -8
- package/front/src/components/crud/ModelList.vue +55 -14
- package/front/src/components/crud/ModelSingle.vue +5 -5
- package/front/src/components/crud/ModelView.vue +88 -28
- package/front/src/components/schema/DataWithSchema.vue +15 -11
- package/front/src/components/schema/SchemaFromDefinition.vue +23 -0
- package/front/src/components/view/AutoView.vue +19 -4
- package/front/src/components/view/DefaultFieldView.vue +1 -1
- package/front/src/logic/actionData.js +8 -5
- package/front/src/logic/schema.js +37 -15
- package/front/src/logic/viewData.js +6 -6
- package/front/src/pages/Action.vue +9 -8
- package/front/src/pages/{Editor.vue → Create.vue} +16 -34
- package/front/src/pages/Edit.vue +76 -0
- package/front/src/pages/Models.vue +1 -1
- package/front/src/pages/View.vue +5 -30
- package/front/src/router.js +15 -3
- package/index.js +2 -0
- package/package.json +14 -14
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="flex flex-col-reverse md:flex-row justify-between items-center">
|
|
3
|
+
<div class="flex flex-col mt-2 md:mt-0">
|
|
4
|
+
<div v-if="savingDraft" class="text-surface-500 dark:text-surface-300 mr-2 flex flex-row items-center">
|
|
5
|
+
<i class="pi pi-spin pi-spinner mr-2" style="font-size: 1.23rem"></i>
|
|
6
|
+
<span>Executing...</span>
|
|
7
|
+
</div>
|
|
8
|
+
<div v-else-if="draftChanged" class="text-sm text-surface-500 dark:text-surface-300 mr-2">
|
|
9
|
+
Draft changed
|
|
10
|
+
</div>
|
|
11
|
+
<Message v-else-if="validationResult" severity="error" variant="simple" size="small" class="mr-2">
|
|
12
|
+
Before running, please correct the errors above.
|
|
13
|
+
</Message>
|
|
14
|
+
</div>
|
|
15
|
+
<div class="flex flex-row">
|
|
16
|
+
<slot name="submit" v-if="!validationResult">
|
|
17
|
+
<div class="ml-2">
|
|
18
|
+
<Button
|
|
19
|
+
type="submit"
|
|
20
|
+
:label="submitting === true ? 'Executing...' : 'Execute'"
|
|
21
|
+
:icon="submitting === true ? 'pi pi-spin pi-spinner' : 'pi pi-play'"
|
|
22
|
+
:disabled="submitting"
|
|
23
|
+
/>
|
|
24
|
+
</div>
|
|
25
|
+
</slot>
|
|
26
|
+
<slot name="reset" v-if="resetButton">
|
|
27
|
+
<div>
|
|
28
|
+
<Button type="reset" label="Reset" class="ml-2" :disabled="!changed" icon="pi pi-eraser"/>
|
|
29
|
+
</div>
|
|
30
|
+
</slot>
|
|
31
|
+
</div>
|
|
32
|
+
</div>
|
|
33
|
+
</template>
|
|
34
|
+
|
|
35
|
+
<script setup>
|
|
36
|
+
|
|
37
|
+
import Message from "primevue/message"
|
|
38
|
+
|
|
39
|
+
import { ref, computed, onMounted, defineProps, defineEmits, toRefs, getCurrentInstance, unref } from 'vue'
|
|
40
|
+
|
|
41
|
+
const props = defineProps({
|
|
42
|
+
actionFormData: {
|
|
43
|
+
type: Object,
|
|
44
|
+
required: true,
|
|
45
|
+
},
|
|
46
|
+
resetButton: {
|
|
47
|
+
type: Boolean,
|
|
48
|
+
required: true,
|
|
49
|
+
},
|
|
50
|
+
options: {
|
|
51
|
+
type: Object,
|
|
52
|
+
default: () => ({})
|
|
53
|
+
},
|
|
54
|
+
i18n: {
|
|
55
|
+
type: String,
|
|
56
|
+
default: ''
|
|
57
|
+
}
|
|
58
|
+
})
|
|
59
|
+
const { actionFormData, resetButton, options, i18n } = toRefs(props)
|
|
60
|
+
|
|
61
|
+
const changed = computed(() => unref(actionFormData).changed.value)
|
|
62
|
+
const draftChanged = computed(() => unref(actionFormData).draftChanged?.value)
|
|
63
|
+
const savingDraft = computed(() => unref(actionFormData).savingDraft?.value)
|
|
64
|
+
const submitting = computed(() => unref(actionFormData).submitting?.value)
|
|
65
|
+
const propertiesErrors = computed(() => unref(actionFormData).propertiesErrors?.value)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
const validationResult = computed(() => {
|
|
69
|
+
const errors = propertiesErrors.value
|
|
70
|
+
if(errors && Object.keys(errors).length > 0) {
|
|
71
|
+
return errors
|
|
72
|
+
}
|
|
73
|
+
return null
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
</script>
|
|
77
|
+
|
|
78
|
+
<style scoped>
|
|
79
|
+
|
|
80
|
+
</style>
|
|
@@ -7,10 +7,41 @@
|
|
|
7
7
|
Action <strong>{{ action }}</strong>
|
|
8
8
|
</div>
|
|
9
9
|
|
|
10
|
-
<
|
|
10
|
+
<div v-if="task">
|
|
11
|
+
<Task :task="rootTask" :tasks="tasksData" />
|
|
12
|
+
<pre>rootTask = {{ rootTask }}</pre>
|
|
13
|
+
</div>
|
|
14
|
+
<div v-else-if="resultWithType">
|
|
15
|
+
<div class="text-xl mb-2">
|
|
16
|
+
Result:
|
|
17
|
+
</div>
|
|
18
|
+
<div class="text-sm text-gray-500">
|
|
19
|
+
<pre>{{ resultWithType }}</pre>
|
|
20
|
+
</div>
|
|
21
|
+
</div>
|
|
22
|
+
<form v-else @submit="handleSubmit" @reset="handleReset">
|
|
11
23
|
<div class="flex flex-col gap-4">
|
|
24
|
+
|
|
25
|
+
<div v-for="[name, parameter] in Object.entries(actionFormData.parameters)"
|
|
26
|
+
class="flex flex-col mb-3">
|
|
27
|
+
<template v-if="!name.endsWith('Type')">
|
|
28
|
+
<div class="min-w-[8rem] font-medium">{{ actionFormData.action.definition.properties[name].label ?? name }}</div>
|
|
29
|
+
<div>
|
|
30
|
+
<InjectedObjectIndentification v-if="actionFormData.parameters[name+'Type']
|
|
31
|
+
?? actionFormData.action.definition.properties[name]?.type
|
|
32
|
+
?? actionFormData.action.definition.properties[name]?.type.split('_').length > 1"
|
|
33
|
+
:type="actionFormData.parameters[name+'Type']
|
|
34
|
+
?? actionFormData.action.definition.properties[name]?.type"
|
|
35
|
+
:object="actionFormData.parameters[name]"
|
|
36
|
+
/>
|
|
37
|
+
<pre v-else>parameter</pre>
|
|
38
|
+
</div>
|
|
39
|
+
</template>
|
|
40
|
+
</div>
|
|
41
|
+
|
|
12
42
|
<auto-editor
|
|
13
43
|
:definition="actionFormData.action.definition"
|
|
44
|
+
:editableProperties="actionFormData.editableProperties"
|
|
14
45
|
v-model="actionFormData.value"
|
|
15
46
|
:rootValue="actionFormData.value"
|
|
16
47
|
:errors="actionFormData.propertiesErrors"
|
|
@@ -49,10 +80,14 @@
|
|
|
49
80
|
|
|
50
81
|
<script setup>
|
|
51
82
|
|
|
52
|
-
import { ref, computed, onMounted, defineProps, defineEmits, toRefs } from 'vue'
|
|
83
|
+
import { ref, computed, onMounted, defineProps, defineEmits, toRefs, watch } from 'vue'
|
|
53
84
|
import Button from 'primevue/button'
|
|
54
85
|
import AutoEditor from '../form/AutoEditor.vue'
|
|
55
86
|
import ActionButtons from './ActionButtons.vue'
|
|
87
|
+
import { Task } from '@live-change/task-frontend'
|
|
88
|
+
|
|
89
|
+
import InjectedObjectIndentification from './InjectedObjectIndentification.vue'
|
|
90
|
+
|
|
56
91
|
import { useToast } from 'primevue/usetoast'
|
|
57
92
|
const toast = useToast()
|
|
58
93
|
|
|
@@ -68,34 +103,128 @@
|
|
|
68
103
|
i18n: {
|
|
69
104
|
type: String,
|
|
70
105
|
default: ''
|
|
106
|
+
},
|
|
107
|
+
initialValue: {
|
|
108
|
+
type: Object,
|
|
109
|
+
default: () => ({})
|
|
110
|
+
},
|
|
111
|
+
parameters: {
|
|
112
|
+
type: Object,
|
|
113
|
+
default: () => ({})
|
|
71
114
|
}
|
|
72
115
|
})
|
|
73
116
|
|
|
74
|
-
const { service, action, i18n } = toRefs(props)
|
|
117
|
+
const { service, action, i18n, initialValue, parameters } = toRefs(props)
|
|
75
118
|
|
|
76
119
|
const emit = defineEmits(['done', 'error'])
|
|
77
120
|
|
|
78
|
-
import { useApi } from '@live-change/vue3-ssr'
|
|
121
|
+
import { useApi, usePath, live } from '@live-change/vue3-ssr'
|
|
79
122
|
const api = useApi()
|
|
123
|
+
const path = usePath()
|
|
124
|
+
|
|
125
|
+
import { useRouter } from 'vue-router'
|
|
126
|
+
const router = useRouter()
|
|
80
127
|
|
|
81
128
|
import { actionData } from '@live-change/frontend-auto-form'
|
|
82
129
|
|
|
83
|
-
const
|
|
130
|
+
const resultWithType = ref(null)
|
|
131
|
+
const task = ref(null)
|
|
132
|
+
|
|
133
|
+
const tasksPath = computed(() => task.value && path.task.tasksByRoot({
|
|
134
|
+
root: task.value,
|
|
135
|
+
rootType: 'task_Task'
|
|
136
|
+
}))
|
|
137
|
+
|
|
138
|
+
const actionFormDataPromise = actionData({
|
|
84
139
|
service: service.value,
|
|
85
140
|
action: action.value,
|
|
86
|
-
i18n: i18n.value
|
|
141
|
+
i18n: i18n.value,
|
|
142
|
+
initialValue: initialValue.value,
|
|
143
|
+
parameters: parameters.value,
|
|
144
|
+
onDone: handleDone
|
|
145
|
+
})
|
|
146
|
+
|
|
147
|
+
const [
|
|
148
|
+
actionFormData,
|
|
149
|
+
tasksData
|
|
150
|
+
] = await Promise.all([
|
|
151
|
+
actionFormDataPromise,
|
|
152
|
+
live(tasksPath)
|
|
153
|
+
])
|
|
154
|
+
|
|
155
|
+
const returnType = computed(() => {
|
|
156
|
+
const returnType = actionFormData.action.definition.returns
|
|
157
|
+
return returnType.type
|
|
87
158
|
})
|
|
88
159
|
|
|
89
|
-
|
|
160
|
+
function handleSubmit(ev) {
|
|
90
161
|
ev.preventDefault()
|
|
91
162
|
actionFormData.submit()
|
|
92
163
|
}
|
|
93
164
|
|
|
94
|
-
|
|
165
|
+
function handleReset(ev) {
|
|
95
166
|
ev.preventDefault()
|
|
96
167
|
actionFormData.reset()
|
|
97
168
|
}
|
|
98
169
|
|
|
170
|
+
function handleDone(result) {
|
|
171
|
+
console.log('handleDone', result)
|
|
172
|
+
handleResult(result, returnType.value)
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function handleResult(result, type) {
|
|
176
|
+
console.log('handleResult', result, type)
|
|
177
|
+
task.value = null
|
|
178
|
+
resultWithType.value = null
|
|
179
|
+
if(type === 'task_Task') {
|
|
180
|
+
task.value = result
|
|
181
|
+
} else if(type.split('_').length === 1) {
|
|
182
|
+
if(typeof result === 'object') {
|
|
183
|
+
resultWithType.value = {
|
|
184
|
+
type: type,
|
|
185
|
+
result: result
|
|
186
|
+
}
|
|
187
|
+
} else { /// redirect to object view
|
|
188
|
+
router.push({
|
|
189
|
+
name: 'auto-form:view',
|
|
190
|
+
params: {
|
|
191
|
+
serviceName: service.value,
|
|
192
|
+
modelName: type.split('_')[0],
|
|
193
|
+
identifiers: [result]
|
|
194
|
+
}
|
|
195
|
+
})
|
|
196
|
+
}
|
|
197
|
+
} else {
|
|
198
|
+
resultWithType.value = {
|
|
199
|
+
type: type,
|
|
200
|
+
result: result
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
const rootTask = computed(() => {
|
|
206
|
+
if(task.value && tasksData.value) {
|
|
207
|
+
return tasksData.value.find(t => t.id === task.value)
|
|
208
|
+
}
|
|
209
|
+
})
|
|
210
|
+
|
|
211
|
+
const rootTaskDone = computed(() => {
|
|
212
|
+
if(rootTask.value) {
|
|
213
|
+
return rootTask.value.state === 'done'
|
|
214
|
+
}
|
|
215
|
+
return false
|
|
216
|
+
})
|
|
217
|
+
|
|
218
|
+
/* watch(rootTaskDone, (done) => {
|
|
219
|
+
if(done) {
|
|
220
|
+
const taskType = rootTask.value.type
|
|
221
|
+
const taskService = rootTask.value.service
|
|
222
|
+
const taskDefinition = api.serviceDefinition(taskService).tasks[taskType]
|
|
223
|
+
handleResult(rootTask.value.result, taskDefinition.returns.type)
|
|
224
|
+
}
|
|
225
|
+
}, { immediate: true }) */
|
|
226
|
+
|
|
227
|
+
|
|
99
228
|
</script>
|
|
100
229
|
|
|
101
230
|
<style scoped>
|
|
@@ -1,8 +1,22 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<template v-if="
|
|
2
|
+
<template v-if="identificationParts.length > 0">
|
|
3
3
|
<span>
|
|
4
|
-
<i :class="[icon, 'mr-2']" style="font-size: 0.9em;"></i>
|
|
5
|
-
|
|
4
|
+
<i v-if="modelDefinition.icon" :class="[modelDefinition.icon, 'mr-2']" style="font-size: 0.9em;"></i>
|
|
5
|
+
<template v-for="(part, index) in identificationParts">
|
|
6
|
+
<i v-if="part.icon" :class="[part.icon, 'mr-2']" style="font-size: 0.9em;"></i>
|
|
7
|
+
<span :class="{ 'mr-2': index < identificationParts.length - 1 }">
|
|
8
|
+
<span v-if="part.isObject">
|
|
9
|
+
<InjectedObjectIndentification :type="part.type" :object="part.value" />
|
|
10
|
+
</span>
|
|
11
|
+
<span v-else-if="part.field">
|
|
12
|
+
{{ part.value }}
|
|
13
|
+
</span>
|
|
14
|
+
<span v-else>
|
|
15
|
+
{{ part.text ?? '' }}
|
|
16
|
+
</span>
|
|
17
|
+
</span>
|
|
18
|
+
</template>
|
|
19
|
+
</span>
|
|
6
20
|
</template>
|
|
7
21
|
<template v-else>
|
|
8
22
|
<span>
|
|
@@ -13,7 +27,7 @@
|
|
|
13
27
|
|
|
14
28
|
<script setup>
|
|
15
29
|
|
|
16
|
-
import { ref, computed, onMounted, defineProps, defineEmits, toRefs } from 'vue'
|
|
30
|
+
import { ref, computed, onMounted, defineProps, defineEmits, toRefs, defineAsyncComponent } from 'vue'
|
|
17
31
|
|
|
18
32
|
const props = defineProps({
|
|
19
33
|
objectType: {
|
|
@@ -70,9 +84,63 @@
|
|
|
70
84
|
})
|
|
71
85
|
})
|
|
72
86
|
|
|
87
|
+
function getDefinitionProperty(path) {
|
|
88
|
+
const parts = path.split('.')
|
|
89
|
+
let current = modelDefinition.value
|
|
90
|
+
for(const part of parts) {
|
|
91
|
+
if(part === '*') {
|
|
92
|
+
return current?.items ?? current?.of
|
|
93
|
+
} else {
|
|
94
|
+
current = current?.properties?.[part]
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return current
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const InjectedObjectIndentification = defineAsyncComponent(() => import('./InjectedObjectIndentification.vue'))
|
|
101
|
+
|
|
73
102
|
const loadedObjectData = await live(objectDataPath)
|
|
74
103
|
const objectData = computed(() => data.value || loadedObjectData.value)
|
|
75
104
|
|
|
105
|
+
function getObjectData(path) {
|
|
106
|
+
const parts = path.split('.')
|
|
107
|
+
let current = objectData.value
|
|
108
|
+
for(const part of parts) {
|
|
109
|
+
current = current[part]
|
|
110
|
+
}
|
|
111
|
+
return current
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const identificationParts = computed(() => {
|
|
115
|
+
const config = identificationConfig.value
|
|
116
|
+
if(!config) return []
|
|
117
|
+
const configArray = Array.isArray(config) ? config : [config]
|
|
118
|
+
return configArray.map(fieldConfig => {
|
|
119
|
+
if(typeof fieldConfig === 'string') {
|
|
120
|
+
const field = getDefinitionProperty(fieldConfig)
|
|
121
|
+
if(field) {
|
|
122
|
+
const isObject = field.type.indexOf('_') > 0
|
|
123
|
+
return { field: fieldConfig, isObject, type: field.type }
|
|
124
|
+
} else {
|
|
125
|
+
return { text: fieldConfig }
|
|
126
|
+
}
|
|
127
|
+
} else if(typeof fieldConfig === 'object') {
|
|
128
|
+
return fieldConfig
|
|
129
|
+
} else {
|
|
130
|
+
throw new Error('Unknown identification config: ' + JSON.stringify(fieldConfig))
|
|
131
|
+
}
|
|
132
|
+
}).map(part => {
|
|
133
|
+
if(part.type === 'any') {
|
|
134
|
+
part.type = getObjectData(part.field + 'Type')
|
|
135
|
+
part.isObject = (part.type && part.type.indexOf('_') > 0) || false
|
|
136
|
+
}
|
|
137
|
+
if(part.field) {
|
|
138
|
+
part.value = getObjectData(part.field)
|
|
139
|
+
}
|
|
140
|
+
return part
|
|
141
|
+
})
|
|
142
|
+
})
|
|
143
|
+
|
|
76
144
|
|
|
77
145
|
const icon = computed(() => {
|
|
78
146
|
if(modelDefinition.value?.iconProperty) return objectData[modelDefinition.value?.iconProperty]
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
})
|
|
46
46
|
const { type, object, data, link, inline } = toRefs(props)
|
|
47
47
|
|
|
48
|
-
import
|
|
48
|
+
import DefaultObjectIdentification from './DefaultObjectIdentification.vue'
|
|
49
49
|
|
|
50
50
|
import { useApi, usePath, live } from '@live-change/vue3-ssr'
|
|
51
51
|
const api = useApi()
|
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
type: type.value,
|
|
65
65
|
service: service.value,
|
|
66
66
|
model: model.value
|
|
67
|
-
},
|
|
67
|
+
}, DefaultObjectIdentification)
|
|
68
68
|
)
|
|
69
69
|
|
|
70
70
|
const modelDefinition = computed(() => {
|
|
@@ -115,7 +115,7 @@
|
|
|
115
115
|
params: {
|
|
116
116
|
serviceName: service.value,
|
|
117
117
|
modelName: model.value,
|
|
118
|
-
|
|
118
|
+
id: objectData.value?.to ?? objectData.value?.id
|
|
119
119
|
}
|
|
120
120
|
}
|
|
121
121
|
})
|
|
@@ -19,17 +19,24 @@
|
|
|
19
19
|
</div>
|
|
20
20
|
</div>
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
<!-- <pre>parentObjects = {{ parentObjects }}</pre>
|
|
23
23
|
<pre>scopesPath = {{ scopesPath }}</pre>
|
|
24
|
-
<pre>scopes = {{ scopes }}</pre>
|
|
24
|
+
<pre>scopes = {{ scopes }}</pre> -->
|
|
25
25
|
|
|
26
26
|
<div class="">
|
|
27
27
|
Service <strong>{{ service }}</strong>
|
|
28
28
|
</div>
|
|
29
|
-
<div class="
|
|
30
|
-
<
|
|
31
|
-
|
|
32
|
-
|
|
29
|
+
<div class="flex flex-row flex-wrap justify-between align-items-top">
|
|
30
|
+
<div class="text-2xl mb-6">
|
|
31
|
+
<span v-if="isNew">Create </span>
|
|
32
|
+
<span v-else>Edit </span>
|
|
33
|
+
<strong>{{ model }}</strong>
|
|
34
|
+
</div>
|
|
35
|
+
<div v-if="!isNew" class="flex flex-row flex-wrap justify-between align-items-top gap-2">
|
|
36
|
+
<router-link :to="viewRoute">
|
|
37
|
+
<Button label="View" icon="pi pi-eye" class="p-button mb-6" />
|
|
38
|
+
</router-link>
|
|
39
|
+
</div>
|
|
33
40
|
</div>
|
|
34
41
|
|
|
35
42
|
<form v-if="editor" @submit="handleSave" @reset="handleReset">
|
|
@@ -162,11 +169,21 @@
|
|
|
162
169
|
console.log("SAVED", saveResult, isNew.value, editor.value.isNew)
|
|
163
170
|
if(saveResult && isNew.value && editor.value.isNew) {
|
|
164
171
|
emit('created', saveResult)
|
|
172
|
+
} else {
|
|
173
|
+
emit('saved', saveResult)
|
|
165
174
|
}
|
|
166
|
-
emit('saved', saveResult)
|
|
167
175
|
}
|
|
168
176
|
|
|
169
|
-
const
|
|
177
|
+
const viewRoute = computed(() => editor.value?.saved && ({
|
|
178
|
+
name: 'auto-form:view',
|
|
179
|
+
params: {
|
|
180
|
+
serviceName: service.value,
|
|
181
|
+
modelName: model.value,
|
|
182
|
+
id: editor.value.saved?.value?.to ?? editor.value.saved?.value?.id
|
|
183
|
+
}
|
|
184
|
+
}))
|
|
185
|
+
|
|
186
|
+
const scopesPath = computed(() => parentObjects.value[0] && path.scope.objectScopes({
|
|
170
187
|
objectType: parentObjects.value[0].objectType, /// TODO: support multiple parent objects!
|
|
171
188
|
object: parentObjects.value[0].object
|
|
172
189
|
}))
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
:key="JSON.stringify(modelsPathRangeConfig)+index"
|
|
28
28
|
:pathFunction="modelsPathRangeFunction"
|
|
29
29
|
:canLoadTop="false" canDropBottom
|
|
30
|
-
loadBottomSensorSize="4000px" dropBottomSensorSize="
|
|
30
|
+
loadBottomSensorSize="4000px" dropBottomSensorSize="7000px">
|
|
31
31
|
<template #empty>
|
|
32
32
|
<div class="text-xl text-surface-800 dark:text-surface-50 my-1 mx-4">
|
|
33
33
|
No <strong>{{ pluralize(model[0].toLowerCase() + model.slice(1)) }}</strong> found.
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
class="text-xl"
|
|
44
44
|
/>
|
|
45
45
|
</router-link>
|
|
46
|
-
<div class="flex flex-row">
|
|
46
|
+
<div class="flex flex-row ml-4">
|
|
47
47
|
<router-link :to="viewRoute(object)" class="no-underline">
|
|
48
48
|
<Button icon="pi pi-eye" severity="primary" label="View" class="mr-2" />
|
|
49
49
|
</router-link>
|
|
@@ -70,9 +70,11 @@
|
|
|
70
70
|
</div>
|
|
71
71
|
</div>
|
|
72
72
|
|
|
73
|
-
<div v-if="modelDefinition.crud?.create" class="mt-2 flex flex-row justify-end mr-2">
|
|
74
|
-
<router-link
|
|
75
|
-
|
|
73
|
+
<div v-if="modelDefinition.crud?.create" class="mt-2 flex flex-row justify-end mr-2 gap-2">
|
|
74
|
+
<router-link v-for="createButton in createButtons" :key="JSON.stringify(createButton.identifiers)"
|
|
75
|
+
:to="createButton.route" class="no-underline2">
|
|
76
|
+
<Button v-if="createButton.as" icon="pi pi-plus" :label="'Create new '+model + ' as '+createButton.as" />
|
|
77
|
+
<Button v-else icon="pi pi-plus" :label="'Create new '+model" />
|
|
76
78
|
</router-link>
|
|
77
79
|
</div>
|
|
78
80
|
|
|
@@ -198,11 +200,11 @@
|
|
|
198
200
|
|
|
199
201
|
function editRoute(object) {
|
|
200
202
|
return {
|
|
201
|
-
name: 'auto-form:
|
|
203
|
+
name: 'auto-form:edit',
|
|
202
204
|
params: {
|
|
203
205
|
serviceName: service.value,
|
|
204
206
|
modelName: model.value,
|
|
205
|
-
|
|
207
|
+
id: object.to ?? object.id
|
|
206
208
|
}
|
|
207
209
|
}
|
|
208
210
|
}
|
|
@@ -213,23 +215,62 @@
|
|
|
213
215
|
params: {
|
|
214
216
|
serviceName: service.value,
|
|
215
217
|
modelName: model.value,
|
|
216
|
-
|
|
218
|
+
id: object.to ?? object.id
|
|
217
219
|
}
|
|
218
220
|
}
|
|
219
221
|
}
|
|
220
222
|
|
|
221
|
-
|
|
222
|
-
const
|
|
223
|
-
if(!identifiersObject) return null
|
|
224
|
-
const identifiers = Object.values(identifiersObject)
|
|
223
|
+
function createRoute(identifiersObject) {
|
|
224
|
+
const identifiersWithNames = Object.entries(identifiersObject).flat()
|
|
225
225
|
return {
|
|
226
|
-
name: 'auto-form:
|
|
226
|
+
name: 'auto-form:create',
|
|
227
227
|
params: {
|
|
228
228
|
serviceName: service.value,
|
|
229
229
|
modelName: model.value,
|
|
230
|
-
|
|
230
|
+
identifiersWithNames
|
|
231
231
|
}
|
|
232
232
|
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
const createButtons = computed(() => {
|
|
236
|
+
const model = modelDefinition.value
|
|
237
|
+
const results = []
|
|
238
|
+
for(const view of viewsArray.value) {
|
|
239
|
+
const identifiersObject = view?.identifiers
|
|
240
|
+
if(!identifiersObject) continue
|
|
241
|
+
|
|
242
|
+
const identifierNames = Object.keys(identifiersObject)
|
|
243
|
+
const fieldParameters = identifierNames.filter(name => model.properties[name])
|
|
244
|
+
const otherParameters = identifierNames.filter(name => !model.properties[name])
|
|
245
|
+
|
|
246
|
+
if(otherParameters.length > 0) {
|
|
247
|
+
const viewName = model.crud[view.name]
|
|
248
|
+
const viewDefinition = serviceDefinition.value.views[viewName]
|
|
249
|
+
for(const otherParameter of otherParameters) {
|
|
250
|
+
const otherParameterType = viewDefinition.properties[otherParameter].type
|
|
251
|
+
const modelParameters = Object.entries(model.properties)
|
|
252
|
+
.filter(([name, property]) => otherParameterType === property.type)
|
|
253
|
+
for(const [name, property] of modelParameters) {
|
|
254
|
+
const newIdentifiersObject = {
|
|
255
|
+
[name]: identifiersObject[otherParameter]
|
|
256
|
+
}
|
|
257
|
+
results.push({
|
|
258
|
+
identifiers: newIdentifiersObject,
|
|
259
|
+
as: name,
|
|
260
|
+
route: createRoute(newIdentifiersObject)
|
|
261
|
+
})
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
} else {
|
|
265
|
+
results.push({
|
|
266
|
+
identifiers: identifiersObject,
|
|
267
|
+
route: createRoute(identifiersObject)
|
|
268
|
+
})
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
}
|
|
273
|
+
return results
|
|
233
274
|
})
|
|
234
275
|
|
|
235
276
|
function deleteObject(event, object) {
|
|
@@ -189,11 +189,11 @@
|
|
|
189
189
|
|
|
190
190
|
function editRoute(object) {
|
|
191
191
|
return {
|
|
192
|
-
name: 'auto-form:
|
|
192
|
+
name: 'auto-form:edit',
|
|
193
193
|
params: {
|
|
194
194
|
serviceName: service.value,
|
|
195
195
|
modelName: model.value,
|
|
196
|
-
|
|
196
|
+
id: object.to ?? object.id
|
|
197
197
|
}
|
|
198
198
|
}
|
|
199
199
|
}
|
|
@@ -204,17 +204,17 @@
|
|
|
204
204
|
params: {
|
|
205
205
|
serviceName: service.value,
|
|
206
206
|
modelName: model.value,
|
|
207
|
-
|
|
207
|
+
id: object.to ?? object.id
|
|
208
208
|
}
|
|
209
209
|
}
|
|
210
210
|
}
|
|
211
211
|
|
|
212
212
|
const createRoute = computed(() => ({
|
|
213
|
-
name: 'auto-form:
|
|
213
|
+
name: 'auto-form:create',
|
|
214
214
|
params: {
|
|
215
215
|
serviceName: service.value,
|
|
216
216
|
modelName: model.value,
|
|
217
|
-
|
|
217
|
+
identifiersWithNames: Object.entries(objectIdentifiers(views.value[0].identifiers)).flat()
|
|
218
218
|
}
|
|
219
219
|
}))
|
|
220
220
|
|