@live-change/frontend-auto-form 0.9.61 → 0.9.63

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.
@@ -41,8 +41,8 @@
41
41
 
42
42
  const { definition, modelValue, propName } = toRefs(props)
43
43
 
44
- import { provideInputConfigByDefinition } from './inputConfigInjection.js'
45
- const inputConfig = computed(() => provideInputConfigByDefinition(definition.value))
44
+ import { injectInputConfigByDefinition } from './inputConfigInjection.js'
45
+ const inputConfig = computed(() => injectInputConfigByDefinition(definition.value))
46
46
 
47
47
  const definitionIf = computed(() => {
48
48
  if(definition.value?.if) {
@@ -86,8 +86,8 @@
86
86
  return true
87
87
  })
88
88
 
89
- import { provideInputConfigByDefinition } from './inputConfigInjection.js'
90
- const inputConfig = computed(() => provideInputConfigByDefinition(definition.value))
89
+ import { injectInputConfigByDefinition } from './inputConfigInjection.js'
90
+ const inputConfig = computed(() => injectInputConfigByDefinition(definition.value))
91
91
 
92
92
  import { validateData } from "@live-change/vue3-components"
93
93
 
@@ -1,14 +1,28 @@
1
1
  <template>
2
2
  <div>
3
3
  <div ref="selectElement" class="p-select p-component p-inputwrapper w-full" @click="toggleObjectPicker">
4
- <span class="p-select-label p-placeholder" tabindex="0" role="combobox">
5
- Select object
4
+ <span v-if="!model" class="p-select-label p-placeholder" tabindex="0" role="combobox">
5
+ <span v-if="isTypeSelectable">
6
+ Select object
7
+ </span>
8
+ <span v-else>
9
+ Select {{ objectModel }}
10
+ </span>
11
+ </span>
12
+ <span v-else class="p-select-label">
13
+ <ObjectIdentification
14
+ :objectType="objectType"
15
+ :object="model"
16
+ class=""
17
+ />
6
18
  </span>
7
19
  <div class="p-select-dropdown" data-pc-section="dropdown">
8
20
  <ChevronDownIcon />
9
21
  </div>
10
22
  </div>
11
23
 
24
+ <!-- <pre>objt = {{ objectType }}</pre> -->
25
+
12
26
  <Popover ref="objectPickerPopover" :pt="{
13
27
  root: {
14
28
  class: 'object-picker-popover overflow-y-auto',
@@ -18,11 +32,13 @@
18
32
  }
19
33
  }
20
34
  }">
21
- <ObjectPicker />
35
+ <ObjectPicker v-model="model" :definition="definition" :properties="properties"
36
+ :rootValue="rootValue" :propName="propName" :i18n="i18n" @selected="handleSelected" />
22
37
  </Popover>
23
38
 
24
39
  <!-- needed to autoload styles: -->
25
- <Select class="hidden" />
40
+ <Select class="hidden" :options="[1,2,3]" />
41
+
26
42
  </div>
27
43
  </template>
28
44
 
@@ -31,8 +47,10 @@
31
47
  import Select from 'primevue/select'
32
48
  import Popover from 'primevue/popover'
33
49
  import ObjectPicker from './ObjectPicker.vue'
50
+ import AutoObjectIdentification from '../crud/DefaultObjectIdentification.vue'
51
+ import { injectComponent } from "@live-change/vue3-components"
34
52
 
35
- import { defineProps, defineEmits, toRefs, ref, defineModel } from 'vue'
53
+ import { defineProps, defineEmits, toRefs, ref, defineModel, computed } from 'vue'
36
54
  import { useElementSize } from '@vueuse/core'
37
55
 
38
56
  const props = defineProps({
@@ -42,14 +60,58 @@
42
60
  properties: {
43
61
  type: Object,
44
62
  default: () => ({})
63
+ },
64
+ rootValue: {
65
+ type: Object,
66
+ default: () => ({})
67
+ },
68
+ propName: {
69
+ type: String,
70
+ default: ''
71
+ },
72
+ i18n: {
73
+ type: String,
74
+ default: ''
45
75
  }
46
76
  })
47
77
 
78
+ const { definition, properties, rootValue, propName, i18n: i18nPrefix } = toRefs(props)
79
+
48
80
  const model = defineModel({
49
81
  required: true
50
82
  })
83
+
84
+ const isTypeSelectable = computed(() => {
85
+ return definition.value.type === 'any'
86
+ })
51
87
 
52
- const { value, definition, modelValue } = toRefs(props)
88
+ const objectType = computed(() => {
89
+ if(definition.value.type !== 'any') {
90
+ return definition.value.type
91
+ }
92
+ const typePropertyName = props.propName + 'Type'
93
+ const typePropertyPath = typePropertyName.split('.')
94
+ return typePropertyPath.reduce((acc, prop) => acc?.[prop], rootValue.value)
95
+ })
96
+
97
+ const objectModel = computed(() => {
98
+ const type = objectType.value
99
+ if(!type) return null
100
+ const [service, model] = type.split('_')
101
+ return model
102
+ })
103
+
104
+ const ObjectIdentification = computed(() => {
105
+ const type = objectType.value
106
+ if(!type) return AutoObjectIdentification
107
+ const [service, model] = type.split('_')
108
+ return injectComponent({
109
+ name: 'ObjectIdentification',
110
+ type,
111
+ service: service,
112
+ model: model
113
+ }, AutoObjectIdentification)
114
+ })
53
115
 
54
116
  const objectPickerPopover = ref()
55
117
  const selectElement = ref()
@@ -59,6 +121,10 @@
59
121
  objectPickerPopover.value.toggle(event)
60
122
  }
61
123
 
124
+ const handleSelected = (object) => {
125
+ objectPickerPopover.value.hide()
126
+ }
127
+
62
128
  </script>
63
129
 
64
130
  <style>
@@ -1,10 +1,248 @@
1
1
  <template>
2
- <div>
3
- Object picker!
2
+ <div>
3
+ <div v-if="!model && !selectedType && typeOptions.length < 8">
4
+ <div class="p-2">
5
+ <div class="text-sm text-surface-600 dark:text-surface-400 mb-2">
6
+ {{ t('objectPicker.selectObjectType') }}
7
+ </div>
8
+ <div class="flex flex-col">
9
+ <div v-for="type in typeOptions" :key="type"
10
+ class="p-2 hover:bg-surface-100 dark:hover:bg-surface-800 cursor-pointer"
11
+ @click="selectedType = type">
12
+ {{ typeLabel(type) }}
13
+ </div>
14
+ </div>
15
+ </div>
4
16
  </div>
17
+ <div v-else>
18
+ <div v-if="isTypeNeeded" class="bg-surface-100 dark:bg-surface-900 p-1 py-2 sticky top-0 z-10">
19
+ <div v-if="typeOptions.length > 1"
20
+ class="flex flex-col gap-2">
21
+ <!-- <label :for="`type-select-${uid}`">{{ t('objectPicker.selectObjectType') }}</label> -->
22
+ <Select v-model="selectedType" :options="typeOptions" :id="`type-select-${uid}`"
23
+ :placeholder="t('objectPicker.selectObjectType')"
24
+ :optionLabel="typeLabel" />
25
+ </div>
26
+ <div v-else>
27
+ <span>{{ t('objectPicker.currentType') }} {{ selectedTypeModel }}</span>
28
+ <span v-if="showServiceName">{{ t('objectPicker.fromService') }} {{ selectedTypeService }}</span>
29
+ </div>
30
+ </div>
31
+
32
+ <div v-if="objectsPathRangeFunction">
33
+ <range-viewer :key="JSON.stringify(objectsPathRangeConfig)"
34
+ :pathFunction="objectsPathRangeFunction"
35
+ :canLoadTop="false" canDropBottom
36
+ loadBottomSensorSize="4000px" dropBottomSensorSize="3000px">
37
+ <template #empty>
38
+ <div class="text-xl text-surface-800 dark:text-surface-50 my-1 mx-4">
39
+ No <strong>
40
+ {{ pluralize(selectedTypeModel[0].toLowerCase() + selectedTypeModel.slice(1)) }}
41
+ </strong> found.
42
+ </div>
43
+ </template>
44
+ <template #default="{ item: object }">
45
+ <div @click="selectObject(object)"
46
+ class="flex flex-row items-center justify-between my-1 py-2 px-4
47
+ bg-surface-100 dark:bg-surface-900 hover:bg-surface-200 dark:hover:bg-surface-800">
48
+ <ObjectIdentification
49
+ :objectType="selectedTypeService + '_' + selectedTypeModel"
50
+ :object="object.to ?? object.id"
51
+ :data="object"
52
+ class=""
53
+ />
54
+ </div>
55
+ </template>
56
+ </range-viewer>
57
+ </div>
58
+ </div>
59
+
60
+
61
+ <!-- <pre>isTypeNeeded = {{ isTypeNeeded }}</pre>
62
+ <pre>typePropertyName = {{ typePropertyName }}</pre>
63
+ <pre>typePropertyPath = {{ typePropertyPath }}</pre>
64
+ <pre>typeModel = {{ typeModel }}</pre> -->
65
+ <!-- <div>
66
+ <pre>objectsPathRangeConfig = {{ objectsPathRangeConfig }}</pre>
67
+ <pre>objectsPathRangeFunction = {{ objectsPathRangeFunction }}</pre>
68
+ <pre>selectedType = {{ selectedType }}</pre>
69
+ <pre>definition = {{ definition }}</pre>
70
+ <pre>properties = {{ properties }}</pre>
71
+ <pre>typeOptions = {{ typeOptions }}</pre>
72
+ <pre>model = {{ model }}</pre>
73
+ </div> -->
74
+ </div>
5
75
  </template>
6
76
 
7
77
  <script setup>
78
+ import Select from 'primevue/select'
79
+ import AutoObjectIdentification from '../crud/DefaultObjectIdentification.vue'
80
+ import { RangeViewer, injectComponent } from "@live-change/vue3-components"
81
+
82
+ import { defineProps, defineEmits, toRefs, ref, defineModel, computed, useId } from 'vue'
83
+ import pluralize from 'pluralize'
84
+
85
+ const uid = useId()
86
+
87
+ const props = defineProps({
88
+ definition: {
89
+ type: Object
90
+ },
91
+ properties: {
92
+ type: Object,
93
+ default: () => ({})
94
+ },
95
+ rootValue: {
96
+ type: Object,
97
+ default: () => ({})
98
+ },
99
+ propName: {
100
+ type: String,
101
+ default: ''
102
+ },
103
+ i18n: {
104
+ type: String,
105
+ default: ''
106
+ },
107
+ showServiceName: {
108
+ type: Boolean,
109
+ default: false
110
+ },
111
+ view: {
112
+ type: String,
113
+ default: 'range'
114
+ }
115
+ })
116
+
117
+ const { definition, properties, rootValue, propName, i18n, view } = toRefs(props)
118
+
119
+ const model = defineModel({
120
+ required: true
121
+ })
122
+
123
+ const emit = defineEmits(['selected'])
124
+
125
+ import { useI18n } from 'vue-i18n'
126
+ const { t: tI18n, te } = useI18n()
127
+ const t = (key, ...params) => tI18n(
128
+ te(i18n.value + propName.value + key)
129
+ ? i18n.value + propName.value + key
130
+ : key, ...params
131
+ )
132
+
133
+ const isTypeNeeded = computed(() => {
134
+ return definition.value.type === 'any'
135
+ })
136
+ const typePropertyName = computed(() => props.propName + 'Type')
137
+ const typePropertyPath = computed(() => typePropertyName.value.split('.'))
138
+ const typeModel = computed({
139
+ get() {
140
+ return typePropertyPath.value.reduce((acc, prop) => acc?.[prop], rootValue.value)
141
+ },
142
+ set(value) {
143
+ const path = typePropertyPath.value
144
+ let data = rootValue.value
145
+ for(let i = 0; i < path.length - 1; i++) {
146
+ const prop = path[i]
147
+ if(data[prop] === undefined || data[prop] === null) {
148
+ data[prop] = {}
149
+ }
150
+ data = data[prop]
151
+ }
152
+ data[path.at(-1)] = value
153
+ }
154
+ })
155
+
156
+ import { getAllTypesWithCrud } from '../../logic/relations'
157
+
158
+ const typeOptions = computed(() => {
159
+ if(definition.value.type === 'any') {
160
+ return definition.value.types ?? getAllTypesWithCrud('read')
161
+ }
162
+ return [definition.value.type]
163
+ })
164
+
165
+ const typeOptionsServices = computed(() => {
166
+ return Array.from(new Set(typeOptions.value.map(option => option.split('_')[0])))
167
+ })
168
+
169
+ const selectedType = ref(null)
170
+
171
+ console.log("Type options", typeOptions.value)
172
+ if(typeModel.value) {
173
+ selectedType.value = typeModel.value
174
+ } else if(typeOptions.value.length === 1) {
175
+ selectedType.value = typeOptions.value[0]
176
+ }
177
+
178
+ const selectedTypeParsed = computed(() => {
179
+ if(selectedType.value) return selectedType.value.split('_')
180
+ return null
181
+ })
182
+
183
+ const selectedTypeService = computed(() => {
184
+ if(selectedTypeParsed.value) return selectedTypeParsed.value[0]
185
+ return null
186
+ })
187
+
188
+ const selectedTypeModel = computed(() => {
189
+ if(selectedTypeParsed.value) return selectedTypeParsed.value[1]
190
+ return null
191
+ })
192
+
193
+ const ObjectIdentification = computed(() => {
194
+ const [service, model] = selectedTypeParsed.value
195
+ return injectComponent({
196
+ name: 'ObjectIdentification',
197
+ type: service + '_' + model,
198
+ service: service,
199
+ model: model
200
+ }, AutoObjectIdentification)
201
+ })
202
+
203
+ function typeLabel(option) {
204
+ const [service, model] = option.split('_')
205
+ if(typeOptionsServices.value.length === 1) {
206
+ return t('objectPicker.modelOption', { model })
207
+ }
208
+ return t('objectPicker.modelOptionWithService', { service, model })
209
+ }
210
+
211
+ import { useApi, usePath, live, reverseRange } from '@live-change/vue3-ssr'
212
+ const api = useApi()
213
+ const path = usePath()
214
+
215
+ const objectsPathRangeConfig = computed(() => {
216
+ if(!selectedTypeParsed.value) return null
217
+ const [service, model] = selectedTypeParsed.value
218
+ const serviceDefinition = api.metadata.api.value.services.find(s => s.name === service)
219
+ const modelDefinition = serviceDefinition.models[model]
220
+ return {
221
+ service,
222
+ model,
223
+ reverse: true,
224
+ view: modelDefinition?.crud?.[view.value ?? 'range']
225
+ }
226
+ })
227
+ const objectsPathRangeFunction = computed(() => {
228
+ 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,
235
+ ...(config.reverse ? reverseRange(range) : range),
236
+ })
237
+ })
238
+
239
+ function selectObject(object) {
240
+ if(isTypeNeeded.value) {
241
+ typeModel.value = selectedType.value
242
+ }
243
+ model.value = object.to ?? object.id
244
+ emit('selected', object)
245
+ }
8
246
 
9
247
  </script>
10
248
 
@@ -8,7 +8,7 @@ export function provideInputConfig(description, inputConfig) {
8
8
  for(let key in description) {
9
9
  for(let value of (description[key] instanceof Array ? description[key] : [description[key]])) {
10
10
  const provideKey = `input:${key}=${value}`
11
- console.log("PROVIDE COMPONENT", provideKey)
11
+ //console.log("PROVIDE INPUT CONFIG", provideKey)
12
12
  provide(provideKey, {
13
13
  inputConfig,
14
14
  description
@@ -26,9 +26,9 @@ export function injectInputConfig(request, defaultInputConfig, factory) {
26
26
 
27
27
  for(let key in request) {
28
28
  const provideKey = `input:${key}=${request[key]}`
29
- console.log("INJECT INPUT CONFIG PROVIDE KEY", provideKey)
29
+ //console.log("INJECT INPUT CONFIG PROVIDE KEY", provideKey)
30
30
  const entry = inject(provideKey, null)
31
- console.log("RESOLVED INPUT CONFIG", entry)
31
+ //console.log("RESOLVED INPUT CONFIG", entry)
32
32
  if(!entry) continue
33
33
  let isValid = true
34
34
  for(let key in entry.description) {
@@ -37,7 +37,7 @@ export function injectInputConfig(request, defaultInputConfig, factory) {
37
37
  if(!value.includes(entry.description[key])) isValid = false
38
38
  } else if(value !== entry.description[key]) isValid = false
39
39
  }
40
- console.log("RESOLVED COMPONENT VALID", isValid, filter(entry))
40
+ //console.log("RESOLVED COMPONENT VALID", isValid, filter(entry))
41
41
  if(isValid && filter(entry)) return entry.inputConfig
42
42
  }
43
43
  return factory ? defaultInputConfig() : defaultInputConfig
@@ -55,7 +55,7 @@ export function inputConfig(src, config) {
55
55
  }
56
56
 
57
57
  import deepmerge from 'deepmerge'
58
- export function provideInputConfigByDefinition(definition) {
58
+ export function injectInputConfigByDefinition(definition) {
59
59
  let baseConfig
60
60
  if(definition?.input && !baseConfig) baseConfig =
61
61
  injectInputConfig({ name: definition.input }, null)
@@ -71,6 +71,8 @@ types.Boolean = inputs.switch = {
71
71
  fieldComponent: defineAsyncComponent(() => import('./SwitchField.vue')),
72
72
  }*/
73
73
 
74
+ types.any = inputs.object = inputConfig(() => import('./ObjectInput.vue'))
75
+
74
76
 
75
77
  export function provideAutoInputConfiguration() {
76
78
  for(let type in types) {
@@ -3,6 +3,27 @@ import { usePath, live, useApi } from '@live-change/vue3-ssr'
3
3
  import { ref, computed, inject, watch } from 'vue'
4
4
  import { synchronized, defaultData } from '@live-change/vue3-components'
5
5
 
6
+ function cyrb128(str) {
7
+ let h1 = 1779033703, h2 = 3144134277,
8
+ h3 = 1013904242, h4 = 2773480762;
9
+ for (let i = 0, k; i < str.length; i++) {
10
+ k = str.charCodeAt(i);
11
+ h1 = h2 ^ Math.imul(h1 ^ k, 597399067);
12
+ h2 = h3 ^ Math.imul(h2 ^ k, 2869860233);
13
+ h3 = h4 ^ Math.imul(h3 ^ k, 951274213);
14
+ h4 = h1 ^ Math.imul(h4 ^ k, 2716044179);
15
+ }
16
+ h1 = Math.imul(h3 ^ (h1 >>> 18), 597399067);
17
+ h2 = Math.imul(h4 ^ (h2 >>> 22), 2869860233);
18
+ h3 = Math.imul(h1 ^ (h3 >>> 17), 951274213);
19
+ h4 = Math.imul(h2 ^ (h4 >>> 19), 2716044179);
20
+ h1 ^= (h2 ^ h3 ^ h4), h2 ^= h1, h3 ^= h1, h4 ^= h1;
21
+ const data = new Uint32Array([h4>>>0, h3>>>0, h2>>>0, h1>>>0])
22
+ // convert to base64
23
+ const data8 = new Uint8Array(data.buffer, data.byteOffset, data.byteLength)
24
+ return btoa(String.fromCharCode(...data8))
25
+ }
26
+
6
27
  export default function editorData(options) {
7
28
  if(!options) throw new Error('options must be provided')
8
29
 
@@ -66,8 +87,11 @@ export default function editorData(options) {
66
87
  }
67
88
  }
68
89
  const isNew = (idKey ? (!identifiers[idKey]) : (!draftIdParts.every(key => identifiers[key])))
69
- const draftId = (idKey ? identifiers[idKey]
90
+ let draftId = (idKey ? identifiers[idKey]
70
91
  : draftIdParts.map(key => JSON.stringify(identifiers[key])).join('_')) ?? 'new'
92
+ if(draftId.length > 16) {
93
+ draftId = cyrb128(draftId).slice(0, 16)
94
+ }
71
95
  const draftIdentifiers = {
72
96
  actionType: serviceName, action: crudMethods.read, targetType: modelName, target: draftId
73
97
  }
@@ -15,6 +15,12 @@ function getWhats(relations) {
15
15
  return relations.map(x => ensureArray(getWhat(x)))
16
16
  }
17
17
 
18
+ function getPropertyNames(relation) {
19
+ if(typeof relation === 'string') return relation[0].toLowerCase() + relation.slice(1)
20
+ if(relation.propertyNames) return relation.propertyNames
21
+ return ensureArray(relation.what).map(x => x[0].toLowerCase() + x.slice(1))
22
+ }
23
+
18
24
  export const relationTypes = {
19
25
  propertyOf: { singular: true, typed: true, owned: true },
20
26
  boundTo: { singular: true, typed: true, owned: false },
@@ -58,10 +64,12 @@ export function getForwardRelations(model, api = useApi()) {
58
64
  if(!Array.isArray(relations)) relations = [relations]
59
65
  for(const relation of relations) {
60
66
  const what = ensureArray(getWhat(relation))
67
+ const fields = ensureArray(getPropertyNames(relation))
61
68
  const result = {
62
69
  from: model,
63
70
  relation: type,
64
- what
71
+ what,
72
+ fields
65
73
  }
66
74
  results.push(result)
67
75
  }
@@ -143,61 +151,83 @@ export function prepareObjectRelations(objectType, object, api = useApi()) {
143
151
  })
144
152
 
145
153
  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
- })
154
+ const views = []
155
+ const singular = relationTypes[relation].singular && fields.length < 2
156
+
157
+ if(singular) {
158
+ views.push({
159
+ name: 'read',
160
+ identifiers: {
161
+ [fields[0]+'Type']: objectType,
162
+ [fields[0]]: object
163
+ }
164
+ })
165
+ } else {
166
+ for(const field of fields) {
167
+ const possibleFieldTypes = (relationConfig[field+'Types'] ?? [])
168
+ .concat(relationConfig.parentsTypes ?? [])
169
+ if(possibleFieldTypes.length === 0 || possibleFieldTypes.includes(objectType)) {
170
+ const name = 'rangeBy' + field[0].toUpperCase() + field.slice(1)
171
+ if(from.crud?.[name]) views.push({
172
+ name,
173
+ identifiers: {
174
+ [field+'Type']: objectType,
175
+ [field]: object
176
+ }
177
+ })
178
+ }
155
179
  }
156
180
  }
181
+ /* console.error("relation", relation, 'from', from, "type", relationTypes[relation],
182
+ "what", what, "fields", fields) */
157
183
  return {
158
184
  model: from.name,
159
185
  service: from.serviceName,
160
186
  fields,
161
187
  relation,
162
188
  what,
163
- identifiers,
189
+ views,
164
190
  access,
165
- singular: relationTypes[relation].singular && what.length < 2
191
+ singular
166
192
  }
167
193
  } else {
194
+ const views = []
168
195
  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 = []
196
+ const name = 'rangeBy_' + objectType
197
+ const typeView = from.crud?.[name]
198
+ ? name
199
+ : undefined
177
200
  if(typeView) {
178
- identifiers.push({
179
- [model[0].toLowerCase() + model.slice(1)]: object
201
+ views.push({
202
+ name: typeView,
203
+ identifiers: {
204
+ [model[0].toLowerCase() + model.slice(1)]: object
205
+ }
180
206
  })
181
207
  } else {
182
208
  for(let i = 0; i < what.length; i++) {
183
209
  if(what[i] !== objectType) continue
184
210
  const propertyName = relationConfig.propertyNames?.[i]
185
211
  ?? model[0].toLowerCase() + model.slice(1)
186
- identifiers.push({
187
- [propertyName]: object
212
+ const name = 'rangeBy' + propertyName[0].toUpperCase() + propertyName.slice(1)
213
+ if(!from.crud?.[name]) continue
214
+ views.push({
215
+ name,
216
+ identifiers: {
217
+ [propertyName]: object
218
+ }
188
219
  })
189
220
  }
190
221
  }
191
- console.log(objectType, "VIEW", view, from, singular)
222
+ console.log(objectType, "VIEWS", views, "FROM", from, "SINGULAR", singular)
192
223
  return {
193
224
  model: from.name,
194
225
  service: from.serviceName,
195
226
  fields,
196
227
  relation,
197
228
  what,
198
- identifiers,
199
229
  access,
200
- view,
230
+ views,
201
231
  singular
202
232
  }
203
233
  }
@@ -205,3 +235,17 @@ export function prepareObjectRelations(objectType, object, api = useApi()) {
205
235
 
206
236
  return preparedBackwardRelations
207
237
  }
238
+
239
+ export function getAllPossibleTypes(api = useApi(), filter = () => true,) {
240
+ return Object.entries(api.services).map(
241
+ ([serviceName, service]) => Object.values(service.models).filter(o => filter(o, service, serviceName)).map(
242
+ model => `${serviceName}_${model.name}`
243
+ ).flat()
244
+ ).flat()
245
+ }
246
+
247
+ export function getAllTypesWithCrud(crud, api = useApi()) {
248
+ return getAllPossibleTypes(api, (model, service, serviceName) => {
249
+ if(model.crud?.[crud]) return true
250
+ })
251
+ }
package/index.js CHANGED
@@ -34,6 +34,10 @@ import ModelList from './front/src/components/crud/ModelList.vue'
34
34
  export { ModelList }
35
35
  import EditorButtons from './front/src/components/crud/EditorButtons.vue'
36
36
  export { EditorButtons }
37
+ import DefaultObjectIdentification from './front/src/components/crud/DefaultObjectIdentification.vue'
38
+ export { DefaultObjectIdentification }
39
+ import ObjectPath from './front/src/components/crud/ObjectPath.vue'
40
+ export { ObjectPath }
37
41
  import AutoObjectIdentification from './front/src/components/crud/AutoObjectIdentification.vue'
38
42
  export { AutoObjectIdentification }
39
43