@live-change/frontend-auto-form 0.9.62 → 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.
@@ -1,19 +1,14 @@
1
1
  <template>
2
- <template v-if="typeof identificationConfig === 'string'">
3
- <span>
4
- <i class="pi pi-box mr-2" style="font-size: 0.9em;"></i>{{ objectData[identificationConfig] }}
5
- </span>
6
- </template>
7
- <template v-else>
8
- <span>
9
- <strong>{{ objectType }}</strong>: {{ object ?? objectData.to ?? objectData.id }}
10
- </span>
11
- </template>
2
+ <router-link v-if="link" :to="viewRoute">
3
+ <ObjectIdentification :objectType="objectType" :object="object" :data="data" />
4
+ </router-link>
5
+ <ObjectIdentification v-else :objectType="objectType" :object="object" :data="data" />
12
6
  </template>
13
7
 
14
8
  <script setup>
15
9
 
16
- import { ref, computed, onMounted, defineProps, defineEmits, toRefs } from 'vue'
10
+ import { defineProps, computed, inject, toRefs } from 'vue'
11
+ import { injectComponent } from '@live-change/vue3-components'
17
12
 
18
13
  const props = defineProps({
19
14
  objectType: {
@@ -25,15 +20,14 @@
25
20
  required: true
26
21
  },
27
22
  data: {
28
- type: Object,
29
- default: null
23
+ type: Object,
30
24
  },
31
- inline: {
25
+ link: {
32
26
  type: Boolean,
33
27
  default: false
34
28
  }
35
29
  })
36
- const { objectType, object, data, inline } = toRefs(props)
30
+ const { objectType, object, data, link } = toRefs(props)
37
31
 
38
32
  import { useApi, usePath, live } from '@live-change/vue3-ssr'
39
33
  const api = useApi()
@@ -46,6 +40,16 @@
46
40
  const service = computed(() => serviceAndModel.value.service)
47
41
  const model = computed(() => serviceAndModel.value.model)
48
42
 
43
+ import DefaultObjectIdentification from './DefaultObjectIdentification.vue'
44
+ const ObjectIdentification = computed(() =>
45
+ injectComponent({
46
+ name: 'ObjectIdentification',
47
+ type: service.value + '_' + model.value,
48
+ service: service.value,
49
+ model: model.value
50
+ }, DefaultObjectIdentification)
51
+ )
52
+
49
53
  const modelDefinition = computed(() => {
50
54
  return api.services?.[service.value]?.models?.[model.value]
51
55
  })
@@ -72,9 +76,34 @@
72
76
  const loadedObjectData = await live(objectDataPath)
73
77
  const objectData = computed(() => data.value || loadedObjectData.value)
74
78
 
79
+ function objectIdentifiers(object) {
80
+ const identifiers = {}
81
+ for(const identifierDefinition of modelDefinition.value.identifiers) {
82
+ if(typeof identifierDefinition === 'string') {
83
+ identifiers[identifierDefinition] = object[identifierDefinition]
84
+ } else {
85
+ if(identifierDefinition.field === 'id') {
86
+ identifiers[identifierDefinition.name] = object?.to ?? object.id
87
+ } else {
88
+ identifiers[identifierDefinition.name] = object[identifierDefinition.field]
89
+ }
90
+ }
91
+ }
92
+ return identifiers
93
+ }
94
+
95
+ const viewRoute = computed(() => {
96
+ return {
97
+ name: 'auto-form:view',
98
+ params: {
99
+ serviceName: service.value,
100
+ modelName: model.value,
101
+ identifiers: Object.values(objectIdentifiers(objectData.value))
102
+ }
103
+ }
104
+ })
105
+
75
106
 
76
107
  </script>
77
108
 
78
- <style scoped>
79
109
 
80
- </style>
@@ -0,0 +1,85 @@
1
+ <template>
2
+ <template v-if="typeof identificationConfig === 'string'">
3
+ <span>
4
+ <i :class="[icon, 'mr-2']" style="font-size: 0.9em;"></i>{{ objectData[identificationConfig] }}
5
+ </span>
6
+ </template>
7
+ <template v-else>
8
+ <span>
9
+ <strong>{{ objectType }}</strong>: {{ object ?? objectData.to ?? objectData.id }}
10
+ </span>
11
+ </template>
12
+ </template>
13
+
14
+ <script setup>
15
+
16
+ import { ref, computed, onMounted, defineProps, defineEmits, toRefs } from 'vue'
17
+
18
+ const props = defineProps({
19
+ objectType: {
20
+ type: String,
21
+ required: true
22
+ },
23
+ object: {
24
+ type: String,
25
+ required: true
26
+ },
27
+ data: {
28
+ type: Object,
29
+ default: null
30
+ },
31
+ inline: {
32
+ type: Boolean,
33
+ default: false
34
+ }
35
+ })
36
+ const { objectType, object, data, inline } = toRefs(props)
37
+
38
+ import { useApi, usePath, live } from '@live-change/vue3-ssr'
39
+ const api = useApi()
40
+ const path = usePath()
41
+
42
+ const serviceAndModel = computed(() => {
43
+ const [service, model] = objectType.value.split('_')
44
+ return { service, model }
45
+ })
46
+ const service = computed(() => serviceAndModel.value.service)
47
+ const model = computed(() => serviceAndModel.value.model)
48
+
49
+ const modelDefinition = computed(() => {
50
+ return api.services?.[service.value]?.models?.[model.value]
51
+ })
52
+
53
+ const identificationViewName = computed(() => {
54
+ return modelDefinition.value?.crud?.identification || modelDefinition.value?.crud?.read
55
+ })
56
+
57
+ const identificationConfig = computed(() => {
58
+ return modelDefinition.value?.identification
59
+ })
60
+
61
+ const objectDataPath = computed(() => {
62
+ if(data.value) return null
63
+ if(!identificationConfig.value) return null
64
+ const viewName = identificationViewName.value
65
+ if(!viewName) return null
66
+ const modelName = model.value
67
+ return path[service.value][viewName]({
68
+ [modelName[0].toLowerCase() + modelName.slice(1)]: object.value
69
+ })
70
+ })
71
+
72
+ const loadedObjectData = await live(objectDataPath)
73
+ const objectData = computed(() => data.value || loadedObjectData.value)
74
+
75
+
76
+ const icon = computed(() => {
77
+ if(modelDefinition.value?.iconProperty) return objectData[modelDefinition.value?.iconProperty]
78
+ return modelDefinition.value?.icon || 'pi pi-box'
79
+ })
80
+
81
+ </script>
82
+
83
+ <style scoped>
84
+
85
+ </style>
@@ -45,7 +45,7 @@
45
45
  })
46
46
  const { type, object, data, link, inline } = toRefs(props)
47
47
 
48
- import AutoObjectIdentification from './AutoObjectIdentification.vue'
48
+ import AutoObjectIdentification from './DefaultObjectIdentification.vue'
49
49
 
50
50
  import { useApi, usePath, live } from '@live-change/vue3-ssr'
51
51
  const api = useApi()
@@ -130,7 +130,7 @@
130
130
  }
131
131
  }])
132
132
 
133
- import AutoObjectIdentification from './AutoObjectIdentification.vue'
133
+ import AutoObjectIdentification from './DefaultObjectIdentification.vue'
134
134
 
135
135
  const ObjectIdentification = computed(() =>
136
136
  injectComponent({
@@ -114,7 +114,7 @@
114
114
  })
115
115
  const { service, model, views } = toRefs(props)
116
116
 
117
- import AutoObjectIdentification from './AutoObjectIdentification.vue'
117
+ import AutoObjectIdentification from './DefaultObjectIdentification.vue'
118
118
 
119
119
  const ObjectIdentification = computed(() =>
120
120
  injectComponent({
@@ -10,7 +10,7 @@
10
10
  <h4>object</h4>
11
11
  <pre>{{ object }}</pre>-->
12
12
 
13
-
13
+ <ScopePath :objectType="service + '_' + model" :object="object.to ?? object.id" class="mb-6" />
14
14
 
15
15
  <div v-if="object">
16
16
  <div class="bg-surface-0 dark:bg-surface-900 p-4 shadow-sm rounded-border mb-6">
@@ -127,6 +127,8 @@
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'
131
+
130
132
  const props = defineProps({
131
133
  service: {
132
134
  type: String,
@@ -153,7 +155,7 @@
153
155
 
154
156
  const emit = defineEmits(['saved', 'draftSaved', 'draftDiscarded', 'saveError', 'created' ])
155
157
 
156
- import AutoObjectIdentification from './AutoObjectIdentification.vue'
158
+ import AutoObjectIdentification from './DefaultObjectIdentification.vue'
157
159
  const ObjectIdentification = computed(() =>
158
160
  injectComponent({
159
161
  name: 'ObjectIdentification',
@@ -0,0 +1,106 @@
1
+ <template>
2
+ <div>
3
+ <!-- <h1>Scope Path</h1>
4
+ <pre>pathsPath = {{ pathsPath }}</pre>
5
+ <pre>paths = {{ paths }}</pre>
6
+ <pre>selectedPaths = {{ selectedPaths }}</pre>
7
+ <pre>selectedPathWithElements = {{ selectedPathWithElements }}</pre> -->
8
+ <div v-for="path in selectedPathsWithElements" :key="path">
9
+ <Breadcrumb :model="path">
10
+ <template #item="{ item }">
11
+ <AutoObjectIdentification :objectType="item.objectType" :object="item.object"
12
+ :link="item.object !== object && item.objectType !== objectType" />
13
+ </template>
14
+ </Breadcrumb>
15
+ </div>
16
+ </div>
17
+ </template>
18
+
19
+ <script setup>
20
+
21
+ import Breadcrumb from 'primevue/breadcrumb'
22
+ import AutoObjectIdentification from './AutoObjectIdentification.vue'
23
+ import { ref, computed, onMounted, defineProps, toRefs, inject } from 'vue'
24
+ const props = defineProps({
25
+ objectType: {
26
+ type: String,
27
+ required: true
28
+ },
29
+ object: {
30
+ type: String,
31
+ required: true
32
+ }
33
+ })
34
+ const { objectType, object } = toRefs(props)
35
+
36
+ import { usePath, live } from '@live-change/vue3-ssr'
37
+ const path = usePath()
38
+
39
+ function longest(scopePaths) {
40
+ return scopePaths.sort((a, b) => b.intermediate.length - a.intermediate.length).at(0)
41
+ }
42
+
43
+ function longestByType(scopePaths) {
44
+ const scopePathsByType = new Map()
45
+ for(const scopePath of scopePaths) {
46
+ const type = scopePath.scopeType
47
+ if(!scopePathsByType.has(type)) scopePathsByType.set(type, [])
48
+ scopePathsByType.get(type).push(scopePath)
49
+ }
50
+ const result = []
51
+ for(const type of scopePathsByType.keys()) {
52
+ result.push(longest(scopePathsByType.get(type)))
53
+ }
54
+ return result
55
+ }
56
+
57
+ function scopePathElements(path) {
58
+ const {objectType, object, scopeType, scope, intermediate} = path
59
+ const root = { objectType: scopeType, object: scope, }
60
+ const elements = [root]
61
+ for(let i = 0; i < intermediate.length; i+=2) {
62
+ const propertyName = intermediate[i]
63
+ elements[elements.length - 1].toProperty = propertyName
64
+ const objectInfo = intermediate[i+1]
65
+ if(objectInfo) {
66
+ const separatorPosition = objectInfo.indexOf(':')
67
+ const objectType = JSON.parse(objectInfo.substring(0, separatorPosition))
68
+ const object = JSON.parse(objectInfo.substring(separatorPosition + 1))
69
+ elements.push({ objectType, object, propertyFrom: propertyName })
70
+ } else {
71
+ elements.push({ objectType, object, propertyFrom: propertyName })
72
+ }
73
+ }
74
+ return elements
75
+ }
76
+
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
+ })
88
+
89
+ const pathsPath = computed(() => scopePathConfig.pathsPath(objectType.value, object.value, scopePathConfig))
90
+
91
+ const [paths] = await Promise.all([
92
+ live(pathsPath)
93
+ ])
94
+
95
+ const selectedPaths = computed(() => {
96
+ return scopePathConfig.scopeSelector(paths.value)
97
+ })
98
+
99
+ const selectedPathsWithElements = computed(
100
+ () => selectedPaths.value.map(scopePath => scopePathConfig.pathElements(scopePath))
101
+ )
102
+
103
+
104
+
105
+ </script>
106
+
@@ -161,8 +161,8 @@
161
161
  && props.modelValue?.length < minLengthValidation.value.length
162
162
  )
163
163
 
164
- import { provideInputConfigByDefinition } from './inputConfigInjection.js'
165
- const inputConfig = computed(() => provideInputConfigByDefinition(definition.value))
164
+ import { injectInputConfigByDefinition } from './inputConfigInjection.js'
165
+ const inputConfig = computed(() => injectInputConfigByDefinition(definition.value))
166
166
 
167
167
  const label = computed(() => props.i18n + (props.label || definition.value.label || props.name))
168
168
 
@@ -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
 
@@ -47,7 +47,7 @@
47
47
  import Select from 'primevue/select'
48
48
  import Popover from 'primevue/popover'
49
49
  import ObjectPicker from './ObjectPicker.vue'
50
- import AutoObjectIdentification from '../crud/AutoObjectIdentification.vue'
50
+ import AutoObjectIdentification from '../crud/DefaultObjectIdentification.vue'
51
51
  import { injectComponent } from "@live-change/vue3-components"
52
52
 
53
53
  import { defineProps, defineEmits, toRefs, ref, defineModel, computed } from 'vue'
@@ -76,7 +76,7 @@
76
76
 
77
77
  <script setup>
78
78
  import Select from 'primevue/select'
79
- import AutoObjectIdentification from '../crud/AutoObjectIdentification.vue'
79
+ import AutoObjectIdentification from '../crud/DefaultObjectIdentification.vue'
80
80
  import { RangeViewer, injectComponent } from "@live-change/vue3-components"
81
81
 
82
82
  import { defineProps, defineEmits, toRefs, ref, defineModel, computed, useId } from 'vue'
@@ -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)
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
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@live-change/frontend-auto-form",
3
- "version": "0.9.62",
3
+ "version": "0.9.63",
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.62",
26
- "@live-change/dao": "^0.9.62",
27
- "@live-change/dao-vue3": "^0.9.62",
28
- "@live-change/dao-websocket": "^0.9.62",
29
- "@live-change/framework": "^0.9.62",
30
- "@live-change/image-frontend": "^0.9.62",
31
- "@live-change/image-service": "^0.9.62",
32
- "@live-change/session-service": "^0.9.62",
33
- "@live-change/vue3-components": "^0.9.62",
34
- "@live-change/vue3-ssr": "^0.9.62",
25
+ "@live-change/cli": "^0.9.63",
26
+ "@live-change/dao": "^0.9.63",
27
+ "@live-change/dao-vue3": "^0.9.63",
28
+ "@live-change/dao-websocket": "^0.9.63",
29
+ "@live-change/framework": "^0.9.63",
30
+ "@live-change/image-frontend": "^0.9.63",
31
+ "@live-change/image-service": "^0.9.63",
32
+ "@live-change/session-service": "^0.9.63",
33
+ "@live-change/vue3-components": "^0.9.63",
34
+ "@live-change/vue3-ssr": "^0.9.63",
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.62",
55
+ "@live-change/codeceptjs-helper": "^0.9.63",
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": "b1b605b7f1fa4fc3de4720afbb401e2cfff080cf"
66
+ "gitHead": "89b9647aeaff9fc66add1f07d225fe4f44d91a39"
67
67
  }