@asteby/metacore-runtime-react 28.6.0 → 28.8.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.
- package/CHANGELOG.md +32 -0
- package/dist/dialogs/import.d.ts.map +1 -1
- package/dist/dialogs/import.js +17 -6
- package/dist/dynamic-columns.d.ts.map +1 -1
- package/dist/dynamic-columns.js +13 -1
- package/dist/dynamic-table.d.ts +10 -1
- package/dist/dynamic-table.d.ts.map +1 -1
- package/dist/dynamic-table.js +10 -3
- package/dist/entity-select.d.ts +43 -0
- package/dist/entity-select.d.ts.map +1 -0
- package/dist/entity-select.js +124 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/print-document-button.d.ts +21 -0
- package/dist/print-document-button.d.ts.map +1 -0
- package/dist/print-document-button.js +32 -0
- package/dist/types.d.ts +29 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/use-print-document.d.ts +25 -0
- package/dist/use-print-document.d.ts.map +1 -0
- package/dist/use-print-document.js +79 -0
- package/package.json +1 -1
- package/src/dialogs/import.tsx +48 -18
- package/src/dynamic-columns.tsx +14 -1
- package/src/dynamic-table.tsx +24 -4
- package/src/entity-select.tsx +316 -0
- package/src/index.ts +4 -0
- package/src/print-document-button.tsx +75 -0
- package/src/types.ts +31 -0
- package/src/use-print-document.ts +112 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,37 @@
|
|
|
1
1
|
# @asteby/metacore-runtime-react
|
|
2
2
|
|
|
3
|
+
## 28.8.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 3db2705: Nuevo primitivo `EntitySelect`: combobox async de un modelo relacionado con las dos affordances del modal dinámico — "+" para CREAR (sin selección) que auto-selecciona el creado, y lápiz para EDITAR el seleccionado. Ambas gateadas por permisos del kernel (useCan: `<model>.create`/`.update`) y 100% dinámicas (el form sale de `/metadata/modal/:model` vía CreateRecordDialog). Reemplaza los pickers bespoke duplicados en POS/purchases por una sola implementación reusable.
|
|
8
|
+
- 8346d8d: PrintDocumentButton: botón reusable de impresión de documentos
|
|
9
|
+
|
|
10
|
+
Componente drop-in sobre usePrintDocument: renderiza un <button> (estilable con
|
|
11
|
+
className) que imprime/descarga/abre un documento del servidor, se deshabilita
|
|
12
|
+
mientras baja el PDF (aria-busy) y reporta errores por onError. Evita recablear
|
|
13
|
+
el hook + estado de carga en cada addon.
|
|
14
|
+
|
|
15
|
+
- 05bc470: usePrintDocument: primitivo reusable para imprimir documentos del servidor
|
|
16
|
+
|
|
17
|
+
Nuevo hook que cualquier addon federado usa para imprimir/descargar/abrir un
|
|
18
|
+
documento renderizado por el motor de docs de ops (ticket, comprobante, orden):
|
|
19
|
+
GET /api/data/:model/:id/documents/:key.pdf. Fetch con auth vía el ApiClient
|
|
20
|
+
inyectado (el endpoint es Bearer-gated, no se puede window.open directo), blob →
|
|
21
|
+
iframe print (modo default, ideal para ticket térmico), download u open. Era el
|
|
22
|
+
primitivo de impresión que faltaba en el SDK (había 0). Habilita el auto-print del
|
|
23
|
+
POS al cerrar venta.
|
|
24
|
+
|
|
25
|
+
### Patch Changes
|
|
26
|
+
|
|
27
|
+
- 233d63b: DynamicTable: una celda `creator` sin actor resuelto (registro creado por el sistema, `created_by` null) muestra "Sistema" en vez de "N/A", consistente con el fallback del historial de actividad. `user`/`avatar`/`search` mantienen "N/A" (vacío = sin asignar).
|
|
28
|
+
|
|
29
|
+
## 28.7.0
|
|
30
|
+
|
|
31
|
+
### Minor Changes
|
|
32
|
+
|
|
33
|
+
- 1c8c4fe: Unifica el flujo de importación alrededor de la `ImportSpec` que sirve el kernel. `starter-core` traía una copia byte a byte del `ImportDialog` de `runtime-react` (414 líneas) que nadie importaba y cuyos endpoints ya habían divergido (`/data/` vs `/dynamic/`): se elimina y el de `runtime-react` queda canónico. El diálogo acepta `.xlsx` además de CSV/JSON, y normaliza los errores por fila del backend nuevo (`{row, column, message}` en validate, `{row, column, error}` en import) sin romper el formato anterior (`{row, field, message}`), que antes renderizaba celdas vacías. `TableMetadata.import` queda tipado (`ImportSpecMeta`/`ImportColumnMeta`): cuando el kernel sirve la spec, la acción de importar aparece sin que el host encienda ninguna bandera, porque el modelo declaró sus columnas o el kernel las derivó de su formulario. Se agregan `hideImport` y `hideExport` por vista, para las tablas con alcance por rol que no quieren el punto de entrada masivo aunque el modelo lo soporte.
|
|
34
|
+
|
|
3
35
|
## 28.6.0
|
|
4
36
|
|
|
5
37
|
### Minor Changes
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"import.d.ts","sourceRoot":"","sources":["../../src/dialogs/import.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"import.d.ts","sourceRoot":"","sources":["../../src/dialogs/import.tsx"],"names":[],"mappings":"AA0BA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAG7C,UAAU,iBAAiB;IACvB,IAAI,EAAE,OAAO,CAAA;IACb,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;IACrC,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,aAAa,CAAA;IACvB,UAAU,CAAC,EAAE,MAAM,IAAI,CAAA;CAC1B;AAqCD,wBAAgB,YAAY,CAAC,EACzB,IAAI,EACJ,YAAY,EACZ,KAAK,EACL,QAAQ,EACR,UAAU,GACb,EAAE,iBAAiB,+BAkWnB"}
|
package/dist/dialogs/import.js
CHANGED
|
@@ -1,12 +1,21 @@
|
|
|
1
1
|
import { jsxs as _jsxs, jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
-
// ImportDialog — three-step CSV/JSON import flow (upload → validate →
|
|
3
|
-
// with per-row error report).
|
|
2
|
+
// ImportDialog — three-step XLSX/CSV/JSON import flow (upload → validate →
|
|
3
|
+
// import with per-row error report). The template, the accepted columns and
|
|
4
|
+
// the validation rules all come from the model's ImportSpec served by the
|
|
5
|
+
// kernel, so this dialog carries no per-model knowledge. Axios-like client is
|
|
6
|
+
// provided by <ApiProvider>.
|
|
4
7
|
import { useState, useEffect, useRef } from 'react';
|
|
5
8
|
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter, Button, Input, Label, Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from '@asteby/metacore-ui/primitives';
|
|
6
9
|
import { Progress } from './_primitives';
|
|
7
10
|
import { toast } from 'sonner';
|
|
8
11
|
import { FileDown, Loader2, Check, AlertCircle } from 'lucide-react';
|
|
9
12
|
import { useApi } from '../api-context';
|
|
13
|
+
function errorColumn(e) {
|
|
14
|
+
return e.column ?? e.field ?? '';
|
|
15
|
+
}
|
|
16
|
+
function errorMessage(e) {
|
|
17
|
+
return e.message ?? e.error ?? '';
|
|
18
|
+
}
|
|
10
19
|
export function ImportDialog({ open, onOpenChange, model, metadata, onImported, }) {
|
|
11
20
|
const api = useApi();
|
|
12
21
|
const [step, setStep] = useState('upload');
|
|
@@ -42,7 +51,7 @@ export function ImportDialog({ open, onOpenChange, model, metadata, onImported,
|
|
|
42
51
|
const url = window.URL.createObjectURL(response.data);
|
|
43
52
|
const link = document.createElement('a');
|
|
44
53
|
link.href = url;
|
|
45
|
-
link.download = `${model}-plantilla.
|
|
54
|
+
link.download = `${model}-plantilla.xlsx`;
|
|
46
55
|
document.body.appendChild(link);
|
|
47
56
|
link.click();
|
|
48
57
|
document.body.removeChild(link);
|
|
@@ -66,7 +75,8 @@ export function ImportDialog({ open, onOpenChange, model, metadata, onImported,
|
|
|
66
75
|
});
|
|
67
76
|
const data = res.data?.data ?? res.data;
|
|
68
77
|
setValidationResult({
|
|
69
|
-
valid: data.valid ?? 0,
|
|
78
|
+
valid: data.rowCount ?? data.valid ?? 0,
|
|
79
|
+
skipped: data.skipped ?? 0,
|
|
70
80
|
errors: data.errors ?? [],
|
|
71
81
|
});
|
|
72
82
|
setStep('validation');
|
|
@@ -98,7 +108,8 @@ export function ImportDialog({ open, onOpenChange, model, metadata, onImported,
|
|
|
98
108
|
const data = res.data?.data ?? res.data;
|
|
99
109
|
setImportResult({
|
|
100
110
|
created: data.created ?? 0,
|
|
101
|
-
|
|
111
|
+
skipped: data.skipped ?? 0,
|
|
112
|
+
errors: data.failures ?? data.errors ?? [],
|
|
102
113
|
});
|
|
103
114
|
setStep('results');
|
|
104
115
|
if ((data.created ?? 0) > 0) {
|
|
@@ -122,6 +133,6 @@ export function ImportDialog({ open, onOpenChange, model, metadata, onImported,
|
|
|
122
133
|
validation: 'Validacion',
|
|
123
134
|
results: 'Resultados',
|
|
124
135
|
};
|
|
125
|
-
return (_jsx(Dialog, { open: open, onOpenChange: onOpenChange, children: _jsxs(DialogContent, { className: "sm:max-w-lg 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: [_jsxs(DialogTitle, { children: ["Importar ", metadata.title] }), _jsx(DialogDescription, { children: stepTitle[step] })] }), _jsxs("div", { className: "flex-1 overflow-y-auto p-6", children: [step === 'upload' && (_jsxs("div", { className: "space-y-6", children: [_jsxs("div", { children: [_jsxs(Button, { variant: "link", className: "px-0 h-auto text-sm", onClick: handleDownloadTemplate, children: [_jsx(FileDown, { className: "h-4 w-4 mr-1" }), "Descargar plantilla
|
|
136
|
+
return (_jsx(Dialog, { open: open, onOpenChange: onOpenChange, children: _jsxs(DialogContent, { className: "sm:max-w-lg 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: [_jsxs(DialogTitle, { children: ["Importar ", metadata.title] }), _jsx(DialogDescription, { children: stepTitle[step] })] }), _jsxs("div", { className: "flex-1 overflow-y-auto p-6", children: [step === 'upload' && (_jsxs("div", { className: "space-y-6", children: [_jsxs("div", { children: [_jsxs(Button, { variant: "link", className: "px-0 h-auto text-sm", onClick: handleDownloadTemplate, children: [_jsx(FileDown, { className: "h-4 w-4 mr-1" }), "Descargar plantilla"] }), _jsx("p", { className: "text-xs text-muted-foreground mt-1", children: "La plantilla trae las columnas, un ejemplo y las instrucciones. Borra la fila de ejemplo antes de subir." })] }), _jsxs("div", { className: "space-y-2", children: [_jsx(Label, { htmlFor: "import-file", className: "text-sm font-medium", children: "Archivo" }), _jsx(Input, { ref: fileInputRef, id: "import-file", type: "file", accept: ".xlsx,.xls,.csv,.json", onChange: handleFileChange, className: "cursor-pointer" }), _jsx("p", { className: "text-xs text-muted-foreground", children: "Formatos aceptados: Excel, CSV, JSON" })] })] })), step === 'validation' && validationResult && (_jsxs("div", { className: "space-y-4", children: [_jsxs("div", { className: "flex items-center gap-4", children: [_jsxs("div", { className: "flex items-center gap-2 text-sm", children: [_jsx(Check, { className: "h-4 w-4 text-green-600" }), _jsxs("span", { children: [_jsx("strong", { children: validationResult.valid }), " valido(s)"] })] }), validationResult.errors.length > 0 && (_jsxs("div", { className: "flex items-center gap-2 text-sm", children: [_jsx(AlertCircle, { className: "h-4 w-4 text-destructive" }), _jsxs("span", { children: [_jsx("strong", { children: validationResult.errors.length }), " error(es)"] })] }))] }), validationResult.skipped > 0 && (_jsxs("p", { className: "text-xs text-muted-foreground", children: ["Se ignoraron ", validationResult.skipped, " fila(s) de ejemplo de la plantilla."] })), validationResult.errors.length > 0 && (_jsx("div", { className: "border rounded-md max-h-60 overflow-auto", children: _jsxs(Table, { children: [_jsx(TableHeader, { children: _jsxs(TableRow, { children: [_jsx(TableHead, { className: "w-16", children: "Fila" }), _jsx(TableHead, { children: "Campo" }), _jsx(TableHead, { children: "Error" })] }) }), _jsx(TableBody, { children: validationResult.errors.map((error, idx) => (_jsxs(TableRow, { children: [_jsx(TableCell, { className: "font-mono text-xs", children: error.row }), _jsx(TableCell, { className: "text-sm", children: errorColumn(error) }), _jsx(TableCell, { className: "text-sm text-destructive", children: errorMessage(error) })] }, idx))) })] }) })), importing && (_jsxs("div", { className: "space-y-2", children: [_jsx(Progress, { value: progress }), _jsxs("p", { className: "text-xs text-muted-foreground text-center", children: ["Importando... ", progress > 0 ? `${progress}%` : ''] })] }))] })), step === 'results' && importResult && (_jsxs("div", { className: "space-y-4", children: [_jsxs("div", { className: "flex items-center gap-4", children: [importResult.created > 0 && (_jsxs("div", { className: "flex items-center gap-2 text-sm", children: [_jsx(Check, { className: "h-4 w-4 text-green-600" }), _jsxs("span", { children: [_jsx("strong", { children: importResult.created }), " creado(s)"] })] })), importResult.errors.length > 0 && (_jsxs("div", { className: "flex items-center gap-2 text-sm", children: [_jsx(AlertCircle, { className: "h-4 w-4 text-destructive" }), _jsxs("span", { children: [_jsx("strong", { children: importResult.errors.length }), " error(es)"] })] }))] }), importResult.created > 0 && importResult.errors.length === 0 && (_jsxs("div", { className: "flex items-center gap-2 rounded-md bg-green-50 dark:bg-green-950/20 p-3 text-sm text-green-700 dark:text-green-400", children: [_jsx(Check, { className: "h-4 w-4 shrink-0" }), "Todos los registros fueron importados correctamente."] })), importResult.errors.length > 0 && (_jsx("div", { className: "border rounded-md max-h-60 overflow-auto", children: _jsxs(Table, { children: [_jsx(TableHeader, { children: _jsxs(TableRow, { children: [_jsx(TableHead, { className: "w-16", children: "Fila" }), _jsx(TableHead, { children: "Campo" }), _jsx(TableHead, { children: "Error" })] }) }), _jsx(TableBody, { children: importResult.errors.map((error, idx) => (_jsxs(TableRow, { children: [_jsx(TableCell, { className: "font-mono text-xs", children: error.row }), _jsx(TableCell, { className: "text-sm", children: errorColumn(error) }), _jsx(TableCell, { className: "text-sm text-destructive", children: errorMessage(error) })] }, idx))) })] }) }))] }))] }), _jsxs(DialogFooter, { className: "p-4 border-t shrink-0", children: [step === 'upload' && (_jsxs(_Fragment, { children: [_jsx(Button, { variant: "outline", onClick: handleClose, children: "Cancelar" }), _jsxs(Button, { onClick: handleValidate, disabled: !file || validating, children: [validating && (_jsx(Loader2, { className: "h-4 w-4 mr-1 animate-spin" })), validating ? 'Validando...' : 'Validar'] })] })), step === 'validation' && (_jsxs(_Fragment, { children: [_jsx(Button, { variant: "outline", onClick: () => setStep('upload'), disabled: importing, children: "Atras" }), _jsxs(Button, { onClick: handleImport, disabled: importing ||
|
|
126
137
|
(validationResult !== null && validationResult.valid === 0), children: [importing && (_jsx(Loader2, { className: "h-4 w-4 mr-1 animate-spin" })), importing ? 'Importando...' : 'Importar'] })] })), step === 'results' && (_jsx(Button, { onClick: handleClose, children: "Cerrar" }))] })] }) }));
|
|
127
138
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dynamic-columns.d.ts","sourceRoot":"","sources":["../src/dynamic-columns.tsx"],"names":[],"mappings":"AAcA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAE9B,OAAO,EAAU,KAAK,MAAM,EAAE,MAAM,UAAU,CAAA;AAwC9C,OAAO,KAAK,EAAiB,gBAAgB,EAAE,MAAM,SAAS,CAAA;AAE9D,OAAO,KAAK,EAER,iBAAiB,EACpB,MAAM,wBAAwB,CAAA;AAE/B,qEAAqE;AACrE,MAAM,WAAW,qBAAqB;IAClC;;;;OAIG;IACH,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAA;IACtC;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;CACtB;AA0BD;;;;GAIG;AACH,eAAO,MAAM,eAAe,GAAI,KAAK,gBAAgB,EAAE,cAAc,MAAM,KAAG,MACzB,CAAA;AAQrD;;;;;GAKG;AACH,eAAO,MAAM,WAAW,GAAI,KAAK,gBAAgB,KAAG,MAAM,GAAG,SAG5D,CAAA;AAED;;;;;;GAMG;AACH,eAAO,MAAM,oBAAoB,GAC7B,KAAK,gBAAgB,EACrB,OAAO,OAAO,EACd,WAAW,MAAM,EACjB,SAAS,MAAM,KAChB,MAyBF,CAAA;AAyCD;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,0BAA0B,GAAI,QAAQ,GAAG,EAAE,KAAK,GAAG,KAAG,OAMlE,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,GAAI,QAAQ,GAAG,EAAE,KAAK,GAAG,KAAG,OAiB5D,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,GAAI,QAAQ,GAAG,EAAE,KAAK,GAAG,KAAG,OACqB,CAAA;AAwFhF;;;;;;;GAOG;AACH,eAAO,MAAM,cAAc,GAAI,KAAK,IAAI,CAAC,gBAAgB,EAAE,KAAK,CAAC,KAAG,MAGnE,CAAA;AAED,6EAA6E;AAC7E,eAAO,MAAM,eAAe,2DAA4D,CAAA;AAExF;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,cAAc,CAC1B,KAAK,EAAE,OAAO,EACd,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,MAAM,EAAE,MAAM,EACd,QAAQ,CAAC,EAAE,MAAM,GAClB;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CA6C5C;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,oBAAoB,GAAI,KAAK,gBAAgB,EAAE,KAAK,GAAG,KAAG,MAWtE,CAAA;AAED;;;;;;GAMG;AACH,eAAO,MAAM,oBAAoB,GAAI,KAAK,gBAAgB,EAAE,KAAK,GAAG,KAAG,MAOtE,CAAA;AAED;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,gBAAgB,GACzB,KAAK,gBAAgB,EACrB,KAAK,GAAG,EACR,OAAO,GAAG,EACV,mBAAe,KAChB,MAAM,GAAG,SAcX,CAAA;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,uBAAuB,GAAI,KAAK,gBAAgB,EAAE,KAAK,GAAG,KAAG,MAOzE,CAAA;AA+ID;;;;GAIG;AACH;;;;;GAKG;AACH,eAAO,MAAM,SAAS,EAAE,KAAK,CAAC,EAAE,CAAC;IAC7B,KAAK,EAAE,OAAO,CAAA;IACd,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAA;CACxC,CAqBA,CAAA;AAED,wBAAgB,4BAA4B,CACxC,OAAO,GAAE,qBAA0B,GACpC,iBAAiB,
|
|
1
|
+
{"version":3,"file":"dynamic-columns.d.ts","sourceRoot":"","sources":["../src/dynamic-columns.tsx"],"names":[],"mappings":"AAcA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAE9B,OAAO,EAAU,KAAK,MAAM,EAAE,MAAM,UAAU,CAAA;AAwC9C,OAAO,KAAK,EAAiB,gBAAgB,EAAE,MAAM,SAAS,CAAA;AAE9D,OAAO,KAAK,EAER,iBAAiB,EACpB,MAAM,wBAAwB,CAAA;AAE/B,qEAAqE;AACrE,MAAM,WAAW,qBAAqB;IAClC;;;;OAIG;IACH,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAA;IACtC;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;CACtB;AA0BD;;;;GAIG;AACH,eAAO,MAAM,eAAe,GAAI,KAAK,gBAAgB,EAAE,cAAc,MAAM,KAAG,MACzB,CAAA;AAQrD;;;;;GAKG;AACH,eAAO,MAAM,WAAW,GAAI,KAAK,gBAAgB,KAAG,MAAM,GAAG,SAG5D,CAAA;AAED;;;;;;GAMG;AACH,eAAO,MAAM,oBAAoB,GAC7B,KAAK,gBAAgB,EACrB,OAAO,OAAO,EACd,WAAW,MAAM,EACjB,SAAS,MAAM,KAChB,MAyBF,CAAA;AAyCD;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,0BAA0B,GAAI,QAAQ,GAAG,EAAE,KAAK,GAAG,KAAG,OAMlE,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,GAAI,QAAQ,GAAG,EAAE,KAAK,GAAG,KAAG,OAiB5D,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,GAAI,QAAQ,GAAG,EAAE,KAAK,GAAG,KAAG,OACqB,CAAA;AAwFhF;;;;;;;GAOG;AACH,eAAO,MAAM,cAAc,GAAI,KAAK,IAAI,CAAC,gBAAgB,EAAE,KAAK,CAAC,KAAG,MAGnE,CAAA;AAED,6EAA6E;AAC7E,eAAO,MAAM,eAAe,2DAA4D,CAAA;AAExF;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,cAAc,CAC1B,KAAK,EAAE,OAAO,EACd,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,MAAM,EAAE,MAAM,EACd,QAAQ,CAAC,EAAE,MAAM,GAClB;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CA6C5C;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,oBAAoB,GAAI,KAAK,gBAAgB,EAAE,KAAK,GAAG,KAAG,MAWtE,CAAA;AAED;;;;;;GAMG;AACH,eAAO,MAAM,oBAAoB,GAAI,KAAK,gBAAgB,EAAE,KAAK,GAAG,KAAG,MAOtE,CAAA;AAED;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,gBAAgB,GACzB,KAAK,gBAAgB,EACrB,KAAK,GAAG,EACR,OAAO,GAAG,EACV,mBAAe,KAChB,MAAM,GAAG,SAcX,CAAA;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,uBAAuB,GAAI,KAAK,gBAAgB,EAAE,KAAK,GAAG,KAAG,MAOzE,CAAA;AA+ID;;;;GAIG;AACH;;;;;GAKG;AACH,eAAO,MAAM,SAAS,EAAE,KAAK,CAAC,EAAE,CAAC;IAC7B,KAAK,EAAE,OAAO,CAAA;IACd,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAA;CACxC,CAqBA,CAAA;AAED,wBAAgB,4BAA4B,CACxC,OAAO,GAAE,qBAA0B,GACpC,iBAAiB,CA+mBnB;AAED;;;;GAIG;AACH,eAAO,MAAM,wBAAwB,EAAE,iBACL,CAAA"}
|
package/dist/dynamic-columns.js
CHANGED
|
@@ -622,7 +622,19 @@ export function makeDefaultGetDynamicColumns(helpers = {}) {
|
|
|
622
622
|
col.tooltip ||
|
|
623
623
|
col.displayField ||
|
|
624
624
|
col.key;
|
|
625
|
-
|
|
625
|
+
// A `creator` cell with no resolved actor means the
|
|
626
|
+
// record was created by the SYSTEM (e.g. an owner /
|
|
627
|
+
// seed row whose `created_by` is null), not a missing
|
|
628
|
+
// value — show "Sistema" rather than "N/A". Matches
|
|
629
|
+
// the record-history actor fallback. `user`/`avatar`/
|
|
630
|
+
// `search` keep "N/A" (empty there means unassigned).
|
|
631
|
+
const resolvedName = getNestedValue(row.original, namePath);
|
|
632
|
+
const name = resolvedName ||
|
|
633
|
+
(renderAs === 'creator'
|
|
634
|
+
? t
|
|
635
|
+
? t('common.system', { defaultValue: 'Sistema' })
|
|
636
|
+
: 'Sistema'
|
|
637
|
+
: 'N/A');
|
|
626
638
|
const desc = getNestedValue(row.original, col.description || '');
|
|
627
639
|
const avatarSrc = resolveAvatarSrc(col, row.original, value, apiBaseUrl);
|
|
628
640
|
return (_jsx(AvatarCell, { name: String(name), desc: desc ? String(desc) : undefined, avatarSrc: avatarSrc, getImageUrl: getImageUrl }));
|
package/dist/dynamic-table.d.ts
CHANGED
|
@@ -10,6 +10,15 @@ export interface DynamicTableProps {
|
|
|
10
10
|
*/
|
|
11
11
|
mutationEndpoint?: string;
|
|
12
12
|
enableUrlSync?: boolean;
|
|
13
|
+
/**
|
|
14
|
+
* Hide the import action on THIS view even when the model supports it.
|
|
15
|
+
* A role-scoped view (e.g. a rep seeing only their own records) usually
|
|
16
|
+
* wants the table without a bulk-import entry point, while the same model
|
|
17
|
+
* keeps it on the admin view. Absent → the model's metadata decides.
|
|
18
|
+
*/
|
|
19
|
+
hideImport?: boolean;
|
|
20
|
+
/** Hide the export action on this view. See `hideImport`. */
|
|
21
|
+
hideExport?: boolean;
|
|
13
22
|
hiddenColumns?: string[];
|
|
14
23
|
onAction?: (action: string, row: any) => void;
|
|
15
24
|
/**
|
|
@@ -64,5 +73,5 @@ export interface DynamicTableProps {
|
|
|
64
73
|
*/
|
|
65
74
|
infiniteScroll?: boolean;
|
|
66
75
|
}
|
|
67
|
-
export declare function DynamicTable({ model, endpoint, mutationEndpoint, enableUrlSync, hiddenColumns, onAction, onRowClick, refreshTrigger, defaultFilters, extraColumns, getDynamicColumns, timeZone, currency, pagination: paginationMode, infiniteScroll: infiniteScrollProp, }: DynamicTableProps): import("react").JSX.Element;
|
|
76
|
+
export declare function DynamicTable({ model, endpoint, mutationEndpoint, enableUrlSync, hideImport, hideExport, hiddenColumns, onAction, onRowClick, refreshTrigger, defaultFilters, extraColumns, getDynamicColumns, timeZone, currency, pagination: paginationMode, infiniteScroll: infiniteScrollProp, }: DynamicTableProps): import("react").JSX.Element;
|
|
68
77
|
//# sourceMappingURL=dynamic-table.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dynamic-table.d.ts","sourceRoot":"","sources":["../src/dynamic-table.tsx"],"names":[],"mappings":"AAgBA,OAAO,EAKH,KAAK,SAAS,EAajB,MAAM,uBAAuB,CAAA;AAgC9B,OAAO,KAAK,EAAsB,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AA2FnF,MAAM,WAAW,iBAAiB;IAC9B,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAA;IACxB,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,KAAK,IAAI,CAAA;IAC7C;;;;;OAKG;IACH,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,IAAI,CAAA;IAC/B,cAAc,CAAC,EAAE,GAAG,CAAA;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IACpC,YAAY,CAAC,EAAE,SAAS,CAAC,GAAG,CAAC,EAAE,CAAA;IAC/B;;;;;OAKG;IACH,iBAAiB,CAAC,EAAE,iBAAiB,CAAA;IACrC;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;;;;;;;;;;;;OAaG;IACH,UAAU,CAAC,EAAE,OAAO,GAAG,UAAU,CAAA;IACjC;;;;OAIG;IACH,cAAc,CAAC,EAAE,OAAO,CAAA;CAC3B;AAED,wBAAgB,YAAY,CAAC,EACzB,KAAK,EACL,QAAQ,EACR,gBAAgB,EAChB,aAAoB,EACpB,aAAkB,EAClB,QAAQ,EACR,UAAU,EACV,cAAc,EACd,cAAc,EACd,YAAiB,EACjB,iBAA4C,EAC5C,QAAQ,EACR,QAAQ,EACR,UAAU,EAAE,cAAc,EAC1B,cAAc,EAAE,kBAA0B,GAC7C,EAAE,iBAAiB,+
|
|
1
|
+
{"version":3,"file":"dynamic-table.d.ts","sourceRoot":"","sources":["../src/dynamic-table.tsx"],"names":[],"mappings":"AAgBA,OAAO,EAKH,KAAK,SAAS,EAajB,MAAM,uBAAuB,CAAA;AAgC9B,OAAO,KAAK,EAAsB,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AA2FnF,MAAM,WAAW,iBAAiB;IAC9B,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB;;;;;OAKG;IACH,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,6DAA6D;IAC7D,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAA;IACxB,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,KAAK,IAAI,CAAA;IAC7C;;;;;OAKG;IACH,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,IAAI,CAAA;IAC/B,cAAc,CAAC,EAAE,GAAG,CAAA;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IACpC,YAAY,CAAC,EAAE,SAAS,CAAC,GAAG,CAAC,EAAE,CAAA;IAC/B;;;;;OAKG;IACH,iBAAiB,CAAC,EAAE,iBAAiB,CAAA;IACrC;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;;;;;;;;;;;;OAaG;IACH,UAAU,CAAC,EAAE,OAAO,GAAG,UAAU,CAAA;IACjC;;;;OAIG;IACH,cAAc,CAAC,EAAE,OAAO,CAAA;CAC3B;AAED,wBAAgB,YAAY,CAAC,EACzB,KAAK,EACL,QAAQ,EACR,gBAAgB,EAChB,aAAoB,EACpB,UAAU,EACV,UAAU,EACV,aAAkB,EAClB,QAAQ,EACR,UAAU,EACV,cAAc,EACd,cAAc,EACd,YAAiB,EACjB,iBAA4C,EAC5C,QAAQ,EACR,QAAQ,EACR,UAAU,EAAE,cAAc,EAC1B,cAAc,EAAE,kBAA0B,GAC7C,EAAE,iBAAiB,+BAgvCnB"}
|
package/dist/dynamic-table.js
CHANGED
|
@@ -103,7 +103,7 @@ function writeStoredPageSize(model, size) {
|
|
|
103
103
|
// quota / private mode — persistence is a nicety, never fatal
|
|
104
104
|
}
|
|
105
105
|
}
|
|
106
|
-
export function DynamicTable({ model, endpoint, mutationEndpoint, enableUrlSync = true, hiddenColumns = [], onAction, onRowClick, refreshTrigger, defaultFilters, extraColumns = [], getDynamicColumns = defaultGetDynamicColumns, timeZone, currency, pagination: paginationMode, infiniteScroll: infiniteScrollProp = false, }) {
|
|
106
|
+
export function DynamicTable({ model, endpoint, mutationEndpoint, enableUrlSync = true, hideImport, hideExport, hiddenColumns = [], onAction, onRowClick, refreshTrigger, defaultFilters, extraColumns = [], getDynamicColumns = defaultGetDynamicColumns, timeZone, currency, pagination: paginationMode, infiniteScroll: infiniteScrollProp = false, }) {
|
|
107
107
|
// The explicit `pagination` prop wins; the legacy `infiniteScroll` boolean
|
|
108
108
|
// still selects the mode when `pagination` is absent (back-compat).
|
|
109
109
|
const infiniteScroll = paginationMode ? paginationMode === 'infinite' : infiniteScrollProp;
|
|
@@ -519,6 +519,13 @@ export function DynamicTable({ model, endpoint, mutationEndpoint, enableUrlSync
|
|
|
519
519
|
return metadata;
|
|
520
520
|
return gateTableMetadata(metadata, model, can, (key, fallback) => t(key, { defaultValue: fallback }));
|
|
521
521
|
}, [metadata, permissionsActive, can, model, t]);
|
|
522
|
+
// Importing is offered when the host opts in explicitly (`canImport`) or,
|
|
523
|
+
// when it says nothing, whenever the kernel served an import spec for the
|
|
524
|
+
// model — which it does for every model with at least one importable form
|
|
525
|
+
// field. That makes the flow work out of the box instead of requiring each
|
|
526
|
+
// host to flip a flag per view.
|
|
527
|
+
const importEnabled = !hideImport && (viewMetadata?.canImport ?? Boolean(viewMetadata?.import?.columns?.length));
|
|
528
|
+
const exportEnabled = !hideExport && Boolean(viewMetadata?.canExport);
|
|
522
529
|
const buildFilterParams = useCallback(() => {
|
|
523
530
|
const params = {};
|
|
524
531
|
if (sorting.length > 0) {
|
|
@@ -1028,7 +1035,7 @@ export function DynamicTable({ model, endpoint, mutationEndpoint, enableUrlSync
|
|
|
1028
1035
|
if (!metadata) {
|
|
1029
1036
|
return _jsx("div", { className: "text-center text-muted-foreground py-8", children: "Error al cargar la configuraci\u00F3n de la tabla." });
|
|
1030
1037
|
}
|
|
1031
|
-
return (_jsxs(OptionsContext.Provider, { value: { optionsMap }, children: [_jsxs("div", { className: 'flex flex-col h-full min-h-0 w-full', children: [_jsx("div", { className: 'pb-4 shrink-0', children: _jsx(DataTableToolbar, { table: table, searchPlaceholder: metadata.searchPlaceholder || 'Buscar...', filters: filters, activeFilters: dynamicFilters, onDynamicFilterChange: handleDynamicFilterChange, dateFilter: { value: dateRange, onChange: setDateRange, placeholder: 'Filtrar por fecha' }, perPageOptions: metadata.perPageOptions, onRefresh: handleRefresh, isLoading: loadingData, selectedCount: Object.keys(rowSelection).length, onBulkDelete: () => setShowBulkDeleteConfirm(true), extraActions: _jsxs(_Fragment, { children: [
|
|
1038
|
+
return (_jsxs(OptionsContext.Provider, { value: { optionsMap }, children: [_jsxs("div", { className: 'flex flex-col h-full min-h-0 w-full', children: [_jsx("div", { className: 'pb-4 shrink-0', children: _jsx(DataTableToolbar, { table: table, searchPlaceholder: metadata.searchPlaceholder || 'Buscar...', filters: filters, activeFilters: dynamicFilters, onDynamicFilterChange: handleDynamicFilterChange, dateFilter: { value: dateRange, onChange: setDateRange, placeholder: 'Filtrar por fecha' }, perPageOptions: metadata.perPageOptions, onRefresh: handleRefresh, isLoading: loadingData, selectedCount: Object.keys(rowSelection).length, onBulkDelete: () => setShowBulkDeleteConfirm(true), extraActions: _jsxs(_Fragment, { children: [exportEnabled && (_jsxs(Button, { variant: "outline", size: "sm", className: "h-8", onClick: () => setExportOpen(true), children: [_jsx(Download, { className: "h-4 w-4 mr-1" }), " Exportar"] })), importEnabled && (_jsxs(Button, { variant: "outline", size: "sm", className: "h-8", onClick: () => setImportOpen(true), children: [_jsx(Upload, { className: "h-4 w-4 mr-1" }), " Importar"] }))] }) }) }), _jsxs("div", { ref: infDesktopRoot, className: 'hidden sm:block flex-1 min-h-0 overflow-auto border rounded-md bg-card', children: [_jsxs(Table, { noWrapper: true, className: cn('min-w-max w-full', aggregateColumns.length > 0 && Object.keys(footerTotals).length > 0 && 'h-full'), children: [_jsx(TableHeader, { className: 'sticky top-0 z-10', children: table.getHeaderGroups().map((headerGroup) => (_jsx(TableRow, { className: 'border-b-0 hover:bg-transparent', children: headerGroup.headers.map((header) => {
|
|
1032
1039
|
const isActionsColumn = header.id === 'actions';
|
|
1033
1040
|
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', isActionsColumn && 'sticky right-0 z-20 bg-card shadow-[-2px_0_5px_-2px_rgba(0,0,0,0.1)]'), children: header.isPlaceholder ? null : flexRender(header.column.columnDef.header, header.getContext()) }, header.id));
|
|
1034
1041
|
}) }, headerGroup.id))) }), _jsx(TableBody, { children: loadingData && data.length === 0 ? (_jsx(TableSkeleton, {})) : table.getRowModel().rows?.length ? (_jsxs(_Fragment, { children: [table.getRowModel().rows.map((row) => (_jsx(TableRow, { "data-state": row.getIsSelected() && 'selected', className: cn(onRowClick && 'cursor-pointer'), onClick: onRowClick ? () => onRowClick(row.original) : undefined, children: row.getVisibleCells().map((cell) => {
|
|
@@ -1065,5 +1072,5 @@ export function DynamicTable({ model, endpoint, mutationEndpoint, enableUrlSync
|
|
|
1065
1072
|
defaultValue: '{{count}} de {{total}}',
|
|
1066
1073
|
count: data.length,
|
|
1067
1074
|
total: rowCount,
|
|
1068
|
-
}) }))) : (_jsx(DataTablePagination, { table: table, pageSizeOptions: metadata.perPageOptions })) })] }), rowActionDialogs, _jsx(AlertDialog, { open: showBulkDeleteConfirm, onOpenChange: (open) => !open && !isBulkDeleting && setShowBulkDeleteConfirm(false), children: _jsxs(AlertDialogContent, { children: [_jsxs(AlertDialogHeader, { children: [_jsx(AlertDialogTitle, { children: isBulkDeleting ? 'Eliminando registros...' : '¿Eliminar múltiples registros?' }), _jsx(AlertDialogDescription, { children: isBulkDeleting ? (_jsxs("div", { className: "space-y-4 mt-4", children: [_jsx(Progress, { value: (bulkDeleteProgress / bulkDeleteTotal) * 100 }), _jsxs("p", { className: "text-center text-sm", children: ["Procesando ", bulkDeleteProgress, " de ", bulkDeleteTotal, " registros..."] })] })) : (_jsxs(_Fragment, { children: ["Esta acci\u00F3n no se puede deshacer. Se eliminar\u00E1n permanentemente ", _jsx("strong", { children: Object.keys(rowSelection).length }), " registro(s) de nuestros servidores."] })) })] }), !isBulkDeleting && (_jsxs(AlertDialogFooter, { children: [_jsx(AlertDialogCancel, { children: t('common.cancel') }), _jsx(AlertDialogAction, { onClick: (e) => { e.preventDefault(); confirmBulkDelete(); }, className: "bg-red-600 hover:bg-red-700", children: "Eliminar todos" })] }))] }) }),
|
|
1075
|
+
}) }))) : (_jsx(DataTablePagination, { table: table, pageSizeOptions: metadata.perPageOptions })) })] }), rowActionDialogs, _jsx(AlertDialog, { open: showBulkDeleteConfirm, onOpenChange: (open) => !open && !isBulkDeleting && setShowBulkDeleteConfirm(false), children: _jsxs(AlertDialogContent, { children: [_jsxs(AlertDialogHeader, { children: [_jsx(AlertDialogTitle, { children: isBulkDeleting ? 'Eliminando registros...' : '¿Eliminar múltiples registros?' }), _jsx(AlertDialogDescription, { children: isBulkDeleting ? (_jsxs("div", { className: "space-y-4 mt-4", children: [_jsx(Progress, { value: (bulkDeleteProgress / bulkDeleteTotal) * 100 }), _jsxs("p", { className: "text-center text-sm", children: ["Procesando ", bulkDeleteProgress, " de ", bulkDeleteTotal, " registros..."] })] })) : (_jsxs(_Fragment, { children: ["Esta acci\u00F3n no se puede deshacer. Se eliminar\u00E1n permanentemente ", _jsx("strong", { children: Object.keys(rowSelection).length }), " registro(s) de nuestros servidores."] })) })] }), !isBulkDeleting && (_jsxs(AlertDialogFooter, { children: [_jsx(AlertDialogCancel, { children: t('common.cancel') }), _jsx(AlertDialogAction, { onClick: (e) => { e.preventDefault(); confirmBulkDelete(); }, className: "bg-red-600 hover:bg-red-700", children: "Eliminar todos" })] }))] }) }), exportEnabled && (_jsx(ExportDialog, { open: exportOpen, onOpenChange: setExportOpen, model: model, metadata: metadata, currentFilters: buildFilterParams(), hasActiveFilters: hasActiveFilters })), importEnabled && (_jsx(ImportDialog, { open: importOpen, onOpenChange: setImportOpen, model: model, metadata: metadata, onImported: handleRefresh })), _jsx(DataTableBulkActions, { table: table, entityName: "registro", children: _jsxs(Button, { variant: "destructive", size: "sm", className: "h-8", onClick: () => setShowBulkDeleteConfirm(true), children: [_jsx(Trash2, { className: "h-4 w-4 mr-1.5" }), " Eliminar"] }) })] }));
|
|
1069
1076
|
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { type LucideIcon } from 'lucide-react';
|
|
2
|
+
/** One searchable option: `value` is the id, `label` the display text. */
|
|
3
|
+
export interface EntitySelectOption {
|
|
4
|
+
value: string;
|
|
5
|
+
label: string;
|
|
6
|
+
description?: string;
|
|
7
|
+
}
|
|
8
|
+
export interface EntitySelectProps {
|
|
9
|
+
/** Kernel model key (e.g. "Supplier", "Warehouse", "Category"). */
|
|
10
|
+
model: string;
|
|
11
|
+
/** Currently selected id (or null). */
|
|
12
|
+
value: string | null;
|
|
13
|
+
/** Label of the selected record (rendered without a re-fetch). */
|
|
14
|
+
label: string | null;
|
|
15
|
+
/** Called with (id, label) on select/create/clear. */
|
|
16
|
+
onSelect: (id: string | null, label: string | null) => void;
|
|
17
|
+
/** Async search over the model. Callers pass their `/api/options/<model>` fetcher. */
|
|
18
|
+
fetcher: (q: string, signal: AbortSignal) => Promise<EntitySelectOption[]>;
|
|
19
|
+
icon?: LucideIcon;
|
|
20
|
+
placeholder?: string;
|
|
21
|
+
searchPlaceholder?: string;
|
|
22
|
+
emptyText?: string;
|
|
23
|
+
/** Preload first results on open and drop the 2-char gate. */
|
|
24
|
+
preload?: boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Permission overrides. By default create/edit are gated by the kernel
|
|
27
|
+
* permissions `<model>.create` / `<model>.update` (useCan). Pass explicit
|
|
28
|
+
* booleans to force them (e.g. a read-only surface).
|
|
29
|
+
*/
|
|
30
|
+
canCreate?: boolean;
|
|
31
|
+
canEdit?: boolean;
|
|
32
|
+
/**
|
|
33
|
+
* CRUD endpoint base for the create/edit dialog. Defaults to the standard
|
|
34
|
+
* org-scoped `/data/<model>/me`, with edit at `/data/<model>/me/<id>`.
|
|
35
|
+
*/
|
|
36
|
+
endpoint?: string;
|
|
37
|
+
/** Record field used as the label after create/edit (default "name"). */
|
|
38
|
+
labelField?: string;
|
|
39
|
+
/** Disable the whole control. */
|
|
40
|
+
disabled?: boolean;
|
|
41
|
+
}
|
|
42
|
+
export declare function EntitySelect({ model, value, label, onSelect, fetcher, icon: Icon, placeholder, searchPlaceholder, emptyText, preload, canCreate, canEdit, endpoint, labelField, disabled, }: EntitySelectProps): import("react").JSX.Element;
|
|
43
|
+
//# sourceMappingURL=entity-select.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entity-select.d.ts","sourceRoot":"","sources":["../src/entity-select.tsx"],"names":[],"mappings":"AAiBA,OAAO,EAA2B,KAAK,UAAU,EAAE,MAAM,cAAc,CAAA;AAiBvE,0EAA0E;AAC1E,MAAM,WAAW,kBAAkB;IAC/B,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,CAAC,EAAE,MAAM,CAAA;CACvB;AAED,MAAM,WAAW,iBAAiB;IAC9B,mEAAmE;IACnE,KAAK,EAAE,MAAM,CAAA;IACb,uCAAuC;IACvC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,kEAAkE;IAClE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,sDAAsD;IACtD,QAAQ,EAAE,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAA;IAC3D,sFAAsF;IACtF,OAAO,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,KAAK,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAAA;IAE1E,IAAI,CAAC,EAAE,UAAU,CAAA;IACjB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,8DAA8D;IAC9D,OAAO,CAAC,EAAE,OAAO,CAAA;IAEjB;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,OAAO,CAAC,EAAE,OAAO,CAAA;IAEjB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,yEAAyE;IACzE,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,iCAAiC;IACjC,QAAQ,CAAC,EAAE,OAAO,CAAA;CACrB;AAOD,wBAAgB,YAAY,CAAC,EACzB,KAAK,EACL,KAAK,EACL,KAAK,EACL,QAAQ,EACR,OAAO,EACP,IAAI,EAAE,IAAI,EACV,WAA4B,EAC5B,iBAA6B,EAC7B,SAA4B,EAC5B,OAAe,EACf,SAAS,EACT,OAAO,EACP,QAAQ,EACR,UAAmB,EACnB,QAAgB,GACnB,EAAE,iBAAiB,+BAuNnB"}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
// EntitySelect — the shared, permission-aware single-select for a related model.
|
|
3
|
+
//
|
|
4
|
+
// A searchable async combobox over a kernel model's records, plus the two
|
|
5
|
+
// affordances every "pick a related record" control should have, exactly like
|
|
6
|
+
// the dynamic create modal's relation fields (Categoría/Marca) do:
|
|
7
|
+
//
|
|
8
|
+
// - nothing selected → a "+" that opens the model's CREATE dialog, and
|
|
9
|
+
// auto-selects the record it creates;
|
|
10
|
+
// - a record selected → a pencil that opens that record's EDIT dialog.
|
|
11
|
+
//
|
|
12
|
+
// Both affordances are gated by the kernel permissions (useCan): the "+" only
|
|
13
|
+
// shows when the user can create the model, the pencil only when they can edit
|
|
14
|
+
// it. Everything is DYNAMIC — the create/edit form comes from the model's
|
|
15
|
+
// `/metadata/modal/:model` schema via <CreateRecordDialog>, so no per-model form
|
|
16
|
+
// code is needed. This lives in the SDK so POS, purchases and any future addon
|
|
17
|
+
// share ONE implementation instead of each re-porting a bespoke picker.
|
|
18
|
+
import { useCallback, useEffect, useState } from 'react';
|
|
19
|
+
import { Search, X, Plus, Pencil } from 'lucide-react';
|
|
20
|
+
import { Button, Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, Popover, PopoverContent, PopoverTrigger, } from '@asteby/metacore-ui';
|
|
21
|
+
import { CreateRecordDialog } from './dialogs/create-record-dialog';
|
|
22
|
+
import { useCan } from './permissions-context';
|
|
23
|
+
import { useApi } from './api-context';
|
|
24
|
+
/** Lowercase model → permission capability namespace (Supplier → supplier). */
|
|
25
|
+
function capabilityNamespace(model) {
|
|
26
|
+
return model.replace(/([a-z0-9])([A-Z])/g, '$1_$2').toLowerCase();
|
|
27
|
+
}
|
|
28
|
+
export function EntitySelect({ model, value, label, onSelect, fetcher, icon: Icon, placeholder = 'Seleccionar…', searchPlaceholder = 'Buscar…', emptyText = 'Sin resultados', preload = false, canCreate, canEdit, endpoint, labelField = 'name', disabled = false, }) {
|
|
29
|
+
const can = useCan();
|
|
30
|
+
const api = useApi();
|
|
31
|
+
const ns = capabilityNamespace(model);
|
|
32
|
+
const mayCreate = canCreate ?? can(`${ns}.create`);
|
|
33
|
+
const mayEdit = canEdit ?? can(`${ns}.update`);
|
|
34
|
+
const base = endpoint ?? `/data/${model}/me`;
|
|
35
|
+
const [open, setOpen] = useState(false);
|
|
36
|
+
const [dialogOpen, setDialogOpen] = useState(false);
|
|
37
|
+
const [dialogRecordId, setDialogRecordId] = useState(undefined);
|
|
38
|
+
const [searchTerm, setSearchTerm] = useState('');
|
|
39
|
+
const [results, setResults] = useState([]);
|
|
40
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
41
|
+
const minChars = preload ? 0 : 2;
|
|
42
|
+
const run = useCallback(async (q, signal) => {
|
|
43
|
+
if (q.length < minChars) {
|
|
44
|
+
setResults([]);
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
setIsLoading(true);
|
|
48
|
+
try {
|
|
49
|
+
const rows = await fetcher(q, signal);
|
|
50
|
+
if (!signal.aborted)
|
|
51
|
+
setResults(rows);
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
if (!signal.aborted)
|
|
55
|
+
setResults([]);
|
|
56
|
+
}
|
|
57
|
+
finally {
|
|
58
|
+
if (!signal.aborted)
|
|
59
|
+
setIsLoading(false);
|
|
60
|
+
}
|
|
61
|
+
}, [fetcher, minChars]);
|
|
62
|
+
useEffect(() => {
|
|
63
|
+
if (!open)
|
|
64
|
+
return;
|
|
65
|
+
const controller = new AbortController();
|
|
66
|
+
const timeout = setTimeout(() => run(searchTerm, controller.signal), 250);
|
|
67
|
+
return () => {
|
|
68
|
+
clearTimeout(timeout);
|
|
69
|
+
controller.abort();
|
|
70
|
+
};
|
|
71
|
+
}, [searchTerm, run, open]);
|
|
72
|
+
const pick = (row) => {
|
|
73
|
+
onSelect(row.value, row.label);
|
|
74
|
+
setOpen(false);
|
|
75
|
+
setSearchTerm('');
|
|
76
|
+
};
|
|
77
|
+
const clear = (e) => {
|
|
78
|
+
e.stopPropagation();
|
|
79
|
+
onSelect(null, null);
|
|
80
|
+
};
|
|
81
|
+
const openCreate = (e) => {
|
|
82
|
+
e.stopPropagation();
|
|
83
|
+
setDialogRecordId(undefined);
|
|
84
|
+
setDialogOpen(true);
|
|
85
|
+
};
|
|
86
|
+
const openEdit = (e) => {
|
|
87
|
+
e.stopPropagation();
|
|
88
|
+
if (!value)
|
|
89
|
+
return;
|
|
90
|
+
setDialogRecordId(value);
|
|
91
|
+
setDialogOpen(true);
|
|
92
|
+
};
|
|
93
|
+
// Read the {id,label} off a saved record and select it. The transport
|
|
94
|
+
// matches the standard org-scoped CRUD the dynamic modal uses, so create/edit
|
|
95
|
+
// stay consistent with the rest of the app.
|
|
96
|
+
const selectSaved = (rec) => {
|
|
97
|
+
if (!rec)
|
|
98
|
+
return;
|
|
99
|
+
const id = rec.id != null ? String(rec.id) : value ?? '';
|
|
100
|
+
const lbl = (rec[labelField] != null && String(rec[labelField])) ||
|
|
101
|
+
(rec.name != null && String(rec.name)) ||
|
|
102
|
+
label ||
|
|
103
|
+
id;
|
|
104
|
+
onSelect(id, lbl);
|
|
105
|
+
};
|
|
106
|
+
return (_jsxs("div", { className: "flex items-center gap-1.5", children: [_jsxs(Popover, { open: open, onOpenChange: disabled ? undefined : setOpen, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsxs(Button, { variant: "outline", disabled: disabled, className: "w-full flex-1 justify-start gap-2 font-normal", children: [Icon && _jsx(Icon, { className: "text-muted-foreground size-4 shrink-0" }), _jsx("span", { className: "flex-1 truncate text-left", children: label ?? placeholder }), value && (_jsx("span", { role: "button", tabIndex: 0, onClick: clear, onKeyDown: (e) => {
|
|
107
|
+
if (e.key === 'Enter' || e.key === ' ')
|
|
108
|
+
clear(e);
|
|
109
|
+
}, className: "hover:bg-accent ml-auto shrink-0 rounded-sm p-0.5", children: _jsx(X, { className: "size-3.5" }) }))] }) }), _jsx(PopoverContent, { className: "p-0", align: "start", style: { width: 'var(--radix-popover-trigger-width)' }, children: _jsxs(Command, { shouldFilter: false, children: [_jsx(CommandInput, { placeholder: searchPlaceholder, value: searchTerm, onValueChange: setSearchTerm }), _jsxs(CommandList, { children: [isLoading && (_jsx("div", { className: "text-muted-foreground py-4 text-center text-sm", children: "Buscando\u2026" })), !isLoading &&
|
|
110
|
+
searchTerm.length >= minChars &&
|
|
111
|
+
results.length === 0 && _jsx(CommandEmpty, { children: emptyText }), !isLoading && results.length > 0 && (_jsx(CommandGroup, { className: "max-h-64 overflow-auto", children: results.map((row) => (_jsxs(CommandItem, { value: row.value, onSelect: () => pick(row), className: "flex flex-col items-start gap-0.5", children: [_jsx("span", { className: "text-sm font-medium", children: row.label }), row.description && (_jsx("span", { className: "text-muted-foreground text-xs", children: row.description }))] }, row.value))) })), !isLoading && !preload && searchTerm.length < minChars && (_jsxs("div", { className: "text-muted-foreground flex flex-col items-center gap-1 py-6", children: [_jsx(Search, { className: "size-5" }), _jsx("span", { className: "text-xs", children: "Escribe al menos 2 caracteres" })] }))] })] }) })] }), value
|
|
112
|
+
? mayEdit && (_jsx(Button, { type: "button", variant: "outline", size: "icon", disabled: disabled, onClick: openEdit, "aria-label": "Editar", title: "Editar", className: "shrink-0", children: _jsx(Pencil, { className: "size-4" }) }))
|
|
113
|
+
: mayCreate && (_jsx(Button, { type: "button", variant: "outline", size: "icon", disabled: disabled, onClick: openCreate, "aria-label": "Crear", title: "Crear", className: "shrink-0", children: _jsx(Plus, { className: "size-4" }) })), dialogOpen && (_jsx(CreateRecordDialog, { modelKey: model, open: dialogOpen, onOpenChange: setDialogOpen, recordId: dialogRecordId, endpoint: base, onCreate: async (data) => {
|
|
114
|
+
const res = await api.post(base, data);
|
|
115
|
+
const rec = (res.data?.data ?? res.data);
|
|
116
|
+
selectSaved(rec);
|
|
117
|
+
return rec.id != null ? { id: String(rec.id) } : undefined;
|
|
118
|
+
}, onUpdate: async (id, data) => {
|
|
119
|
+
const res = await api.put(`${base}/${id}`, data);
|
|
120
|
+
const rec = (res.data?.data ?? res.data);
|
|
121
|
+
selectSaved({ id, ...rec });
|
|
122
|
+
return { id: String(id) };
|
|
123
|
+
} }))] }));
|
|
124
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -29,6 +29,8 @@ export * from './navigation-builder';
|
|
|
29
29
|
export * from './i18n-provider';
|
|
30
30
|
export * from './api-context';
|
|
31
31
|
export * from './use-addon-settings';
|
|
32
|
+
export * from './use-print-document';
|
|
33
|
+
export * from './print-document-button';
|
|
32
34
|
export * from './metadata-cache';
|
|
33
35
|
export { ADDON_MANIFEST_CHANGED_TYPE, wireHotSwapInvalidation, useManifestHotSwapSubscriber, type AddonManifestChangedMessage, type ManifestHotSwapClient, type WireHotSwapInvalidationOptions, } from './manifest-hotswap-subscriber';
|
|
34
36
|
export { useHotSwapReload, applyHotSwapReload, withVersionParam, clearFederationContainer, shortenHash, type HotSwapReloadStrategy, type HotSwapReloadConfig, type HotSwapReloadAction, type HotSwapReloadDeps, type UseHotSwapReloadResult, } from './hotswap-reload-policy';
|
|
@@ -43,6 +45,8 @@ export { DynamicRecordDialog, ViewValue } from './dialogs/dynamic-record';
|
|
|
43
45
|
export { normalizeRefFieldsForSubmit } from './dialogs/normalize-submit';
|
|
44
46
|
export type { DynamicRecordDialogProps, FieldDef, FieldOption, GetImageUrl } from './dialogs/dynamic-record';
|
|
45
47
|
export { CreateRecordDialog } from './dialogs/create-record-dialog';
|
|
48
|
+
export { EntitySelect } from './entity-select';
|
|
49
|
+
export type { EntitySelectProps, EntitySelectOption } from './entity-select';
|
|
46
50
|
export { ViewRecordDialog } from './dialogs/view-record-dialog';
|
|
47
51
|
export type { ModelKey, ModelSchema, CreateResult, RecordDialogProps, CreateRecordDialogProps, ViewRecordDialogProps, } from './dialogs/types';
|
|
48
52
|
export { ExportDialog } from './dialogs/export';
|
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
|
@@ -34,6 +34,8 @@ export * from './navigation-builder';
|
|
|
34
34
|
export * from './i18n-provider';
|
|
35
35
|
export * from './api-context';
|
|
36
36
|
export * from './use-addon-settings';
|
|
37
|
+
export * from './use-print-document';
|
|
38
|
+
export * from './print-document-button';
|
|
37
39
|
export * from './metadata-cache';
|
|
38
40
|
export { ADDON_MANIFEST_CHANGED_TYPE, wireHotSwapInvalidation, useManifestHotSwapSubscriber, } from './manifest-hotswap-subscriber';
|
|
39
41
|
export { useHotSwapReload, applyHotSwapReload, withVersionParam, clearFederationContainer, shortenHash, } from './hotswap-reload-policy';
|
|
@@ -46,6 +48,7 @@ export { NIL_UUID, isNilUuid, normalizeNilUuid } from './nil-uuid';
|
|
|
46
48
|
export { DynamicRecordDialog, ViewValue } from './dialogs/dynamic-record';
|
|
47
49
|
export { normalizeRefFieldsForSubmit } from './dialogs/normalize-submit';
|
|
48
50
|
export { CreateRecordDialog } from './dialogs/create-record-dialog';
|
|
51
|
+
export { EntitySelect } from './entity-select';
|
|
49
52
|
export { ViewRecordDialog } from './dialogs/view-record-dialog';
|
|
50
53
|
export { ExportDialog } from './dialogs/export';
|
|
51
54
|
export { ImportDialog } from './dialogs/import';
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { type PrintDocumentArgs } from './use-print-document';
|
|
3
|
+
export interface PrintDocumentButtonProps extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, 'onError'> {
|
|
4
|
+
/** Model KEY the document is declared against (e.g. "SalesOrder"). */
|
|
5
|
+
model: string;
|
|
6
|
+
/** Record id. */
|
|
7
|
+
id: string;
|
|
8
|
+
/** Document key from contributions.documents[].key (e.g. "sale_ticket"). */
|
|
9
|
+
documentKey: string;
|
|
10
|
+
/** print (default) | download | open — see usePrintDocument. */
|
|
11
|
+
mode?: PrintDocumentArgs['mode'];
|
|
12
|
+
/** Download filename (mode="download"). */
|
|
13
|
+
filename?: string;
|
|
14
|
+
/** Called if the fetch/print fails (surface it to a toast in the host). */
|
|
15
|
+
onError?: (err: unknown) => void;
|
|
16
|
+
/** Rendered while the PDF is being fetched, in place of children. */
|
|
17
|
+
pendingLabel?: React.ReactNode;
|
|
18
|
+
children?: React.ReactNode;
|
|
19
|
+
}
|
|
20
|
+
export declare function PrintDocumentButton({ model, id, documentKey, mode, filename, onError, pendingLabel, children, disabled, onClick, ...rest }: PrintDocumentButtonProps): React.JSX.Element;
|
|
21
|
+
//# sourceMappingURL=print-document-button.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"print-document-button.d.ts","sourceRoot":"","sources":["../src/print-document-button.tsx"],"names":[],"mappings":"AASA,OAAO,KAAgC,MAAM,OAAO,CAAA;AACpD,OAAO,EAAoB,KAAK,iBAAiB,EAAE,MAAM,sBAAsB,CAAA;AAE/E,MAAM,WAAW,wBACb,SAAQ,IAAI,CAAC,KAAK,CAAC,oBAAoB,CAAC,iBAAiB,CAAC,EAAE,SAAS,CAAC;IACtE,sEAAsE;IACtE,KAAK,EAAE,MAAM,CAAA;IACb,iBAAiB;IACjB,EAAE,EAAE,MAAM,CAAA;IACV,4EAA4E;IAC5E,WAAW,EAAE,MAAM,CAAA;IACnB,gEAAgE;IAChE,IAAI,CAAC,EAAE,iBAAiB,CAAC,MAAM,CAAC,CAAA;IAChC,2CAA2C;IAC3C,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,2EAA2E;IAC3E,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,IAAI,CAAA;IAChC,qEAAqE;IACrE,YAAY,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC9B,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;CAC7B;AAED,wBAAgB,mBAAmB,CAAC,EAChC,KAAK,EACL,EAAE,EACF,WAAW,EACX,IAAI,EACJ,QAAQ,EACR,OAAO,EACP,YAAY,EACZ,QAAQ,EACR,QAAQ,EACR,OAAO,EACP,GAAG,IAAI,EACV,EAAE,wBAAwB,qBA+B1B"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
// PrintDocumentButton — a drop-in button that prints/downloads a server-rendered
|
|
3
|
+
// document via usePrintDocument, so an addon doesn't re-wire the hook + loading
|
|
4
|
+
// state every time. Headless-friendly: it renders a plain <button> you style
|
|
5
|
+
// with `className`, disables itself while the PDF is fetching, and reports
|
|
6
|
+
// failures through `onError` (no toast dependency baked in).
|
|
7
|
+
//
|
|
8
|
+
// Example:
|
|
9
|
+
// <PrintDocumentButton model="SalesOrder" id={sale.id} documentKey="sale_ticket"
|
|
10
|
+
// className="btn">Imprimir ticket</PrintDocumentButton>
|
|
11
|
+
import { useCallback, useState } from 'react';
|
|
12
|
+
import { usePrintDocument } from './use-print-document';
|
|
13
|
+
export function PrintDocumentButton({ model, id, documentKey, mode, filename, onError, pendingLabel, children, disabled, onClick, ...rest }) {
|
|
14
|
+
const printDocument = usePrintDocument();
|
|
15
|
+
const [busy, setBusy] = useState(false);
|
|
16
|
+
const handleClick = useCallback(async (e) => {
|
|
17
|
+
onClick?.(e);
|
|
18
|
+
if (e.defaultPrevented)
|
|
19
|
+
return;
|
|
20
|
+
setBusy(true);
|
|
21
|
+
try {
|
|
22
|
+
await printDocument({ model, id, key: documentKey, mode, filename });
|
|
23
|
+
}
|
|
24
|
+
catch (err) {
|
|
25
|
+
onError?.(err);
|
|
26
|
+
}
|
|
27
|
+
finally {
|
|
28
|
+
setBusy(false);
|
|
29
|
+
}
|
|
30
|
+
}, [printDocument, model, id, documentKey, mode, filename, onError, onClick]);
|
|
31
|
+
return (_jsx("button", { type: "button", ...rest, disabled: disabled || busy, "aria-busy": busy || undefined, onClick: handleClick, children: busy && pendingLabel != null ? pendingLabel : children }));
|
|
32
|
+
}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,3 +1,22 @@
|
|
|
1
|
+
/** One spreadsheet column of a model's import template. Mirrors the kernel's
|
|
2
|
+
* `modelbase.ImportColumn`. */
|
|
3
|
+
export interface ImportColumnMeta {
|
|
4
|
+
key: string;
|
|
5
|
+
header: string;
|
|
6
|
+
aliases?: string[];
|
|
7
|
+
required?: boolean;
|
|
8
|
+
type?: string;
|
|
9
|
+
example?: string;
|
|
10
|
+
hint?: string;
|
|
11
|
+
generator?: string;
|
|
12
|
+
}
|
|
13
|
+
/** A model's spreadsheet-import declaration. Mirrors `modelbase.ImportSpec`. */
|
|
14
|
+
export interface ImportSpecMeta {
|
|
15
|
+
columns: ImportColumnMeta[];
|
|
16
|
+
maxRows?: number;
|
|
17
|
+
sheetName?: string;
|
|
18
|
+
instructions?: string[];
|
|
19
|
+
}
|
|
1
20
|
export interface TableMetadata {
|
|
2
21
|
title: string;
|
|
3
22
|
endpoint: string;
|
|
@@ -12,6 +31,16 @@ export interface TableMetadata {
|
|
|
12
31
|
canExport?: boolean;
|
|
13
32
|
canImport?: boolean;
|
|
14
33
|
canCreate?: boolean;
|
|
34
|
+
/**
|
|
35
|
+
* The model's spreadsheet-import declaration, served by the kernel: the
|
|
36
|
+
* columns of the generated template and the headers accepted when parsing
|
|
37
|
+
* a filled file back in. The kernel derives it from the model's form
|
|
38
|
+
* fields when the model declares nothing, and omits the field entirely
|
|
39
|
+
* when the model has no importable column — so its presence is the signal
|
|
40
|
+
* that importing is meaningful for this model. Purely additive; older
|
|
41
|
+
* kernels omit it.
|
|
42
|
+
*/
|
|
43
|
+
import?: ImportSpecMeta;
|
|
15
44
|
/**
|
|
16
45
|
* Child relations of this model, served by the kernel (>= v0.41.0). A
|
|
17
46
|
* generic detail page renders one `DynamicRelation` panel per entry via
|