@asteby/metacore-runtime-react 18.11.0 → 18.12.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 +6 -0
- package/dist/dynamic-table.d.ts +9 -3
- package/dist/dynamic-table.d.ts.map +1 -1
- package/dist/dynamic-table.js +6 -5
- package/package.json +1 -1
- package/src/dynamic-table.tsx +23 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# @asteby/metacore-runtime-react
|
|
2
2
|
|
|
3
|
+
## 18.12.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- e661c1f: Add `onRowClick` prop to `DynamicTable` — when provided, each data row becomes clickable (cursor-pointer) and calls `onRowClick(row)` on click. Clicks on the checkbox (select column) and action buttons are stopped from propagating so they do not trigger the row handler. Behaviour is unchanged when the prop is not supplied.
|
|
8
|
+
|
|
3
9
|
## 18.11.0
|
|
4
10
|
|
|
5
11
|
### Minor Changes
|
package/dist/dynamic-table.d.ts
CHANGED
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
import { type ColumnDef } from '@tanstack/react-table';
|
|
2
2
|
import type { GetDynamicColumns } from './dynamic-columns-shim';
|
|
3
|
-
interface DynamicTableProps {
|
|
3
|
+
export interface DynamicTableProps {
|
|
4
4
|
model: string;
|
|
5
5
|
endpoint?: string;
|
|
6
6
|
enableUrlSync?: boolean;
|
|
7
7
|
hiddenColumns?: string[];
|
|
8
8
|
onAction?: (action: string, row: any) => void;
|
|
9
|
+
/**
|
|
10
|
+
* Called when the user clicks anywhere on a data row (not on a checkbox,
|
|
11
|
+
* action button, or interactive element inside the cell). When provided,
|
|
12
|
+
* each row becomes focusable (cursor-pointer). Absent → rows are not
|
|
13
|
+
* clickable and the behaviour is unchanged.
|
|
14
|
+
*/
|
|
15
|
+
onRowClick?: (row: any) => void;
|
|
9
16
|
refreshTrigger?: any;
|
|
10
17
|
defaultFilters?: Record<string, any>;
|
|
11
18
|
extraColumns?: ColumnDef<any>[];
|
|
@@ -30,6 +37,5 @@ interface DynamicTableProps {
|
|
|
30
37
|
*/
|
|
31
38
|
currency?: string;
|
|
32
39
|
}
|
|
33
|
-
export declare function DynamicTable({ model, endpoint, enableUrlSync, hiddenColumns, onAction, refreshTrigger, defaultFilters, extraColumns, getDynamicColumns, timeZone, currency, }: DynamicTableProps): import("react").JSX.Element;
|
|
34
|
-
export {};
|
|
40
|
+
export declare function DynamicTable({ model, endpoint, enableUrlSync, hiddenColumns, onAction, onRowClick, refreshTrigger, defaultFilters, extraColumns, getDynamicColumns, timeZone, currency, }: DynamicTableProps): import("react").JSX.Element;
|
|
35
41
|
//# sourceMappingURL=dynamic-table.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dynamic-table.d.ts","sourceRoot":"","sources":["../src/dynamic-table.tsx"],"names":[],"mappings":"AAiBA,OAAO,EAKH,KAAK,SAAS,EAajB,MAAM,uBAAuB,CAAA;AAgC9B,OAAO,KAAK,EAAsB,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAUnF,
|
|
1
|
+
{"version":3,"file":"dynamic-table.d.ts","sourceRoot":"","sources":["../src/dynamic-table.tsx"],"names":[],"mappings":"AAiBA,OAAO,EAKH,KAAK,SAAS,EAajB,MAAM,uBAAuB,CAAA;AAgC9B,OAAO,KAAK,EAAsB,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAUnF,MAAM,WAAW,iBAAiB;IAC9B,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,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;CACpB;AAED,wBAAgB,YAAY,CAAC,EACzB,KAAK,EACL,QAAQ,EACR,aAAoB,EACpB,aAAkB,EAClB,QAAQ,EACR,UAAU,EACV,cAAc,EACd,cAAc,EACd,YAAiB,EACjB,iBAA4C,EAC5C,QAAQ,EACR,QAAQ,GACX,EAAE,iBAAiB,+BA+3BnB"}
|
package/dist/dynamic-table.js
CHANGED
|
@@ -31,7 +31,7 @@ import { getSearchableColumnKeys } from './column-visibility';
|
|
|
31
31
|
import { DynamicRecordDialog } from './dialogs/dynamic-record';
|
|
32
32
|
import { ExportDialog } from './dialogs/export';
|
|
33
33
|
import { ImportDialog } from './dialogs/import';
|
|
34
|
-
export function DynamicTable({ model, endpoint, enableUrlSync = true, hiddenColumns = [], onAction, refreshTrigger, defaultFilters, extraColumns = [], getDynamicColumns = defaultGetDynamicColumns, timeZone, currency, }) {
|
|
34
|
+
export function DynamicTable({ model, endpoint, enableUrlSync = true, hiddenColumns = [], onAction, onRowClick, refreshTrigger, defaultFilters, extraColumns = [], getDynamicColumns = defaultGetDynamicColumns, timeZone, currency, }) {
|
|
35
35
|
const { t, i18n } = useTranslation();
|
|
36
36
|
const api = useApi();
|
|
37
37
|
const currentBranch = useCurrentBranch();
|
|
@@ -623,9 +623,10 @@ export function DynamicTable({ model, endpoint, enableUrlSync = true, hiddenColu
|
|
|
623
623
|
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: [metadata.canExport && (_jsxs(Button, { variant: "outline", size: "sm", className: "h-8", onClick: () => setExportOpen(true), children: [_jsx(Download, { className: "h-4 w-4 mr-1" }), " Exportar"] })), metadata.canImport && (_jsxs(Button, { variant: "outline", size: "sm", className: "h-8", onClick: () => setImportOpen(true), children: [_jsx(Upload, { className: "h-4 w-4 mr-1" }), " Importar"] }))] }) }) }), _jsx("div", { 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) => {
|
|
624
624
|
const isActionsColumn = header.id === 'actions';
|
|
625
625
|
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));
|
|
626
|
-
}) }, 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', children: row.getVisibleCells().map((cell) => {
|
|
626
|
+
}) }, 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) => {
|
|
627
627
|
const isActionsColumn = cell.column.id === 'actions';
|
|
628
|
-
|
|
628
|
+
const isSelectColumn = cell.column.id === 'select';
|
|
629
|
+
return (_jsx(TableCell, { style: cell.column.columnDef.size ? { width: cell.column.columnDef.size } : undefined, className: cn('py-2', isActionsColumn && 'sticky right-0 bg-card shadow-[-2px_0_5px_-2px_rgba(0,0,0,0.1)]'), onClick: (isActionsColumn || isSelectColumn) ? (e) => e.stopPropagation() : undefined, children: flexRender(cell.column.columnDef.cell, cell.getContext()) }, cell.id));
|
|
629
630
|
}) }, row.id))), aggregateColumns.length > 0 && Object.keys(footerTotals).length > 0 && (_jsx(TableRow, { className: 'border-0 hover:bg-transparent', children: _jsx(TableCell, { colSpan: columns.length, className: 'h-full p-0' }) }))] })) : (_jsx(TableRow, { className: 'border-b-0 hover:bg-transparent', children: _jsx(TableCell, { colSpan: columns.length, className: 'h-full p-0', children: _jsxs("div", { className: "flex h-full py-12 flex-col items-center justify-center gap-2 text-muted-foreground", children: [_jsx("div", { className: "flex h-20 w-20 items-center justify-center rounded-full bg-muted/50", children: _jsx(Inbox, { className: "h-10 w-10" }) }), _jsxs("div", { className: "flex flex-col items-center gap-1", children: [_jsx("h3", { className: "text-lg font-semibold text-foreground", children: "No se encontraron resultados" }), _jsx("p", { className: "text-sm text-muted-foreground", children: "No hay datos para mostrar en este momento." })] })] }) }) })) }), aggregateColumns.length > 0 && Object.keys(footerTotals).length > 0 && (_jsx(TableFooter, { className: "bg-transparent", children: _jsx(TableRow, { className: "hover:bg-transparent", children: table.getVisibleLeafColumns().map((leaf, idx) => {
|
|
630
631
|
const col = (metadata?.columns ?? []).find((c) => c.key === leaf.id);
|
|
631
632
|
const isFirst = idx === 0;
|
|
@@ -640,10 +641,10 @@ export function DynamicTable({ model, endpoint, enableUrlSync = true, hiddenColu
|
|
|
640
641
|
const cells = row.getVisibleCells();
|
|
641
642
|
const actionsCell = cells.find((c) => c.column.id === 'actions');
|
|
642
643
|
const dataCells = cells.filter((c) => c.column.id !== 'actions' && c.column.id !== 'select');
|
|
643
|
-
return (_jsxs("div", { "data-state": row.getIsSelected() && 'selected', className: 'flex flex-col gap-1.5 rounded-lg border bg-card p-3 data-[state=selected]:border-primary/40', children: [dataCells.map((cell) => {
|
|
644
|
+
return (_jsxs("div", { "data-state": row.getIsSelected() && 'selected', className: cn('flex flex-col gap-1.5 rounded-lg border bg-card p-3 data-[state=selected]:border-primary/40', onRowClick && 'cursor-pointer'), onClick: onRowClick ? () => onRowClick(row.original) : undefined, children: [dataCells.map((cell) => {
|
|
644
645
|
const header = cell.column.columnDef.header;
|
|
645
646
|
const label = typeof header === 'string' ? header : cell.column.id;
|
|
646
647
|
return (_jsxs("div", { className: 'flex items-start justify-between gap-3 text-sm', children: [_jsx("span", { className: 'shrink-0 text-muted-foreground', children: label }), _jsx("span", { className: 'min-w-0 break-words text-right font-medium', children: flexRender(cell.column.columnDef.cell, cell.getContext()) })] }, cell.id));
|
|
647
|
-
}), actionsCell && (_jsx("div", { className: 'flex justify-end border-t pt-2', children: flexRender(actionsCell.column.columnDef.cell, actionsCell.getContext()) }))] }, row.id));
|
|
648
|
+
}), actionsCell && (_jsx("div", { className: 'flex justify-end border-t pt-2', onClick: onRowClick ? (e) => e.stopPropagation() : undefined, children: flexRender(actionsCell.column.columnDef.cell, actionsCell.getContext()) }))] }, row.id));
|
|
648
649
|
})) : (_jsxs("div", { className: 'flex flex-col items-center justify-center gap-2 rounded-lg border bg-card py-12 text-muted-foreground', children: [_jsx("div", { className: 'flex h-16 w-16 items-center justify-center rounded-full bg-muted/50', children: _jsx(Inbox, { className: 'h-8 w-8' }) }), _jsx("h3", { className: 'text-base font-semibold text-foreground', children: "No se encontraron resultados" }), _jsx("p", { className: 'text-sm text-muted-foreground', children: "No hay datos para mostrar en este momento." })] })) }), _jsx("div", { className: 'shrink-0 pt-4', children: _jsx(DataTablePagination, { table: table, pageSizeOptions: metadata.perPageOptions }) })] }), _jsx(AlertDialog, { open: !!rowToDelete, onOpenChange: (open) => !open && setRowToDelete(null), children: _jsxs(AlertDialogContent, { children: [_jsxs(AlertDialogHeader, { children: [_jsx(AlertDialogTitle, { children: "\u00BFEst\u00E1 absolutamente seguro?" }), _jsx(AlertDialogDescription, { children: "Esta acci\u00F3n no se puede deshacer. Esto eliminar\u00E1 permanentemente el registro seleccionado de nuestros servidores." })] }), _jsxs(AlertDialogFooter, { children: [_jsx(AlertDialogCancel, { disabled: isDeleting, children: t('common.cancel') }), _jsx(AlertDialogAction, { onClick: (e) => { e.preventDefault(); confirmDelete(); }, className: "bg-red-600 hover:bg-red-700", disabled: isDeleting, children: isDeleting ? 'Eliminando...' : 'Eliminar' })] })] }) }), _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" })] }))] }) }), _jsx(DynamicRecordDialog, { open: recordDialog.open, onOpenChange: (open) => setRecordDialog((prev) => ({ ...prev, open })), mode: recordDialog.mode, model: model, recordId: recordDialog.recordId, endpoint: endpoint, onSaved: handleRefresh }), metadata.canExport && (_jsx(ExportDialog, { open: exportOpen, onOpenChange: setExportOpen, model: model, metadata: metadata, currentFilters: buildFilterParams(), hasActiveFilters: hasActiveFilters })), metadata.canImport && (_jsx(ImportDialog, { open: importOpen, onOpenChange: setImportOpen, model: model, metadata: metadata, onImported: handleRefresh })), actionModal.action && (_jsx(ActionModalDispatcher, { open: actionModal.open, onOpenChange: (open) => setActionModal((prev) => ({ ...prev, open })), action: actionModal.action, model: model, record: actionModal.record, endpoint: endpoint, onSuccess: 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"] }) })] }));
|
|
649
650
|
}
|
package/package.json
CHANGED
package/src/dynamic-table.tsx
CHANGED
|
@@ -75,12 +75,19 @@ import { DynamicRecordDialog } from './dialogs/dynamic-record'
|
|
|
75
75
|
import { ExportDialog } from './dialogs/export'
|
|
76
76
|
import { ImportDialog } from './dialogs/import'
|
|
77
77
|
|
|
78
|
-
interface DynamicTableProps {
|
|
78
|
+
export interface DynamicTableProps {
|
|
79
79
|
model: string
|
|
80
80
|
endpoint?: string
|
|
81
81
|
enableUrlSync?: boolean
|
|
82
82
|
hiddenColumns?: string[]
|
|
83
83
|
onAction?: (action: string, row: any) => void
|
|
84
|
+
/**
|
|
85
|
+
* Called when the user clicks anywhere on a data row (not on a checkbox,
|
|
86
|
+
* action button, or interactive element inside the cell). When provided,
|
|
87
|
+
* each row becomes focusable (cursor-pointer). Absent → rows are not
|
|
88
|
+
* clickable and the behaviour is unchanged.
|
|
89
|
+
*/
|
|
90
|
+
onRowClick?: (row: any) => void
|
|
84
91
|
refreshTrigger?: any
|
|
85
92
|
defaultFilters?: Record<string, any>
|
|
86
93
|
extraColumns?: ColumnDef<any>[]
|
|
@@ -112,6 +119,7 @@ export function DynamicTable({
|
|
|
112
119
|
enableUrlSync = true,
|
|
113
120
|
hiddenColumns = [],
|
|
114
121
|
onAction,
|
|
122
|
+
onRowClick,
|
|
115
123
|
refreshTrigger,
|
|
116
124
|
defaultFilters,
|
|
117
125
|
extraColumns = [],
|
|
@@ -781,14 +789,21 @@ export function DynamicTable({
|
|
|
781
789
|
) : table.getRowModel().rows?.length ? (
|
|
782
790
|
<>
|
|
783
791
|
{table.getRowModel().rows.map((row: Row<any>) => (
|
|
784
|
-
<TableRow
|
|
792
|
+
<TableRow
|
|
793
|
+
key={row.id}
|
|
794
|
+
data-state={row.getIsSelected() && 'selected'}
|
|
795
|
+
className={cn(onRowClick && 'cursor-pointer')}
|
|
796
|
+
onClick={onRowClick ? () => onRowClick(row.original) : undefined}
|
|
797
|
+
>
|
|
785
798
|
{row.getVisibleCells().map((cell: Cell<any, unknown>) => {
|
|
786
799
|
const isActionsColumn = cell.column.id === 'actions'
|
|
800
|
+
const isSelectColumn = cell.column.id === 'select'
|
|
787
801
|
return (
|
|
788
802
|
<TableCell
|
|
789
803
|
key={cell.id}
|
|
790
804
|
style={cell.column.columnDef.size ? { width: cell.column.columnDef.size } : undefined}
|
|
791
805
|
className={cn('py-2', isActionsColumn && 'sticky right-0 bg-card shadow-[-2px_0_5px_-2px_rgba(0,0,0,0.1)]')}
|
|
806
|
+
onClick={(isActionsColumn || isSelectColumn) ? (e: React.MouseEvent) => e.stopPropagation() : undefined}
|
|
792
807
|
>
|
|
793
808
|
{flexRender(cell.column.columnDef.cell, cell.getContext())}
|
|
794
809
|
</TableCell>
|
|
@@ -888,7 +903,8 @@ export function DynamicTable({
|
|
|
888
903
|
<div
|
|
889
904
|
key={row.id}
|
|
890
905
|
data-state={row.getIsSelected() && 'selected'}
|
|
891
|
-
className='flex flex-col gap-1.5 rounded-lg border bg-card p-3 data-[state=selected]:border-primary/40'
|
|
906
|
+
className={cn('flex flex-col gap-1.5 rounded-lg border bg-card p-3 data-[state=selected]:border-primary/40', onRowClick && 'cursor-pointer')}
|
|
907
|
+
onClick={onRowClick ? () => onRowClick(row.original) : undefined}
|
|
892
908
|
>
|
|
893
909
|
{dataCells.map((cell: Cell<any, unknown>) => {
|
|
894
910
|
const header = cell.column.columnDef.header
|
|
@@ -903,7 +919,10 @@ export function DynamicTable({
|
|
|
903
919
|
)
|
|
904
920
|
})}
|
|
905
921
|
{actionsCell && (
|
|
906
|
-
<div
|
|
922
|
+
<div
|
|
923
|
+
className='flex justify-end border-t pt-2'
|
|
924
|
+
onClick={onRowClick ? (e: React.MouseEvent) => e.stopPropagation() : undefined}
|
|
925
|
+
>
|
|
907
926
|
{flexRender(actionsCell.column.columnDef.cell, actionsCell.getContext())}
|
|
908
927
|
</div>
|
|
909
928
|
)}
|