qdadm 0.50.0 → 0.51.3

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": "qdadm",
3
- "version": "0.50.0",
3
+ "version": "0.51.3",
4
4
  "description": "Vue 3 framework for admin dashboards with PrimeVue",
5
5
  "author": "quazardous",
6
6
  "license": "MIT",
@@ -87,6 +87,7 @@ import { useBreadcrumb } from './useBreadcrumb'
87
87
  import { useEntityItemPage } from './useEntityItemPage'
88
88
  import { registerGuardDialog, unregisterGuardDialog } from './useGuardStore'
89
89
  import { deepClone } from '../utils/transformers'
90
+ import { getSiblingRoutes } from '../module/moduleRegistry'
90
91
 
91
92
  export function useEntityItemFormPage(config = {}) {
92
93
  const {
@@ -109,7 +110,9 @@ export function useEntityItemFormPage(config = {}) {
109
110
  // Validation options
110
111
  validateOnBlur = true, // Validate field on blur
111
112
  validateOnSubmit = true, // Validate all fields before submit
112
- showErrorSummary = false // Show error summary at top of form
113
+ showErrorSummary = false, // Show error summary at top of form
114
+ // Field generation
115
+ generateFormFields = true // Auto-generate fields from manager schema
113
116
  } = config
114
117
 
115
118
  const router = useRouter()
@@ -316,11 +319,19 @@ export function useEntityItemFormPage(config = {}) {
316
319
  }
317
320
 
318
321
  if (andClose) {
319
- router.push({ name: routePrefix })
322
+ // For child entities, redirect to sibling list route with parent params
323
+ const listRoute = findListRoute()
324
+ router.push(listRoute)
320
325
  } else if (!isEdit.value && redirectOnCreate) {
321
- // Redirect to edit mode after create
322
- const newId = responseData[manager.idField] || responseData.id || responseData.key
323
- router.replace({ name: `${routePrefix}-${editRouteSuffix}`, params: { id: newId } })
326
+ // Redirect to edit mode after create (only for top-level entities)
327
+ // Child entities with parent config go to list instead (edit route may not exist)
328
+ if (parentConfig.value) {
329
+ const listRoute = findListRoute()
330
+ router.replace(listRoute)
331
+ } else {
332
+ const newId = responseData[manager.idField] || responseData.id || responseData.key
333
+ router.replace({ name: `${routePrefix}-${editRouteSuffix}`, params: { id: newId } })
334
+ }
324
335
  }
325
336
 
326
337
  return responseData
@@ -393,12 +404,59 @@ export function useEntityItemFormPage(config = {}) {
393
404
 
394
405
  // ============ NAVIGATION ============
395
406
 
407
+ /**
408
+ * Find the list route for redirects after save/cancel
409
+ * For child entities: finds sibling list route with parent params
410
+ * For top-level entities: uses routePrefix
411
+ *
412
+ * When parent has multiple child entity types (e.g., bots → commands AND bots → logs),
413
+ * we find the list route matching the current entity's route prefix.
414
+ */
415
+ function findListRoute() {
416
+ // If has parent config, find sibling list route
417
+ if (parentConfig.value) {
418
+ const { entity: parentEntityName, param } = parentConfig.value
419
+ const siblings = getSiblingRoutes(parentEntityName, param)
420
+
421
+ // Extract base route name from current route (e.g., 'bot-commands-create' → 'bot-commands')
422
+ const currentRouteName = route.name || ''
423
+ const baseRouteName = currentRouteName.replace(/-(create|edit|new)$/, '')
424
+
425
+ // Find list routes among siblings (exclude create/edit/new routes)
426
+ const listRoutes = siblings.filter(r => {
427
+ const name = r.name || ''
428
+ const path = r.path || ''
429
+ return !name.match(/-(create|edit|new)$/) && !path.match(/\/(create|edit|new)$/)
430
+ })
431
+
432
+ // Prefer route matching current entity's base name
433
+ let listRoute = listRoutes.find(r => r.name === baseRouteName)
434
+
435
+ // Fallback: try route containing routePrefix (e.g., 'bot-commands' contains 'command')
436
+ if (!listRoute && routePrefix) {
437
+ listRoute = listRoutes.find(r => r.name?.includes(routePrefix))
438
+ }
439
+
440
+ // Last fallback: first list route
441
+ if (!listRoute && listRoutes.length > 0) {
442
+ listRoute = listRoutes[0]
443
+ }
444
+
445
+ if (listRoute?.name) {
446
+ return { name: listRoute.name, params: route.params }
447
+ }
448
+ }
449
+
450
+ // Default: top-level entity list
451
+ return { name: routePrefix }
452
+ }
453
+
396
454
  function cancel() {
397
- router.push({ name: routePrefix })
455
+ router.push(findListRoute())
398
456
  }
399
457
 
400
458
  function goToList() {
401
- router.push({ name: routePrefix })
459
+ router.push(findListRoute())
402
460
  }
403
461
 
404
462
  // ============ FIELDS ============
@@ -598,11 +656,41 @@ export function useEntityItemFormPage(config = {}) {
598
656
  } else if (currentIndex === -1) {
599
657
  // New field, add at end
600
658
  fieldOrder.value.push(name)
659
+ } else {
660
+ // Existing field without repositioning, restore at original position
661
+ fieldOrder.value.splice(currentIndex, 0, name)
601
662
  }
602
663
 
603
664
  return builderApi
604
665
  }
605
666
 
667
+ /**
668
+ * Update an existing field configuration
669
+ *
670
+ * Use this to modify properties of auto-generated fields.
671
+ * Throws error if field doesn't exist (use addField for new fields).
672
+ *
673
+ * @param {string} name - Field name to update
674
+ * @param {object} fieldConfig - Properties to merge with existing config
675
+ * @returns {object} - The builder instance for chaining
676
+ *
677
+ * @example
678
+ * form.updateField('book_id', { disabled: true })
679
+ * form.updateField('email', { validate: v => v.includes('@') || 'Invalid' })
680
+ */
681
+ function updateField(name, fieldConfig) {
682
+ if (!fieldsMap.value.has(name)) {
683
+ throw new Error(`Field '${name}' does not exist. Use addField() to create new fields.`)
684
+ }
685
+
686
+ // Merge with existing config (keeps position)
687
+ const existingConfig = fieldsMap.value.get(name)
688
+ const mergedConfig = { ...existingConfig, ...fieldConfig }
689
+ fieldsMap.value.set(name, mergedConfig)
690
+
691
+ return builderApi
692
+ }
693
+
606
694
  /**
607
695
  * Exclude a field from generation
608
696
  * Call before generateFields() or use exclude option
@@ -1123,6 +1211,7 @@ export function useEntityItemFormPage(config = {}) {
1123
1211
  confirmDelete,
1124
1212
  reset,
1125
1213
  goToList,
1214
+ findListRoute,
1126
1215
 
1127
1216
  // Dirty tracking
1128
1217
  takeSnapshot,
@@ -1134,6 +1223,7 @@ export function useEntityItemFormPage(config = {}) {
1134
1223
  generateFields,
1135
1224
  resolveReferences,
1136
1225
  addField,
1226
+ updateField,
1137
1227
  removeField,
1138
1228
  excludeField,
1139
1229
  getFieldConfig,
@@ -1188,5 +1278,15 @@ export function useEntityItemFormPage(config = {}) {
1188
1278
  events: formEvents
1189
1279
  }
1190
1280
 
1281
+ // Auto-generate fields from manager schema if enabled
1282
+ if (generateFormFields) {
1283
+ generateFields()
1284
+ }
1285
+
1286
+ // Auto-disable parent foreignKey field (it's auto-filled from route)
1287
+ if (parentConfig.value?.foreignKey && fieldsMap.value.has(parentConfig.value.foreignKey)) {
1288
+ updateField(parentConfig.value.foreignKey, { disabled: true })
1289
+ }
1290
+
1191
1291
  return builderApi
1192
1292
  }