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

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.
@@ -98,7 +98,7 @@
98
98
  params: {
99
99
  serviceName: service.value,
100
100
  modelName: model.value,
101
- identifiers: Object.values(objectIdentifiers(objectData.value))
101
+ id: objectData.value?.to ?? objectData.value?.id
102
102
  }
103
103
  }
104
104
  })
@@ -1,8 +1,22 @@
1
1
  <template>
2
- <template v-if="typeof identificationConfig === 'string'">
2
+ <template v-if="identificationParts.length > 0">
3
3
  <span>
4
- <i :class="[icon, 'mr-2']" style="font-size: 0.9em;"></i>{{ objectData[identificationConfig] }}
5
- </span>
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 AutoObjectIdentification from './DefaultObjectIdentification.vue'
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
- }, AutoObjectIdentification)
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
- identifiers: Object.values(objectIdentifiers(objectData.value))
118
+ id: objectData.value?.to ?? objectData.value?.id
119
119
  }
120
120
  }
121
121
  })
@@ -19,9 +19,9 @@
19
19
  </div>
20
20
  </div>
21
21
 
22
- <pre>parentObjects = {{ parentObjects }}</pre>
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>
@@ -171,19 +171,19 @@
171
171
  emit('created', saveResult)
172
172
  } else {
173
173
  emit('saved', saveResult)
174
- }
174
+ }
175
175
  }
176
176
 
177
- const viewRoute = computed(() => ({
178
- name: 'auto-form:editor',
177
+ const viewRoute = computed(() => editor.value?.saved && ({
178
+ name: 'auto-form:view',
179
179
  params: {
180
180
  serviceName: service.value,
181
181
  modelName: model.value,
182
- identifiers: Object.values(identifiers.value)
182
+ id: editor.value.saved?.value?.to ?? editor.value.saved?.value?.id
183
183
  }
184
184
  }))
185
185
 
186
- const scopesPath = computed(() => path.scope.objectScopes({
186
+ const scopesPath = computed(() => parentObjects.value[0] && path.scope.objectScopes({
187
187
  objectType: parentObjects.value[0].objectType, /// TODO: support multiple parent objects!
188
188
  object: parentObjects.value[0].object
189
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="3000px">
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 :to="createRoute" class="no-underline2">
75
- <Button icon="pi pi-plus" :label="'Create new '+model" />
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:editor',
203
+ name: 'auto-form:edit',
202
204
  params: {
203
205
  serviceName: service.value,
204
206
  modelName: model.value,
205
- identifiers: Object.values(objectIdentifiers(object))
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
- identifiers: Object.values(objectIdentifiers(object))
218
+ id: object.to ?? object.id
217
219
  }
218
220
  }
219
221
  }
220
222
 
221
- const createRoute = computed(() => {
222
- const identifiersObject = viewsArray?.value[0]?.identifiers
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:editor',
226
+ name: 'auto-form:create',
227
227
  params: {
228
228
  serviceName: service.value,
229
229
  modelName: model.value,
230
- identifiers
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:editor',
192
+ name: 'auto-form:edit',
193
193
  params: {
194
194
  serviceName: service.value,
195
195
  modelName: model.value,
196
- identifiers: Object.values(objectIdentifiers(object))
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
- identifiers: Object.values(objectIdentifiers(object))
207
+ id: object.to ?? object.id
208
208
  }
209
209
  }
210
210
  }
211
211
 
212
212
  const createRoute = computed(() => ({
213
- name: 'auto-form:editor',
213
+ name: 'auto-form:create',
214
214
  params: {
215
215
  serviceName: service.value,
216
216
  modelName: model.value,
217
- identifiers: Object.values(objectIdentifiers(views.value[0].identifiers))
217
+ identifiersWithNames: Object.entries(objectIdentifiers(views.value[0].identifiers)).flat()
218
218
  }
219
219
  }))
220
220
 
@@ -11,12 +11,12 @@
11
11
  </div>
12
12
  <div class="flex flex-row flex-wrap justify-between align-items-top">
13
13
  <div class="text-2xl mb-6">
14
- <strong>{{ model }}</strong>
14
+ <strong class="mr-2">{{ model }}</strong>
15
15
  <ObjectIdentification
16
16
  :objectType="service + '_' + model"
17
17
  :object="object.to ?? object.id"
18
18
  :data="object"
19
- class="ml-2"
19
+ class=""
20
20
  />
21
21
  </div>
22
22
  <div class="flex flex-row flex-wrap justify-between align-items-top gap-2">
@@ -32,12 +32,18 @@
32
32
 
33
33
  </div>
34
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>
35
+ <div v-if="connectedActions"
36
+ class="bg-surface-0 dark:bg-surface-900 p-4 shadow-sm rounded-border mb-6">
37
+ <div class="text-xl mb-3">
38
+ Actions
39
+ </div>
40
+ <div class="flex flex-row flex-wrap gap-2">
41
+ <div v-for="action of connectedActions" class="mb-0">
42
+ <!-- <pre>{{ action }}</pre> -->
43
+ <router-link :to="actionRoute(action)">
44
+ <Button :label="action.label" icon="pi pi-play" class="p-button mb-0" />
45
+ </router-link>
46
+ </div>
41
47
  </div>
42
48
  </div>
43
49
 
@@ -111,7 +117,7 @@
111
117
  </div>
112
118
  <pre>accessControlRoles = {{ accessControlRoles }}</pre> -->
113
119
 
114
- <pre>identifiers = {{ identifiers }}</pre>
120
+ <pre>id = {{ id }}</pre>
115
121
 
116
122
  <pre>definition = {{ modelDefinition }}</pre>
117
123
 
@@ -147,9 +153,9 @@
147
153
  type: String,
148
154
  required: true,
149
155
  },
150
- identifiers: {
151
- type: Object,
152
- default: () => ({})
156
+ id: {
157
+ type: String,
158
+ required: true,
153
159
  },
154
160
  attributes: {
155
161
  type: Object,
@@ -160,7 +166,7 @@
160
166
  default: ''
161
167
  }
162
168
  })
163
- const { service, model, identifiers, attributes, i18n } = toRefs(props)
169
+ const { service, model, id, attributes, i18n } = toRefs(props)
164
170
 
165
171
  const emit = defineEmits(['saved', 'draftSaved', 'draftDiscarded', 'saveError', 'created' ])
166
172
 
@@ -191,6 +197,7 @@
191
197
  ...action
192
198
  }
193
199
  const actionDefinition = api.getServiceDefinition(config.service).actions[config.name]
200
+ if(!actionDefinition) throw new Error("Action " + config.service + "_" + config.name + " definition not found")
194
201
  const label = actionDefinition.label ?? action.label ?? actionDefinition.name
195
202
  return {
196
203
  ...config,
@@ -210,7 +217,7 @@
210
217
  const viewDataPromise = viewData({
211
218
  service: service.value,
212
219
  model: model.value,
213
- identifiers: identifiers.value,
220
+ id: id.value,
214
221
  path, api
215
222
  })
216
223
 
@@ -254,11 +261,11 @@
254
261
  const accessControlRoles = computed(() => modelDefinition.value?.accessRoles ?? [])
255
262
 
256
263
  const editRoute = computed(() => ({
257
- name: 'auto-form:editor',
264
+ name: 'auto-form:edit',
258
265
  params: {
259
266
  serviceName: service.value,
260
267
  modelName: model.value,
261
- identifiers: Object.values(identifiers.value)
268
+ id: id.value
262
269
  }
263
270
  }))
264
271
 
@@ -85,12 +85,25 @@
85
85
  filter: viewFilter.value
86
86
  }))
87
87
 
88
+ import { useApi } from '@live-change/vue3-ssr'
89
+ const api = useApi()
90
+
88
91
  const viewComponent = computed(() => {
89
92
  const type = definition.value.type ?? 'Object'
90
- const defaultComponent = (type === 'Object')
91
- ? defineAsyncComponent(() => import('./ObjectView.vue'))
92
- : defineAsyncComponent(() => import('./JsonView.vue'))
93
- return injectComponent(viewComponentRequest.value, defineAsyncComponent(() => import('./JsonView.vue')))
93
+ let defaultComponent = undefined
94
+ if(type.indexOf('_') > 0) {
95
+ const [service, model] = type.split('_')
96
+ const modelDefinition = api.getServiceDefinition(service)?.models[model]
97
+ if(modelDefinition) {
98
+ defaultComponent = defineAsyncComponent(() => import('../crud/InjectedObjectIndentification.vue'))
99
+ }
100
+ }
101
+ if(!defaultComponent) {
102
+ defaultComponent = (type === 'Object')
103
+ ? defineAsyncComponent(() => import('./ObjectView.vue'))
104
+ : defineAsyncComponent(() => import('./JsonView.vue'))
105
+ }
106
+ return injectComponent(viewComponentRequest.value, defaultComponent)
94
107
  })
95
108
 
96
109
  const viewClass = computed(() => [definition.value?.view?.class, props.class])
@@ -102,6 +115,8 @@
102
115
  ...(definition.value?.view?.attributes),
103
116
  ...(props.attributes),
104
117
  value: value.value,
118
+ type: definition.value.type,
119
+ object: value.value,
105
120
  definition: definition.value,
106
121
  class: viewClass.value,
107
122
  style: viewStyle.value,
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <div class="field" :class="fieldClass" :style="fieldStyle">
2
+ <div class="field flex flex-col" :class="fieldClass" :style="fieldStyle">
3
3
  <slot name="label"
4
4
  v-bind="{ uid, value, definition, viewClass, viewStyle, attributes, propName, rootValue, i18n }">
5
5
  <label :for="uid" class="font-medium text-lg">{{ t( label ) }}</label>
@@ -39,24 +39,25 @@ export function schemaFromDefinition(definition, data, type, appContext = getCur
39
39
  properties[key] = {
40
40
  type: 'string',
41
41
  enum: prop.enum,
42
- description: `Type of ${keyWithoutType}`
42
+ enumDescriptions: prop.enumDescriptions,
43
+ description: `Type of ${keyWithoutType}`,
43
44
  }
44
45
  properties[keyWithoutType] = {
45
46
  type: 'string',
46
- description: `Id of Object with type defined in ${key}`
47
+ description: `Id of Object with type defined in ${key}`,
47
48
  }
48
49
  }
49
50
  }
50
51
  return {
51
52
  type: 'object',
52
53
  properties,
53
- description: definition.description
54
+ description: definition.description,
54
55
  }
55
56
  } else if(type === 'Array') {
56
57
  const schema = {
57
58
  type: 'array',
58
59
  items: schemaFromDefinition(definition.items ?? definition.of, data?.[0], undefined, appContext),
59
- description: definition.description
60
+ description: definition.description,
60
61
  }
61
62
  if(data) {
62
63
  for(const item of data) {
@@ -67,7 +68,9 @@ export function schemaFromDefinition(definition, data, type, appContext = getCur
67
68
  } else if(type === 'String') {
68
69
  return {
69
70
  type: 'string',
70
- description: definition.description
71
+ description: definition.description,
72
+ enum: definition.enum,
73
+ enumDescriptions: definition.enumDescriptions
71
74
  }
72
75
  } else if(type === 'Number') {
73
76
  return {
@@ -5,7 +5,7 @@ export default async function viewData(options) {
5
5
  if(!options) throw new Error('options must be provided')
6
6
 
7
7
  const {
8
- identifiers,
8
+ id,
9
9
  service: serviceName,
10
10
  model: modelName,
11
11
 
@@ -13,22 +13,22 @@ export default async function viewData(options) {
13
13
  api = useApi(),
14
14
  } = options
15
15
 
16
- if(!identifiers) throw new Error('identifiers must be defined')
16
+ if(!id) throw new Error('id must be defined')
17
17
  if(!serviceName || !modelName) throw new Error('service and model must be defined')
18
18
 
19
19
  const service = api.services[serviceName]
20
20
  const model = service.models[modelName]
21
21
  const {
22
- crudMethods = model.crud,
23
- identifiersNames = model.identifiers,
22
+ crudMethods = model.crud
24
23
  //editableProperties = model.editableProperties ?? Object.keys(model.properties)
25
24
  } = options
26
25
 
27
26
  if(!crudMethods) throw new Error('crud methods must be defined in model or options')
28
- if(!identifiersNames) throw new Error('identifiers names must be defined in model or options')
29
27
  // if(!editableProperties) throw new Error('editableProperties must be defined in model or options')
30
28
 
31
- const savedDataPath = path[serviceName][crudMethods.read](identifiers)
29
+ const savedDataPath = path[serviceName][crudMethods.read]({
30
+ [modelName[0].toLowerCase() + modelName.slice(1)]: id
31
+ })
32
32
 
33
33
  let data
34
34
  let error
@@ -29,20 +29,12 @@
29
29
  type: String,
30
30
  required: true,
31
31
  },
32
- identifiers: {
32
+ identifiersWithNames: {
33
33
  type: Array,
34
34
  default: () => []
35
- },
36
- identifiersTypes: {
37
- type: Array,
38
- default: () => undefined
39
- },
40
- identifiersProperties: {
41
- type: Array,
42
- default: () => undefined
43
35
  }
44
36
  })
45
- const { serviceName, modelName, identifiers } = toRefs(props)
37
+ const { serviceName, modelName, identifiersWithNames } = toRefs(props)
46
38
 
47
39
  import { useApi, usePath, live } from '@live-change/vue3-ssr'
48
40
  const api = useApi()
@@ -58,13 +50,10 @@
58
50
 
59
51
  const identifiersObject = computed(() => {
60
52
  const result = {}
61
- for(const [i, identifier] of Object.entries(identifiers.value)) {
62
- const identifierDefinition = modelDefinition.value.identifiers[i]
63
- if(typeof identifierDefinition === 'string') {
64
- result[identifierDefinition] = identifier
65
- } else {
66
- result[identifierDefinition.name] = identifier
67
- }
53
+ for(let i = 0; i < identifiersWithNames.value.length; i+=2) {
54
+ const name = identifiersWithNames.value[i]
55
+ const identifier = identifiersWithNames.value[i+1]
56
+ result[name] = identifier
68
57
  }
69
58
  return result
70
59
  })
@@ -73,35 +62,17 @@
73
62
  const router = useRouter()
74
63
 
75
64
  function handleCreated(id) {
76
- const newIdentifiers = modelDefinition.value.identifiers.map((identifier, i) => {
77
- if(typeof identifier === 'object' && identifier.field === 'id') {
78
- return id
79
- }
80
- return identifiers.value[i]
81
- })
82
-
65
+ console.log("HANDLE CREATED", id)
83
66
  //console.log("newIdentifiers", newIdentifiers)
84
- if(JSON.stringify(identifiers.value) !== JSON.stringify(newIdentifiers)) {
85
- router.push({
86
- name: 'auto-form:view',
87
- params: {
88
- serviceName: serviceName.value,
89
- modelName: modelName.value,
90
- identifiers: newIdentifiers
91
- }
92
- })
93
- }
94
- }
95
-
96
- function handleSaved(id) {
97
67
  router.push({
98
68
  name: 'auto-form:view',
99
69
  params: {
100
70
  serviceName: serviceName.value,
101
71
  modelName: modelName.value,
102
- identifiers: identifiers.value
72
+ id
103
73
  }
104
74
  })
75
+
105
76
  }
106
77
 
107
78
  </script>
@@ -0,0 +1,76 @@
1
+ <template>
2
+ <div class="w-full lg:w-8/12 md:w-11/12">
3
+
4
+ <!-- <pre>{{ identifiers }}</pre>
5
+ <pre>{{ modelDefinition.identifiers }}</pre> -->
6
+ <!-- <pre>{{identifiersObject}}</pre> -->
7
+
8
+ <div class="bg-surface-0 dark:bg-surface-900 p-4 shadow-sm rounded-border">
9
+
10
+ <ModelEditor :service="serviceName" :model="modelName" :identifiers="identifiersObject" draft
11
+ @saved="handleSaved" />
12
+
13
+ </div>
14
+ </div>
15
+ </template>
16
+
17
+ <script setup>
18
+
19
+ import ModelEditor from "../components/crud/ModelEditor.vue"
20
+
21
+ import { ref, computed, onMounted, defineProps, toRefs } from 'vue'
22
+
23
+ const props = defineProps({
24
+ serviceName: {
25
+ type: String,
26
+ required: true,
27
+ },
28
+ modelName: {
29
+ type: String,
30
+ required: true,
31
+ },
32
+ id: {
33
+ type: String,
34
+ required: true,
35
+ }
36
+ })
37
+ const { serviceName, modelName, id } = toRefs(props)
38
+
39
+ import { useApi, usePath, live } from '@live-change/vue3-ssr'
40
+ const api = useApi()
41
+ const path = usePath()
42
+
43
+ const modelDefinition = computed(() => {
44
+ const service = api.services[serviceName.value]
45
+ if(!service) return null
46
+ const model = service.models[modelName.value]
47
+ if(!model) return null
48
+ return model
49
+ })
50
+
51
+ const identifiersObject = computed(() => {
52
+ return {
53
+ [modelName.value[0].toLowerCase() + modelName.value.slice(1)]: id.value
54
+ }
55
+ })
56
+
57
+ import { useRouter } from 'vue-router'
58
+ const router = useRouter()
59
+
60
+ function handleSaved(result) {
61
+ console.log("HANDLE SAVED", result)
62
+ router.push({
63
+ name: 'auto-form:view',
64
+ params: {
65
+ serviceName: serviceName.value,
66
+ modelName: modelName.value,
67
+ id: id.value
68
+ }
69
+ })
70
+ }
71
+
72
+ </script>
73
+
74
+ <style scoped>
75
+
76
+ </style>
@@ -73,7 +73,7 @@
73
73
 
74
74
  function createRoute(serviceName, model) {
75
75
  return {
76
- name: 'auto-form:editor',
76
+ name: 'auto-form:create',
77
77
  params: {
78
78
  serviceName,
79
79
  modelName: model.name
@@ -1,7 +1,7 @@
1
1
  <template>
2
2
  <div class="w-full lg:w-8/12 md:w-11/12">
3
3
 
4
- <ModelView :service="serviceName" :model="modelName" :identifiers="identifiersObject" />
4
+ <ModelView :service="serviceName" :model="modelName" :id="id" />
5
5
 
6
6
  </div>
7
7
  </template>
@@ -21,37 +21,12 @@
21
21
  type: String,
22
22
  required: true,
23
23
  },
24
- identifiers: {
25
- type: Array,
26
- default: []
27
- }
28
- })
29
- const { serviceName, modelName, identifiers } = toRefs(props)
30
-
31
- import { useApi, usePath, live } from '@live-change/vue3-ssr'
32
- const api = useApi()
33
- const path = usePath()
34
-
35
- const modelDefinition = computed(() => {
36
- const service = api.services[serviceName.value]
37
- if(!service) return null
38
- const model = service.models[modelName.value]
39
- if(!model) return null
40
- return model
41
- })
42
-
43
- const identifiersObject = computed(() => {
44
- const result = {}
45
- for(const [i, identifier] of Object.entries(identifiers.value)) {
46
- const identifierDefinition = modelDefinition.value.identifiers[i]
47
- if(typeof identifierDefinition === 'string') {
48
- result[identifierDefinition] = identifier
49
- } else {
50
- result[identifierDefinition.name] = identifier
51
- }
24
+ id: {
25
+ type: String,
26
+ required: true,
52
27
  }
53
- return result
54
28
  })
29
+ const { serviceName, modelName, id } = toRefs(props)
55
30
 
56
31
  </script>
57
32
 
@@ -15,13 +15,19 @@ export function autoFormRoutes(config = {}) {
15
15
  }),
16
16
 
17
17
  route({
18
- name: 'auto-form:editor', path: prefix + '/editor/:serviceName/:modelName/:identifiers*', meta: { },
19
- component: () => import("./pages/Editor.vue"),
18
+ name: 'auto-form:create', path: prefix + '/create/:serviceName/:modelName/:identifiersWithNames*', meta: { },
19
+ component: () => import("./pages/Create.vue"),
20
20
  props: true
21
21
  }),
22
22
 
23
23
  route({
24
- name: 'auto-form:view', path: prefix + '/view/:serviceName/:modelName/:identifiers*', meta: { },
24
+ name: 'auto-form:edit', path: prefix + '/edit/:serviceName/:modelName/:id', meta: { },
25
+ component: () => import("./pages/Edit.vue"),
26
+ props: true
27
+ }),
28
+
29
+ route({
30
+ name: 'auto-form:view', path: prefix + '/view/:serviceName/:modelName/:id', meta: { },
25
31
  component: () => import("./pages/View.vue"),
26
32
  props: true
27
33
  }),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@live-change/frontend-auto-form",
3
- "version": "0.9.86",
3
+ "version": "0.9.88",
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.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",
25
+ "@live-change/cli": "^0.9.88",
26
+ "@live-change/dao": "^0.9.88",
27
+ "@live-change/dao-vue3": "^0.9.88",
28
+ "@live-change/dao-websocket": "^0.9.88",
29
+ "@live-change/framework": "^0.9.88",
30
+ "@live-change/image-frontend": "^0.9.88",
31
+ "@live-change/image-service": "^0.9.88",
32
+ "@live-change/session-service": "^0.9.88",
33
+ "@live-change/vue3-components": "^0.9.88",
34
+ "@live-change/vue3-ssr": "^0.9.88",
35
35
  "@vueuse/core": "^12.3.0",
36
36
  "codeceptjs-assert": "^0.0.5",
37
37
  "compression": "^1.7.5",
@@ -49,10 +49,10 @@
49
49
  "v-shared-element": "3.1.1",
50
50
  "vue-meta": "^3.0.0-alpha.9",
51
51
  "vue-router": "^4.5.0",
52
- "vue3-scroll-border": "0.1.6"
52
+ "vue3-scroll-border": "0.1.7"
53
53
  },
54
54
  "devDependencies": {
55
- "@live-change/codeceptjs-helper": "^0.9.86",
55
+ "@live-change/codeceptjs-helper": "^0.9.88",
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": "7b0013ef101d9033402eeec45fd1be60e151aada"
66
+ "gitHead": "c042d36f63a6cc50158c3b3385f7f21ea98b847d"
67
67
  }