@live-change/frontend-auto-form 0.9.65 → 0.9.66

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.
@@ -6,7 +6,7 @@
6
6
  </template>
7
7
  <template v-else>
8
8
  <span>
9
- <strong>{{ objectType }}</strong>: {{ object ?? objectData.to ?? objectData.id }}
9
+ <strong>{{ objectType }}</strong>: {{ object ?? objectData?.to ?? objectData?.id }}
10
10
  </span>
11
11
  </template>
12
12
  </template>
@@ -40,11 +40,12 @@
40
40
  const path = usePath()
41
41
 
42
42
  const serviceAndModel = computed(() => {
43
+ if(!objectType.value) return null
43
44
  const [service, model] = objectType.value.split('_')
44
45
  return { service, model }
45
46
  })
46
- const service = computed(() => serviceAndModel.value.service)
47
- const model = computed(() => serviceAndModel.value.model)
47
+ const service = computed(() => serviceAndModel.value?.service)
48
+ const model = computed(() => serviceAndModel.value?.model)
48
49
 
49
50
  const modelDefinition = computed(() => {
50
51
  return api.services?.[service.value]?.models?.[model.value]
@@ -5,6 +5,23 @@
5
5
  <h4>definition</h4>
6
6
  <pre>{{ modelDefinition }}</pre>
7
7
  -->
8
+ <div v-if="editor && editor.saved?.value?.id" >
9
+ <ObjectPath :objectType="service + '_' + model" :object="editor?.saved?.value?.id" class="mb-6" />
10
+ </div>
11
+ <div v-else-if="editor && !editor.saved?.value">
12
+ <div v-for="parentObject in parentObjects">
13
+ <ObjectPath :objectType="parentObject.objectType" :object="parentObject.object"
14
+ class="mb-6" more>
15
+ <template #more="slotProps">
16
+ New {{ model }}
17
+ </template>
18
+ </ObjectPath>
19
+ </div>
20
+ </div>
21
+
22
+ <pre>parentObjects = {{ parentObjects }}</pre>
23
+ <pre>scopesPath = {{ scopesPath }}</pre>
24
+ <pre>scopes = {{ scopes }}</pre>
8
25
 
9
26
  <div class="">
10
27
  Service <strong>{{ service }}</strong>
@@ -55,7 +72,9 @@
55
72
  import EditorButtons from './EditorButtons.vue'
56
73
  import AutoField from "../form/AutoField.vue"
57
74
 
58
- import { ref, computed, onMounted, defineProps, defineEmits, toRefs } from 'vue'
75
+ import ObjectPath from './ObjectPath.vue'
76
+
77
+ import { ref, computed, onMounted, defineProps, defineEmits, toRefs, inject, provide } from 'vue'
59
78
 
60
79
  const props = defineProps({
61
80
  service: {
@@ -95,6 +114,9 @@
95
114
  return api.services?.[service.value]?.models?.[model.value]
96
115
  })
97
116
 
117
+ import { parentObjectsFromIdentifiers } from '../../logic/relations.js'
118
+ const parentObjects = computed(() => parentObjectsFromIdentifiers(identifiers.value, modelDefinition.value))
119
+
98
120
  import { editorData } from "@live-change/frontend-auto-form"
99
121
  import { computedAsync } from "@vueuse/core"
100
122
  import InjectedObjectIndentification from './InjectedObjectIndentification.vue'
@@ -142,6 +164,35 @@
142
164
  emit('saved', saveResult)
143
165
  }
144
166
 
167
+ const scopesPath = computed(() => path.scope.objectScopes({
168
+ objectType: parentObjects.value[0].objectType, /// TODO: support multiple parent objects!
169
+ object: parentObjects.value[0].object
170
+ }))
171
+
172
+ const [scopes] = await Promise.all([
173
+ live(scopesPath)
174
+ ])
175
+
176
+ console.log("SCOPES", scopes)
177
+ provide('scopePickerConfig', {
178
+ objectsPathRangeConfig: (service, model, definition, modelDefinition) => computed(() => {
179
+ const scopeType = scopes.value[0].scopeType // TODO: support multiple scopes!
180
+ const scope = scopes.value[0].scope
181
+ return {
182
+ service,
183
+ model,
184
+ reverse: true,
185
+ viewPath: (range) => path.scope.scopeObjects({
186
+ scopeType,
187
+ scope,
188
+ objectType: `${service}_${model}`,
189
+ ...range
190
+ }),
191
+ parameters: {}
192
+ }
193
+ })
194
+ })
195
+
145
196
  </script>
146
197
 
147
198
  <style scoped>
@@ -19,7 +19,8 @@
19
19
  </div>
20
20
 
21
21
  <!-- <pre>modelsPathRangeConfig = {{ modelsPathRangeConfig }}</pre>
22
- <pre>modelsPathRangeFunctions = {{ modelsPathRangeFunctions }}</pre> -->
22
+ <pre>modelsPathRangeFunctions = {{ modelsPathRangeFunctions }}</pre>
23
+ <pre>modelsPathRangeFunctionsResults = {{ modelsPathRangeFunctions.map(x => x({})) }}</pre> -->
23
24
 
24
25
  <div class="bg-surface-0 dark:bg-surface-900 p-4 shadow-sm rounded-border" v-if="modelsPathRangeFunctions">
25
26
  <range-viewer v-for="(modelsPathRangeFunction, index) in modelsPathRangeFunctions"
@@ -177,6 +178,8 @@
177
178
  }))
178
179
  })
179
180
 
181
+ console.log("modelsPathRangeFunctions", modelsPathRangeFunctions.value)
182
+
180
183
  function objectIdentifiers(object) {
181
184
  const identifiers = {}
182
185
  for(const identifierDefinition of modelDefinition.value.identifiers) {
@@ -3,7 +3,6 @@
3
3
  <!-- <h4>definition</h4>
4
4
  <pre>{{ modelDefinition }}</pre>-->
5
5
 
6
-
7
6
  <div class="bg-surface-0 dark:bg-surface-900 w-full p-4 shadow-sm rounded-border mb-2">
8
7
  <slot name="header">
9
8
  <div class="">
@@ -215,7 +214,7 @@
215
214
  params: {
216
215
  serviceName: service.value,
217
216
  modelName: model.value,
218
- identifiers: Object.values(objectIdentifiers(identifiers.value[0]))
217
+ identifiers: Object.values(objectIdentifiers(views.value[0].identifiers))
219
218
  }
220
219
  }))
221
220
 
@@ -226,7 +225,12 @@
226
225
  object,
227
226
  acceptClass: "p-button-danger",
228
227
  accept: async () => {
229
- await api.actions[service.value][modelDefinition.value.crud.delete]({
228
+ console.log("deleteObject", object)
229
+ console.log("objectIdentifiers", objectIdentifiers(object))
230
+ console.log("modelDefinition", modelDefinition.value)
231
+ const method = api.actions[service.value][modelDefinition.value.crud.reset]
232
+ || api.actions[service.value][modelDefinition.value.crud.delete]
233
+ await method({
230
234
  ...objectIdentifiers(object)
231
235
  });
232
236
  toast.add({ severity: "info", summary: model.value + " deleted", life: 1500 });
@@ -10,9 +10,9 @@
10
10
  <h4>object</h4>
11
11
  <pre>{{ object }}</pre>-->
12
12
 
13
- <ScopePath :objectType="service + '_' + model" :object="object.to ?? object.id" class="mb-6" />
14
-
15
13
  <div v-if="object">
14
+ <ObjectPath :objectType="service + '_' + model" :object="object.to ?? object.id" class="mb-6" />
15
+
16
16
  <div class="bg-surface-0 dark:bg-surface-900 p-4 shadow-sm rounded-border mb-6">
17
17
 
18
18
  <div class="">
@@ -127,7 +127,7 @@
127
127
  import { ref, computed, onMounted, defineProps, defineEmits, toRefs } from 'vue'
128
128
  import { RangeViewer, injectComponent, InjectComponent } from "@live-change/vue3-components"
129
129
 
130
- import ScopePath from './ObjectPath.vue'
130
+ import ObjectPath from './ObjectPath.vue'
131
131
 
132
132
  const props = defineProps({
133
133
  service: {
@@ -6,10 +6,15 @@
6
6
  <pre>selectedPaths = {{ selectedPaths }}</pre>
7
7
  <pre>selectedPathWithElements = {{ selectedPathWithElements }}</pre> -->
8
8
  <div v-for="path in selectedPathsWithElements" :key="path">
9
- <Breadcrumb :model="path">
9
+ <Breadcrumb :model="more ? [...path, 'dupa'] : path">
10
10
  <template #item="{ item }">
11
- <AutoObjectIdentification :objectType="item.objectType" :object="item.object"
12
- :link="item.object !== object && item.objectType !== objectType" />
11
+ <div>
12
+ <slot v-if="typeof item === 'string'" name="more">
13
+ more...
14
+ </slot>
15
+ <AutoObjectIdentification v-else :objectType="item.objectType" :object="item.object"
16
+ :link="more || (item.object !== object && item.objectType !== objectType)" />
17
+ </div>
13
18
  </template>
14
19
  </Breadcrumb>
15
20
  </div>
@@ -29,9 +34,13 @@
29
34
  object: {
30
35
  type: String,
31
36
  required: true
37
+ },
38
+ more: {
39
+ type: Boolean,
40
+ default: false
32
41
  }
33
42
  })
34
- const { objectType, object } = toRefs(props)
43
+ const { objectType, object, more } = toRefs(props)
35
44
 
36
45
  import { usePath, live } from '@live-change/vue3-ssr'
37
46
  const path = usePath()
@@ -74,30 +83,35 @@
74
83
  return elements
75
84
  }
76
85
 
77
- const scopePathConfig = inject('scopePathConfig', {
78
- scopeType: undefined,
79
- scope: undefined,
80
- scopeSelector: longestByType,
81
- pathsPath: (objectType, object, config) => path.scope.objectScopePaths({
82
- objectType, object,
83
- scopeType: config.scopeType,
84
- scope: config.scope
85
- }),
86
- pathElements: scopePathElements
87
- })
86
+ const objectPathConfig = inject(`objectPathConfig:${objectType.value}`,
87
+ inject('objectPathConfig', {
88
+ scopeType: undefined,
89
+ scope: undefined,
90
+ scopeSelector: longestByType,
91
+ pathsPath: (objectType, object, config) => path.scope.objectScopePaths({
92
+ objectType, object,
93
+ scopeType: config.scopeType,
94
+ scope: config.scope
95
+ }),
96
+ pathElements: scopePathElements
97
+ })
98
+ )
99
+
100
+ console.log('objectPathConfig', objectPathConfig.value)
101
+
88
102
 
89
- const pathsPath = computed(() => scopePathConfig.pathsPath(objectType.value, object.value, scopePathConfig))
103
+ const pathsPath = computed(() => objectPathConfig.pathsPath(objectType.value, object.value, objectPathConfig))
90
104
 
91
105
  const [paths] = await Promise.all([
92
106
  live(pathsPath)
93
107
  ])
94
108
 
95
109
  const selectedPaths = computed(() => {
96
- return scopePathConfig.scopeSelector(paths.value)
110
+ return objectPathConfig.scopeSelector(paths.value)
97
111
  })
98
112
 
99
113
  const selectedPathsWithElements = computed(
100
- () => selectedPaths.value.map(scopePath => scopePathConfig.pathElements(scopePath))
114
+ () => selectedPaths.value.map(scopePath => objectPathConfig.pathElements(scopePath))
101
115
  )
102
116
 
103
117
 
@@ -45,6 +45,7 @@
45
45
  <div @click="selectObject(object)"
46
46
  class="flex flex-row items-center justify-between my-1 py-2 px-4
47
47
  bg-surface-100 dark:bg-surface-900 hover:bg-surface-200 dark:hover:bg-surface-800">
48
+ <!-- <pre>{{ object }}</pre> -->
48
49
  <ObjectIdentification
49
50
  :objectType="selectedTypeService + '_' + selectedTypeModel"
50
51
  :object="object.to ?? object.id"
@@ -79,7 +80,7 @@
79
80
  import AutoObjectIdentification from '../crud/DefaultObjectIdentification.vue'
80
81
  import { RangeViewer, injectComponent } from "@live-change/vue3-components"
81
82
 
82
- import { defineProps, defineEmits, toRefs, ref, defineModel, computed, useId } from 'vue'
83
+ import { defineProps, defineEmits, toRefs, ref, defineModel, computed, useId, inject, unref } from 'vue'
83
84
  import pluralize from 'pluralize'
84
85
 
85
86
  const uid = useId()
@@ -210,28 +211,38 @@
210
211
 
211
212
  import { useApi, usePath, live, reverseRange } from '@live-change/vue3-ssr'
212
213
  const api = useApi()
213
- const path = usePath()
214
+ const path = usePath()
215
+
216
+ const scopePickerConfig = inject(`scopePickerConfig:${definition.value.source}`,
217
+ inject('scopePickerConfig', {
218
+ objectsPathRangeConfig: (service, model, definition, modelDefinition) => {
219
+ const rangeView = modelDefinition?.crud?.[view.value ?? 'range']
220
+ if(!rangeView) return null
221
+ if(!path[service]) return null
222
+ if(!path[service][rangeView]) return null
223
+ return {
224
+ service,
225
+ model,
226
+ reverse: true,
227
+ viewPath: (parameters) => path[service][rangeView](parameters),
228
+ parameters: {}
229
+ }
230
+ }
231
+ })
232
+ )
214
233
 
215
234
  const objectsPathRangeConfig = computed(() => {
216
235
  if(!selectedTypeParsed.value) return null
217
236
  const [service, model] = selectedTypeParsed.value
218
237
  const serviceDefinition = api.metadata.api.value.services.find(s => s.name === service)
219
238
  const modelDefinition = serviceDefinition.models[model]
220
- return {
221
- service,
222
- model,
223
- reverse: true,
224
- view: modelDefinition?.crud?.[view.value ?? 'range']
225
- }
239
+ return unref(scopePickerConfig.objectsPathRangeConfig(service, model, definition.value, modelDefinition))
226
240
  })
227
241
  const objectsPathRangeFunction = computed(() => {
228
242
  const config = objectsPathRangeConfig.value
229
- if(!config) return null
230
- const rangeView = config.view
231
- if(!path[config.service]) return null
232
- if(!path[config.service][rangeView]) return null
233
- return (range) => path[config.service][rangeView]({
234
- //...ident,
243
+ if(!config) return null
244
+ return (range) => config.viewPath({
245
+ ...config.parameters,
235
246
  ...(config.reverse ? reverseRange(range) : range),
236
247
  })
237
248
  })
@@ -249,3 +249,25 @@ export function getAllTypesWithCrud(crud, api = useApi()) {
249
249
  if(model.crud?.[crud]) return true
250
250
  })
251
251
  }
252
+
253
+ export function parentObjectsFromIdentifiers(identifiers, modelDefinition) {
254
+ console.log("identifiers", identifiers, "modelDefinition", modelDefinition)
255
+ const results = []
256
+ for(const [key, value] of Object.entries(identifiers)) {
257
+ if(key.endsWith('Type')) continue
258
+ const propertyDefinition = modelDefinition.properties[key]
259
+ const propertyType = propertyDefinition.type
260
+ if(propertyType === 'any') {
261
+ results.push({
262
+ objectType: identifiers[key + 'Type'],
263
+ object: value
264
+ })
265
+ } else {
266
+ results.push({
267
+ objectType: propertyType,
268
+ object: value
269
+ })
270
+ }
271
+ }
272
+ return results
273
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@live-change/frontend-auto-form",
3
- "version": "0.9.65",
3
+ "version": "0.9.66",
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.65",
26
- "@live-change/dao": "^0.9.65",
27
- "@live-change/dao-vue3": "^0.9.65",
28
- "@live-change/dao-websocket": "^0.9.65",
29
- "@live-change/framework": "^0.9.65",
30
- "@live-change/image-frontend": "^0.9.65",
31
- "@live-change/image-service": "^0.9.65",
32
- "@live-change/session-service": "^0.9.65",
33
- "@live-change/vue3-components": "^0.9.65",
34
- "@live-change/vue3-ssr": "^0.9.65",
25
+ "@live-change/cli": "^0.9.66",
26
+ "@live-change/dao": "^0.9.66",
27
+ "@live-change/dao-vue3": "^0.9.66",
28
+ "@live-change/dao-websocket": "^0.9.66",
29
+ "@live-change/framework": "^0.9.66",
30
+ "@live-change/image-frontend": "^0.9.66",
31
+ "@live-change/image-service": "^0.9.66",
32
+ "@live-change/session-service": "^0.9.66",
33
+ "@live-change/vue3-components": "^0.9.66",
34
+ "@live-change/vue3-ssr": "^0.9.66",
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.65",
55
+ "@live-change/codeceptjs-helper": "^0.9.66",
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": "574c45a457f93e58966da6db4d4f80137dc463b6"
66
+ "gitHead": "8c76cb48a8cb459f3cfe08983f5b288c10e5f688"
67
67
  }