@stonecrop/desktop 0.13.6 → 0.13.8

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stonecrop/desktop",
3
- "version": "0.13.6",
3
+ "version": "0.13.8",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "author": {
@@ -32,11 +32,11 @@
32
32
  "**/*.css"
33
33
  ],
34
34
  "dependencies": {
35
- "@stonecrop/aform": "0.13.6",
36
- "@stonecrop/atable": "0.13.6",
37
- "@stonecrop/stonecrop": "0.13.6",
38
- "@stonecrop/themes": "0.13.6",
39
- "@stonecrop/schema": "0.13.6"
35
+ "@stonecrop/aform": "0.13.8",
36
+ "@stonecrop/atable": "0.13.8",
37
+ "@stonecrop/stonecrop": "0.13.8",
38
+ "@stonecrop/themes": "0.13.8",
39
+ "@stonecrop/schema": "0.13.8"
40
40
  },
41
41
  "peerDependencies": {
42
42
  "vue": "^3.5.33"
@@ -120,7 +120,29 @@ const currentViewData = computed<Record<string, any>>({
120
120
  // Return a plain shallow copy so AForm mutations don't propagate directly into
121
121
  // the HST reactive object, which would bypass field-trigger diffing and cause
122
122
  // setupDeepReactivity to fire triggers for all fields on every keystroke.
123
- return { ...record?.get('') }
123
+ const flat: Record<string, any> = { ...record?.get('') }
124
+
125
+ // AFieldset receives data[fieldsetFieldname] as its data prop, so the fieldset's
126
+ // children must be grouped under the fieldset key. The server returns flat SQL rows,
127
+ // so we nest fieldset children here before AForm renders them.
128
+ const doctype = stonecrop.value.registry.registry[currentDoctype.value]
129
+ if (doctype) {
130
+ for (const field of doctype.getSchemaArray()) {
131
+ if (
132
+ 'fieldtype' in field &&
133
+ field.fieldtype === 'Fieldset' &&
134
+ 'schema' in field &&
135
+ Array.isArray(field.schema)
136
+ ) {
137
+ const nested: Record<string, any> = {}
138
+ for (const child of field.schema as any[]) {
139
+ if (child.fieldname) nested[child.fieldname] = flat[child.fieldname]
140
+ }
141
+ flat[field.fieldname] = nested
142
+ }
143
+ }
144
+ }
145
+ return flat
124
146
  } catch {
125
147
  return {}
126
148
  }
@@ -131,9 +153,38 @@ const currentViewData = computed<Record<string, any>>({
131
153
  }
132
154
 
133
155
  try {
156
+ // AForm emits nested data for fieldsets: { fieldsetKey: { childA: val } }.
157
+ // HST and the server both expect flat rows, so flatten fieldset values back before writing.
158
+ const doctype = stonecrop.value.registry.registry[currentDoctype.value]
159
+ const fieldsetNames = new Set<string>()
160
+ if (doctype) {
161
+ for (const field of doctype.getSchemaArray()) {
162
+ if ('fieldtype' in field && field.fieldtype === 'Fieldset') {
163
+ fieldsetNames.add(field.fieldname)
164
+ }
165
+ }
166
+ }
167
+
168
+ // Two-pass flatten: non-fieldset keys first, then fieldset children.
169
+ // Fieldset children must be applied last — AForm may emit stale flat copies
170
+ // of fieldset children alongside the updated nested value, and the nested
171
+ // value must win regardless of key insertion order.
172
+ const flatData: Record<string, any> = {}
173
+ const fieldsetValues: Record<string, any>[] = []
174
+ for (const [key, value] of Object.entries(newData)) {
175
+ if (fieldsetNames.has(key) && value && typeof value === 'object' && !Array.isArray(value)) {
176
+ fieldsetValues.push(value)
177
+ } else {
178
+ flatData[key] = value
179
+ }
180
+ }
181
+ for (const nestedValue of fieldsetValues) {
182
+ Object.assign(flatData, nestedValue)
183
+ }
184
+
134
185
  // Only update fields that actually changed to avoid triggering actions for unchanged fields
135
186
  const hstStore = stonecrop.value.getStore()
136
- for (const [fieldname, value] of Object.entries(newData)) {
187
+ for (const [fieldname, value] of Object.entries(flatData)) {
137
188
  const fieldPath = `${currentDoctype.value}.${currentRecordId.value}.${fieldname}`
138
189
  const currentValue = hstStore.has(fieldPath) ? hstStore.get(fieldPath) : undefined
139
190
  if (currentValue !== value) {
@@ -445,6 +496,21 @@ const createNewRecord = async () => {
445
496
  await doNavigate({ view: 'record', doctype: routeDoctype.value, recordId: newId })
446
497
  }
447
498
 
499
+ // Flatten Fieldset containers into individual columns for list/table views.
500
+ // A Fieldset groups form fields visually but has no DB column; its children are the
501
+ // actual data fields and should appear as flat columns in a list view.
502
+ const flattenFieldsets = (fields: SchemaTypes[]): SchemaTypes[] => {
503
+ const result: SchemaTypes[] = []
504
+ for (const field of fields) {
505
+ if ('fieldtype' in field && field.fieldtype === 'Fieldset' && 'schema' in field && Array.isArray(field.schema)) {
506
+ result.push(...flattenFieldsets(field.schema as SchemaTypes[]))
507
+ } else {
508
+ result.push(field)
509
+ }
510
+ }
511
+ return result
512
+ }
513
+
448
514
  // Schema generator functions - moved here to be available to computed properties
449
515
  const getDoctypesSchema = (): SchemaTypes[] => {
450
516
  if (!availableDoctypes.length) return []
@@ -533,7 +599,10 @@ const getRecordsSchema = (): SchemaTypes[] => {
533
599
  fieldname: 'records_table',
534
600
  component: 'ATable',
535
601
  kind: 'table',
536
- schema: [...(schema as ColumnSchema[]), { fieldname: 'actions', label: 'Actions', fieldtype: 'Data' }],
602
+ schema: [
603
+ ...(flattenFieldsets(schema) as ColumnSchema[]),
604
+ { fieldname: 'actions', label: 'Actions', fieldtype: 'Data' },
605
+ ],
537
606
  config: {
538
607
  view: 'list',
539
608
  fullWidth: true,