@live-change/frontend-auto-form 0.9.197 → 0.9.199

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/README.md ADDED
@@ -0,0 +1,139 @@
1
+ ---
2
+ title: @live-change/frontend-auto-form
3
+ ---
4
+
5
+ ## @live-change/frontend-auto-form
6
+
7
+ `@live-change/frontend-auto-form` to moduł do **automatycznego generowania formularzy i CRUD-ów** na podstawie:
8
+
9
+ - definicji modeli i akcji po stronie serwera (Live Change)
10
+ - metadanych wygenerowanych przez `@live-change/framework` i dostępnych przez `@live-change/vue3-ssr`
11
+
12
+ Zapewnia:
13
+
14
+ - komponenty **pól formularza** (`AutoField`, `AutoInput`, `AutoEditor`, `ModelEditor`, `ModelView`, `ModelSingle`, `ActionForm`, itp.)
15
+ - provider-y konfiguracji (`provideAutoViewComponents`, `provideAutoInputConfiguration`, `provideMetadataBasedAutoInputConfiguration`)
16
+ - lokalizacje (`locales`) używane w aplikacjach takich jak `family-tree` i `speed-dating`
17
+
18
+ ### Podstawowa integracja
19
+
20
+ W `App.vue` typowej aplikacji włączasz auto-form globalnie:
21
+
22
+ ```javascript
23
+ import {
24
+ provideAutoViewComponents,
25
+ provideAutoInputConfiguration,
26
+ provideMetadataBasedAutoInputConfiguration
27
+ } from '@live-change/frontend-auto-form'
28
+
29
+ provideAutoViewComponents()
30
+ provideAutoInputConfiguration()
31
+ provideMetadataBasedAutoInputConfiguration()
32
+ ```
33
+
34
+ oraz dodajesz lokalizacje do i18n w `front/src/config.js`:
35
+
36
+ ```javascript
37
+ import { locales as autoFormLocales } from '@live-change/frontend-auto-form'
38
+
39
+ export default {
40
+ i18n: {
41
+ messages: {
42
+ en: deepmerge.all([
43
+ baseLocales.en,
44
+ autoFormLocales.en,
45
+ // ...
46
+ ]),
47
+ pl: deepmerge.all([
48
+ baseLocales.pl || {},
49
+ autoFormLocales.pl || {},
50
+ // ...
51
+ ])
52
+ }
53
+ }
54
+ }
55
+ ```
56
+
57
+ ### Kluczowe komponenty
58
+
59
+ #### `AutoField`
60
+
61
+ Generuje pojedyncze pole formularza na podstawie definicji właściwości modelu lub akcji:
62
+
63
+ ```vue
64
+ <AutoField
65
+ :definition="definition.properties.firstName"
66
+ v-model="editable.firstName"
67
+ :error="validationResult?.propertyErrors?.firstName"
68
+ :label="t('profile.firstName')"
69
+ />
70
+ ```
71
+
72
+ Możesz wstrzykiwać własny layout przez sloty (`#default`, `#label`, `#error`), jak w `ProfileSettings.vue` (`speed-dating`).
73
+
74
+ #### `AutoInput` i `AutoEditor`
75
+
76
+ `AutoInput` – pojedyncze pole edycyjne na podstawie definicji,
77
+
78
+ `AutoEditor` – edytor całego obiektu (modelu) na podstawie definicji:
79
+
80
+ ```vue
81
+ <auto-editor
82
+ :definition="eventDefinition"
83
+ v-model="editable"
84
+ :rootValue="editable"
85
+ i18n="event."
86
+ />
87
+ ```
88
+
89
+ W przykładzie z `speed-dating/front/src/pages/events/[event]/edit.vue`:
90
+
91
+ - `eventDefinition` pochodzi z `api.services.speedDating.models.Event`
92
+ - `editable` jest synchronizowane z widokiem i akcją poprzez `synchronized`
93
+
94
+ #### `ModelEditor`, `ModelView`, `ModelSingle`
95
+
96
+ Te komponenty łączą:
97
+
98
+ - definicję modelu
99
+ - widoki i akcje (DAO)
100
+ - generowane formularze i widoki list/szczegółów
101
+
102
+ Są używane m.in. w:
103
+
104
+ - `speed-dating/front/src/pages/events/[event]/surveys.vue` (`ModelEditor` dla ankiet)
105
+ - `family-tree` – ekrany ustawień i edytory szablonów
106
+
107
+ ### Flow od modelu do CRUD
108
+
109
+ 1. **Definicja modelu i akcji** w serwisie po stronie serwera (np. `Event`, `TreeSettings`).
110
+ 2. **Eksport metadanych** przez Live Change i odczyt przez `@live-change/vue3-ssr` (`api.services[service].models[Model]`).
111
+ 3. **Auto-form** generuje formularze i widoki:
112
+ - `AutoField` dla pojedynczych pól,
113
+ - `AutoEditor` / `ModelEditor` dla całych obiektów,
114
+ - `ActionForm` / `ActionEditor` dla akcji.
115
+
116
+ ### Przykłady z projektów
117
+
118
+ #### `family-tree`
119
+
120
+ - `front/src/components/TreeSettings.vue`:
121
+ - `AutoField` użyty do edycji zagnieżdżonych ustawień (rootPerson, format, marginesy, tło, tytuł)
122
+ - integracja z PrimeVue (Dropdown, Slider, InputNumber) przez sloty
123
+ - `front/src/components/marketing/*Editor.vue`:
124
+ - `AutoField`, `editorData` do edycji szablonów i obrazów reklamowych
125
+ - `front/src/pages/tree/[tree]/settings.vue`:
126
+ - użycie `editorData` z `@live-change/frontend-auto-form` do spięcia formularza z modelem ustawień
127
+
128
+ #### `speed-dating`
129
+
130
+ - `front/src/components/profile/ProfileSettings.vue`:
131
+ - `AutoField` dla pól identyfikacji użytkownika, z własnymi layoutami i walidacją
132
+ - integracja z `synchronized` i serwisem `draft`
133
+ - `front/src/pages/events/[event]/edit.vue`:
134
+ - `AutoInput`, `AutoField`, `AutoEditor` do edycji eventu
135
+ - `front/src/pages/events/[event]/surveys.vue`:
136
+ - `ModelEditor` do edycji ankiet powiązanych z eventem
137
+
138
+ Te pliki są najlepszym odniesieniem, jeśli chcesz szybko zobaczyć, jak układa się flow od modelu do działającego CRUD-a.
139
+
@@ -107,8 +107,8 @@
107
107
  required: true,
108
108
  },
109
109
  views: {
110
- type: Object,
111
- default: () => ({})
110
+ type: Array,
111
+ default: () => ([{}])
112
112
  },
113
113
  })
114
114
  const { service, model, views } = toRefs(props)
@@ -124,7 +124,7 @@
124
124
  }, AutoObjectIdentification)
125
125
  )
126
126
 
127
- import { useApi, usePath, live } from '@live-change/vue3-ssr'
127
+ import { useApi, usePath, live, view } from '@live-change/vue3-ssr'
128
128
  const api = useApi()
129
129
  const path = usePath()
130
130
 
@@ -25,6 +25,7 @@ export default function editorData(options) {
25
25
  recursive = true,
26
26
  debounce = 600,
27
27
  timeField = 'lastUpdate',
28
+ crudSource = 'crud',
28
29
 
29
30
  savedToast = "Saved",
30
31
  savedDraftToast = "Draft saved",
@@ -56,7 +57,7 @@ export default function editorData(options) {
56
57
  const service = api.services[serviceName]
57
58
  const model = service.models[modelName]
58
59
  const {
59
- crudMethods = model.crud,
60
+ crudMethods = model[crudSource],
60
61
  identifiersNames = model.identifiers,
61
62
  editableProperties = model.editableProperties ?? Object.keys(model.properties),
62
63
  } = options
@@ -130,7 +131,8 @@ export default function editorData(options) {
130
131
  const savedIdentifiers = {}
131
132
  for(const identifier of identifiersNames) {
132
133
  if(typeof identifier === 'object') {
133
- savedIdentifiers[identifier.name] = savedData.value?.[identifier.name] ?? draftData.value?.data?.[identifier.name]
134
+ savedIdentifiers[identifier.name] = savedData.value?.[identifier.field] ?? savedData.value?.[identifier.name]
135
+ ?? draftData.value?.data?.[identifier.field] ?? draftData.value?.data?.[identifier.name]
134
136
  } else {
135
137
  savedIdentifiers[identifier] = savedData.value?.[identifier] ?? draftData.value?.data?.[identifier]
136
138
  }
@@ -196,7 +196,8 @@ export function prepareObjectRelations(objectType, object, api = useApi()) {
196
196
  const name = 'rangeBy_' + objectType
197
197
  const typeView = from.crud?.[name]
198
198
  ? name
199
- : undefined
199
+ : undefined
200
+
200
201
  if(typeView) {
201
202
  views.push({
202
203
  name: typeView,
@@ -205,18 +206,27 @@ export function prepareObjectRelations(objectType, object, api = useApi()) {
205
206
  }
206
207
  })
207
208
  } else {
208
- for(let i = 0; i < what.length; i++) {
209
- if(what[i] !== objectType) continue
210
- const propertyName = relationConfig.propertyNames?.[i]
211
- ?? model[0].toLowerCase() + model.slice(1)
212
- const name = 'rangeBy' + propertyName[0].toUpperCase() + propertyName.slice(1)
213
- if(!from.crud?.[name]) continue
209
+ if(singular) {
214
210
  views.push({
215
- name,
211
+ name: 'read',
216
212
  identifiers: {
217
- [propertyName]: object
213
+ [model[0].toLowerCase() + model.slice(1)]: object
218
214
  }
219
215
  })
216
+ } else {
217
+ for(let i = 0; i < what.length; i++) {
218
+ if(what[i] !== objectType) continue
219
+ const propertyName = relationConfig.propertyNames?.[i]
220
+ ?? model[0].toLowerCase() + model.slice(1)
221
+ const name = 'rangeBy' + propertyName[0].toUpperCase() + propertyName.slice(1)
222
+ if(!from.crud?.[name]) continue
223
+ views.push({
224
+ name,
225
+ identifiers: {
226
+ [propertyName]: object
227
+ }
228
+ })
229
+ }
220
230
  }
221
231
  }
222
232
  console.log(objectType, "VIEWS", views, "FROM", from, "SINGULAR", singular)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@live-change/frontend-auto-form",
3
- "version": "0.9.197",
3
+ "version": "0.9.199",
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.197",
26
- "@live-change/dao": "^0.9.197",
27
- "@live-change/dao-vue3": "^0.9.197",
28
- "@live-change/dao-websocket": "^0.9.197",
29
- "@live-change/framework": "^0.9.197",
30
- "@live-change/image-frontend": "^0.9.197",
31
- "@live-change/image-service": "^0.9.197",
32
- "@live-change/session-service": "^0.9.197",
33
- "@live-change/vue3-components": "^0.9.197",
34
- "@live-change/vue3-ssr": "^0.9.197",
25
+ "@live-change/cli": "^0.9.199",
26
+ "@live-change/dao": "^0.9.199",
27
+ "@live-change/dao-vue3": "^0.9.199",
28
+ "@live-change/dao-websocket": "^0.9.199",
29
+ "@live-change/framework": "^0.9.199",
30
+ "@live-change/image-frontend": "^0.9.199",
31
+ "@live-change/image-service": "^0.9.199",
32
+ "@live-change/session-service": "^0.9.199",
33
+ "@live-change/vue3-components": "^0.9.199",
34
+ "@live-change/vue3-ssr": "^0.9.199",
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.7"
53
53
  },
54
54
  "devDependencies": {
55
- "@live-change/codeceptjs-helper": "^0.9.197",
55
+ "@live-change/codeceptjs-helper": "^0.9.199",
56
56
  "codeceptjs": "^3.7.6",
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": "8231c2ed8bc3beed2c732aa5727174417f19082b"
66
+ "gitHead": "1900043a10cf9ad49b9cc33a539fb973706de962"
67
67
  }