@live-change/frontend-auto-form 0.9.16 → 0.9.18

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.
@@ -1,11 +1,10 @@
1
1
  <template>
2
2
  <div>
3
- <!--
4
- <h4>identifiers as object</h4>
5
- <pre>{{ identifiersObject }}</pre>
3
+ <!--
6
4
 
7
5
  <h4>definition</h4>
8
- <pre>{{ modelDefinition }}</pre>-->
6
+ <pre>{{ modelDefinition }}</pre>
7
+ -->
9
8
 
10
9
  <div class="">
11
10
  Service <strong>{{ service }}</strong>
@@ -3,6 +3,9 @@
3
3
  <!-- <h4>definition</h4>
4
4
  <pre>{{ modelDefinition }}</pre>-->
5
5
 
6
+ <pre>{{ modelsPathRangeConfig.view }}</pre>
7
+ <pre>{{ identifiers }}</pre>
8
+
6
9
  <div class="surface-card w-full p-3 shadow-1 border-round mb-2">
7
10
  <slot name="header">
8
11
  <div class="">
@@ -15,8 +18,9 @@
15
18
  </slot>
16
19
  </div>
17
20
 
18
- <div class="surface-card p-3 shadow-1 border-round" v-if="modelsPathRangeFunction">
19
- <range-viewer :key="JSON.stringify(modelsPathRangeConfig)"
21
+ <div class="surface-card p-3 shadow-1 border-round" v-if="modelsPathRangeFunctions">
22
+ <range-viewer v-for="(modelsPathRangeFunction, index) in modelsPathRangeFunctions"
23
+ :key="JSON.stringify(modelsPathRangeConfig)+index"
20
24
  :pathFunction="modelsPathRangeFunction"
21
25
  :canLoadTop="false" canDropBottom
22
26
  loadBottomSensorSize="4000px" dropBottomSensorSize="3000px">
@@ -83,7 +87,6 @@
83
87
  </div>
84
88
  </template>
85
89
  </ConfirmPopup>
86
-
87
90
  </div>
88
91
  </template>
89
92
 
@@ -114,8 +117,12 @@
114
117
  type: Object,
115
118
  default: () => ({})
116
119
  },
120
+ view: {
121
+ type: String,
122
+ default: undefined
123
+ }
117
124
  })
118
- const { service, model, identifiers } = toRefs(props)
125
+ const { service, model, identifiers, view } = toRefs(props)
119
126
 
120
127
  import AutoObjectIdentification from './AutoObjectIdentification.vue'
121
128
 
@@ -141,18 +148,21 @@
141
148
  service: service.value,
142
149
  model: model.value,
143
150
  definition: modelDefinition.value,
144
- reverse: true
151
+ reverse: true,
152
+ view: modelDefinition.value?.crud?.[view.value ?? 'range']
145
153
  }
146
154
  })
147
- const modelsPathRangeFunction = computed(() => {
155
+ const modelsPathRangeFunctions = computed(() => {
148
156
  const config = modelsPathRangeConfig.value
149
- const rangeView = config.definition?.crud?.range
157
+ const rangeView = config.view
150
158
  if(!path[config.service]) return null
151
159
  if(!path[config.service][rangeView]) return null
152
- return (range) => path[config.service][rangeView]({
153
- ...identifiers.value,
160
+ let idents = identifiers.value
161
+ if(!Array.isArray(idents)) idents = [idents]
162
+ return idents.map(ident => (range) => path[config.service][rangeView]({
163
+ ...ident,
154
164
  ...(config.reverse ? reverseRange(range) : range),
155
- })
165
+ }))
156
166
  })
157
167
 
158
168
  function objectIdentifiers(object) {
@@ -198,7 +208,7 @@
198
208
  params: {
199
209
  serviceName: service.value,
200
210
  modelName: model.value,
201
- identifiers: Object.values(identifiers.value)
211
+ identifiers: Object.values(identifiers.value[0])
202
212
  }
203
213
  }))
204
214
 
@@ -0,0 +1,226 @@
1
+ <template>
2
+ <div>
3
+ <!-- <h4>definition</h4>
4
+ <pre>{{ modelDefinition }}</pre>-->
5
+
6
+
7
+ <div class="surface-card w-full p-3 shadow-1 border-round mb-2">
8
+ <slot name="header">
9
+ <div class="">
10
+ Service <strong>{{ service }}</strong>
11
+ </div>
12
+ <div class="text-2xl">
13
+ <strong>{{ model }}</strong>
14
+ </div>
15
+ </slot>
16
+ </div>
17
+
18
+ <div class="surface-card p-3 shadow-1 border-round" v-if="modelsPaths">
19
+ <div v-for="({ value: object }, index) in (modelsData ?? [])">
20
+ <div v-if="!object" class="text-xl text-800 my-1 mx-3">
21
+ <strong>{{ model }}</strong> not found.
22
+ </div>
23
+ <div v-else
24
+ :key="JSON.stringify(modelsPaths[index])+index"
25
+ class="flex flex-row align-items-center justify-content-between my-3">
26
+ <router-link :to="viewRoute(object)" class="no-underline text-color">
27
+ <ObjectIdentification
28
+ :objectType="service + '_' + model"
29
+ :object="object.to ?? object.id"
30
+ :data="object"
31
+ class="text-xl"
32
+ />
33
+ </router-link>
34
+ <div class="flex flex-row">
35
+ <router-link :to="viewRoute(object)" class="no-underline">
36
+ <Button icon="pi pi-eye" severity="primary" label="View" class="mr-2" />
37
+ </router-link>
38
+
39
+ <router-link :to="editRoute(object)" class="no-underline">
40
+ <Button icon="pi pi-pencil" severity="primary" label="Edit" class="mr-2" />
41
+ </router-link>
42
+
43
+ <Button v-if="modelDefinition.crud?.delete" @click="ev => deleteObject(ev, object)"
44
+ icon="pi pi-eraser" severity="primary" label="Delete" class="mr-2" />
45
+ </div>
46
+ </div>
47
+ </div>
48
+ </div>
49
+ <div v-else class="flex align-items-start p-4 bg-pink-100 border-round border-1 border-pink-300 mb-4">
50
+ <i class="pi pi-times-circle text-pink-900 text-2xl mr-3" />
51
+ <div class="mr-3">
52
+ <div class="text-pink-900 font-medium text-xl mb-3 line-height-1">Not authorized</div>
53
+ <p class="m-0 p-0 text-pink-700">
54
+ You do not have sufficient privileges to use this feature of this object.
55
+ </p>
56
+ </div>
57
+ </div>
58
+
59
+ <div v-if="modelDefinition.crud?.create && !modelsData.find(x => x?.value)"
60
+ class="mt-2 flex flex-row justify-content-end mr-2">
61
+ <router-link :to="createRoute" class="no-underline2">
62
+ <Button icon="pi pi-plus" :label="'Set '+model" />
63
+ </router-link>
64
+ </div>
65
+
66
+ <ConfirmPopup group="delete">
67
+ <template #message="slotProps">
68
+ <div class="flex flex-row align-items-center w-full gap-3 border-bottom-1 surface-border px-3 pt-1 pb-1">
69
+ <i class="pi pi-trash text-3xl text-primary-500"></i>
70
+ <p>
71
+ Do you want to delete {{ model[0].toLowerCase() + model.slice(1) }}
72
+ <ObjectIdentification
73
+ :objectType="service + '_' + model"
74
+ :object="slotProps.message.object.to ?? slotProps.message.object.id"
75
+ :data="slotProps.message.object"
76
+ />
77
+ ?
78
+ </p>
79
+ </div>
80
+ </template>
81
+ </ConfirmPopup>
82
+
83
+ </div>
84
+ </template>
85
+
86
+ <script setup>
87
+
88
+ import ConfirmPopup from "primevue/confirmpopup"
89
+ import Button from "primevue/button"
90
+
91
+ import { useToast } from 'primevue/usetoast'
92
+ const toast = useToast()
93
+ import { useConfirm } from 'primevue/useconfirm'
94
+ const confirm = useConfirm()
95
+
96
+ import { ref, computed, onMounted, defineProps, toRefs } from 'vue'
97
+ import { RangeViewer, injectComponent } from "@live-change/vue3-components"
98
+
99
+ const props = defineProps({
100
+ service: {
101
+ type: String,
102
+ required: true,
103
+ },
104
+ model: {
105
+ type: String,
106
+ required: true,
107
+ },
108
+ identifiers: {
109
+ type: Object,
110
+ default: () => ({})
111
+ },
112
+ })
113
+ const { service, model, identifiers } = toRefs(props)
114
+
115
+ import AutoObjectIdentification from './AutoObjectIdentification.vue'
116
+
117
+ const ObjectIdentification = computed(() =>
118
+ injectComponent({
119
+ name: 'ObjectIdentification',
120
+ type: service.value + '_' + model.value,
121
+ service: service.value,
122
+ model: model.value
123
+ }, AutoObjectIdentification)
124
+ )
125
+
126
+ import { useApi, usePath, live } from '@live-change/vue3-ssr'
127
+ const api = useApi()
128
+ const path = usePath()
129
+
130
+ const modelDefinition = computed(() => {
131
+ return api.services?.[service.value]?.models?.[model.value]
132
+ })
133
+
134
+ const modelsPathConfig = computed(() => {
135
+ return {
136
+ service: service.value,
137
+ model: model.value,
138
+ definition: modelDefinition.value,
139
+ }
140
+ })
141
+ const modelsPaths = computed(() => {
142
+ const config = modelsPathConfig.value
143
+ const readView = config.definition?.crud?.read
144
+ if(!path[config.service]) return null
145
+ if(!path[config.service][readView]) return null
146
+ let idents = identifiers.value
147
+ if(!Array.isArray(idents)) idents = [idents]
148
+ return idents.map(ident => path[config.service][readView]({
149
+ ...ident
150
+ }))
151
+ })
152
+
153
+ const modelsData = await Promise.all(
154
+ modelsPaths.value.map(path => live(path))
155
+ )
156
+
157
+ function objectIdentifiers(object) {
158
+ const identifiers = {}
159
+ for(const identifierDefinition of modelDefinition.value.identifiers) {
160
+ if(typeof identifierDefinition === 'string') {
161
+ identifiers[identifierDefinition] = object[identifierDefinition]
162
+ } else {
163
+ if(identifierDefinition.field === 'id') {
164
+ identifiers[identifierDefinition.name] = object?.to ?? object.id
165
+ } else {
166
+ identifiers[identifierDefinition.name] = object[identifierDefinition.field]
167
+ }
168
+ }
169
+ }
170
+ return identifiers
171
+ }
172
+
173
+ function editRoute(object) {
174
+ return {
175
+ name: 'auto-form:editor',
176
+ params: {
177
+ serviceName: service.value,
178
+ modelName: model.value,
179
+ identifiers: Object.values(objectIdentifiers(object))
180
+ }
181
+ }
182
+ }
183
+
184
+ function viewRoute(object) {
185
+ return {
186
+ name: 'auto-form:view',
187
+ params: {
188
+ serviceName: service.value,
189
+ modelName: model.value,
190
+ identifiers: Object.values(objectIdentifiers(object))
191
+ }
192
+ }
193
+ }
194
+
195
+ const createRoute = computed(() => ({
196
+ name: 'auto-form:editor',
197
+ params: {
198
+ serviceName: service.value,
199
+ modelName: model.value,
200
+ identifiers: Object.values(objectIdentifiers(identifiers.value[0]))
201
+ }
202
+ }))
203
+
204
+ function deleteObject(event, object) {
205
+ confirm.require({
206
+ group: 'delete',
207
+ target: event.currentTarget,
208
+ object,
209
+ acceptClass: "p-button-danger",
210
+ accept: async () => {
211
+ await api.actions[service.value][modelDefinition.value.crud.delete]({
212
+ ...objectIdentifiers(object)
213
+ });
214
+ toast.add({ severity: "info", summary: model.value + " deleted", life: 1500 });
215
+ },
216
+ reject: () => {
217
+ toast.add({ severity: "error", summary: "Rejected", detail: "You have rejected", life: 3e3 });
218
+ }
219
+ });
220
+ }
221
+
222
+ </script>
223
+
224
+ <style scoped>
225
+
226
+ </style>
@@ -30,9 +30,9 @@
30
30
 
31
31
  </div>
32
32
 
33
- <div v-for="itemRelation of itemRelations">
34
- <ModelList :service="itemRelation.from.serviceName" :model="itemRelation.from.name"
35
- :identifiers="relatedIdentifiers">
33
+ <div v-for="preparedRelation of visibleObjectRelations" class="mb-4">
34
+ <ModelSingle :service="preparedRelation.service" :model="preparedRelation.model"
35
+ :identifiers="preparedRelation.identifiers">
36
36
  <template #header>
37
37
  <div class="text-xl">
38
38
  <ObjectIdentification
@@ -42,24 +42,42 @@
42
42
  class="mr-2"
43
43
  />
44
44
  <span class="mr-2 font-medium">{{ model }}'s</span>
45
- <span class="font-bold">{{ pluralize(itemRelation.from.name) }}</span>:
45
+ <span class="font-bold">{{ preparedRelation.model }}</span>:
46
46
  </div>
47
47
  </template>
48
+ </ModelSingle>
49
+ </div>
48
50
 
51
+ <div v-for="preparedRelation of visibleRangeRelations" class="mb-4">
52
+ <ModelList :service="preparedRelation.service" :model="preparedRelation.model"
53
+ :identifiers="preparedRelation.identifiers" :view="preparedRelation.view">
54
+ <template #header>
55
+ <div class="text-xl">
56
+ <ObjectIdentification
57
+ :objectType="service + '_' + model"
58
+ :object="object.to ?? object.id"
59
+ :data="object"
60
+ class="mr-2"
61
+ />
62
+ <span class="mr-2 font-medium">{{ model }}'s</span>
63
+ <span class="font-bold">{{ pluralize(preparedRelation.model) }}</span>:
64
+ </div>
65
+ </template>
49
66
  </ModelList>
50
-
51
- <pre>{{ relatedIdentifiers }}</pre>
52
-
53
- <pre>{{ itemRelation }}</pre>
54
-
55
67
  </div>
56
68
 
57
- <!-- <div class="surface-card p-3 shadow-1 border-round">
69
+ <div class="surface-card p-3 shadow-1 border-round">
70
+
71
+ <pre>{{ preparedRelations }}</pre>
58
72
 
59
73
  <h4>Backward relations</h4>
60
- <pre>{{ backwardRelations }}</pre>
74
+ <pre>{{
75
+ backwardRelations.map(
76
+ ({ from, relation, what }) => ({ from: from.serviceName + '_' + from.name, relation, what })
77
+ )
78
+ }}</pre>
61
79
 
62
- </div>-->
80
+ </div>
63
81
 
64
82
  </div>
65
83
  </template>
@@ -68,10 +86,11 @@
68
86
 
69
87
  import AutoView from '../view/AutoView.vue'
70
88
  import ModelList from './ModelList.vue'
89
+ import ModelSingle from './ModelSingle.vue'
71
90
 
72
91
  import pluralize from 'pluralize'
73
92
  import { ref, computed, onMounted, defineProps, defineEmits, toRefs } from 'vue'
74
- import { RangeViewer, injectComponent } from "@live-change/vue3-components"
93
+ import { RangeViewer, injectComponent, InjectComponent } from "@live-change/vue3-components"
75
94
 
76
95
  const props = defineProps({
77
96
  service: {
@@ -118,9 +137,9 @@
118
137
  return api.services?.[service.value]?.models?.[model.value]
119
138
  })
120
139
 
121
- import { getForwardRelations, getBackwardRelations } from '../../logic/relations.js'
140
+ import { getForwardRelations, getBackwardRelations, anyRelationsTypes, prepareObjectRelations } from '../../logic/relations.js'
122
141
  const forwardRelations = computed(() => getForwardRelations(modelDefinition.value, () => true, api))
123
- const backwardRelations = computed(() => getBackwardRelations(modelDefinition.value, api))
142
+ const backwardRelations = computed(() => getBackwardRelations(modelDefinition.value, api))
124
143
 
125
144
  const itemRelations = computed(
126
145
  () => backwardRelations.value.filter(relation => relation.relation === 'itemOf')
@@ -143,6 +162,25 @@
143
162
  [model.value[0].toLowerCase() + model.value.slice(1)]: object.value.to ?? object.value.id
144
163
  }))
145
164
 
165
+
166
+ const preparedRelations = computed(() => {
167
+ const objectType = service.value + '_' + model.value
168
+ return prepareObjectRelations(objectType, object.value.to ?? object.value.id, api)
169
+ })
170
+
171
+ const visibleRangeRelations = computed(() => preparedRelations.value.filter(preparedRelation => {
172
+ if(preparedRelation.view && preparedRelation.access.value[preparedRelation.view]) return true
173
+ if(preparedRelation.access.value.range) return true
174
+ return false
175
+ }))
176
+
177
+ const visibleObjectRelations = computed(() => preparedRelations.value.filter(preparedRelation => {
178
+ if(!preparedRelation.singular) return false
179
+ if(!preparedRelation.access.value.read) return false
180
+ return true
181
+ }))
182
+
183
+
146
184
  </script>
147
185
 
148
186
  <style scoped>
@@ -65,7 +65,7 @@ export default function editorData(options) {
65
65
  draftIdParts.push(identifier)
66
66
  }
67
67
  }
68
- const isNew = (idKey ? (!identifiers[idKey]) : (!draftIdParts.some(key => !identifiers[key])))
68
+ const isNew = (idKey ? (!identifiers[idKey]) : (!draftIdParts.some(key => identifiers[key])))
69
69
  const draftId = (idKey ? identifiers[idKey]
70
70
  : draftIdParts.map(key => JSON.stringify(identifiers[key])).join('_')) ?? 'new'
71
71
  const draftIdentifiers = {
@@ -202,6 +202,7 @@ export default function editorData(options) {
202
202
  saveDraft: synchronizedData.save,
203
203
  savingDraft: synchronizedData.saving,
204
204
  saved: savedData,
205
+ savedPath: savedDataPath,
205
206
  draft: draftData,
206
207
  sourceChanged /// needed for draft discard on concurrent save
207
208
  }
@@ -239,6 +240,7 @@ export default function editorData(options) {
239
240
  save: synchronizedData.save,
240
241
  saving: synchronizedData.saving,
241
242
  saved: savedData,
243
+ savedPath: savedDataPath,
242
244
  reset,
243
245
  model,
244
246
  }
@@ -1,4 +1,10 @@
1
1
  import { useApi } from '@live-change/vue3-ssr'
2
+ import { computed } from 'vue'
3
+
4
+ function ensureArray(value) {
5
+ if(!Array.isArray(value)) return [value]
6
+ return value
7
+ }
2
8
 
3
9
  function getWhat(relation) {
4
10
  if(typeof relation === 'string') return relation
@@ -6,11 +12,26 @@ function getWhat(relation) {
6
12
  }
7
13
  function getWhats(relations) {
8
14
  if(!Array.isArray(relations)) relations = [relations]
9
- return relations.map(getWhat)
15
+ return relations.map(x => ensureArray(getWhat(x)))
16
+ }
17
+
18
+ export const relationTypes = {
19
+ propertyOf: { singular: true, typed: true, owned: true },
20
+ boundTo: { singular: true, typed: true, owned: false },
21
+ itemOf: { singular: false, typed: true, owned: true },
22
+ relatedTo: { singular: false, typed: true, owned: false },
23
+ propertyOfAny: { singular: true, typed: false, owned: true },
24
+ boundToAny: { singular: true, typed: false, owned: false },
25
+ itemOfAny: { singular: false, typed: false, owned: true },
26
+ relatedToAny: { singular: false, typed: false, owned: false }
10
27
  }
11
28
 
12
- export const typedRelationsTypes = ['propertyOf', 'itemOf', 'boundTo', 'relatedTo']
13
- export const anyRelationsTypes = typedRelationsTypes.map(relation => relation + 'Any')
29
+ export const typedRelationsTypes = Object.entries(relationTypes)
30
+ .filter(([key, value]) => value.typed)
31
+ .map(([key, value]) => key)
32
+ export const anyRelationsTypes = Object.entries(relationTypes)
33
+ .filter(([key, value]) => !value.typed)
34
+ .map(([key, value]) => key)
14
35
 
15
36
  export function getModelByTypeName(model, api = useApi()) {
16
37
  if(typeof model === 'string') {
@@ -27,20 +48,51 @@ export function getServiceByName(service, api = useApi()) {
27
48
  return service
28
49
  }
29
50
 
30
- export function getForwardRelations(model, filter = () => true, api = useApi()) {
51
+ export function getForwardRelations(model, api = useApi()) {
31
52
  model = getModelByTypeName(model, api)
32
53
  const results = []
33
54
  for(const type of typedRelationsTypes) {
55
+ const relationType = relationTypes[type]
56
+ let relations = model[type]
57
+ if(!relations) continue
58
+ if(!Array.isArray(relations)) relations = [relations]
59
+ for(const relation of relations) {
60
+ const what = ensureArray(getWhat(relation))
61
+ const result = {
62
+ from: model,
63
+ relation: type,
64
+ what
65
+ }
66
+ results.push(result)
67
+ }
68
+ }
69
+ for(const type of anyRelationsTypes) {
70
+ const relationType = relationTypes[type]
34
71
  let relations = model[type]
35
72
  if(!relations) continue
36
73
  if(!Array.isArray(relations)) relations = [relations]
37
74
  for(const relation of relations) {
75
+ const fields = (Array.isArray(relation.to) ? relation.to : [relation.to ?? 'owner'])
76
+ const possibleTypes = fields.map(other => {
77
+ const name = other.name ? other.name : other
78
+ const typesConfig = relation[name + 'Types'] || []
79
+ const otherTypes = other.types || []
80
+ return Array.from(new Set(
81
+ typesConfig.concat(otherTypes)
82
+ ))
83
+ })
84
+ const allTypes = Array.from(new Set(
85
+ (relation.parentsTypes || [])
86
+ .concat(possibleTypes.filter(x => !!x).flat()
87
+ )))
38
88
  const result = {
39
89
  from: model,
90
+ fields,
40
91
  relation: type,
41
- what: getWhat(relation),
92
+ what: allTypes,
93
+ any: allTypes.length === 0
42
94
  }
43
- if(filter(result)) results.push(result)
95
+ results.push(result)
44
96
  }
45
97
  }
46
98
  return results
@@ -49,10 +101,10 @@ export function getForwardRelations(model, filter = () => true, api = useApi())
49
101
  export function getBackwardRelations(model, api = useApi()) {
50
102
  model = getModelByTypeName(model, api)
51
103
  const key = `${model.serviceName}_${model.name}`
52
- console.log("KEY", key)
104
+ //console.log("KEY", key)
53
105
  return Object.values(api.services).map(
54
106
  service => Object.values(service.models).map(
55
- model => getForwardRelations(model, ({ what }) => what === key, api)
107
+ model => getForwardRelations(model, api).filter(({ what, any }) => what.includes(key))
56
108
  ).flat()
57
109
  ).flat()
58
110
  }
@@ -74,3 +126,82 @@ export function getModelsWithRelation(relationName, api = useApi()) {
74
126
  service => getServiceModelsWithRelation(service, relationName, api)
75
127
  ).flat()))
76
128
  }
129
+
130
+ export function prepareObjectRelations(objectType, object, api = useApi()) {
131
+ const [service, model] = objectType.split('_')
132
+ const backwardRelations = getBackwardRelations(objectType, api)
133
+ const preparedBackwardRelations = backwardRelations.map(({ relation, from, what, fields }) => {
134
+ const relationConfig = from[relation]
135
+
136
+ const access = computed(() => {
137
+ const serviceMetadata = api.metadata.api.value.services.find(s => s.name === from.serviceName)
138
+ return Object.fromEntries(
139
+ Object.entries(from.crud).map(([key, value]) =>
140
+ [key, !!serviceMetadata.actions[value] || !!serviceMetadata.views[value]]
141
+ )
142
+ )
143
+ })
144
+
145
+ if(anyRelationsTypes.includes(relation)) {
146
+ const identifiers = []
147
+ for(const field of fields) {
148
+ const possibleFieldTypes = (relationConfig[field+'Types'] ?? [])
149
+ .concat(relationConfig.parentsTypes ?? [])
150
+ if(possibleFieldTypes.length === 0 || possibleFieldTypes.includes(objectType)) {
151
+ identifiers.push({
152
+ [field+'Type']: objectType,
153
+ [field]: object
154
+ })
155
+ }
156
+ }
157
+ return {
158
+ model: from.name,
159
+ service: from.serviceName,
160
+ fields,
161
+ relation,
162
+ what,
163
+ identifiers,
164
+ access,
165
+ singular: relationTypes[relation].singular && what.length < 2
166
+ }
167
+ } else {
168
+ const singular = relationTypes[relation].singular && what.length < 2
169
+ const typeView = from.crud?.['rangeBy_'+objectType]
170
+ ? 'rangeBy_'+objectType
171
+ : undefined
172
+ const view = relationConfig?.view ?? (singular
173
+ ? undefined
174
+ : typeView
175
+ ) ?? undefined
176
+ const identifiers = []
177
+ if(typeView) {
178
+ identifiers.push({
179
+ [model[0].toLowerCase() + model.slice(1)]: object
180
+ })
181
+ } else {
182
+ for(let i = 0; i < what.length; i++) {
183
+ if(what[i] !== objectType) continue
184
+ const propertyName = relationConfig.propertyNames?.[i]
185
+ ?? model[0].toLowerCase() + model.slice(1)
186
+ identifiers.push({
187
+ [propertyName]: object
188
+ })
189
+ }
190
+ }
191
+ console.log(objectType, "VIEW", view, from, singular)
192
+ return {
193
+ model: from.name,
194
+ service: from.serviceName,
195
+ fields,
196
+ relation,
197
+ what,
198
+ identifiers,
199
+ access,
200
+ view,
201
+ singular
202
+ }
203
+ }
204
+ })
205
+
206
+ return preparedBackwardRelations
207
+ }
@@ -1,5 +1,10 @@
1
1
  <template>
2
2
  <div class="w-full lg:w-8 md:w-11">
3
+
4
+ <!-- <pre>{{ identifiers }}</pre>
5
+ <pre>{{ modelDefinition.identifiers }}</pre>
6
+ <pre>{{identifiersObject}}</pre>-->
7
+
3
8
  <div class="surface-card p-3 shadow-1 border-round">
4
9
 
5
10
  <ModelEditor :service="serviceName" :model="modelName" :identifiers="identifiersObject" draft
@@ -26,7 +31,15 @@
26
31
  },
27
32
  identifiers: {
28
33
  type: Array,
29
- default: []
34
+ default: () => []
35
+ },
36
+ identifiersTypes: {
37
+ type: Array,
38
+ default: () => undefined
39
+ },
40
+ identifiersProperties: {
41
+ type: Array,
42
+ default: () => undefined
30
43
  }
31
44
  })
32
45
  const { serviceName, modelName, identifiers } = toRefs(props)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@live-change/frontend-auto-form",
3
- "version": "0.9.16",
3
+ "version": "0.9.18",
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",
@@ -21,20 +21,20 @@
21
21
  },
22
22
  "type": "module",
23
23
  "dependencies": {
24
- "@fortawesome/fontawesome-free": "^6.5.2",
25
- "@live-change/cli": "^0.9.16",
26
- "@live-change/dao": "^0.9.16",
27
- "@live-change/dao-vue3": "^0.9.16",
28
- "@live-change/dao-websocket": "^0.9.16",
29
- "@live-change/framework": "^0.9.16",
30
- "@live-change/image-frontend": "^0.9.16",
31
- "@live-change/image-service": "^0.9.16",
32
- "@live-change/session-service": "^0.9.16",
33
- "@live-change/vue3-components": "^0.9.16",
34
- "@live-change/vue3-ssr": "^0.9.16",
35
- "@vueuse/core": "^10.11.0",
24
+ "@fortawesome/fontawesome-free": "^6.7.2",
25
+ "@live-change/cli": "^0.9.18",
26
+ "@live-change/dao": "^0.9.18",
27
+ "@live-change/dao-vue3": "^0.9.18",
28
+ "@live-change/dao-websocket": "^0.9.18",
29
+ "@live-change/framework": "^0.9.18",
30
+ "@live-change/image-frontend": "^0.9.18",
31
+ "@live-change/image-service": "^0.9.18",
32
+ "@live-change/session-service": "^0.9.18",
33
+ "@live-change/vue3-components": "^0.9.18",
34
+ "@live-change/vue3-ssr": "^0.9.18",
35
+ "@vueuse/core": "^12.3.0",
36
36
  "codeceptjs-assert": "^0.0.5",
37
- "compression": "^1.7.4",
37
+ "compression": "^1.7.5",
38
38
  "cross-env": "^7.0.3",
39
39
  "get-port-sync": "1.0.1",
40
40
  "pica": "^9.0.1",
@@ -43,25 +43,25 @@
43
43
  "primeicons": "^7.0.0",
44
44
  "primevue": "^3.52.0",
45
45
  "rollup-plugin-node-builtins": "^2.1.2",
46
- "rollup-plugin-visualizer": "5.12.0",
46
+ "rollup-plugin-visualizer": "5.14.0",
47
47
  "serialize-javascript": "^6.0.2",
48
- "serve-static": "^1.15.0",
48
+ "serve-static": "^1.16.2",
49
49
  "v-shared-element": "3.1.1",
50
50
  "vue-meta": "^3.0.0-alpha.9",
51
- "vue-router": "^4.3.3",
51
+ "vue-router": "^4.5.0",
52
52
  "vue3-scroll-border": "0.1.6"
53
53
  },
54
54
  "devDependencies": {
55
- "@live-change/codeceptjs-helper": "^0.9.16",
56
- "codeceptjs": "^3.6.5",
55
+ "@live-change/codeceptjs-helper": "^0.9.18",
56
+ "codeceptjs": "^3.6.10",
57
57
  "generate-password": "1.7.1",
58
- "playwright": "1.48.1",
58
+ "playwright": "1.49.1",
59
59
  "random-profile-generator": "^2.3.0",
60
- "txtgen": "^3.0.6",
61
- "webdriverio": "^8.40.2"
60
+ "txtgen": "^3.0.7",
61
+ "webdriverio": "^9.5.1"
62
62
  },
63
63
  "author": "Michał Łaszczewski <michal@laszczewski.pl>",
64
64
  "license": "ISC",
65
65
  "description": "",
66
- "gitHead": "226df9fa7eb682f6d7da5e4541eb320e8309facf"
66
+ "gitHead": "d7fd7ad0a0ea331caea9dc8385439b9c637525ed"
67
67
  }