@asteby/metacore-runtime-react 28.8.0 → 29.0.1
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/CHANGELOG.md +31 -0
- package/dist/action-modal-dispatcher.js +1 -1
- package/dist/dialogs/dynamic-record.d.ts.map +1 -1
- package/dist/dialogs/dynamic-record.js +1 -1
- package/dist/dynamic-relation.d.ts +4 -0
- package/dist/dynamic-relation.d.ts.map +1 -1
- package/dist/dynamic-relation.js +119 -16
- package/dist/dynamic-relations.d.ts +22 -1
- package/dist/dynamic-relations.d.ts.map +1 -1
- package/dist/dynamic-relations.js +16 -3
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/types.d.ts +9 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/__tests__/relation-embed-gate.test.tsx +110 -0
- package/src/action-modal-dispatcher.tsx +3 -1
- package/src/dialogs/dynamic-record.tsx +6 -1
- package/src/dynamic-relation.tsx +165 -23
- package/src/dynamic-relations.tsx +34 -2
- package/src/index.ts +1 -0
- package/src/types.ts +9 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,36 @@
|
|
|
1
1
|
# @asteby/metacore-runtime-react
|
|
2
2
|
|
|
3
|
+
## 29.0.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- be357ff: fix(runtime-react): las sub-tablas de relación resuelven las columnas `ref` al
|
|
8
|
+
nombre del registro en vez del uuid crudo.
|
|
9
|
+
|
|
10
|
+
`OneToManyRelation` construía sus columnas sin precargar las opciones de las
|
|
11
|
+
columnas `ref` (a diferencia de `<DynamicTable>`, que las mete en `OptionsContext`),
|
|
12
|
+
así que una celda `ref` (p.ej. el Producto de un renglón de orden de compra)
|
|
13
|
+
mostraba el uuid. Ahora la sub-tabla precarga `/api/options/<Model>` de sus
|
|
14
|
+
columnas `useOptions && searchEndpoint` y las provee vía `OptionsContext.Provider`,
|
|
15
|
+
igual que la tabla principal — el chip muestra "Nombre / SKU".
|
|
16
|
+
|
|
17
|
+
## 29.0.0
|
|
18
|
+
|
|
19
|
+
### Minor Changes
|
|
20
|
+
|
|
21
|
+
- 13ef5ed: Subtablas de relación: embebido opt-in (`embed`) + paginación y búsqueda
|
|
22
|
+
|
|
23
|
+
El modal de registro embebía TODAS las relaciones `one_to_many` del modelo, y cada subtabla pedía el modelo hijo completo (`/data/<hijo>?f_<fk>=eq:<id>`, sin `page`/`per_page`). Abrir "Editar Almacén" cargaba miles de existencias y traspasos dentro de un formulario.
|
|
24
|
+
|
|
25
|
+
- `DynamicRelations` acepta `embedOnly`: filtra por `RelationMeta.embed` (nuevo, servido por el kernel). Lo pasan los dos modales — el de registro y el de acción. La página de detalle autónoma sigue mostrando todas las relaciones.
|
|
26
|
+
- `RelationMeta.embed?: boolean` en los tipos; ausente = no embebe (tolera kernels que aún no lo sirven).
|
|
27
|
+
- `OneToManyRelation` pagina server-side (`page`/`per_page`, 25 por página) con scroll infinito, buscador server-side (`search`, con debounce), contador "cargadas de total" y scroll propio acotado en alto.
|
|
28
|
+
|
|
29
|
+
### Patch Changes
|
|
30
|
+
|
|
31
|
+
- Updated dependencies [e801041]
|
|
32
|
+
- @asteby/metacore-ui@2.13.0
|
|
33
|
+
|
|
3
34
|
## 28.8.0
|
|
4
35
|
|
|
5
36
|
### Minor Changes
|
|
@@ -458,7 +458,7 @@ function GenericActionModal({ open, onOpenChange, action, model, record, endpoin
|
|
|
458
458
|
resolveWidget(field) === 'textarea' ||
|
|
459
459
|
resolveWidget(field) === 'richtext';
|
|
460
460
|
return (_jsxs(FieldCell, { fullWidth: fullWidth, children: [_jsx(FieldLabel, { htmlFor: field.key, required: field.required, children: tl(field.label) }), renderField(field, formData[field.key], (v) => updateField(field.key, v), formData), fieldErrors[field.key] && (_jsx("p", { className: "text-destructive text-xs mt-1", children: fieldErrors[field.key] }))] }, field.key));
|
|
461
|
-
}), relations.length > 0 && (_jsx(FieldCell, { fullWidth: true, children: _jsx(DynamicRelations, { record: record, relations: relations, lineSubtable: true }) }))] }) }), _jsxs(DialogFooter, { className: "shrink-0", children: [_jsx(Button, { variant: "outline", onClick: () => onOpenChange(false), disabled: executing, children: t('common.cancel') }), _jsxs(Button, { onClick: execute, disabled: executing, style: action.color ? { backgroundColor: action.color, color: 'white' } : undefined, children: [executing ? _jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }) : _jsx(DynamicIcon, { name: action.icon, className: "mr-2 h-4 w-4" }), tl(action.label)] })] })] }) }));
|
|
461
|
+
}), relations.length > 0 && (_jsx(FieldCell, { fullWidth: true, children: _jsx(DynamicRelations, { record: record, relations: relations, lineSubtable: true, embedOnly: true }) }))] }) }), _jsxs(DialogFooter, { className: "shrink-0", children: [_jsx(Button, { variant: "outline", onClick: () => onOpenChange(false), disabled: executing, children: t('common.cancel') }), _jsxs(Button, { onClick: execute, disabled: executing, style: action.color ? { backgroundColor: action.color, color: 'white' } : undefined, children: [executing ? _jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }) : _jsx(DynamicIcon, { name: action.icon, className: "mr-2 h-4 w-4" }), tl(action.label)] })] })] }) }));
|
|
462
462
|
}
|
|
463
463
|
// buildFieldDefaults seeds formData for a set of action fields, honoring the
|
|
464
464
|
// same line-items prefill spec + boolean/empty rules GenericActionModal uses, so
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dynamic-record.d.ts","sourceRoot":"","sources":["../../src/dialogs/dynamic-record.tsx"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"dynamic-record.d.ts","sourceRoot":"","sources":["../../src/dialogs/dynamic-record.tsx"],"names":[],"mappings":"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"}
|
|
@@ -638,7 +638,7 @@ export function DynamicRecordDialog({ open, onOpenChange, mode, model, recordId,
|
|
|
638
638
|
setStepIndex(Math.min(clampedStep + 1, groups.length - 1));
|
|
639
639
|
};
|
|
640
640
|
const goBackStep = () => setStepIndex(Math.max(clampedStep - 1, 0));
|
|
641
|
-
return (_jsx(Dialog, { open: open, onOpenChange: onOpenChange, children: _jsxs(DialogContent, { className: "sm:max-w-2xl max-h-[90vh] flex flex-col p-0 gap-0 overflow-hidden", children: [_jsxs(DialogHeader, { className: "p-6 pb-4 border-b shrink-0", children: [_jsx(DialogTitle, { children: title }), _jsx(DialogDescription, { children: config.description })] }), _jsx("div", { className: "flex-1 overflow-y-auto p-6", children: loading ? (_jsx(LoadingSkeleton, {})) : modalMeta ? (_jsx(ModelContext.Provider, { value: model, children: _jsx(ImageUrlContext.Provider, { value: getImageUrl, children: _jsx(TimeZoneContext.Provider, { value: timeZone, children: _jsxs(CurrencyContext.Provider, { value: currency, children: [_jsxs("form", { id: "dynamic-record-form", onSubmit: handleSubmit, className: "grid gap-y-4", children: [isSteps && (_jsx(WizardProgress, { groups: groups, stepIndex: clampedStep })), (isSteps ? [groups[clampedStep]] : groups).map(group => (_jsx(FieldSection, { group: group, children: _jsx("div", { className: "grid grid-cols-1 gap-x-6 gap-y-4 sm:grid-cols-2", children: renderFields(group.fields) }) }, group.key))), record?.external_url && (_jsx("div", { className: "grid grid-cols-1 sm:grid-cols-2", children: _jsx("div", { className: "sm:col-span-2 min-w-0", children: _jsxs("a", { href: record.external_url, target: "_blank", rel: "noreferrer", className: "inline-flex items-center gap-1.5 text-sm text-primary hover:underline mt-1", children: [_jsx(ExternalLink, { className: "h-3.5 w-3.5" }), "Ver en ", record.external_provider ?? 'proveedor externo'] }) }) }))] }), !isCreate && record && relations.length > 0 && (_jsx("div", { className: "mt-6", children: _jsx(DynamicRelations, { record: record, relations: relations, lineSubtable: true, canCreate: mode === 'edit', canEdit: mode === 'edit', canDelete: mode === 'edit', onChange: handleChildChange }) }))] }) }) }) })) : null }), _jsxs(DialogFooter, { className: "p-4 border-t shrink-0 sm:justify-between", children: [isView && onOpenFullPage ? (_jsxs(Button, { variant: "ghost", size: "sm", className: "text-muted-foreground", onClick: () => { onOpenChange(false); onOpenFullPage(); }, children: [_jsx(ExternalLink, { className: "mr-1.5 h-3.5 w-3.5" }), "Ver p\u00E1gina completa"] })) : _jsx("span", {}), _jsxs("div", { className: "flex items-center gap-2", children: [isSteps && clampedStep > 0 ? (_jsx(Button, { variant: "outline", onClick: goBackStep, disabled: saving || deleting, children: "Anterior" })) : (_jsx(Button, { variant: "outline", onClick: () => onOpenChange(false), disabled: saving || deleting, children: config.cancelLabel })), isView && onDelete && (_jsxs(Button, { variant: "destructive", onClick: handleDelete, disabled: deleting || loading, children: [deleting && _jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }), deleting ? 'Eliminando...' : 'Eliminar'] })), isView && onEdit && (_jsx(Button, { onClick: onEdit, disabled: deleting || loading, children: "Editar" })), isEditable && isSteps && !isLastStep && (_jsx(Button, { type: "button", onClick: goNextStep, disabled: saving || loading, children: "Siguiente" })), isEditable && (!isSteps || isLastStep) && (_jsxs(Button, { type: "submit", form: "dynamic-record-form", disabled: saving || loading, children: [saving && _jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }), saving ? config.submittingLabel : config.submitLabel] }))] })] })] }) }));
|
|
641
|
+
return (_jsx(Dialog, { open: open, onOpenChange: onOpenChange, children: _jsxs(DialogContent, { className: "sm:max-w-2xl max-h-[90vh] flex flex-col p-0 gap-0 overflow-hidden", children: [_jsxs(DialogHeader, { className: "p-6 pb-4 border-b shrink-0", children: [_jsx(DialogTitle, { children: title }), _jsx(DialogDescription, { children: config.description })] }), _jsx("div", { className: "flex-1 overflow-y-auto p-6", children: loading ? (_jsx(LoadingSkeleton, {})) : modalMeta ? (_jsx(ModelContext.Provider, { value: model, children: _jsx(ImageUrlContext.Provider, { value: getImageUrl, children: _jsx(TimeZoneContext.Provider, { value: timeZone, children: _jsxs(CurrencyContext.Provider, { value: currency, children: [_jsxs("form", { id: "dynamic-record-form", onSubmit: handleSubmit, className: "grid gap-y-4", children: [isSteps && (_jsx(WizardProgress, { groups: groups, stepIndex: clampedStep })), (isSteps ? [groups[clampedStep]] : groups).map(group => (_jsx(FieldSection, { group: group, children: _jsx("div", { className: "grid grid-cols-1 gap-x-6 gap-y-4 sm:grid-cols-2", children: renderFields(group.fields) }) }, group.key))), record?.external_url && (_jsx("div", { className: "grid grid-cols-1 sm:grid-cols-2", children: _jsx("div", { className: "sm:col-span-2 min-w-0", children: _jsxs("a", { href: record.external_url, target: "_blank", rel: "noreferrer", className: "inline-flex items-center gap-1.5 text-sm text-primary hover:underline mt-1", children: [_jsx(ExternalLink, { className: "h-3.5 w-3.5" }), "Ver en ", record.external_provider ?? 'proveedor externo'] }) }) }))] }), !isCreate && record && relations.length > 0 && (_jsx("div", { className: "mt-6", children: _jsx(DynamicRelations, { record: record, relations: relations, lineSubtable: true, embedOnly: true, canCreate: mode === 'edit', canEdit: mode === 'edit', canDelete: mode === 'edit', onChange: handleChildChange }) }))] }) }) }) })) : null }), _jsxs(DialogFooter, { className: "p-4 border-t shrink-0 sm:justify-between", children: [isView && onOpenFullPage ? (_jsxs(Button, { variant: "ghost", size: "sm", className: "text-muted-foreground", onClick: () => { onOpenChange(false); onOpenFullPage(); }, children: [_jsx(ExternalLink, { className: "mr-1.5 h-3.5 w-3.5" }), "Ver p\u00E1gina completa"] })) : _jsx("span", {}), _jsxs("div", { className: "flex items-center gap-2", children: [isSteps && clampedStep > 0 ? (_jsx(Button, { variant: "outline", onClick: goBackStep, disabled: saving || deleting, children: "Anterior" })) : (_jsx(Button, { variant: "outline", onClick: () => onOpenChange(false), disabled: saving || deleting, children: config.cancelLabel })), isView && onDelete && (_jsxs(Button, { variant: "destructive", onClick: handleDelete, disabled: deleting || loading, children: [deleting && _jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }), deleting ? 'Eliminando...' : 'Eliminar'] })), isView && onEdit && (_jsx(Button, { onClick: onEdit, disabled: deleting || loading, children: "Editar" })), isEditable && isSteps && !isLastStep && (_jsx(Button, { type: "button", onClick: goNextStep, disabled: saving || loading, children: "Siguiente" })), isEditable && (!isSteps || isLastStep) && (_jsxs(Button, { type: "submit", form: "dynamic-record-form", disabled: saving || loading, children: [saving && _jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }), saving ? config.submittingLabel : config.submitLabel] }))] })] })] }) }));
|
|
642
642
|
}
|
|
643
643
|
function LoadingSkeleton() {
|
|
644
644
|
return (_jsx("div", { className: "grid grid-cols-1 sm:grid-cols-2 gap-x-6 gap-y-4", children: Array.from({ length: 6 }).map((_, i) => (_jsxs("div", { className: "flex flex-col gap-1.5", children: [_jsx(Skeleton, { className: "h-3.5 w-24" }), _jsx(Skeleton, { className: "h-9 w-full" })] }, i))) }));
|
|
@@ -13,6 +13,10 @@ export interface DynamicRelationStrings {
|
|
|
13
13
|
selectPlaceholder: string;
|
|
14
14
|
selectSearchPlaceholder: string;
|
|
15
15
|
selectEmpty: string;
|
|
16
|
+
/** Placeholder del buscador de la sub-tabla 1:N. */
|
|
17
|
+
searchPlaceholder: string;
|
|
18
|
+
/** Pie de la sub-tabla: "{{loaded}} de {{total}}". */
|
|
19
|
+
countLabel: string;
|
|
16
20
|
}
|
|
17
21
|
interface CommonProps {
|
|
18
22
|
/** id del registro padre. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dynamic-relation.d.ts","sourceRoot":"","sources":["../src/dynamic-relation.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"dynamic-relation.d.ts","sourceRoot":"","sources":["../src/dynamic-relation.tsx"],"names":[],"mappings":"AAmEA,YAAY,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAA;AACrE,OAAO,EACH,kBAAkB,EAClB,uBAAuB,EACvB,kBAAkB,EAClB,yBAAyB,EACzB,wBAAwB,EACxB,aAAa,EACb,wBAAwB,EACxB,kBAAkB,EAClB,WAAW,EACX,eAAe,EACf,cAAc,GACjB,MAAM,4BAA4B,CAAA;AAEnC,MAAM,WAAW,sBAAsB;IACnC,KAAK,EAAE,MAAM,CAAA;IACb,UAAU,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;IACjB,WAAW,EAAE,MAAM,CAAA;IACnB,kBAAkB,EAAE,MAAM,CAAA;IAC1B,wBAAwB,EAAE,MAAM,CAAA;IAChC,WAAW,EAAE,MAAM,CAAA;IACnB,SAAS,EAAE,MAAM,CAAA;IACjB,iBAAiB,EAAE,MAAM,CAAA;IACzB,uBAAuB,EAAE,MAAM,CAAA;IAC/B,WAAW,EAAE,MAAM,CAAA;IACnB,oDAAoD;IACpD,iBAAiB,EAAE,MAAM,CAAA;IACzB,sDAAsD;IACtD,UAAU,EAAE,MAAM,CAAA;CACrB;AAwBD,UAAU,WAAW;IACjB,6BAA6B;IAC7B,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAA;IACzB;;;;;;OAMG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAChC,+DAA+D;IAC/D,aAAa,CAAC,EAAE,MAAM,EAAE,CAAA;IACxB;;;;;;;;;;OAUG;IACH,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,uCAAuC;IACvC,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,qCAAqC;IACrC,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,2BAA2B;IAC3B,OAAO,CAAC,EAAE,OAAO,CAAC,sBAAsB,CAAC,CAAA;IACzC,yBAAyB;IACzB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,+DAA+D;IAC/D,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAA;CACxB;AAED,MAAM,WAAW,6BAA8B,SAAQ,WAAW;IAC9D,IAAI,EAAE,aAAa,CAAA;IACnB,yFAAyF;IACzF,KAAK,EAAE,MAAM,CAAA;IACb,kDAAkD;IAClD,UAAU,EAAE,MAAM,CAAA;IAClB,mDAAmD;IACnD,QAAQ,CAAC,EAAE,MAAM,CAAA;CACpB;AAED,MAAM,WAAW,8BAA+B,SAAQ,WAAW;IAC/D,IAAI,EAAE,cAAc,CAAA;IACpB,wEAAwE;IACxE,OAAO,EAAE,MAAM,CAAA;IACf,sEAAsE;IACtE,UAAU,EAAE,MAAM,CAAA;IAClB,6BAA6B;IAC7B,UAAU,EAAE,MAAM,CAAA;IAClB,oEAAoE;IACpE,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,mEAAmE;IACnE,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,uEAAuE;IACvE,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;CACtB;AAED,MAAM,MAAM,oBAAoB,GAC1B,6BAA6B,GAC7B,8BAA8B,CAAA;AAEpC,wBAAgB,eAAe,CAAC,KAAK,EAAE,oBAAoB,+BAK1D"}
|
package/dist/dynamic-relation.js
CHANGED
|
@@ -4,20 +4,22 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
4
4
|
// - "one_to_many": lista inline editable que cuelga del registro padre.
|
|
5
5
|
// - "many_to_many": multi-select sobre la tabla destino con sync a la pivot.
|
|
6
6
|
// La RFC completa vive en `packages/runtime-react/docs/relations.md`.
|
|
7
|
-
import { useCallback, useEffect, useMemo, useState } from 'react';
|
|
7
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
8
8
|
import { useTranslation } from 'react-i18next';
|
|
9
9
|
import { flexRender, getCoreRowModel, useReactTable, } from '@tanstack/react-table';
|
|
10
10
|
import { cn } from '@asteby/metacore-ui/lib';
|
|
11
|
-
import { Button, Skeleton, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, Dialog, DialogContent, DialogHeader, DialogTitle, MultiSelect, Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from '@asteby/metacore-ui/primitives';
|
|
12
|
-
import { Plus, Trash2, Pencil } from 'lucide-react';
|
|
11
|
+
import { Button, Skeleton, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, Dialog, DialogContent, DialogHeader, DialogTitle, Input, MultiSelect, Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from '@asteby/metacore-ui/primitives';
|
|
12
|
+
import { Plus, Trash2, Pencil, Search } from 'lucide-react';
|
|
13
13
|
import { useApi } from './api-context';
|
|
14
14
|
import { useMetadataCache } from './metadata-cache';
|
|
15
|
+
import { OptionsContext } from './options-context';
|
|
15
16
|
import { DynamicForm } from './dynamic-form';
|
|
16
17
|
import { useImageUrl } from './image-url-context';
|
|
17
18
|
import { useTimeZone, useCurrency } from './org-runtime-context';
|
|
18
19
|
import { makeDefaultGetDynamicColumns } from './dynamic-columns';
|
|
19
20
|
import { isColumnVisibleInLineSubtable } from './column-visibility';
|
|
20
21
|
import { useOptionsResolver } from './use-options-resolver';
|
|
22
|
+
import { dedupeById, useInfiniteScrollSentinel } from './use-infinite-scroll';
|
|
21
23
|
import { buildCreatePayload, buildPivotAttachPayload, buildPivotRowIndex, buildRelationFilterParams, deriveRelationFormFields, diffSelection, extractSelectedTargetIds, pickOptionLabel, relationRowKey, } from './dynamic-relation-helpers';
|
|
22
24
|
export { buildCreatePayload, buildPivotAttachPayload, buildPivotRowIndex, buildRelationFilterParams, deriveRelationFormFields, diffSelection, extractSelectedTargetIds, formatRelationCell, objectLabel, pickOptionLabel, relationRowKey, } from './dynamic-relation-helpers';
|
|
23
25
|
const DEFAULT_STRINGS = {
|
|
@@ -33,7 +35,13 @@ const DEFAULT_STRINGS = {
|
|
|
33
35
|
selectPlaceholder: 'Seleccionar…',
|
|
34
36
|
selectSearchPlaceholder: 'Buscar…',
|
|
35
37
|
selectEmpty: 'Sin resultados.',
|
|
38
|
+
searchPlaceholder: 'Buscar…',
|
|
39
|
+
countLabel: '{{loaded}} de {{total}}',
|
|
36
40
|
};
|
|
41
|
+
// Tamaño de página de la sub-tabla 1:N. Antes la lista pedía el hijo COMPLETO
|
|
42
|
+
// (sin page/per_page), así que abrir un almacén traía todas sus existencias y
|
|
43
|
+
// traspasos. Se pagina de a 25 y el resto entra por scroll infinito.
|
|
44
|
+
const REL_PAGE_SIZE = 25;
|
|
37
45
|
export function DynamicRelation(props) {
|
|
38
46
|
if (props.kind === 'many_to_many') {
|
|
39
47
|
return _jsx(ManyToManyRelation, { ...props });
|
|
@@ -58,8 +66,22 @@ function OneToManyRelation({ kind, model, foreignKey, parentId, filters, endpoin
|
|
|
58
66
|
const cachedMeta = getMetadata(model);
|
|
59
67
|
const labels = { ...DEFAULT_STRINGS, ...(strings || {}) };
|
|
60
68
|
const [metadata, setMetadata] = useState(cachedMeta || null);
|
|
69
|
+
// Options for the ref/relation columns so their cells render the record's
|
|
70
|
+
// NAME (+ SKU subtitle) instead of the raw uuid. The main <DynamicTable>
|
|
71
|
+
// preloads these into OptionsContext; a sub-table skipped it, so a `ref`
|
|
72
|
+
// column (e.g. a purchase order line's Product) showed the bare uuid.
|
|
73
|
+
const [optionsMap, setOptionsMap] = useState(new Map());
|
|
61
74
|
const [rows, setRows] = useState([]);
|
|
62
75
|
const [loading, setLoading] = useState(true);
|
|
76
|
+
// Paginación server-side + scroll infinito, igual que <DynamicTable>.
|
|
77
|
+
const [total, setTotal] = useState(0);
|
|
78
|
+
const [page, setPage] = useState(1);
|
|
79
|
+
const [loadingMore, setLoadingMore] = useState(false);
|
|
80
|
+
// El backend devolvió una página corta: no hay más filas aunque meta.total
|
|
81
|
+
// diga otra cosa (drift count/list dispararía el sentinel para siempre).
|
|
82
|
+
const [exhausted, setExhausted] = useState(false);
|
|
83
|
+
const [search, setSearch] = useState('');
|
|
84
|
+
const [debouncedSearch, setDebouncedSearch] = useState('');
|
|
63
85
|
const [formOpen, setFormOpen] = useState(false);
|
|
64
86
|
const [editingRow, setEditingRow] = useState(null);
|
|
65
87
|
const [rowToDelete, setRowToDelete] = useState(null);
|
|
@@ -69,12 +91,65 @@ function OneToManyRelation({ kind, model, foreignKey, parentId, filters, endpoin
|
|
|
69
91
|
// literal each render). Keeps fetchAll from re-firing on identity churn while
|
|
70
92
|
// still reacting to real scope changes.
|
|
71
93
|
const filtersKey = useMemo(() => (filters ? JSON.stringify(filters) : ''), [filters]);
|
|
72
|
-
|
|
73
|
-
|
|
94
|
+
// La metadata se lee por ref dentro del fetch: si entrara como dependencia,
|
|
95
|
+
// resolverla dispararía un segundo fetch de datos por cada montaje.
|
|
96
|
+
const metadataRef = useRef(metadata);
|
|
97
|
+
metadataRef.current = metadata;
|
|
98
|
+
// Debounce del buscador: cada tecla no puede pegarle al servidor.
|
|
99
|
+
useEffect(() => {
|
|
100
|
+
const id = setTimeout(() => setDebouncedSearch(search.trim()), 300);
|
|
101
|
+
return () => clearTimeout(id);
|
|
102
|
+
}, [search]);
|
|
103
|
+
// Preload the options of the ref/relation columns (same shape <DynamicTable>
|
|
104
|
+
// uses: `useOptions && searchEndpoint`) so their cells resolve the referenced
|
|
105
|
+
// record's name via OptionsContext instead of printing the raw uuid.
|
|
106
|
+
const refEndpointsKey = useMemo(() => {
|
|
107
|
+
const eps = (metadata?.columns || [])
|
|
108
|
+
.filter((c) => c.useOptions && c.searchEndpoint)
|
|
109
|
+
.map((c) => c.searchEndpoint);
|
|
110
|
+
return Array.from(new Set(eps)).sort().join('|');
|
|
111
|
+
}, [metadata]);
|
|
112
|
+
useEffect(() => {
|
|
113
|
+
if (!refEndpointsKey) {
|
|
114
|
+
setOptionsMap((prev) => (prev.size ? new Map() : prev));
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
const endpoints = refEndpointsKey.split('|');
|
|
118
|
+
let cancelled = false;
|
|
119
|
+
void Promise.all(endpoints.map(async (ep) => {
|
|
120
|
+
try {
|
|
121
|
+
const res = (await api.get(ep));
|
|
122
|
+
return [ep, res.data?.success ? res.data.data || [] : []];
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
return [ep, []];
|
|
126
|
+
}
|
|
127
|
+
})).then((entries) => {
|
|
128
|
+
if (!cancelled)
|
|
129
|
+
setOptionsMap(new Map(entries));
|
|
130
|
+
});
|
|
131
|
+
return () => {
|
|
132
|
+
cancelled = true;
|
|
133
|
+
};
|
|
134
|
+
}, [api, refEndpointsKey]);
|
|
135
|
+
const optionsCtx = useMemo(() => ({ optionsMap }), [optionsMap]);
|
|
136
|
+
// fetchPage REEMPLAZA (página 1) o ANEXA (scroll infinito). Antes esta lista
|
|
137
|
+
// pedía el modelo hijo entero sin page/per_page.
|
|
138
|
+
const fetchPage = useCallback(async (nextPage, append) => {
|
|
139
|
+
if (append)
|
|
140
|
+
setLoadingMore(true);
|
|
141
|
+
else
|
|
142
|
+
setLoading(true);
|
|
74
143
|
try {
|
|
75
|
-
const params =
|
|
144
|
+
const params = {
|
|
145
|
+
...buildRelationFilterParams(foreignKey, parentId, filters),
|
|
146
|
+
page: nextPage,
|
|
147
|
+
per_page: REL_PAGE_SIZE,
|
|
148
|
+
};
|
|
149
|
+
if (debouncedSearch)
|
|
150
|
+
params.search = debouncedSearch;
|
|
76
151
|
const [metaRes, dataRes] = await Promise.all([
|
|
77
|
-
|
|
152
|
+
metadataRef.current ? Promise.resolve(null) : api.get(`/metadata/table/${model}`),
|
|
78
153
|
api.get(dataEndpoint, { params }),
|
|
79
154
|
]);
|
|
80
155
|
if (metaRes && metaRes.data?.success) {
|
|
@@ -83,18 +158,44 @@ function OneToManyRelation({ kind, model, foreignKey, parentId, filters, endpoin
|
|
|
83
158
|
cacheMetadata(model, fresh);
|
|
84
159
|
}
|
|
85
160
|
const list = dataRes.data;
|
|
86
|
-
if (list.success)
|
|
87
|
-
|
|
161
|
+
if (list.success) {
|
|
162
|
+
const fetched = list.data || [];
|
|
163
|
+
setRows((prev) => (append ? dedupeById(prev, fetched) : fetched));
|
|
164
|
+
setPage(nextPage);
|
|
165
|
+
if (list.meta?.total !== undefined)
|
|
166
|
+
setTotal(list.meta.total);
|
|
167
|
+
else if (!append)
|
|
168
|
+
setTotal(fetched.length);
|
|
169
|
+
setExhausted(fetched.length < REL_PAGE_SIZE);
|
|
170
|
+
}
|
|
88
171
|
}
|
|
89
172
|
catch (err) {
|
|
90
173
|
console.error('DynamicRelation fetch error', err);
|
|
91
174
|
}
|
|
92
175
|
finally {
|
|
93
|
-
|
|
176
|
+
if (append)
|
|
177
|
+
setLoadingMore(false);
|
|
178
|
+
else
|
|
179
|
+
setLoading(false);
|
|
94
180
|
}
|
|
95
181
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
96
|
-
}, [api, dataEndpoint, foreignKey, parentId, filtersKey,
|
|
97
|
-
|
|
182
|
+
}, [api, dataEndpoint, foreignKey, parentId, filtersKey, model, cacheMetadata, debouncedSearch]);
|
|
183
|
+
// Recarga desde la primera página. Es lo que corren create/edit/delete.
|
|
184
|
+
const fetchAll = useCallback(async () => {
|
|
185
|
+
await fetchPage(1, false);
|
|
186
|
+
}, [fetchPage]);
|
|
187
|
+
// Un cambio de padre/scope/búsqueda vuelve a la página 1.
|
|
188
|
+
useEffect(() => { fetchPage(1, false); }, [fetchPage]);
|
|
189
|
+
const canLoadMore = !loading && !loadingMore && !exhausted && rows.length < total;
|
|
190
|
+
const { rootRef, sentinelRef } = useInfiniteScrollSentinel({
|
|
191
|
+
onLoadMore: () => { if (canLoadMore)
|
|
192
|
+
fetchPage(page + 1, true); },
|
|
193
|
+
disabled: !canLoadMore,
|
|
194
|
+
});
|
|
195
|
+
// El buscador solo aparece cuando hay algo que buscar: una sub-tabla de 3
|
|
196
|
+
// líneas no necesita chrome extra. Se queda visible mientras haya término
|
|
197
|
+
// activo para no dejar al usuario sin forma de limpiarlo.
|
|
198
|
+
const showSearch = debouncedSearch !== '' || search !== '' || total > REL_PAGE_SIZE;
|
|
98
199
|
const formFields = useMemo(() => deriveRelationFormFields(metadata, foreignKey), [metadata, foreignKey]);
|
|
99
200
|
const visibleColumns = useMemo(() => {
|
|
100
201
|
if (!metadata?.columns)
|
|
@@ -199,10 +300,12 @@ function OneToManyRelation({ kind, model, foreignKey, parentId, filters, endpoin
|
|
|
199
300
|
setSubmitting(false);
|
|
200
301
|
}
|
|
201
302
|
}, [api, dataEndpoint, fetchAll, onChange, rowToDelete]);
|
|
202
|
-
return (_jsxs("div", { className: className, "data-relation-kind": kind, "data-relation-model": model, children: [(labels.title || canCreate) && (_jsxs("div", { className: "flex items-center justify-between pb-3", children: [labels.title ? _jsx("h3", { className: "text-sm font-medium", children: labels.title }) : _jsx("span", {}), canCreate && (_jsxs(Button, { size: "sm", variant: "outline", onClick: () => { setEditingRow(null); setFormOpen(true); }, children: [_jsx(Plus, { className: "h-4 w-4 mr-1" }), labels.addLabel] }))] })), loading ? (_jsx("div", { className: "space-y-2", children: Array.from({ length: 3 }).map((_, i) => (_jsx(Skeleton, { className: "h-10 w-full" }, `rel-skeleton-${i}`))) })) : rows.length === 0 ? (_jsx("div", { className: "text-center text-sm text-muted-foreground py-8 border rounded-md bg-muted/30", children: labels.emptyState })) : (_jsx("div", { className: "overflow-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
303
|
+
return (_jsxs("div", { className: className, "data-relation-kind": kind, "data-relation-model": model, children: [(labels.title || canCreate || showSearch) && (_jsxs("div", { className: "flex items-center justify-between gap-2 pb-3", children: [labels.title ? _jsx("h3", { className: "text-sm font-medium", children: labels.title }) : _jsx("span", {}), _jsxs("div", { className: "flex items-center gap-2", children: [showSearch && (_jsxs("div", { className: "relative", children: [_jsx(Search, { className: "absolute start-2 top-1/2 h-3.5 w-3.5 -translate-y-1/2 text-muted-foreground" }), _jsx(Input, { value: search, onChange: (e) => setSearch(e.target.value), placeholder: labels.searchPlaceholder, className: "h-8 w-40 ps-7 sm:w-56" })] })), canCreate && (_jsxs(Button, { size: "sm", variant: "outline", onClick: () => { setEditingRow(null); setFormOpen(true); }, children: [_jsx(Plus, { className: "h-4 w-4 mr-1" }), labels.addLabel] }))] })] })), loading ? (_jsx("div", { className: "space-y-2", children: Array.from({ length: 3 }).map((_, i) => (_jsx(Skeleton, { className: "h-10 w-full" }, `rel-skeleton-${i}`))) })) : rows.length === 0 ? (_jsx("div", { className: "text-center text-sm text-muted-foreground py-8 border rounded-md bg-muted/30", children: labels.emptyState })) : (_jsx(OptionsContext.Provider, { value: optionsCtx, children: _jsxs("div", { ref: rootRef, className: "overflow-auto max-h-[60vh] border rounded-md bg-card", children: [_jsxs(Table, { noWrapper: true, className: "w-full", children: [_jsx(TableHeader, { children: table.getHeaderGroups().map((headerGroup) => (_jsx(TableRow, { className: "border-b-0 hover:bg-transparent", children: headerGroup.headers.map((header) => {
|
|
304
|
+
const isActions = header.id === 'actions';
|
|
305
|
+
return (_jsx(TableHead, { colSpan: header.colSpan, style: header.column.columnDef.size ? { width: header.column.columnDef.size } : undefined, className: cn('bg-card border-b h-10', isActions && 'text-right'), children: header.isPlaceholder ? null : flexRender(header.column.columnDef.header, header.getContext()) }, header.id));
|
|
306
|
+
}) }, headerGroup.id))) }), _jsx(TableBody, { children: table.getRowModel().rows.map((row, idx) => (_jsx(TableRow, { children: row.getVisibleCells().map((cell) => (_jsx(TableCell, { style: cell.column.columnDef.size ? { width: cell.column.columnDef.size } : undefined, className: "py-2", children: flexRender(cell.column.columnDef.cell, cell.getContext()) }, cell.id))) }, relationRowKey(row.original, idx, foreignKey)))) })] }), loadingMore && (_jsx("div", { className: "p-2", children: _jsx(Skeleton, { className: "h-8 w-full" }) })), _jsx("div", { ref: sentinelRef, "aria-hidden": true, className: "h-px w-full" })] }) })), !loading && rows.length > 0 && total > rows.length && (_jsx("div", { className: "pt-2 text-end text-xs text-muted-foreground", children: labels.countLabel
|
|
307
|
+
.replace('{{loaded}}', String(rows.length))
|
|
308
|
+
.replace('{{total}}', String(total)) })), _jsx(Dialog, { open: formOpen, onOpenChange: (open) => { setFormOpen(open); if (!open)
|
|
206
309
|
setEditingRow(null); }, children: _jsxs(DialogContent, { children: [_jsx(DialogHeader, { children: _jsx(DialogTitle, { children: editingRow ? labels.editLabel : labels.addLabel }) }), _jsx(DynamicForm, { fields: formFields, initialValues: editingRow || undefined, onSubmit: handleSubmit, onCancel: () => { setFormOpen(false); setEditingRow(null); }, submitLabel: labels.saveLabel, cancelLabel: labels.cancelLabel, disabled: submitting })] }) }), _jsx(AlertDialog, { open: !!rowToDelete, onOpenChange: (open) => !open && setRowToDelete(null), children: _jsxs(AlertDialogContent, { children: [_jsxs(AlertDialogHeader, { children: [_jsx(AlertDialogTitle, { children: labels.confirmRemoveTitle }), _jsx(AlertDialogDescription, { children: labels.confirmRemoveDescription })] }), _jsxs(AlertDialogFooter, { children: [_jsx(AlertDialogCancel, { disabled: submitting, children: labels.cancelLabel }), _jsx(AlertDialogAction, { onClick: (e) => { e.preventDefault(); handleDelete(); }, className: "bg-red-600 hover:bg-red-700", disabled: submitting, children: labels.removeLabel })] })] }) })] }));
|
|
207
310
|
}
|
|
208
311
|
function ManyToManyRelation({ kind, through, references, foreignKey, referencesKey, parentId, filters, pivotEndpoint, referencesEndpoint, displayKey, canCreate = true, canDelete = true, readonly, readOnly, strings, className, onChange, }) {
|
|
@@ -37,6 +37,19 @@ export interface DynamicRelationsProps {
|
|
|
37
37
|
* autónoma conserva todas las columnas.
|
|
38
38
|
*/
|
|
39
39
|
lineSubtable?: boolean;
|
|
40
|
+
/**
|
|
41
|
+
* Solo renderiza las relaciones de COMPOSICIÓN — las que el kernel marca
|
|
42
|
+
* con `embed: true` (las líneas de un documento). Es lo que usan los MODALES
|
|
43
|
+
* de registro: antes embebían TODAS las relaciones one_to_many del modelo,
|
|
44
|
+
* así que abrir "Editar Almacén" arrastraba miles de existencias y traspasos
|
|
45
|
+
* al formulario. Las relaciones no embebidas siguen accesibles desde su
|
|
46
|
+
* propia página / la vista de detalle, que renderiza el listado completo.
|
|
47
|
+
*
|
|
48
|
+
* Default false: una página de detalle autónoma sigue mostrando todas.
|
|
49
|
+
* Una relación sin `embed` (kernel viejo) NO se embebe — el gate falla del
|
|
50
|
+
* lado seguro.
|
|
51
|
+
*/
|
|
52
|
+
embedOnly?: boolean;
|
|
40
53
|
/** Bubble up when any panel's data changes (create/delete/attach/detach). */
|
|
41
54
|
onChange?: (relation: RelationMeta) => void;
|
|
42
55
|
}
|
|
@@ -55,5 +68,13 @@ export declare function resolveParentId(record: {
|
|
|
55
68
|
* both places is safe.
|
|
56
69
|
*/
|
|
57
70
|
export declare function buildRelationFilters(relation: Pick<RelationMeta, 'foreign_key' | 'scope'>, parentId: string | number): Record<string, string>;
|
|
58
|
-
|
|
71
|
+
/**
|
|
72
|
+
* ¿La relación es de COMPOSICIÓN (embebible en un modal)? Solo `embed: true`
|
|
73
|
+
* califica: la ausencia del flag — un kernel viejo que todavía no lo sirve —
|
|
74
|
+
* significa NO embeber, que es el lado seguro (el costo de un falso negativo
|
|
75
|
+
* es un panel de menos en el modal; el de un falso positivo, miles de filas
|
|
76
|
+
* dentro de un formulario).
|
|
77
|
+
*/
|
|
78
|
+
export declare function isEmbedded(rel: Pick<RelationMeta, 'embed'>): boolean;
|
|
79
|
+
export declare function DynamicRelations({ record, relations, parentIdKey, className, panelClassName, canCreate, canDelete, canEdit, strings, lineSubtable, embedOnly, onChange, }: DynamicRelationsProps): import("react").JSX.Element | null;
|
|
59
80
|
//# sourceMappingURL=dynamic-relations.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dynamic-relations.d.ts","sourceRoot":"","sources":["../src/dynamic-relations.tsx"],"names":[],"mappings":"AAcA,OAAO,EAAmB,KAAK,sBAAsB,EAAE,MAAM,oBAAoB,CAAA;AACjF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAE3C,MAAM,WAAW,qBAAqB;IAClC;;;OAGG;IACH,MAAM,EAAE;QAAE,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;QAAC,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,GAAG,IAAI,GAAG,SAAS,CAAA;IACzE,gEAAgE;IAChE,SAAS,EAAE,YAAY,EAAE,GAAG,IAAI,GAAG,SAAS,CAAA;IAC5C;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,6CAA6C;IAC7C,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,mCAAmC;IACnC,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB;;;OAGG;IACH,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,8DAA8D;IAC9D,OAAO,CAAC,EAAE,OAAO,CAAC,sBAAsB,CAAC,CAAA;IACzC;;;;;;OAMG;IACH,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,6EAA6E;IAC7E,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,YAAY,KAAK,IAAI,CAAA;CAC9C;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAC3B,MAAM,EAAE;IAAE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;CAAE,GAAG,IAAI,GAAG,SAAS,EACnD,WAAW,SAAO,GACnB,MAAM,GAAG,MAAM,GAAG,SAAS,CAM7B;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAChC,QAAQ,EAAE,IAAI,CAAC,YAAY,EAAE,aAAa,GAAG,OAAO,CAAC,EACrD,QAAQ,EAAE,MAAM,GAAG,MAAM,GAC1B,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAUxB;AAOD,wBAAgB,gBAAgB,CAAC,EAC7B,MAAM,EACN,SAAS,EACT,WAAkB,EAClB,SAAS,EACT,cAAc,EACd,SAAgB,EAChB,SAAgB,EAChB,OAAc,EACd,OAAO,EACP,YAAoB,EACpB,QAAQ,GACX,EAAE,qBAAqB,
|
|
1
|
+
{"version":3,"file":"dynamic-relations.d.ts","sourceRoot":"","sources":["../src/dynamic-relations.tsx"],"names":[],"mappings":"AAcA,OAAO,EAAmB,KAAK,sBAAsB,EAAE,MAAM,oBAAoB,CAAA;AACjF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAE3C,MAAM,WAAW,qBAAqB;IAClC;;;OAGG;IACH,MAAM,EAAE;QAAE,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;QAAC,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,GAAG,IAAI,GAAG,SAAS,CAAA;IACzE,gEAAgE;IAChE,SAAS,EAAE,YAAY,EAAE,GAAG,IAAI,GAAG,SAAS,CAAA;IAC5C;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,6CAA6C;IAC7C,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,mCAAmC;IACnC,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB;;;OAGG;IACH,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,8DAA8D;IAC9D,OAAO,CAAC,EAAE,OAAO,CAAC,sBAAsB,CAAC,CAAA;IACzC;;;;;;OAMG;IACH,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB;;;;;;;;;;;OAWG;IACH,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,6EAA6E;IAC7E,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,YAAY,KAAK,IAAI,CAAA;CAC9C;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAC3B,MAAM,EAAE;IAAE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;CAAE,GAAG,IAAI,GAAG,SAAS,EACnD,WAAW,SAAO,GACnB,MAAM,GAAG,MAAM,GAAG,SAAS,CAM7B;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAChC,QAAQ,EAAE,IAAI,CAAC,YAAY,EAAE,aAAa,GAAG,OAAO,CAAC,EACrD,QAAQ,EAAE,MAAM,GAAG,MAAM,GAC1B,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAUxB;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,IAAI,CAAC,YAAY,EAAE,OAAO,CAAC,GAAG,OAAO,CAEpE;AAOD,wBAAgB,gBAAgB,CAAC,EAC7B,MAAM,EACN,SAAS,EACT,WAAkB,EAClB,SAAS,EACT,cAAc,EACd,SAAgB,EAChB,SAAgB,EAChB,OAAc,EACd,OAAO,EACP,YAAoB,EACpB,SAAiB,EACjB,QAAQ,GACX,EAAE,qBAAqB,sCA8EvB"}
|
|
@@ -48,16 +48,29 @@ export function buildRelationFilters(relation, parentId) {
|
|
|
48
48
|
out[relation.foreign_key] = String(parentId);
|
|
49
49
|
return out;
|
|
50
50
|
}
|
|
51
|
+
/**
|
|
52
|
+
* ¿La relación es de COMPOSICIÓN (embebible en un modal)? Solo `embed: true`
|
|
53
|
+
* califica: la ausencia del flag — un kernel viejo que todavía no lo sirve —
|
|
54
|
+
* significa NO embeber, que es el lado seguro (el costo de un falso negativo
|
|
55
|
+
* es un panel de menos en el modal; el de un falso positivo, miles de filas
|
|
56
|
+
* dentro de un formulario).
|
|
57
|
+
*/
|
|
58
|
+
export function isEmbedded(rel) {
|
|
59
|
+
return rel.embed === true;
|
|
60
|
+
}
|
|
51
61
|
/** Stable React key for a relation panel. */
|
|
52
62
|
function relationKey(rel, idx) {
|
|
53
63
|
return rel.name || `${rel.through}-${rel.foreign_key}-${idx}`;
|
|
54
64
|
}
|
|
55
|
-
export function DynamicRelations({ record, relations, parentIdKey = 'id', className, panelClassName, canCreate = true, canDelete = true, canEdit = true, strings, lineSubtable = false, onChange, }) {
|
|
65
|
+
export function DynamicRelations({ record, relations, parentIdKey = 'id', className, panelClassName, canCreate = true, canDelete = true, canEdit = true, strings, lineSubtable = false, embedOnly = false, onChange, }) {
|
|
56
66
|
const parentId = useMemo(() => resolveParentId(record, parentIdKey), [record, parentIdKey]);
|
|
57
|
-
|
|
67
|
+
// Gate de composición: en un modal solo entran las relaciones marcadas
|
|
68
|
+
// `embed` por el kernel. Fuera del modal la lista pasa entera.
|
|
69
|
+
const visible = useMemo(() => (embedOnly ? (relations || []).filter(isEmbedded) : relations || []), [relations, embedOnly]);
|
|
70
|
+
if (parentId === undefined || visible.length === 0) {
|
|
58
71
|
return null;
|
|
59
72
|
}
|
|
60
|
-
return (_jsx("div", { className: cn('space-y-6', className), "data-dynamic-relations": "", children:
|
|
73
|
+
return (_jsx("div", { className: cn('space-y-6', className), "data-dynamic-relations": "", children: visible.map((rel, idx) => {
|
|
61
74
|
const filters = buildRelationFilters(rel, parentId);
|
|
62
75
|
const panelStrings = {
|
|
63
76
|
...(strings || {}),
|
package/dist/index.d.ts
CHANGED
|
@@ -53,7 +53,7 @@ export { ExportDialog } from './dialogs/export';
|
|
|
53
53
|
export { ImportDialog } from './dialogs/import';
|
|
54
54
|
export { DynamicCRUDPage, type DynamicCRUDPageProps, type DynamicCRUDPageStrings, type DynamicCRUDPageClasses, } from './dynamic-crud-page';
|
|
55
55
|
export { DynamicRelation, type DynamicRelationProps, type DynamicRelationStrings, type DynamicRelationKind, buildRelationFilterParams, buildCreatePayload, deriveRelationFormFields, relationRowKey, } from './dynamic-relation';
|
|
56
|
-
export { DynamicRelations, resolveParentId, buildRelationFilters, type DynamicRelationsProps, } from './dynamic-relations';
|
|
56
|
+
export { DynamicRelations, resolveParentId, buildRelationFilters, isEmbedded, type DynamicRelationsProps, } from './dynamic-relations';
|
|
57
57
|
export { registerModelExtension, getModelExtension, clearModelExtensions, type ModelExtension, type ModelExtensionProps, } from './model-extension-registry';
|
|
58
58
|
export { isColumnVisibleInTable, isColumnVisibleInModal, isColumnVisibleInLineSubtable, AUDIT_SUBTABLE_COLUMN_KEYS, getSearchableColumnKeys, } from './column-visibility';
|
|
59
59
|
export { useOptionsResolver, projectOption, type ResolvedOption, type OptionsMeta, type UseOptionsResolverArgs, type UseOptionsResolverResult, } from './use-options-resolver';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -54,7 +54,7 @@ export { ExportDialog } from './dialogs/export';
|
|
|
54
54
|
export { ImportDialog } from './dialogs/import';
|
|
55
55
|
export { DynamicCRUDPage, } from './dynamic-crud-page';
|
|
56
56
|
export { DynamicRelation, buildRelationFilterParams, buildCreatePayload, deriveRelationFormFields, relationRowKey, } from './dynamic-relation';
|
|
57
|
-
export { DynamicRelations, resolveParentId, buildRelationFilters, } from './dynamic-relations';
|
|
57
|
+
export { DynamicRelations, resolveParentId, buildRelationFilters, isEmbedded, } from './dynamic-relations';
|
|
58
58
|
export { registerModelExtension, getModelExtension, clearModelExtensions, } from './model-extension-registry';
|
|
59
59
|
export { isColumnVisibleInTable, isColumnVisibleInModal, isColumnVisibleInLineSubtable, AUDIT_SUBTABLE_COLUMN_KEYS, getSearchableColumnKeys, } from './column-visibility';
|
|
60
60
|
export { useOptionsResolver, projectOption, } from './use-options-resolver';
|
package/dist/types.d.ts
CHANGED
|
@@ -197,6 +197,15 @@ export interface RelationMeta {
|
|
|
197
197
|
readonly?: boolean;
|
|
198
198
|
/** camelCase alias for `readonly`. */
|
|
199
199
|
readOnly?: boolean;
|
|
200
|
+
/**
|
|
201
|
+
* Composition relation: its children are PART of the parent record (a
|
|
202
|
+
* document's lines), so the record MODAL embeds them as a sub-table.
|
|
203
|
+
* Opt-in — a modal renders only the relations carrying this flag, which is
|
|
204
|
+
* what keeps opening a warehouse from loading every stock movement it has.
|
|
205
|
+
* Served by the kernel from the manifest relation's `embed`. Absent (older
|
|
206
|
+
* kernels) = not embedded.
|
|
207
|
+
*/
|
|
208
|
+
embed?: boolean;
|
|
200
209
|
}
|
|
201
210
|
export interface FilterDefinition {
|
|
202
211
|
key: string;
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@asteby/metacore-runtime-react",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "29.0.1",
|
|
4
4
|
"description": "React runtime for metacore hosts — renders addon contributions dynamically",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"sonner": ">=1.7",
|
|
39
39
|
"zustand": ">=5",
|
|
40
40
|
"@asteby/metacore-sdk": "^3.4.0",
|
|
41
|
-
"@asteby/metacore-ui": "^2.
|
|
41
|
+
"@asteby/metacore-ui": "^2.13.0"
|
|
42
42
|
},
|
|
43
43
|
"peerDependenciesMeta": {
|
|
44
44
|
"@tanstack/react-router": {
|
|
@@ -68,7 +68,7 @@
|
|
|
68
68
|
"vitest": "^4.0.0",
|
|
69
69
|
"zustand": "^5.0.0",
|
|
70
70
|
"@asteby/metacore-sdk": "3.4.0",
|
|
71
|
-
"@asteby/metacore-ui": "2.
|
|
71
|
+
"@asteby/metacore-ui": "2.13.0"
|
|
72
72
|
},
|
|
73
73
|
"scripts": {
|
|
74
74
|
"build": "tsc -p tsconfig.json",
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
// @vitest-environment happy-dom
|
|
2
|
+
//
|
|
3
|
+
// Dos contratos de las sub-tablas de relación:
|
|
4
|
+
// 1. El MODAL de registro embebe SOLO las relaciones de composición (`embed`).
|
|
5
|
+
// Antes embebía todas las one_to_many, así que abrir un almacén arrastraba
|
|
6
|
+
// miles de existencias y traspasos adentro del formulario.
|
|
7
|
+
// 2. La sub-tabla 1:N pagina server-side (page/per_page) en vez de pedir el
|
|
8
|
+
// modelo hijo entero.
|
|
9
|
+
import { describe, it, expect, vi } from 'vitest'
|
|
10
|
+
import { render, waitFor } from '@testing-library/react'
|
|
11
|
+
import { ApiProvider, type ApiClient } from '../api-context'
|
|
12
|
+
import { DynamicRelations, isEmbedded } from '../dynamic-relations'
|
|
13
|
+
import type { RelationMeta } from '../types'
|
|
14
|
+
|
|
15
|
+
const items: RelationMeta = {
|
|
16
|
+
name: 'items',
|
|
17
|
+
kind: 'one_to_many',
|
|
18
|
+
through: 'OrderItem',
|
|
19
|
+
foreign_key: 'order_id',
|
|
20
|
+
embed: true,
|
|
21
|
+
}
|
|
22
|
+
const movements: RelationMeta = {
|
|
23
|
+
name: 'movements',
|
|
24
|
+
kind: 'one_to_many',
|
|
25
|
+
through: 'StockMovement',
|
|
26
|
+
foreign_key: 'order_id',
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// api.get sirve metadata para cualquier modelo y una página de datos con
|
|
30
|
+
// meta.total, que es lo que la sub-tabla usa para decidir si hay más.
|
|
31
|
+
function makeApi(total = 0) {
|
|
32
|
+
const get = vi.fn().mockImplementation((url: string) => {
|
|
33
|
+
if (url.startsWith('/metadata/table/')) {
|
|
34
|
+
return Promise.resolve({
|
|
35
|
+
data: {
|
|
36
|
+
success: true,
|
|
37
|
+
data: {
|
|
38
|
+
columns: [{ key: 'name', label: 'Nombre', type: 'text' }],
|
|
39
|
+
actions: [],
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
})
|
|
43
|
+
}
|
|
44
|
+
return Promise.resolve({ data: { success: true, data: [], meta: { total } } })
|
|
45
|
+
})
|
|
46
|
+
return {
|
|
47
|
+
api: { get, post: vi.fn(), put: vi.fn(), delete: vi.fn() } as unknown as ApiClient,
|
|
48
|
+
get,
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function renderRelations({ total, ...props }: any) {
|
|
53
|
+
const { api, get } = makeApi(total ?? 0)
|
|
54
|
+
const utils = render(
|
|
55
|
+
<ApiProvider client={api}>
|
|
56
|
+
<DynamicRelations record={{ id: 'p1' }} {...props} />
|
|
57
|
+
</ApiProvider>,
|
|
58
|
+
)
|
|
59
|
+
return { ...utils, get }
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
describe('isEmbedded', () => {
|
|
63
|
+
it('solo acepta embed === true', () => {
|
|
64
|
+
expect(isEmbedded(items)).toBe(true)
|
|
65
|
+
expect(isEmbedded(movements)).toBe(false)
|
|
66
|
+
// Kernel viejo que todavía no sirve el flag: no embeber (lado seguro).
|
|
67
|
+
expect(isEmbedded({} as RelationMeta)).toBe(false)
|
|
68
|
+
expect(isEmbedded({ embed: false })).toBe(false)
|
|
69
|
+
})
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
describe('DynamicRelations embedOnly', () => {
|
|
73
|
+
it('con embedOnly deja pasar solo las relaciones de composición', () => {
|
|
74
|
+
const { container } = renderRelations({
|
|
75
|
+
relations: [items, movements],
|
|
76
|
+
embedOnly: true,
|
|
77
|
+
})
|
|
78
|
+
const panels = container.querySelectorAll('[data-relation-model]')
|
|
79
|
+
expect(panels.length).toBe(1)
|
|
80
|
+
expect(panels[0].getAttribute('data-relation-model')).toBe('OrderItem')
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
it('sin ninguna relación embebida no renderiza nada (ni el wrapper)', () => {
|
|
84
|
+
const { container } = renderRelations({ relations: [movements], embedOnly: true })
|
|
85
|
+
expect(container.querySelector('[data-dynamic-relations]')).toBeNull()
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
it('sin embedOnly (página de detalle) muestra todas', () => {
|
|
89
|
+
const { container } = renderRelations({ relations: [items, movements] })
|
|
90
|
+
expect(container.querySelectorAll('[data-relation-model]').length).toBe(2)
|
|
91
|
+
})
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
describe('sub-tabla 1:N', () => {
|
|
95
|
+
it('pide la primera página acotada en vez de la relación entera', async () => {
|
|
96
|
+
const { get } = renderRelations({ relations: [items], embedOnly: true, total: 900 })
|
|
97
|
+
await waitFor(() => {
|
|
98
|
+
const call = get.mock.calls.find(([url]: any[]) => url === '/data/OrderItem')
|
|
99
|
+
expect(call).toBeTruthy()
|
|
100
|
+
const params = call![1].params
|
|
101
|
+
expect(params.page).toBe(1)
|
|
102
|
+
expect(params.per_page).toBeGreaterThan(0)
|
|
103
|
+
expect(params.per_page).toBeLessThanOrEqual(50)
|
|
104
|
+
// El scope del padre sigue viajando en la query.
|
|
105
|
+
expect(params.f_order_id).toBe('eq:p1')
|
|
106
|
+
// Sin término, no se manda búsqueda.
|
|
107
|
+
expect(params.search).toBeUndefined()
|
|
108
|
+
})
|
|
109
|
+
})
|
|
110
|
+
})
|
|
@@ -686,7 +686,9 @@ function GenericActionModal({ open, onOpenChange, action, model, record, endpoin
|
|
|
686
686
|
})}
|
|
687
687
|
{relations.length > 0 && (
|
|
688
688
|
<FieldCell fullWidth>
|
|
689
|
-
|
|
689
|
+
{/* Igual que el modal de registro: solo las
|
|
690
|
+
relaciones de composición se embeben. */}
|
|
691
|
+
<DynamicRelations record={record} relations={relations} lineSubtable embedOnly />
|
|
690
692
|
</FieldCell>
|
|
691
693
|
)}
|
|
692
694
|
</FieldGrid>
|
|
@@ -996,7 +996,11 @@ export function DynamicRecordDialog({
|
|
|
996
996
|
</form>
|
|
997
997
|
|
|
998
998
|
|
|
999
|
-
{/*
|
|
999
|
+
{/* Líneas del documento: SOLO las relaciones de
|
|
1000
|
+
composición (`embed`). El resto de las 1:N —
|
|
1001
|
+
existencias, traspasos, cualquier colección grande
|
|
1002
|
+
de gestión independiente — vive en su propia
|
|
1003
|
+
página, no adentro de este formulario.
|
|
1000
1004
|
View = strictly read-only; edit = add/edit/delete. */}
|
|
1001
1005
|
{!isCreate && record && relations.length > 0 && (
|
|
1002
1006
|
<div className="mt-6">
|
|
@@ -1004,6 +1008,7 @@ export function DynamicRecordDialog({
|
|
|
1004
1008
|
record={record}
|
|
1005
1009
|
relations={relations}
|
|
1006
1010
|
lineSubtable
|
|
1011
|
+
embedOnly
|
|
1007
1012
|
canCreate={mode === 'edit'}
|
|
1008
1013
|
canEdit={mode === 'edit'}
|
|
1009
1014
|
canDelete={mode === 'edit'}
|
package/src/dynamic-relation.tsx
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// - "one_to_many": lista inline editable que cuelga del registro padre.
|
|
4
4
|
// - "many_to_many": multi-select sobre la tabla destino con sync a la pivot.
|
|
5
5
|
// La RFC completa vive en `packages/runtime-react/docs/relations.md`.
|
|
6
|
-
import { useCallback, useEffect, useMemo, useState } from 'react'
|
|
6
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
|
7
7
|
import { useTranslation } from 'react-i18next'
|
|
8
8
|
import {
|
|
9
9
|
type ColumnDef,
|
|
@@ -31,6 +31,7 @@ import {
|
|
|
31
31
|
DialogContent,
|
|
32
32
|
DialogHeader,
|
|
33
33
|
DialogTitle,
|
|
34
|
+
Input,
|
|
34
35
|
MultiSelect,
|
|
35
36
|
Table,
|
|
36
37
|
TableBody,
|
|
@@ -39,15 +40,17 @@ import {
|
|
|
39
40
|
TableHeader,
|
|
40
41
|
TableRow,
|
|
41
42
|
} from '@asteby/metacore-ui/primitives'
|
|
42
|
-
import { Plus, Trash2, Pencil } from 'lucide-react'
|
|
43
|
+
import { Plus, Trash2, Pencil, Search } from 'lucide-react'
|
|
43
44
|
import { useApi } from './api-context'
|
|
44
45
|
import { useMetadataCache } from './metadata-cache'
|
|
46
|
+
import { OptionsContext } from './options-context'
|
|
45
47
|
import { DynamicForm } from './dynamic-form'
|
|
46
48
|
import { useImageUrl } from './image-url-context'
|
|
47
49
|
import { useTimeZone, useCurrency } from './org-runtime-context'
|
|
48
50
|
import { makeDefaultGetDynamicColumns } from './dynamic-columns'
|
|
49
51
|
import { isColumnVisibleInLineSubtable } from './column-visibility'
|
|
50
52
|
import { useOptionsResolver } from './use-options-resolver'
|
|
53
|
+
import { dedupeById, useInfiniteScrollSentinel } from './use-infinite-scroll'
|
|
51
54
|
import type { ApiResponse, ColumnDefinition, TableMetadata } from './types'
|
|
52
55
|
import {
|
|
53
56
|
buildCreatePayload,
|
|
@@ -90,6 +93,10 @@ export interface DynamicRelationStrings {
|
|
|
90
93
|
selectPlaceholder: string
|
|
91
94
|
selectSearchPlaceholder: string
|
|
92
95
|
selectEmpty: string
|
|
96
|
+
/** Placeholder del buscador de la sub-tabla 1:N. */
|
|
97
|
+
searchPlaceholder: string
|
|
98
|
+
/** Pie de la sub-tabla: "{{loaded}} de {{total}}". */
|
|
99
|
+
countLabel: string
|
|
93
100
|
}
|
|
94
101
|
|
|
95
102
|
const DEFAULT_STRINGS: DynamicRelationStrings = {
|
|
@@ -105,8 +112,15 @@ const DEFAULT_STRINGS: DynamicRelationStrings = {
|
|
|
105
112
|
selectPlaceholder: 'Seleccionar…',
|
|
106
113
|
selectSearchPlaceholder: 'Buscar…',
|
|
107
114
|
selectEmpty: 'Sin resultados.',
|
|
115
|
+
searchPlaceholder: 'Buscar…',
|
|
116
|
+
countLabel: '{{loaded}} de {{total}}',
|
|
108
117
|
}
|
|
109
118
|
|
|
119
|
+
// Tamaño de página de la sub-tabla 1:N. Antes la lista pedía el hijo COMPLETO
|
|
120
|
+
// (sin page/per_page), así que abrir un almacén traía todas sus existencias y
|
|
121
|
+
// traspasos. Se pagina de a 25 y el resto entra por scroll infinito.
|
|
122
|
+
const REL_PAGE_SIZE = 25
|
|
123
|
+
|
|
110
124
|
interface CommonProps {
|
|
111
125
|
/** id del registro padre. */
|
|
112
126
|
parentId: string | number
|
|
@@ -231,8 +245,22 @@ function OneToManyRelation({
|
|
|
231
245
|
const labels = { ...DEFAULT_STRINGS, ...(strings || {}) }
|
|
232
246
|
|
|
233
247
|
const [metadata, setMetadata] = useState<TableMetadata | null>(cachedMeta || null)
|
|
248
|
+
// Options for the ref/relation columns so their cells render the record's
|
|
249
|
+
// NAME (+ SKU subtitle) instead of the raw uuid. The main <DynamicTable>
|
|
250
|
+
// preloads these into OptionsContext; a sub-table skipped it, so a `ref`
|
|
251
|
+
// column (e.g. a purchase order line's Product) showed the bare uuid.
|
|
252
|
+
const [optionsMap, setOptionsMap] = useState<Map<string, any[]>>(new Map())
|
|
234
253
|
const [rows, setRows] = useState<any[]>([])
|
|
235
254
|
const [loading, setLoading] = useState(true)
|
|
255
|
+
// Paginación server-side + scroll infinito, igual que <DynamicTable>.
|
|
256
|
+
const [total, setTotal] = useState(0)
|
|
257
|
+
const [page, setPage] = useState(1)
|
|
258
|
+
const [loadingMore, setLoadingMore] = useState(false)
|
|
259
|
+
// El backend devolvió una página corta: no hay más filas aunque meta.total
|
|
260
|
+
// diga otra cosa (drift count/list dispararía el sentinel para siempre).
|
|
261
|
+
const [exhausted, setExhausted] = useState(false)
|
|
262
|
+
const [search, setSearch] = useState('')
|
|
263
|
+
const [debouncedSearch, setDebouncedSearch] = useState('')
|
|
236
264
|
const [formOpen, setFormOpen] = useState(false)
|
|
237
265
|
const [editingRow, setEditingRow] = useState<any | null>(null)
|
|
238
266
|
const [rowToDelete, setRowToDelete] = useState<any | null>(null)
|
|
@@ -244,12 +272,67 @@ function OneToManyRelation({
|
|
|
244
272
|
// still reacting to real scope changes.
|
|
245
273
|
const filtersKey = useMemo(() => (filters ? JSON.stringify(filters) : ''), [filters])
|
|
246
274
|
|
|
247
|
-
|
|
248
|
-
|
|
275
|
+
// La metadata se lee por ref dentro del fetch: si entrara como dependencia,
|
|
276
|
+
// resolverla dispararía un segundo fetch de datos por cada montaje.
|
|
277
|
+
const metadataRef = useRef<TableMetadata | null>(metadata)
|
|
278
|
+
metadataRef.current = metadata
|
|
279
|
+
|
|
280
|
+
// Debounce del buscador: cada tecla no puede pegarle al servidor.
|
|
281
|
+
useEffect(() => {
|
|
282
|
+
const id = setTimeout(() => setDebouncedSearch(search.trim()), 300)
|
|
283
|
+
return () => clearTimeout(id)
|
|
284
|
+
}, [search])
|
|
285
|
+
|
|
286
|
+
// Preload the options of the ref/relation columns (same shape <DynamicTable>
|
|
287
|
+
// uses: `useOptions && searchEndpoint`) so their cells resolve the referenced
|
|
288
|
+
// record's name via OptionsContext instead of printing the raw uuid.
|
|
289
|
+
const refEndpointsKey = useMemo(() => {
|
|
290
|
+
const eps = (metadata?.columns || [])
|
|
291
|
+
.filter((c) => (c as any).useOptions && (c as any).searchEndpoint)
|
|
292
|
+
.map((c) => (c as any).searchEndpoint as string)
|
|
293
|
+
return Array.from(new Set(eps)).sort().join('|')
|
|
294
|
+
}, [metadata])
|
|
295
|
+
|
|
296
|
+
useEffect(() => {
|
|
297
|
+
if (!refEndpointsKey) {
|
|
298
|
+
setOptionsMap((prev) => (prev.size ? new Map() : prev))
|
|
299
|
+
return
|
|
300
|
+
}
|
|
301
|
+
const endpoints = refEndpointsKey.split('|')
|
|
302
|
+
let cancelled = false
|
|
303
|
+
void Promise.all(
|
|
304
|
+
endpoints.map(async (ep) => {
|
|
305
|
+
try {
|
|
306
|
+
const res = (await api.get(ep)) as { data: ApiResponse<any[]> }
|
|
307
|
+
return [ep, res.data?.success ? res.data.data || [] : []] as const
|
|
308
|
+
} catch {
|
|
309
|
+
return [ep, [] as any[]] as const
|
|
310
|
+
}
|
|
311
|
+
}),
|
|
312
|
+
).then((entries) => {
|
|
313
|
+
if (!cancelled) setOptionsMap(new Map(entries))
|
|
314
|
+
})
|
|
315
|
+
return () => {
|
|
316
|
+
cancelled = true
|
|
317
|
+
}
|
|
318
|
+
}, [api, refEndpointsKey])
|
|
319
|
+
|
|
320
|
+
const optionsCtx = useMemo(() => ({ optionsMap }), [optionsMap])
|
|
321
|
+
|
|
322
|
+
// fetchPage REEMPLAZA (página 1) o ANEXA (scroll infinito). Antes esta lista
|
|
323
|
+
// pedía el modelo hijo entero sin page/per_page.
|
|
324
|
+
const fetchPage = useCallback(async (nextPage: number, append: boolean) => {
|
|
325
|
+
if (append) setLoadingMore(true)
|
|
326
|
+
else setLoading(true)
|
|
249
327
|
try {
|
|
250
|
-
const params
|
|
328
|
+
const params: Record<string, any> = {
|
|
329
|
+
...buildRelationFilterParams(foreignKey, parentId, filters),
|
|
330
|
+
page: nextPage,
|
|
331
|
+
per_page: REL_PAGE_SIZE,
|
|
332
|
+
}
|
|
333
|
+
if (debouncedSearch) params.search = debouncedSearch
|
|
251
334
|
const [metaRes, dataRes] = await Promise.all([
|
|
252
|
-
|
|
335
|
+
metadataRef.current ? Promise.resolve(null) : api.get(`/metadata/table/${model}`),
|
|
253
336
|
api.get(dataEndpoint, { params }),
|
|
254
337
|
])
|
|
255
338
|
if (metaRes && (metaRes as any).data?.success) {
|
|
@@ -258,16 +341,41 @@ function OneToManyRelation({
|
|
|
258
341
|
cacheMetadata(model, fresh)
|
|
259
342
|
}
|
|
260
343
|
const list = (dataRes as { data: ApiResponse<any[]> }).data
|
|
261
|
-
if (list.success)
|
|
344
|
+
if (list.success) {
|
|
345
|
+
const fetched = list.data || []
|
|
346
|
+
setRows((prev) => (append ? dedupeById(prev, fetched) : fetched))
|
|
347
|
+
setPage(nextPage)
|
|
348
|
+
if (list.meta?.total !== undefined) setTotal(list.meta.total)
|
|
349
|
+
else if (!append) setTotal(fetched.length)
|
|
350
|
+
setExhausted(fetched.length < REL_PAGE_SIZE)
|
|
351
|
+
}
|
|
262
352
|
} catch (err) {
|
|
263
353
|
console.error('DynamicRelation fetch error', err)
|
|
264
354
|
} finally {
|
|
265
|
-
|
|
355
|
+
if (append) setLoadingMore(false)
|
|
356
|
+
else setLoading(false)
|
|
266
357
|
}
|
|
267
358
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
268
|
-
}, [api, dataEndpoint, foreignKey, parentId, filtersKey,
|
|
359
|
+
}, [api, dataEndpoint, foreignKey, parentId, filtersKey, model, cacheMetadata, debouncedSearch])
|
|
360
|
+
|
|
361
|
+
// Recarga desde la primera página. Es lo que corren create/edit/delete.
|
|
362
|
+
const fetchAll = useCallback(async () => {
|
|
363
|
+
await fetchPage(1, false)
|
|
364
|
+
}, [fetchPage])
|
|
365
|
+
|
|
366
|
+
// Un cambio de padre/scope/búsqueda vuelve a la página 1.
|
|
367
|
+
useEffect(() => { fetchPage(1, false) }, [fetchPage])
|
|
368
|
+
|
|
369
|
+
const canLoadMore = !loading && !loadingMore && !exhausted && rows.length < total
|
|
370
|
+
const { rootRef, sentinelRef } = useInfiniteScrollSentinel<HTMLDivElement, HTMLDivElement>({
|
|
371
|
+
onLoadMore: () => { if (canLoadMore) fetchPage(page + 1, true) },
|
|
372
|
+
disabled: !canLoadMore,
|
|
373
|
+
})
|
|
269
374
|
|
|
270
|
-
|
|
375
|
+
// El buscador solo aparece cuando hay algo que buscar: una sub-tabla de 3
|
|
376
|
+
// líneas no necesita chrome extra. Se queda visible mientras haya término
|
|
377
|
+
// activo para no dejar al usuario sin forma de limpiarlo.
|
|
378
|
+
const showSearch = debouncedSearch !== '' || search !== '' || total > REL_PAGE_SIZE
|
|
271
379
|
|
|
272
380
|
const formFields = useMemo(
|
|
273
381
|
() => deriveRelationFormFields(metadata, foreignKey),
|
|
@@ -410,19 +518,32 @@ function OneToManyRelation({
|
|
|
410
518
|
|
|
411
519
|
return (
|
|
412
520
|
<div className={className} data-relation-kind={kind} data-relation-model={model}>
|
|
413
|
-
{(labels.title || canCreate) && (
|
|
414
|
-
<div className="flex items-center justify-between pb-3">
|
|
521
|
+
{(labels.title || canCreate || showSearch) && (
|
|
522
|
+
<div className="flex items-center justify-between gap-2 pb-3">
|
|
415
523
|
{labels.title ? <h3 className="text-sm font-medium">{labels.title}</h3> : <span />}
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
524
|
+
<div className="flex items-center gap-2">
|
|
525
|
+
{showSearch && (
|
|
526
|
+
<div className="relative">
|
|
527
|
+
<Search className="absolute start-2 top-1/2 h-3.5 w-3.5 -translate-y-1/2 text-muted-foreground" />
|
|
528
|
+
<Input
|
|
529
|
+
value={search}
|
|
530
|
+
onChange={(e: React.ChangeEvent<HTMLInputElement>) => setSearch(e.target.value)}
|
|
531
|
+
placeholder={labels.searchPlaceholder}
|
|
532
|
+
className="h-8 w-40 ps-7 sm:w-56"
|
|
533
|
+
/>
|
|
534
|
+
</div>
|
|
535
|
+
)}
|
|
536
|
+
{canCreate && (
|
|
537
|
+
<Button
|
|
538
|
+
size="sm"
|
|
539
|
+
variant="outline"
|
|
540
|
+
onClick={() => { setEditingRow(null); setFormOpen(true) }}
|
|
541
|
+
>
|
|
542
|
+
<Plus className="h-4 w-4 mr-1" />
|
|
543
|
+
{labels.addLabel}
|
|
544
|
+
</Button>
|
|
545
|
+
)}
|
|
546
|
+
</div>
|
|
426
547
|
</div>
|
|
427
548
|
)}
|
|
428
549
|
|
|
@@ -440,7 +561,11 @@ function OneToManyRelation({
|
|
|
440
561
|
// Real metadata-driven table — same metacore-ui primitives and
|
|
441
562
|
// cell renderers as `<DynamicTable>` so headers, money/currency,
|
|
442
563
|
// FK thumbnails, dates and badges all match the main table.
|
|
443
|
-
|
|
564
|
+
// `max-h` + scroll propio: la sub-tabla no puede estirar el modal
|
|
565
|
+
// del padre a lo alto de cientos de filas. El sentinel del fondo
|
|
566
|
+
// pide la página siguiente al entrar en vista.
|
|
567
|
+
<OptionsContext.Provider value={optionsCtx}>
|
|
568
|
+
<div ref={rootRef} className="overflow-auto max-h-[60vh] border rounded-md bg-card">
|
|
444
569
|
<Table noWrapper className="w-full">
|
|
445
570
|
<TableHeader>
|
|
446
571
|
{table.getHeaderGroups().map((headerGroup: HeaderGroup<any>) => (
|
|
@@ -477,6 +602,23 @@ function OneToManyRelation({
|
|
|
477
602
|
))}
|
|
478
603
|
</TableBody>
|
|
479
604
|
</Table>
|
|
605
|
+
{loadingMore && (
|
|
606
|
+
<div className="p-2">
|
|
607
|
+
<Skeleton className="h-8 w-full" />
|
|
608
|
+
</div>
|
|
609
|
+
)}
|
|
610
|
+
<div ref={sentinelRef} aria-hidden className="h-px w-full" />
|
|
611
|
+
</div>
|
|
612
|
+
</OptionsContext.Provider>
|
|
613
|
+
)}
|
|
614
|
+
|
|
615
|
+
{/* Cuánto de la relación se ve. Sin esto una sub-tabla paginada
|
|
616
|
+
miente: parece completa cuando solo trae la primera página. */}
|
|
617
|
+
{!loading && rows.length > 0 && total > rows.length && (
|
|
618
|
+
<div className="pt-2 text-end text-xs text-muted-foreground">
|
|
619
|
+
{labels.countLabel
|
|
620
|
+
.replace('{{loaded}}', String(rows.length))
|
|
621
|
+
.replace('{{total}}', String(total))}
|
|
480
622
|
</div>
|
|
481
623
|
)}
|
|
482
624
|
|
|
@@ -49,6 +49,19 @@ export interface DynamicRelationsProps {
|
|
|
49
49
|
* autónoma conserva todas las columnas.
|
|
50
50
|
*/
|
|
51
51
|
lineSubtable?: boolean
|
|
52
|
+
/**
|
|
53
|
+
* Solo renderiza las relaciones de COMPOSICIÓN — las que el kernel marca
|
|
54
|
+
* con `embed: true` (las líneas de un documento). Es lo que usan los MODALES
|
|
55
|
+
* de registro: antes embebían TODAS las relaciones one_to_many del modelo,
|
|
56
|
+
* así que abrir "Editar Almacén" arrastraba miles de existencias y traspasos
|
|
57
|
+
* al formulario. Las relaciones no embebidas siguen accesibles desde su
|
|
58
|
+
* propia página / la vista de detalle, que renderiza el listado completo.
|
|
59
|
+
*
|
|
60
|
+
* Default false: una página de detalle autónoma sigue mostrando todas.
|
|
61
|
+
* Una relación sin `embed` (kernel viejo) NO se embebe — el gate falla del
|
|
62
|
+
* lado seguro.
|
|
63
|
+
*/
|
|
64
|
+
embedOnly?: boolean
|
|
52
65
|
/** Bubble up when any panel's data changes (create/delete/attach/detach). */
|
|
53
66
|
onChange?: (relation: RelationMeta) => void
|
|
54
67
|
}
|
|
@@ -90,6 +103,17 @@ export function buildRelationFilters(
|
|
|
90
103
|
return out
|
|
91
104
|
}
|
|
92
105
|
|
|
106
|
+
/**
|
|
107
|
+
* ¿La relación es de COMPOSICIÓN (embebible en un modal)? Solo `embed: true`
|
|
108
|
+
* califica: la ausencia del flag — un kernel viejo que todavía no lo sirve —
|
|
109
|
+
* significa NO embeber, que es el lado seguro (el costo de un falso negativo
|
|
110
|
+
* es un panel de menos en el modal; el de un falso positivo, miles de filas
|
|
111
|
+
* dentro de un formulario).
|
|
112
|
+
*/
|
|
113
|
+
export function isEmbedded(rel: Pick<RelationMeta, 'embed'>): boolean {
|
|
114
|
+
return rel.embed === true
|
|
115
|
+
}
|
|
116
|
+
|
|
93
117
|
/** Stable React key for a relation panel. */
|
|
94
118
|
function relationKey(rel: RelationMeta, idx: number): string {
|
|
95
119
|
return rel.name || `${rel.through}-${rel.foreign_key}-${idx}`
|
|
@@ -106,6 +130,7 @@ export function DynamicRelations({
|
|
|
106
130
|
canEdit = true,
|
|
107
131
|
strings,
|
|
108
132
|
lineSubtable = false,
|
|
133
|
+
embedOnly = false,
|
|
109
134
|
onChange,
|
|
110
135
|
}: DynamicRelationsProps) {
|
|
111
136
|
const parentId = useMemo(
|
|
@@ -113,7 +138,14 @@ export function DynamicRelations({
|
|
|
113
138
|
[record, parentIdKey],
|
|
114
139
|
)
|
|
115
140
|
|
|
116
|
-
|
|
141
|
+
// Gate de composición: en un modal solo entran las relaciones marcadas
|
|
142
|
+
// `embed` por el kernel. Fuera del modal la lista pasa entera.
|
|
143
|
+
const visible = useMemo(
|
|
144
|
+
() => (embedOnly ? (relations || []).filter(isEmbedded) : relations || []),
|
|
145
|
+
[relations, embedOnly],
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
if (parentId === undefined || visible.length === 0) {
|
|
117
149
|
return null
|
|
118
150
|
}
|
|
119
151
|
|
|
@@ -122,7 +154,7 @@ export function DynamicRelations({
|
|
|
122
154
|
// pedido" and "Facturas" in the view modal) — without it consecutive
|
|
123
155
|
// panels sat flush against each other with no breathing room.
|
|
124
156
|
<div className={cn('space-y-6', className)} data-dynamic-relations="">
|
|
125
|
-
{
|
|
157
|
+
{visible.map((rel, idx) => {
|
|
126
158
|
const filters = buildRelationFilters(rel, parentId)
|
|
127
159
|
const panelStrings: Partial<DynamicRelationStrings> = {
|
|
128
160
|
...(strings || {}),
|
package/src/index.ts
CHANGED
package/src/types.ts
CHANGED
|
@@ -194,6 +194,15 @@ export interface RelationMeta {
|
|
|
194
194
|
readonly?: boolean
|
|
195
195
|
/** camelCase alias for `readonly`. */
|
|
196
196
|
readOnly?: boolean
|
|
197
|
+
/**
|
|
198
|
+
* Composition relation: its children are PART of the parent record (a
|
|
199
|
+
* document's lines), so the record MODAL embeds them as a sub-table.
|
|
200
|
+
* Opt-in — a modal renders only the relations carrying this flag, which is
|
|
201
|
+
* what keeps opening a warehouse from loading every stock movement it has.
|
|
202
|
+
* Served by the kernel from the manifest relation's `embed`. Absent (older
|
|
203
|
+
* kernels) = not embedded.
|
|
204
|
+
*/
|
|
205
|
+
embed?: boolean
|
|
197
206
|
}
|
|
198
207
|
|
|
199
208
|
export interface FilterDefinition {
|