@live-change/frontend-auto-form 0.9.64 → 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.
- package/front/src/components/crud/DefaultObjectIdentification.vue +4 -3
- package/front/src/components/crud/ModelEditor.vue +52 -1
- package/front/src/components/crud/ModelList.vue +4 -1
- package/front/src/components/crud/ModelSingle.vue +7 -3
- package/front/src/components/crud/ModelView.vue +3 -3
- package/front/src/components/crud/ObjectPath.vue +32 -18
- package/front/src/components/form/ObjectPicker.vue +25 -14
- package/front/src/logic/relations.js +22 -0
- package/package.json +13 -13
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
</template>
|
|
7
7
|
<template v-else>
|
|
8
8
|
<span>
|
|
9
|
-
<strong>{{ objectType }}</strong>: {{ object ?? objectData
|
|
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
|
|
47
|
-
const model = computed(() => serviceAndModel.value
|
|
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
|
|
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(
|
|
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
|
-
|
|
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
|
|
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
|
-
<
|
|
12
|
-
|
|
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
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
objectType, object,
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
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(() =>
|
|
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
|
|
110
|
+
return objectPathConfig.scopeSelector(paths.value)
|
|
97
111
|
})
|
|
98
112
|
|
|
99
113
|
const selectedPathsWithElements = computed(
|
|
100
|
-
() => selectedPaths.value.map(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
|
-
|
|
231
|
-
|
|
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.
|
|
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.
|
|
26
|
-
"@live-change/dao": "^0.9.
|
|
27
|
-
"@live-change/dao-vue3": "^0.9.
|
|
28
|
-
"@live-change/dao-websocket": "^0.9.
|
|
29
|
-
"@live-change/framework": "^0.9.
|
|
30
|
-
"@live-change/image-frontend": "^0.9.
|
|
31
|
-
"@live-change/image-service": "^0.9.
|
|
32
|
-
"@live-change/session-service": "^0.9.
|
|
33
|
-
"@live-change/vue3-components": "^0.9.
|
|
34
|
-
"@live-change/vue3-ssr": "^0.9.
|
|
25
|
+
"@live-change/cli": "^0.9.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.
|
|
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": "
|
|
66
|
+
"gitHead": "8c76cb48a8cb459f3cfe08983f5b288c10e5f688"
|
|
67
67
|
}
|