@live-change/frontend-auto-form 0.9.85 → 0.9.86

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.
@@ -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
- <form @submit="handleSubmit" @reset="handleReset">
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 actionFormData = await actionData({
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
- const handleSubmit = (ev) => {
160
+ function handleSubmit(ev) {
90
161
  ev.preventDefault()
91
162
  actionFormData.submit()
92
163
  }
93
164
 
94
- const handleReset = (ev) => {
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>
@@ -26,10 +26,17 @@
26
26
  <div class="">
27
27
  Service <strong>{{ service }}</strong>
28
28
  </div>
29
- <div class="text-2xl mb-6">
30
- <span v-if="isNew">Create </span>
31
- <span v-else>Edit </span>
32
- <strong>{{ model }}</strong>
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,10 +169,20 @@
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)
165
- }
166
- emit('saved', saveResult)
172
+ } else {
173
+ emit('saved', saveResult)
174
+ }
167
175
  }
168
176
 
177
+ const viewRoute = computed(() => ({
178
+ name: 'auto-form:editor',
179
+ params: {
180
+ serviceName: service.value,
181
+ modelName: model.value,
182
+ identifiers: Object.values(identifiers.value)
183
+ }
184
+ }))
185
+
169
186
  const scopesPath = computed(() => path.scope.objectScopes({
170
187
  objectType: parentObjects.value[0].objectType, /// TODO: support multiple parent objects!
171
188
  object: parentObjects.value[0].object
@@ -1,15 +1,6 @@
1
1
  <template>
2
2
  <div>
3
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
4
  <div v-if="object">
14
5
  <ObjectPath :objectType="service + '_' + model" :object="object.to ?? object.id" class="mb-6" />
15
6
 
@@ -41,6 +32,15 @@
41
32
 
42
33
  </div>
43
34
 
35
+ <div v-if="connectedActions" class="bg-surface-0 dark:bg-surface-900 p-4 shadow-sm rounded-border mb-6">
36
+ <div v-for="action of connectedActions" class="mb-6">
37
+ <pre>{{ action }}</pre>
38
+ <router-link :to="actionRoute(action)">
39
+ <Button :label="action.label" icon="pi pi-play" class="p-button mb-6" />
40
+ </router-link>
41
+ </div>
42
+ </div>
43
+
44
44
  <div v-for="preparedRelation of visibleObjectRelations" class="mb-6">
45
45
  <ModelSingle :service="preparedRelation.service" :model="preparedRelation.model"
46
46
  :views="preparedRelation.views">
@@ -98,7 +98,7 @@
98
98
 
99
99
  <div class="bg-surface-0 dark:bg-surface-900 p-4 shadow-sm rounded-border">
100
100
 
101
- <pre>visibleRangeRelations = {{ visibleRangeRelations }}</pre>
101
+ <!-- <pre>visibleRangeRelations = {{ visibleRangeRelations }}</pre>
102
102
  <pre>preparedRelations = {{ preparedRelations }}</pre>
103
103
 
104
104
  <div v-if="backwardRelations">
@@ -109,9 +109,13 @@
109
109
  )
110
110
  }}</pre>
111
111
  </div>
112
+ <pre>accessControlRoles = {{ accessControlRoles }}</pre> -->
113
+
114
+ <pre>identifiers = {{ identifiers }}</pre>
112
115
 
116
+ <pre>definition = {{ modelDefinition }}</pre>
113
117
 
114
- <pre>accessControlRoles = {{ accessControlRoles }}</pre>
118
+ <pre>object = {{ object }}</pre>
115
119
 
116
120
  </div>
117
121
 
@@ -178,6 +182,24 @@
178
182
  return api.services?.[service.value]?.models?.[model.value]
179
183
  })
180
184
 
185
+ const connectedActions = computed(() => {
186
+ const srcActions = modelDefinition.value?.connectedActions
187
+ if(!srcActions) return null
188
+ return Object.values(srcActions).map(action => {
189
+ const config = {
190
+ service: service.value,
191
+ ...action
192
+ }
193
+ const actionDefinition = api.getServiceDefinition(config.service).actions[config.name]
194
+ const label = actionDefinition.label ?? action.label ?? actionDefinition.name
195
+ return {
196
+ ...config,
197
+ definition: actionDefinition,
198
+ label
199
+ }
200
+ })
201
+ })
202
+
181
203
  import { getForwardRelations, getBackwardRelations, anyRelationsTypes, prepareObjectRelations }
182
204
  from '../../logic/relations.js'
183
205
  const forwardRelations = computed(() => getForwardRelations(modelDefinition.value, () => true, api))
@@ -205,14 +227,18 @@
205
227
  return prepareObjectRelations(objectType.value, object.value.to ?? object.value.id, api)
206
228
  })
207
229
 
208
- const visibleRangeRelations = computed(() => preparedRelations.value.map(preparedRelation => {
209
- const accessibleViews = preparedRelation.views.filter(view => preparedRelation.access.value[view.name])
210
- if(accessibleViews.length === 0) return null
211
- return {
212
- ...preparedRelation,
213
- views: accessibleViews
214
- }
215
- }).filter(x => x !== null))
230
+ const visibleRangeRelations = computed(() => preparedRelations.value
231
+ .filter(preparedRelation => !preparedRelation.singular)
232
+ .map(preparedRelation => {
233
+ const accessibleViews = preparedRelation.views.filter(view => preparedRelation.access.value[view.name])
234
+ if(accessibleViews.length === 0) return null
235
+ return {
236
+ ...preparedRelation,
237
+ views: accessibleViews
238
+ }
239
+ })
240
+ .filter(x => x !== null)
241
+ )
216
242
 
217
243
  const visibleObjectRelations = computed(() => preparedRelations.value.filter(preparedRelation => {
218
244
  if(!preparedRelation.singular) return false
@@ -236,6 +262,33 @@
236
262
  }
237
263
  }))
238
264
 
265
+ function actionRoute(action) {
266
+ const myType = service.value + '_' + model.value
267
+ const parameterName = action.objectParameter ??
268
+ Object.entries(action.definition.properties).find(([key, value]) => value.type === myType)?.[0] ??
269
+ Object.keys(action.definition.properties)?.[0]
270
+
271
+ if(parameterName) {
272
+ const parametersJson = JSON.stringify({
273
+ [parameterName]: object.value.to ?? object.value.id
274
+ })
275
+ return {
276
+ name: 'auto-form:actionParameters',
277
+ params: {
278
+ serviceName: action.service,
279
+ actionName: action.name,
280
+ parametersJson
281
+ }
282
+ }
283
+ }
284
+ return {
285
+ name: 'auto-form:action',
286
+ params: {
287
+ serviceName: action.service,
288
+ actionName: action.name
289
+ }
290
+ }
291
+ }
239
292
 
240
293
  </script>
241
294
 
@@ -1,14 +1,14 @@
1
1
  <template>
2
- <div>
3
- <div class="surface-card p-3">
4
- <h4>#### Schema:</h4>
5
- <pre>{{ '```\n' + JSON.stringify(schema, null, 2) + '\n```' }}</pre>
6
- </div>
7
- <div class="surface-card p-3">
8
- <h4>#### Data:</h4>
9
- <pre>{{ '```\n' + JSON.stringify(clearData, null, 2) + '\n```' }}</pre>
10
- </div>
11
- </div>
2
+ <pre>
3
+ #### {{ prefix }} Data Schema
4
+
5
+ {{ JSON.stringify(schema, null, 2) }}
6
+
7
+
8
+ #### {{ prefix }} Data:
9
+
10
+ {{ JSON.stringify(clearData, null, 2) }}
11
+ </pre>
12
12
  </template>
13
13
 
14
14
  <script setup>
@@ -19,7 +19,11 @@
19
19
  data: {
20
20
  type: Object,
21
21
  required: true,
22
- }
22
+ },
23
+ prefix: {
24
+ type: String,
25
+ default: ''
26
+ }
23
27
  })
24
28
  const { data } = toRefs(props)
25
29
 
@@ -0,0 +1,23 @@
1
+ <template>
2
+ <pre>{{ schema }}</pre>
3
+ </template>
4
+
5
+ <script setup>
6
+
7
+ import { schemaFromDefinition } from "../../logic/schema.js"
8
+ import { defineProps, toRefs, computed, getCurrentInstance } from "vue"
9
+
10
+ const props = defineProps({
11
+ definition: {
12
+ type: Object,
13
+ required: true,
14
+ }
15
+ })
16
+
17
+ const { definition } = toRefs(props)
18
+
19
+ const appContext = getCurrentInstance().appContext
20
+
21
+ const schema = computed(() => schemaFromDefinition(definition.value, undefined, undefined, appContext))
22
+
23
+ </script>
@@ -11,7 +11,7 @@ export default async function actionData(options) {
11
11
  if(!options) throw new Error('options must be provided')
12
12
 
13
13
  const {
14
- parameters,
14
+ parameters = {},
15
15
  initialValue = {},
16
16
 
17
17
  service: serviceName,
@@ -50,7 +50,10 @@ export default async function actionData(options) {
50
50
  if(!service) throw new Error('service must be defined in options')
51
51
  const action = service.actions[actionName]
52
52
  if(!action) throw new Error('action must be defined in options')
53
-
53
+
54
+ const editableProperties = (action.definition.editableProperties ?? Object.keys(action.definition.properties))
55
+ .filter(key => !parameters[key])
56
+
54
57
  let draftIdParts = []
55
58
  let idKey = null
56
59
  for(const [parameterName, parameter] of Object.entries(parameters || {})) {
@@ -152,7 +155,6 @@ export default async function actionData(options) {
152
155
  const result = await submitData(synchronizedData.value.value)
153
156
  if(result === Error) return // silent return on error, because it's handled in onError
154
157
  if(draftData.value) await removeDraftAction(draftIdentifiers)
155
- onDone(result)
156
158
  if(toast && doneToast) toast.add({ severity: 'success', summary: doneToast, life: 1500 })
157
159
  }
158
160
 
@@ -179,6 +181,7 @@ export default async function actionData(options) {
179
181
  return {
180
182
  parameters,
181
183
  initialValue,
184
+ editableProperties,
182
185
  value: synchronizedData.value,
183
186
  changed,
184
187
  submit,
@@ -200,7 +203,6 @@ export default async function actionData(options) {
200
203
  async function submit() {
201
204
  const result = await submitData(formData.value)
202
205
  if(result === Error) return // silent return on error, because it's handled in onError
203
- onSaved(result)
204
206
  if(toast && doneToast) toast.add({ severity: 'success', summary: doneToast, life: 1500 })
205
207
  }
206
208
 
@@ -214,8 +216,9 @@ export default async function actionData(options) {
214
216
  }
215
217
 
216
218
  return {
217
- parameters,
219
+ parameters,
218
220
  initialValue,
221
+ editableProperties,
219
222
  value: formData,
220
223
  changed,
221
224
  submit,
@@ -28,21 +28,40 @@ function addSchema(schemas, schema) {
28
28
  export function schemaFromDefinition(definition, data, type, appContext = getCurrentInstance().appContext) {
29
29
  if(!type) type = definition.type
30
30
  if(type === 'Object') {
31
+ const properties = Object.fromEntries(
32
+ Object.entries(definition.properties).map(
33
+ ([key, value]) => [key, schemaFromDefinition(value, data?.[key], undefined, appContext)])
34
+ )
35
+ for(const key in definition.properties) {
36
+ const prop = definition.properties[key]
37
+ if(key.endsWith('Type') && prop.type === 'type') {
38
+ const keyWithoutType = key.slice(0, -4)
39
+ properties[key] = {
40
+ type: 'string',
41
+ enum: prop.enum,
42
+ description: `Type of ${keyWithoutType}`
43
+ }
44
+ properties[keyWithoutType] = {
45
+ type: 'string',
46
+ description: `Id of Object with type defined in ${key}`
47
+ }
48
+ }
49
+ }
31
50
  return {
32
51
  type: 'object',
33
- properties: Object.fromEntries(
34
- Object.entries(definition.properties).map(([key, value]) => [key, schemaFromDefinition(value, data[key], undefined, appContext)])
35
- ),
52
+ properties,
36
53
  description: definition.description
37
54
  }
38
55
  } else if(type === 'Array') {
39
56
  const schema = {
40
57
  type: 'array',
41
- items: schemaFromDefinition(definition.items ?? definition.of, data[0], undefined, appContext),
58
+ items: schemaFromDefinition(definition.items ?? definition.of, data?.[0], undefined, appContext),
42
59
  description: definition.description
43
60
  }
44
- for(const item of data) {
45
- extendSchema(schema.items, item, schema.items.modelName, schema.items.serviceName)
61
+ if(data) {
62
+ for(const item of data) {
63
+ extendSchema(schema.items, item, schema.items.modelName, schema.items.serviceName)
64
+ }
46
65
  }
47
66
  return schema
48
67
  } else if(type === 'String') {
@@ -70,9 +89,8 @@ export function schemaFromDefinition(definition, data, type, appContext = getCur
70
89
  const api = useApi(appContext)
71
90
  const [serviceName, modelName] = definition.type.split('_')
72
91
  const serviceDefinition = api.getServiceDefinition(serviceName)
73
- const modelDefinition = serviceDefinition?.models?.[modelName]
74
- //console.log("MODEL DEFINITION", modelDefinition, "DATA", data, typeof data)
75
- if(typeof data === 'string') {
92
+ const modelDefinition = serviceDefinition?.models?.[modelName]
93
+ if(!data || typeof data === 'string') {
76
94
  return {
77
95
  type: 'string',
78
96
  description: `Id of ${modelName} from ${serviceName} service.`
@@ -94,6 +112,7 @@ export function schemaFromDefinition(definition, data, type, appContext = getCur
94
112
  }
95
113
 
96
114
  function extendSchema(schema, data, viewName, serviceName, appContext) {
115
+ if(!data) return
97
116
  if(Array.isArray(data)) {
98
117
  if(!schema.items) {
99
118
  schema.items = generateSchema(data, schema, 'items', appContext)
@@ -108,7 +127,7 @@ function extendSchema(schema, data, viewName, serviceName, appContext) {
108
127
  description: schema.modelName ? `Id of ${schema.modelName} from ${schema.serviceName} service.` : `Id.`
109
128
  }
110
129
  } else {
111
- generateSchema(value, schema.properties, property)
130
+ generateSchema(value, schema.properties, property, appContext)
112
131
  }
113
132
  }
114
133
  }
@@ -116,7 +135,7 @@ function extendSchema(schema, data, viewName, serviceName, appContext) {
116
135
  }
117
136
 
118
137
  function generateSchema(data, schemaObject, schemaProperty, appContext) {
119
- const api = useApi(appContext)
138
+ const api = useApi(appContext)
120
139
  if(!schemaObject[schemaProperty]) {
121
140
  schemaObject[schemaProperty] = {
122
141
  anyOf: []
@@ -180,4 +199,4 @@ export function cleanData(data) {
180
199
  }
181
200
  return cleanedProperties
182
201
  }
183
- }
202
+ }
@@ -1,18 +1,14 @@
1
1
  <template>
2
2
  <div class="w-full lg:w-8/12 md:w-11/12">
3
3
  <div class="bg-surface-0 dark:bg-surface-900 p-4 shadow-sm rounded-border">
4
- <div class="text-xl mb-2">
5
- Service <strong>{{ serviceName }}</strong>
6
- </div>
7
- <div class="text-2xl mb-4">
8
- Action <strong>{{ actionName }}</strong>
9
- </div>
10
4
 
11
5
  <ActionForm
12
6
  :service="serviceName"
13
- :action="actionName"
7
+ :action="actionName"
8
+ :parameters="parameters"
14
9
  @done="handleDone"
15
10
  />
11
+
16
12
  </div>
17
13
  </div>
18
14
  </template>
@@ -29,9 +25,14 @@
29
25
  actionName: {
30
26
  type: String,
31
27
  required: true
28
+ },
29
+ parametersJson: {
30
+ type: String
32
31
  }
33
32
  })
34
- const { serviceName, actionName } = toRefs(props)
33
+ const { serviceName, actionName, parametersJson } = toRefs(props)
34
+
35
+ const parameters = computed(() => parametersJson.value ? JSON.parse(parametersJson.value) : {})
35
36
 
36
37
  import { useApi } from '@live-change/vue3-ssr'
37
38
  const api = useApi()
@@ -8,7 +8,7 @@
8
8
  <div class="bg-surface-0 dark:bg-surface-900 p-4 shadow-sm rounded-border">
9
9
 
10
10
  <ModelEditor :service="serviceName" :model="modelName" :identifiers="identifiersObject" draft
11
- @created="handleCreated"/>
11
+ @created="handleCreated" @saved="handleSaved" />
12
12
 
13
13
  </div>
14
14
  </div>
@@ -83,7 +83,7 @@
83
83
  //console.log("newIdentifiers", newIdentifiers)
84
84
  if(JSON.stringify(identifiers.value) !== JSON.stringify(newIdentifiers)) {
85
85
  router.push({
86
- name: 'auto-form:editor',
86
+ name: 'auto-form:view',
87
87
  params: {
88
88
  serviceName: serviceName.value,
89
89
  modelName: modelName.value,
@@ -93,6 +93,17 @@
93
93
  }
94
94
  }
95
95
 
96
+ function handleSaved(id) {
97
+ router.push({
98
+ name: 'auto-form:view',
99
+ params: {
100
+ serviceName: serviceName.value,
101
+ modelName: modelName.value,
102
+ identifiers: identifiers.value
103
+ }
104
+ })
105
+ }
106
+
96
107
  </script>
97
108
 
98
109
  <style scoped>
@@ -38,6 +38,12 @@ export function autoFormRoutes(config = {}) {
38
38
  props: true
39
39
  }),
40
40
 
41
+ route({
42
+ name: 'auto-form:actionParameters', path: prefix + '/action/:serviceName/:actionName/:parametersJson', meta: { },
43
+ component: () => import("./pages/Action.vue"),
44
+ props: true
45
+ }),
46
+
41
47
  ]
42
48
  }
43
49
 
package/index.js CHANGED
@@ -47,6 +47,8 @@ export * from './front/src/router.js'
47
47
 
48
48
  import DataWithSchema from './front/src/components/schema/DataWithSchema.vue'
49
49
  export { DataWithSchema }
50
+ import SchemaFromDefinition from './front/src/components/schema/SchemaFromDefinition.vue'
51
+ export { SchemaFromDefinition }
50
52
  export * from './front/src/logic/schema.js'
51
53
 
52
54
  import en from "./front/locales/en.json"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@live-change/frontend-auto-form",
3
- "version": "0.9.85",
3
+ "version": "0.9.86",
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.85",
26
- "@live-change/dao": "^0.9.85",
27
- "@live-change/dao-vue3": "^0.9.85",
28
- "@live-change/dao-websocket": "^0.9.85",
29
- "@live-change/framework": "^0.9.85",
30
- "@live-change/image-frontend": "^0.9.85",
31
- "@live-change/image-service": "^0.9.85",
32
- "@live-change/session-service": "^0.9.85",
33
- "@live-change/vue3-components": "^0.9.85",
34
- "@live-change/vue3-ssr": "^0.9.85",
25
+ "@live-change/cli": "^0.9.86",
26
+ "@live-change/dao": "^0.9.86",
27
+ "@live-change/dao-vue3": "^0.9.86",
28
+ "@live-change/dao-websocket": "^0.9.86",
29
+ "@live-change/framework": "^0.9.86",
30
+ "@live-change/image-frontend": "^0.9.86",
31
+ "@live-change/image-service": "^0.9.86",
32
+ "@live-change/session-service": "^0.9.86",
33
+ "@live-change/vue3-components": "^0.9.86",
34
+ "@live-change/vue3-ssr": "^0.9.86",
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.85",
55
+ "@live-change/codeceptjs-helper": "^0.9.86",
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": "126afb0aad3ab6e03aa5742726f429c95c46783a"
66
+ "gitHead": "7b0013ef101d9033402eeec45fd1be60e151aada"
67
67
  }