@asteby/metacore-runtime-react 47.0.0 → 48.0.0

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.
Files changed (178) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/dist/action-modal-dispatcher.d.ts.map +1 -1
  3. package/dist/action-modal-dispatcher.js +24 -4
  4. package/dist/audit-info.d.ts +54 -0
  5. package/dist/audit-info.d.ts.map +1 -0
  6. package/dist/audit-info.js +142 -0
  7. package/dist/business/catalog-product-search.d.ts +25 -0
  8. package/dist/business/catalog-product-search.d.ts.map +1 -0
  9. package/dist/business/catalog-product-search.js +57 -0
  10. package/dist/business/catalog.d.ts.map +1 -1
  11. package/dist/business/catalog.js +2 -0
  12. package/dist/business/document-editor-model.d.ts +107 -0
  13. package/dist/business/document-editor-model.d.ts.map +1 -0
  14. package/dist/business/document-editor-model.js +279 -0
  15. package/dist/business/document-editor-panels.d.ts +64 -0
  16. package/dist/business/document-editor-panels.d.ts.map +1 -0
  17. package/dist/business/document-editor-panels.js +58 -0
  18. package/dist/business/document-editor.d.ts +27 -0
  19. package/dist/business/document-editor.d.ts.map +1 -0
  20. package/dist/business/document-editor.js +445 -0
  21. package/dist/business/document-lines.d.ts.map +1 -1
  22. package/dist/business/document-lines.js +5 -1
  23. package/dist/business/index.d.ts +5 -0
  24. package/dist/business/index.d.ts.map +1 -1
  25. package/dist/business/index.js +5 -0
  26. package/dist/business/line-items.d.ts +7 -0
  27. package/dist/business/line-items.d.ts.map +1 -1
  28. package/dist/business/line-items.js +6 -1
  29. package/dist/business/payment-allocator.d.ts +19 -0
  30. package/dist/business/payment-allocator.d.ts.map +1 -0
  31. package/dist/business/payment-allocator.js +31 -0
  32. package/dist/business/product-search.d.ts +4 -0
  33. package/dist/business/product-search.d.ts.map +1 -1
  34. package/dist/dialogs/dynamic-record.d.ts.map +1 -1
  35. package/dist/dialogs/dynamic-record.js +19 -8
  36. package/dist/document-form-dialog.d.ts +31 -2
  37. package/dist/document-form-dialog.d.ts.map +1 -1
  38. package/dist/document-form-dialog.js +43 -11
  39. package/dist/dynamic-columns-helpers.d.ts +9 -0
  40. package/dist/dynamic-columns-helpers.d.ts.map +1 -1
  41. package/dist/dynamic-columns-helpers.js +19 -0
  42. package/dist/dynamic-columns.d.ts +8 -2
  43. package/dist/dynamic-columns.d.ts.map +1 -1
  44. package/dist/dynamic-columns.js +21 -5
  45. package/dist/dynamic-crud-page.d.ts +6 -0
  46. package/dist/dynamic-crud-page.d.ts.map +1 -1
  47. package/dist/dynamic-crud-page.js +14 -5
  48. package/dist/dynamic-form-schema.d.ts.map +1 -1
  49. package/dist/dynamic-form-schema.js +15 -3
  50. package/dist/dynamic-form.d.ts +16 -1
  51. package/dist/dynamic-form.d.ts.map +1 -1
  52. package/dist/dynamic-form.js +81 -20
  53. package/dist/dynamic-kanban.d.ts +9 -3
  54. package/dist/dynamic-kanban.d.ts.map +1 -1
  55. package/dist/dynamic-kanban.js +39 -13
  56. package/dist/dynamic-line-items.d.ts.map +1 -1
  57. package/dist/dynamic-line-items.js +3 -0
  58. package/dist/dynamic-multi-select-field.d.ts.map +1 -1
  59. package/dist/dynamic-multi-select-field.js +2 -0
  60. package/dist/dynamic-relation-helpers.d.ts.map +1 -1
  61. package/dist/dynamic-relation-helpers.js +8 -0
  62. package/dist/dynamic-relation.js +1 -1
  63. package/dist/dynamic-select-field.d.ts.map +1 -1
  64. package/dist/dynamic-select-field.js +4 -0
  65. package/dist/index.d.ts +8 -2
  66. package/dist/index.d.ts.map +1 -1
  67. package/dist/index.js +17 -2
  68. package/dist/installed-addons-context.d.ts +15 -0
  69. package/dist/installed-addons-context.d.ts.map +1 -0
  70. package/dist/installed-addons-context.js +39 -0
  71. package/dist/option-filter.d.ts +31 -0
  72. package/dist/option-filter.d.ts.map +1 -0
  73. package/dist/option-filter.js +49 -0
  74. package/dist/org-runtime-context.d.ts +8 -0
  75. package/dist/org-runtime-context.d.ts.map +1 -1
  76. package/dist/org-runtime-context.js +8 -0
  77. package/dist/org-runtime-provider.d.ts +3 -1
  78. package/dist/org-runtime-provider.d.ts.map +1 -1
  79. package/dist/org-runtime-provider.js +3 -3
  80. package/dist/primitives/aging.d.ts +34 -0
  81. package/dist/primitives/aging.d.ts.map +1 -0
  82. package/dist/primitives/aging.js +48 -0
  83. package/dist/primitives/allocation.d.ts +42 -0
  84. package/dist/primitives/allocation.d.ts.map +1 -0
  85. package/dist/primitives/allocation.js +59 -0
  86. package/dist/primitives/approvals.d.ts +71 -0
  87. package/dist/primitives/approvals.d.ts.map +1 -0
  88. package/dist/primitives/approvals.js +48 -0
  89. package/dist/primitives/contributions.d.ts +82 -0
  90. package/dist/primitives/contributions.d.ts.map +1 -0
  91. package/dist/primitives/contributions.js +126 -0
  92. package/dist/primitives/document-kinds.d.ts +25 -0
  93. package/dist/primitives/document-kinds.d.ts.map +1 -0
  94. package/dist/primitives/document-kinds.js +26 -0
  95. package/dist/primitives/index.d.ts +8 -0
  96. package/dist/primitives/index.d.ts.map +1 -0
  97. package/dist/primitives/index.js +23 -0
  98. package/dist/primitives/panels.d.ts +68 -0
  99. package/dist/primitives/panels.d.ts.map +1 -0
  100. package/dist/primitives/panels.js +3 -0
  101. package/dist/primitives/use-contributions.d.ts +15 -0
  102. package/dist/primitives/use-contributions.d.ts.map +1 -0
  103. package/dist/primitives/use-contributions.js +30 -0
  104. package/dist/record-prefill-bar.d.ts +11 -0
  105. package/dist/record-prefill-bar.d.ts.map +1 -0
  106. package/dist/record-prefill-bar.js +33 -0
  107. package/dist/types.d.ts +142 -0
  108. package/dist/types.d.ts.map +1 -1
  109. package/dist/use-options-resolver.d.ts +8 -0
  110. package/dist/use-options-resolver.d.ts.map +1 -1
  111. package/dist/use-options-resolver.js +8 -2
  112. package/package.json +5 -5
  113. package/src/__tests__/action-modal-grid-layout.test.tsx +1 -1
  114. package/src/__tests__/apply-sidebar-layout.test.ts +1 -1
  115. package/src/__tests__/audit-info.test.tsx +103 -0
  116. package/src/__tests__/catalog-product-search.test.ts +61 -0
  117. package/src/__tests__/dependent-options.test.tsx +12 -5
  118. package/src/__tests__/document-editor-model.test.ts +167 -0
  119. package/src/__tests__/document-editor.test.tsx +261 -0
  120. package/src/__tests__/document-form-dialog.test.tsx +118 -3
  121. package/src/__tests__/dynamic-form-select-edit.test.tsx +155 -0
  122. package/src/__tests__/dynamic-kanban.test.tsx +24 -3
  123. package/src/__tests__/dynamic-record-extension-label.test.tsx +88 -0
  124. package/src/__tests__/dynamic-table-infinite-scroll.test.tsx +4 -0
  125. package/src/__tests__/installed-addons-context.test.tsx +50 -0
  126. package/src/__tests__/line-item-totals.test.ts +28 -0
  127. package/src/__tests__/line-items-lock-rows.test.tsx +2 -1
  128. package/src/__tests__/option-filter.test.tsx +115 -0
  129. package/src/__tests__/primitives-federated.test.tsx +156 -0
  130. package/src/__tests__/primitives.test.ts +224 -0
  131. package/src/__tests__/record-prefill-bar.test.tsx +50 -0
  132. package/src/__tests__/structured-view-value.test.tsx +5 -1
  133. package/src/__tests__/wizard-action-modal.test.tsx +1 -1
  134. package/src/action-modal-dispatcher.tsx +47 -4
  135. package/src/audit-info.tsx +219 -0
  136. package/src/business/catalog-product-search.ts +87 -0
  137. package/src/business/catalog.ts +2 -0
  138. package/src/business/document-editor-model.ts +325 -0
  139. package/src/business/document-editor-panels.tsx +164 -0
  140. package/src/business/document-editor.tsx +727 -0
  141. package/src/business/document-lines.ts +5 -1
  142. package/src/business/index.ts +5 -0
  143. package/src/business/line-items.ts +15 -1
  144. package/src/business/payment-allocator.tsx +110 -0
  145. package/src/business/product-search.ts +4 -0
  146. package/src/dialogs/dynamic-record.tsx +42 -6
  147. package/src/document-form-dialog.tsx +92 -12
  148. package/src/dropdown-menu-entry.test.ts +23 -0
  149. package/src/dynamic-columns-helpers.ts +22 -0
  150. package/src/dynamic-columns.tsx +23 -6
  151. package/src/dynamic-crud-page.tsx +22 -3
  152. package/src/dynamic-form-schema.ts +15 -2
  153. package/src/dynamic-form.tsx +120 -39
  154. package/src/dynamic-kanban.tsx +41 -10
  155. package/src/dynamic-line-items.tsx +3 -0
  156. package/src/dynamic-multi-select-field.tsx +2 -0
  157. package/src/dynamic-relation-helpers.ts +9 -0
  158. package/src/dynamic-relation.tsx +7 -2
  159. package/src/dynamic-select-field.tsx +4 -0
  160. package/src/index.ts +34 -1
  161. package/src/installed-addons-context.tsx +58 -0
  162. package/src/option-filter.ts +88 -0
  163. package/src/org-runtime-context.ts +10 -0
  164. package/src/org-runtime-provider.tsx +7 -2
  165. package/src/primitives/aging.ts +76 -0
  166. package/src/primitives/allocation.ts +104 -0
  167. package/src/primitives/approvals.ts +103 -0
  168. package/src/primitives/contributions.ts +208 -0
  169. package/src/primitives/document-kinds.ts +62 -0
  170. package/src/primitives/index.ts +23 -0
  171. package/src/primitives/panels.ts +59 -0
  172. package/src/primitives/use-contributions.ts +42 -0
  173. package/src/record-prefill-bar.tsx +62 -0
  174. package/src/row-action-stage-gate.test.ts +33 -0
  175. package/src/types.ts +142 -0
  176. package/src/use-options-resolver.ts +19 -1
  177. package/vitest.config.ts +1 -0
  178. package/vitest.setup.ts +7 -0
package/src/types.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import type { OptionFilter } from './option-filter'
1
2
  // Shared metadata shape consumed by every host. Some hosts add a `link`
2
3
  // action type with a `linkUrl` template — represented here as part of the
3
4
  // `type` union so the SDK can render it uniformly.
@@ -34,6 +35,40 @@ export interface DocumentFormLines {
34
35
  required?: boolean
35
36
  /** Título del paso. Default «Renglones». */
36
37
  title?: string
38
+ /**
39
+ * Qué captura el grid (ver primitives/document-kinds LinesMode). Default `sale`.
40
+ * `allocation` cambia el grid por PaymentAllocator (documentos abiertos de la
41
+ * contraparte); `credit` limita cantidades a facturado − acreditado.
42
+ */
43
+ kind?: 'sale' | 'purchase' | 'credit' | 'allocation' | 'workorder'
44
+ /** Solo `kind: allocation`: de dónde salen los documentos abiertos. */
45
+ open_documents?: DocumentFormOpenDocuments
46
+ /**
47
+ * Cómo se captura el descuento: `percent` (default del grid), `amount`
48
+ * (importe) o `both`. Debe coincidir con la fórmula del modelo de renglones:
49
+ * si el backend calcula `quantity * unit_price - discount`, declara `amount`
50
+ * (con `percent` un 10 % se restaría como $10).
51
+ */
52
+ discount_mode?: 'percent' | 'amount' | 'both'
53
+ }
54
+
55
+ /** Documentos con saldo de la contraparte para PaymentAllocator. */
56
+ export interface DocumentFormOpenDocuments {
57
+ /** Modelo (p. ej. `customers.Invoice`, `purchases.SupplierInvoice`). */
58
+ model: string
59
+ /** Campo del documento que apunta a la contraparte (`customer_id`). */
60
+ party_field: string
61
+ balance_field: string
62
+ number_field: string
63
+ total_field?: string
64
+ due_field?: string
65
+ issued_field?: string
66
+ /** Columna con el método (PUE/PPD…); el núcleo solo la muestra. */
67
+ method_field?: string
68
+ /** Campo del renglón de la acción donde va el id y el monto (`invoice_id`, `amount`). */
69
+ line_document_field: string
70
+ line_amount_field: string
71
+ option_filter?: unknown
37
72
  }
38
73
 
39
74
  /** Un tipo de documento (Factura, Nota de crédito, REP, Global, Traslado…). */
@@ -54,6 +89,67 @@ export interface DocumentFormType {
54
89
  endpoint?: string
55
90
  /** Texto del botón final. Default «Crear». */
56
91
  submit_label?: string
92
+ /**
93
+ * `wizard` (default: Datos → Siguiente → Renglones) o `editor`: UNA pantalla
94
+ * por secciones (contraparte, origen, renglones o reparto, totales, «Opciones
95
+ * fiscales» plegadas, vista previa opcional). Ver DocumentEditor.
96
+ */
97
+ layout?: 'wizard' | 'editor'
98
+ /** Contraparte del documento (cliente / proveedor). Solo `layout: editor`. */
99
+ party?: DocumentFormParty
100
+ /** «Cargar desde…»: documentos origen cuyos renglones se copian. */
101
+ sources?: DocumentFormSource[]
102
+ /** Vista previa / validación previa (acción del modelo con `analyze: true`). */
103
+ preview?: DocumentFormPreview
104
+ /**
105
+ * Guardar llamando a una acción del modelo (placement `create`) en vez del
106
+ * create genérico. P. ej. Payment → `collect_multi_payment_create`, que ya
107
+ * reparte el pago en PaymentAllocation dentro de una transacción.
108
+ */
109
+ submit_action?: string
110
+ }
111
+
112
+ /** Contraparte: qué campo del encabezado la elige y qué muestra su tarjeta. */
113
+ export interface DocumentFormParty {
114
+ /** Campo del encabezado (dynamic_select) con el id. P. ej. `customer_id`. */
115
+ field: string
116
+ /** Modelo de la contraparte. P. ej. `customers.Customer`. */
117
+ model: string
118
+ /** Endpoint de lectura. Default `/data/<model>`. */
119
+ endpoint?: string
120
+ /** Columnas de la tarjeta; además se muestran las extensiones `fiscal_data.*`. */
121
+ summary?: string[]
122
+ /** Columnas de crédito/saldo (si existen en el modelo). */
123
+ credit?: { limit?: string; balance?: string; overdue?: string; hold_reason?: string }
124
+ }
125
+
126
+ /** Un documento origen para «Cargar desde…». */
127
+ export interface DocumentFormSource {
128
+ key: string
129
+ label: string
130
+ /** Modelo origen (p. ej. `quotes.Quote`). Si el addon no está, se oculta. */
131
+ model: string
132
+ /** Relación one_to_many con los renglones (p. ej. `items`). */
133
+ lines: string
134
+ /** Mapeo renglón origen → LineItem (`description: product_name`, `discount: discount_pct`…). */
135
+ map?: Record<string, string>
136
+ /** Campos del encabezado que se copian del origen (`customer_id: customer_id`). */
137
+ header?: Record<string, string>
138
+ /** Campo del documento que guarda el vínculo (p. ej. `sales_order_id`). */
139
+ link_field?: string
140
+ /** Filtro de opciones del selector del origen (mismo contrato que option_filter). */
141
+ option_filter?: unknown
142
+ /** Addon requerido (gating de UI; el servidor revalida). */
143
+ requires_addon?: string
144
+ }
145
+
146
+ /** Vista previa: acción de fila sobre el borrador, llamada con `analyze: true`. */
147
+ export interface DocumentFormPreview {
148
+ /** Clave de la acción (p. ej. `preview_cfdi`, de fiscal_mexico). */
149
+ action: string
150
+ /** Addon que la aporta (si no está instalado, el panel muestra solo totales). */
151
+ requires_addon?: string
152
+ label?: string
57
153
  }
58
154
 
59
155
  export interface DocumentFormsManifest {
@@ -64,6 +160,21 @@ export interface DocumentFormsManifest {
64
160
  types: DocumentFormType[]
65
161
  }
66
162
 
163
+ /**
164
+ * Audit columns of a model, served by the kernel (>= v0.188) on the table
165
+ * metadata. Each value is the COLUMN NAME (the key in the row), not a value;
166
+ * a key is omitted when the model lacks that column (append-only ledgers have
167
+ * only `created_*`). Purely additive — older kernels omit `audit` entirely.
168
+ */
169
+ export interface AuditMeta {
170
+ created_at?: string
171
+ created_by?: string
172
+ updated_at?: string
173
+ updated_by?: string
174
+ deleted_at?: string
175
+ deleted_by?: string
176
+ }
177
+
67
178
  export interface TableMetadata {
68
179
  title: string
69
180
  endpoint: string
@@ -78,6 +189,11 @@ export interface TableMetadata {
78
189
  canExport?: boolean
79
190
  canImport?: boolean
80
191
  canCreate?: boolean
192
+ /**
193
+ * Audit columns (when/who) of the model. Feeds `<AuditInfo>`; absent on
194
+ * older kernels or models without audit columns.
195
+ */
196
+ audit?: AuditMeta
81
197
  /**
82
198
  * Formularios de alta guiados por tipo de documento (FAC-12). Cuando trae
83
199
  * al menos un tipo, `DynamicCRUDPage` abre `DocumentFormDialog` en lugar del
@@ -380,6 +496,16 @@ export interface ColumnDefinition {
380
496
  * widgets — `searchEndpoint` stays as the legacy escape hatch.
381
497
  */
382
498
  ref?: string
499
+ /**
500
+ * Hides options of this relation/dynamic picker (e.g. cancelled invoices in
501
+ * the payments selector). One rule or a list (AND), tested client-side
502
+ * against the option's extra columns (`meta`): `{ field: 'status', not_in:
503
+ * ['cancelada'] }`. The options endpoint must return that column. Absent →
504
+ * the picker lists everything (retrocompat). See `option-filter.ts`.
505
+ */
506
+ optionFilter?: OptionFilter
507
+ /** snake_case alias served by the kernel manifest for `optionFilter`. */
508
+ option_filter?: OptionFilter
383
509
  /**
384
510
  * Write-time rules the SDK also pre-flights. Object form `{regex,min,max,custom}`
385
511
  * or a Laravel / go-playground string (`required|min:2|email`).
@@ -526,6 +652,12 @@ export interface ActionFieldDef {
526
652
  label: string
527
653
  type: string
528
654
  required?: boolean
655
+ /**
656
+ * Campo de solo lectura (escrito por el servidor/sistema): `DynamicForm` lo
657
+ * oculta y lo excluye de defaults y submit. Acepta el alias `readOnly`.
658
+ */
659
+ readonly?: boolean
660
+ readOnly?: boolean
529
661
  /**
530
662
  * Explicit nullability flag served by the kernel (v0.77.1+) from
531
663
  * `modelbase.FieldDef.Nullable` (populated as `!Required`). An optional `ref`
@@ -546,6 +678,16 @@ export interface ActionFieldDef {
546
678
  * `useOptionsResolver` against `/api/options/<ref>?field=id`.
547
679
  */
548
680
  ref?: string
681
+ /**
682
+ * Hides options of this relation/dynamic picker (e.g. cancelled invoices in
683
+ * the payments selector). One rule or a list (AND), tested client-side
684
+ * against the option's extra columns (`meta`): `{ field: 'status', not_in:
685
+ * ['cancelada'] }`. The options endpoint must return that column. Absent →
686
+ * the picker lists everything (retrocompat). See `option-filter.ts`.
687
+ */
688
+ optionFilter?: OptionFilter
689
+ /** snake_case alias served by the kernel manifest for `optionFilter`. */
690
+ option_filter?: OptionFilter
549
691
  /**
550
692
  * snake_case aliases the kernel manifest may serve for a belongs_to FK
551
693
  * target instead of `ref`. Treated as equivalent to `ref` by the SDK so a
@@ -12,6 +12,7 @@
12
12
  // free; legacy callers that still ship `searchEndpoint` keep working.
13
13
  import { useEffect, useMemo, useRef, useState } from 'react'
14
14
  import { useApi } from './api-context'
15
+ import { applyOptionFilter, type OptionFilterRule } from './option-filter'
15
16
  import { loadQueryPart, optionsBatchToken, optionsModelFromUrl } from './query-batch'
16
17
 
17
18
  export interface ResolvedOption {
@@ -90,6 +91,13 @@ export interface UseOptionsResolverArgs {
90
91
  * `fieldKey` / `query` / `limit` exactly the same way.
91
92
  */
92
93
  endpoint?: string
94
+ /**
95
+ * Client-side rules that hide fetched options (see `option-filter.ts`).
96
+ * Empty/undefined → no filtering (retrocompat).
97
+ */
98
+ optionFilter?: OptionFilterRule[]
99
+ /** Current selection: never hidden by `optionFilter`, so its label survives. */
100
+ keepValue?: unknown
93
101
  }
94
102
 
95
103
  export interface UseOptionsResolverResult {
@@ -182,6 +190,8 @@ export function useOptionsResolver(args: UseOptionsResolverArgs): UseOptionsReso
182
190
  enabled = true,
183
191
  endpoint,
184
192
  filterValue,
193
+ optionFilter,
194
+ keepValue,
185
195
  } = args
186
196
 
187
197
  const api = useApi()
@@ -322,8 +332,16 @@ export function useOptionsResolver(args: UseOptionsResolverArgs): UseOptionsReso
322
332
  }
323
333
  }, [api, url, effectiveField, query, limit, enabled, filterValue, refreshKey])
324
334
 
335
+ // Rules arrive as a fresh array each render; key on their content.
336
+ const filterKey = optionFilter && optionFilter.length > 0 ? JSON.stringify(optionFilter) : ''
337
+ const visibleOptions = useMemo(
338
+ () => (filterKey ? applyOptionFilter(options, optionFilter ?? [], keepValue) : options),
339
+ // eslint-disable-next-line react-hooks/exhaustive-deps
340
+ [options, filterKey, keepValue],
341
+ )
342
+
325
343
  return {
326
- options,
344
+ options: visibleOptions,
327
345
  meta,
328
346
  loading,
329
347
  error,
package/vitest.config.ts CHANGED
@@ -5,5 +5,6 @@ export default defineConfig({
5
5
  environment: 'node',
6
6
  include: ['src/**/*.test.ts', 'src/**/*.test.tsx'],
7
7
  setupFiles: ['./vitest.setup.ts'],
8
+ testTimeout: 15000,
8
9
  },
9
10
  })
package/vitest.setup.ts CHANGED
@@ -27,3 +27,10 @@ function installMemoryStorage(name: 'localStorage' | 'sessionStorage') {
27
27
 
28
28
  installMemoryStorage('localStorage')
29
29
  installMemoryStorage('sessionStorage')
30
+
31
+ // `waitFor` defaults to 1s; the DynamicTable/DynamicKanban suites render large
32
+ // trees and miss it when the whole monorepo's tests run in parallel (turbo).
33
+ // A longer ceiling only affects failing waits, passing tests return immediately.
34
+ import { configure } from '@testing-library/react'
35
+
36
+ configure({ asyncUtilTimeout: 5000 })