@asteby/metacore-runtime-react 20.1.6 → 21.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,48 @@
1
1
  # @asteby/metacore-runtime-react
2
2
 
3
+ ## 21.0.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 84aeaf2: feat(kanban): dynamic column filters on DynamicKanban
8
+
9
+ The board now filters like its DynamicTable sibling. A filter bar above the
10
+ lanes exposes a global search box plus one chip per filterable field (from
11
+ `metadata.filters[]` and every `filterable` column), driving the SAME
12
+ server-side `f_<key>=<op>:<value>` / `search` params — so a model's table and
13
+ kanban views filter identically.
14
+ - **ui**: extracted the per-column filter popover into a new, TanStack-agnostic
15
+ `ColumnFilterControl` (select/boolean/dynamic_select/text/number_range/
16
+ date_range). `FilterableColumnHeader` now delegates its filter UI to it
17
+ (behavior unchanged); it also powers the kanban's labeled filter chips.
18
+ - **runtime-react**: new `useDynamicFilters(metadata)` hook owning the filter
19
+ state, option prefetch, config derivation and param serialization (factored
20
+ out of DynamicTable's inline logic). `DynamicKanban` consumes it and gains a
21
+ `defaultFilters` prop for parity with DynamicTable.
22
+
23
+ ### Patch Changes
24
+
25
+ - Updated dependencies [84aeaf2]
26
+ - @asteby/metacore-ui@2.7.0
27
+
28
+ ## 20.1.7
29
+
30
+ ### Patch Changes
31
+
32
+ - 649de1b: fix(kanban): card "…" actions (Ver / Editar / Eliminar / custom) now work and are permission-gated
33
+
34
+ The per-card kebab menu on the kanban board forwarded the raw action object to a
35
+ no-op, so clicking Ver/Editar/Eliminar did nothing, and the menu was not filtered
36
+ by permission. The dispatch logic was extracted from `DynamicTable` into a shared
37
+ `useDynamicRowActions` hook (delete-confirm dialog, view/edit → host `onAction`
38
+ string contract or the built-in record dialog, link → navigate, custom →
39
+ ActionModal) that both renderers now use, so a kanban card behaves identically to a
40
+ table row. The card actions are resolved through the new `resolveRowActions` helper
41
+ — the same capability gate (`useCan`/`gateTableMetadata`) and implicit View/Edit/
42
+ Delete trio materialization the table's action column uses — so an action the user
43
+ lacks permission for no longer appears. `DynamicKanban` gains an optional
44
+ `onAction(action: string, row)` prop mirroring `DynamicTable`.
45
+
3
46
  ## 20.1.6
4
47
 
5
48
  ### Patch Changes
@@ -50,6 +50,18 @@ export declare const formatAggregateTotal: (col: ColumnDefinition, value: unknow
50
50
  * - row with no `status` field → all actions shown.
51
51
  */
52
52
  export declare const isActionAllowedForRowState: (action: any, row: any) => boolean;
53
+ /**
54
+ * Declarative `condition` gate for a per-row action: shows the action only when
55
+ * the row's `field` satisfies the `eq | neq | in | not_in` operator. No
56
+ * condition declared → always shown. Unknown operator → permissive.
57
+ */
58
+ export declare const isActionConditionMet: (action: any, row: any) => boolean;
59
+ /**
60
+ * Whether a per-row action should appear for `row`: both the state-machine gate
61
+ * (`requiresState`) AND the declarative `condition` must pass. Shared by the
62
+ * table's action column and the kanban card menu so they hide/show identically.
63
+ */
64
+ export declare const isRowActionVisible: (action: any, row: any) => boolean;
53
65
  /**
54
66
  * Resolves the relation sibling object a backend serves alongside an FK column.
55
67
  * For a column keyed `category_id` the data row also carries
@@ -1 +1 @@
1
- {"version":3,"file":"dynamic-columns.d.ts","sourceRoot":"","sources":["../src/dynamic-columns.tsx"],"names":[],"mappings":"AAgBA,OAAO,EAAU,KAAK,MAAM,EAAE,MAAM,UAAU,CAAA;AAiC9C,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;AA8DD;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,0BAA0B,GAAI,QAAQ,GAAG,EAAE,KAAK,GAAG,KAAG,OAMlE,CAAA;AAqKD;;;;;;;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;AAsID;;;;GAIG;AACH,wBAAgB,4BAA4B,CACxC,OAAO,GAAE,qBAA0B,GACpC,iBAAiB,CA+nBnB;AAED;;;;GAIG;AACH,eAAO,MAAM,wBAAwB,EAAE,iBACL,CAAA"}
1
+ {"version":3,"file":"dynamic-columns.d.ts","sourceRoot":"","sources":["../src/dynamic-columns.tsx"],"names":[],"mappings":"AAgBA,OAAO,EAAU,KAAK,MAAM,EAAE,MAAM,UAAU,CAAA;AAiC9C,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;AA8DD;;;;;;;;;;;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;AAqKhF;;;;;;;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;AAsID;;;;GAIG;AACH,wBAAgB,4BAA4B,CACxC,OAAO,GAAE,qBAA0B,GACpC,iBAAiB,CA6mBnB;AAED;;;;GAIG;AACH,eAAO,MAAM,wBAAwB,EAAE,iBACL,CAAA"}
@@ -141,6 +141,36 @@ export const isActionAllowedForRowState = (action, row) => {
141
141
  return true;
142
142
  return requires.map(String).includes(String(status));
143
143
  };
144
+ /**
145
+ * Declarative `condition` gate for a per-row action: shows the action only when
146
+ * the row's `field` satisfies the `eq | neq | in | not_in` operator. No
147
+ * condition declared → always shown. Unknown operator → permissive.
148
+ */
149
+ export const isActionConditionMet = (action, row) => {
150
+ if (!action?.condition)
151
+ return true;
152
+ const { field, operator, value } = action.condition;
153
+ const rowValue = String(row?.[field] ?? '');
154
+ const values = Array.isArray(value) ? value : [value];
155
+ switch (operator) {
156
+ case 'eq':
157
+ return rowValue === values[0];
158
+ case 'neq':
159
+ return rowValue !== values[0];
160
+ case 'in':
161
+ return values.includes(rowValue);
162
+ case 'not_in':
163
+ return !values.includes(rowValue);
164
+ default:
165
+ return true;
166
+ }
167
+ };
168
+ /**
169
+ * Whether a per-row action should appear for `row`: both the state-machine gate
170
+ * (`requiresState`) AND the declarative `condition` must pass. Shared by the
171
+ * table's action column and the kanban card menu so they hide/show identically.
172
+ */
173
+ export const isRowActionVisible = (action, row) => isActionAllowedForRowState(action, row) && isActionConditionMet(action, row);
144
174
  const lowerFirst = (value) => {
145
175
  if (!value)
146
176
  return value;
@@ -793,26 +823,7 @@ export function makeDefaultGetDynamicColumns(helpers = {}) {
793
823
  maxSize: 80,
794
824
  meta: {},
795
825
  cell: ({ row }) => (_jsx("div", { className: "flex items-center justify-end", children: _jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsxs(Button, { variant: "ghost", className: "h-8 w-8 p-0", children: [_jsx("span", { className: "sr-only", children: "Abrir men\u00FA" }), _jsx(MoreHorizontal, { className: "h-4 w-4" })] }) }), _jsx(DropdownMenuContent, { align: "end", children: resolvedActions
796
- .filter((action) => isActionAllowedForRowState(action, row.original))
797
- .filter((action) => {
798
- if (!action.condition)
799
- return true;
800
- const { field, operator, value } = action.condition;
801
- const rowValue = String(row.original[field] ?? '');
802
- const values = Array.isArray(value) ? value : [value];
803
- switch (operator) {
804
- case 'eq':
805
- return rowValue === values[0];
806
- case 'neq':
807
- return rowValue !== values[0];
808
- case 'in':
809
- return values.includes(rowValue);
810
- case 'not_in':
811
- return !values.includes(rowValue);
812
- default:
813
- return true;
814
- }
815
- })
826
+ .filter((action) => isRowActionVisible(action, row.original))
816
827
  .map((action) => (_jsxs(DropdownMenuItem, { onClick: () => onAction && onAction(action.key, row.original), children: [_jsx(DynamicIcon, { name: action.icon, className: "mr-2 h-4 w-4" }), action.label] }, action.key))) })] }) })),
817
828
  });
818
829
  }
@@ -52,6 +52,13 @@ export interface DynamicKanbanProps {
52
52
  refreshTrigger?: any;
53
53
  /** Called when a card is clicked (outside its action menu). */
54
54
  onCardClick?: (row: any) => void;
55
+ /**
56
+ * Host hook for `view`/`edit` card actions (STRING contract — same as
57
+ * DynamicTable's `onAction`). When provided, `view`/`edit` route to the host
58
+ * (e.g. its seeded record modal); when omitted they open the SDK's built-in
59
+ * record dialog. `delete`/link/custom actions are always handled in-SDK.
60
+ */
61
+ onAction?: (action: string, row: any) => void;
55
62
  /**
56
63
  * Max cards fetched per lane render. Kanban shows all cards at once (no
57
64
  * pagination UI), so it requests a single large page. Defaults to 200.
@@ -61,6 +68,11 @@ export interface DynamicKanbanProps {
61
68
  timeZone?: string;
62
69
  /** ISO 4217 currency for money card fields (org config). */
63
70
  currency?: string;
71
+ /**
72
+ * Static equality filters always applied to the board (never shown as a
73
+ * removable chip). Same contract as DynamicTable's `defaultFilters`.
74
+ */
75
+ defaultFilters?: Record<string, any>;
64
76
  }
65
- export declare function DynamicKanban({ model, endpoint, refreshTrigger, onCardClick, pageSize, timeZone, currency, }: DynamicKanbanProps): React.JSX.Element;
77
+ export declare function DynamicKanban({ model, endpoint, refreshTrigger, onCardClick, onAction, pageSize, timeZone, currency, defaultFilters, }: DynamicKanbanProps): React.JSX.Element;
66
78
  //# sourceMappingURL=dynamic-kanban.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"dynamic-kanban.d.ts","sourceRoot":"","sources":["../src/dynamic-kanban.tsx"],"names":[],"mappings":"AAyBA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAoC9B,OAAO,KAAK,EACR,aAAa,EACb,gBAAgB,EAGhB,SAAS,EACT,eAAe,EAClB,MAAM,SAAS,CAAA;AAMhB;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,aAAa,GAAG,SAAS,EAAE,CAejE;AAQD;;;;;GAKG;AACH,eAAO,MAAM,eAAe,mBAAmB,CAAA;AAE/C,wBAAgB,YAAY,CACxB,OAAO,EAAE,GAAG,EAAE,EACd,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,SAAS,EAAE,GACpB,GAAG,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,CAepB;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAC/B,WAAW,EAAE,eAAe,EAAE,GAAG,SAAS,EAC1C,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,GACX,OAAO,CAOT;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAC/B,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,EAC3B,MAAM,EAAE,MAAM,GAAG,MAAM,EACvB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,GACnB,GAAG,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,CAYpB;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC7B,QAAQ,EAAE,aAAa,EACvB,SAAS,SAAI,GACd;IAAE,KAAK,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAAC,MAAM,EAAE,gBAAgB,EAAE,CAAA;CAAE,CAkBhE;AA8BD,MAAM,WAAW,kBAAkB;IAC/B,6DAA6D;IAC7D,KAAK,EAAE,MAAM,CAAA;IACb;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,kFAAkF;IAClF,cAAc,CAAC,EAAE,GAAG,CAAA;IACpB,+DAA+D;IAC/D,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,IAAI,CAAA;IAChC;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,2DAA2D;IAC3D,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,4DAA4D;IAC5D,QAAQ,CAAC,EAAE,MAAM,CAAA;CACpB;AAED,wBAAgB,aAAa,CAAC,EAC1B,KAAK,EACL,QAAQ,EACR,cAAc,EACd,WAAW,EACX,QAAc,EACd,QAAQ,EACR,QAAQ,GACX,EAAE,kBAAkB,qBAmSpB"}
1
+ {"version":3,"file":"dynamic-kanban.d.ts","sourceRoot":"","sources":["../src/dynamic-kanban.tsx"],"names":[],"mappings":"AA0BA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAuC9B,OAAO,KAAK,EACR,aAAa,EACb,gBAAgB,EAGhB,SAAS,EACT,eAAe,EAClB,MAAM,SAAS,CAAA;AAMhB;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,aAAa,GAAG,SAAS,EAAE,CAejE;AAQD;;;;;GAKG;AACH,eAAO,MAAM,eAAe,mBAAmB,CAAA;AAE/C,wBAAgB,YAAY,CACxB,OAAO,EAAE,GAAG,EAAE,EACd,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,SAAS,EAAE,GACpB,GAAG,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,CAepB;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAC/B,WAAW,EAAE,eAAe,EAAE,GAAG,SAAS,EAC1C,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,GACX,OAAO,CAOT;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAC/B,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,EAC3B,MAAM,EAAE,MAAM,GAAG,MAAM,EACvB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,GACnB,GAAG,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,CAYpB;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC7B,QAAQ,EAAE,aAAa,EACvB,SAAS,SAAI,GACd;IAAE,KAAK,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAAC,MAAM,EAAE,gBAAgB,EAAE,CAAA;CAAE,CAkBhE;AA8BD,MAAM,WAAW,kBAAkB;IAC/B,6DAA6D;IAC7D,KAAK,EAAE,MAAM,CAAA;IACb;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,kFAAkF;IAClF,cAAc,CAAC,EAAE,GAAG,CAAA;IACpB,+DAA+D;IAC/D,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,IAAI,CAAA;IAChC;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,KAAK,IAAI,CAAA;IAC7C;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,2DAA2D;IAC3D,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,4DAA4D;IAC5D,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;CACvC;AAED,wBAAgB,aAAa,CAAC,EAC1B,KAAK,EACL,QAAQ,EACR,cAAc,EACd,WAAW,EACX,QAAQ,EACR,QAAc,EACd,QAAQ,EACR,QAAQ,EACR,cAAc,GACjB,EAAE,kBAAkB,qBAsXpB"}
@@ -2,18 +2,20 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
2
2
  import { useCallback, useEffect, useMemo, useState } from 'react';
3
3
  import { useTranslation } from 'react-i18next';
4
4
  import { DndContext, DragOverlay, PointerSensor, useSensor, useSensors, useDraggable, useDroppable, } from '@dnd-kit/core';
5
- import { MoreHorizontal } from 'lucide-react';
5
+ import { MoreHorizontal, Search, X } from 'lucide-react';
6
6
  import { toast } from 'sonner';
7
- import { Badge, Button, Card, CardContent, DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, Skeleton, } from '@asteby/metacore-ui/primitives';
7
+ import { Badge, Button, Card, CardContent, DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, Input, Skeleton, } from '@asteby/metacore-ui/primitives';
8
+ import { ColumnFilterControl } from '@asteby/metacore-ui/data-table';
8
9
  import { generateBadgeStyles, optionColor } from '@asteby/metacore-ui/lib';
9
10
  import { useApi } from './api-context';
11
+ import { useDynamicFilters } from './use-dynamic-filters';
10
12
  import { useMetadataCache } from './metadata-cache';
11
13
  import { ActivityValueRenderer } from './activity-value-renderer';
12
- import { ActionModalDispatcher } from './action-modal-dispatcher';
13
- import { useModelActions } from './model-action-toolbar';
14
14
  import { DynamicIcon } from './dynamic-icon';
15
15
  import { isColumnVisibleInTable } from './column-visibility';
16
- import { isActionAllowedForRowState } from './dynamic-columns';
16
+ import { isRowActionVisible } from './dynamic-columns';
17
+ import { useCan, usePermissionsActive, resolveRowActions } from './permissions-context';
18
+ import { useDynamicRowActions } from './dynamic-row-actions';
17
19
  // ---------------------------------------------------------------------------
18
20
  // Pure helpers (exported for unit tests — no React, no transport)
19
21
  // ---------------------------------------------------------------------------
@@ -146,7 +148,7 @@ function useIsDarkTheme() {
146
148
  }, []);
147
149
  return isDark;
148
150
  }
149
- export function DynamicKanban({ model, endpoint, refreshTrigger, onCardClick, pageSize = 200, timeZone, currency, }) {
151
+ export function DynamicKanban({ model, endpoint, refreshTrigger, onCardClick, onAction, pageSize = 200, timeZone, currency, defaultFilters, }) {
150
152
  const { t, i18n } = useTranslation();
151
153
  const api = useApi();
152
154
  const isDark = useIsDarkTheme();
@@ -158,7 +160,6 @@ export function DynamicKanban({ model, endpoint, refreshTrigger, onCardClick, pa
158
160
  const [loadingData, setLoadingData] = useState(true);
159
161
  // Active drag card id (for the DragOverlay + drop-zone highlighting).
160
162
  const [activeId, setActiveId] = useState(null);
161
- const [actionModal, setActionModal] = useState({ action: null, record: null });
162
163
  const sensors = useSensors(useSensor(PointerSensor, { activationConstraint: { distance: 5 } }));
163
164
  // ---- metadata fetch (same path as DynamicTable) ----
164
165
  useEffect(() => {
@@ -195,6 +196,10 @@ export function DynamicKanban({ model, endpoint, refreshTrigger, onCardClick, pa
195
196
  };
196
197
  // eslint-disable-next-line react-hooks/exhaustive-deps
197
198
  }, [model]);
199
+ // Shared metadata-driven filter engine — the SAME configs, option prefetch
200
+ // and `f_<key>` serialization DynamicTable uses, so the board filters
201
+ // identically to its table sibling.
202
+ const { globalFilter, setGlobalFilter, columnFilterConfigs, filterParams, activeFilterCount, clearAll, } = useDynamicFilters(metadata, { defaultFilters });
198
203
  // ---- records fetch (same path as DynamicTable, single large page) ----
199
204
  const fetchData = useCallback(async () => {
200
205
  if (!metadata)
@@ -202,7 +207,7 @@ export function DynamicKanban({ model, endpoint, refreshTrigger, onCardClick, pa
202
207
  setLoadingData(true);
203
208
  try {
204
209
  const res = (await api.get(endpoint || `/data/${model}`, {
205
- params: { page: 1, per_page: pageSize },
210
+ params: { page: 1, per_page: pageSize, ...filterParams },
206
211
  }));
207
212
  if (res.data.success)
208
213
  setRecords(res.data.data || []);
@@ -213,19 +218,57 @@ export function DynamicKanban({ model, endpoint, refreshTrigger, onCardClick, pa
213
218
  finally {
214
219
  setLoadingData(false);
215
220
  }
216
- }, [api, endpoint, model, metadata, pageSize]);
221
+ }, [api, endpoint, model, metadata, pageSize, filterParams]);
222
+ // Refetch when metadata resolves, on an explicit refresh, or when the
223
+ // filters change. `fetchData` is stable while `filterParams` is unchanged
224
+ // (both memoized), so this only re-runs on real input changes. Debounced so
225
+ // typing in the search box doesn't fire a request per keystroke.
217
226
  useEffect(() => {
218
- if (metadata)
227
+ if (!metadata)
228
+ return;
229
+ const handle = setTimeout(() => {
219
230
  void fetchData();
220
- // eslint-disable-next-line react-hooks/exhaustive-deps
221
- }, [metadata, refreshTrigger]);
231
+ }, 200);
232
+ return () => clearTimeout(handle);
233
+ }, [fetchData, metadata, refreshTrigger]);
234
+ // Filterable fields for the toolbar, in metadata order (explicit filters
235
+ // first, then filterable columns), each labeled from its metadata source.
236
+ const filterFields = useMemo(() => {
237
+ if (!metadata)
238
+ return [];
239
+ const out = [];
240
+ for (const [key, config] of columnFilterConfigs) {
241
+ const f = metadata.filters?.find((x) => x.key === key);
242
+ const c = metadata.columns.find((x) => x.key === key);
243
+ const rawLabel = f?.label || c?.label || key;
244
+ out.push({ key, label: t(rawLabel, { defaultValue: rawLabel }), config });
245
+ }
246
+ return out;
247
+ }, [metadata, columnFilterConfigs, t]);
222
248
  const stages = useMemo(() => (metadata ? deriveStages(metadata) : []), [metadata]);
223
249
  const groupByKey = metadata?.group_by || '';
224
250
  const transitions = metadata?.transitions;
225
251
  const grouped = useMemo(() => groupByStage(records, groupByKey, stages), [records, groupByKey, stages]);
226
252
  const { title: titleCol, fields: fieldCols } = useMemo(() => (metadata ? selectCardColumns(metadata) : { title: null, fields: [] }), [metadata]);
227
- // Row-placement actions reused verbatim from the table's plumbing.
228
- const rowActions = useModelActions(model, ['row'], metadata?.actions);
253
+ // Row-placement actions resolved EXACTLY like DynamicTable's action column:
254
+ // capability-gated (when a <PermissionsProvider> is mounted) and with the
255
+ // implicit View/Edit/Delete trio materialized for CRUD models. An action the
256
+ // user lacks permission for never appears.
257
+ const can = useCan();
258
+ const permissionsActive = usePermissionsActive();
259
+ const rowActions = useMemo(() => metadata
260
+ ? resolveRowActions(metadata, model, can, permissionsActive, (k, fb) => t(k, { defaultValue: fb }))
261
+ : [], [metadata, model, can, permissionsActive, t]);
262
+ // Shared row-action dispatch + dialogs — view/edit/delete/link/custom behave
263
+ // identically to a table row (the card menu used to forward the raw action
264
+ // object to the host and silently no-op).
265
+ const { handleInternalAction, dialogs: rowActionDialogs } = useDynamicRowActions({
266
+ model,
267
+ endpoint,
268
+ metadata,
269
+ onAction,
270
+ onRefresh: fetchData,
271
+ });
229
272
  const cardById = useMemo(() => {
230
273
  const m = new Map();
231
274
  for (const r of records)
@@ -302,19 +345,13 @@ export function DynamicKanban({ model, endpoint, refreshTrigger, onCardClick, pa
302
345
  order: Number.MAX_SAFE_INTEGER,
303
346
  });
304
347
  }
305
- return (_jsxs(DndContext, { sensors: sensors, onDragStart: onDragStart, onDragEnd: onDragEnd, children: [_jsx("div", { className: "flex min-w-0 gap-4 overflow-x-auto p-1", "data-testid": "kanban-board", children: lanes.map((stage) => {
306
- const cards = grouped.get(stage.key) ?? [];
307
- const droppableAllowed = !activeId ||
308
- stage.key === activeStage ||
309
- isTransitionAllowed(transitions, activeStage, stage.key);
310
- return (_jsx(KanbanLane, { stage: stage, count: cards.length, isDark: isDark, dimmed: !!activeId && !droppableAllowed, disabled: !!activeId && !droppableAllowed, children: loadingData && cards.length === 0 ? (_jsxs(_Fragment, { children: [_jsx(Skeleton, { className: "h-20 w-full" }), _jsx(Skeleton, { className: "h-20 w-full" })] })) : cards.length === 0 ? (_jsx("p", { className: "px-1 py-6 text-center text-xs text-muted-foreground", children: t('kanban.emptyLane', { defaultValue: 'Sin tarjetas' }) })) : (cards.map((card) => (_jsx(KanbanCard, { card: card, titleCol: titleCol, fieldCols: fieldCols, actions: rowActions, locale: i18n.language, timeZone: timeZone, currency: currency, onClick: onCardClick, onAction: (action, record) => setActionModal({ action, record }) }, String(card.id))))) }, stage.key));
311
- }) }), _jsx(DragOverlay, { children: activeCard ? (_jsx(CardPreview, { card: activeCard, titleCol: titleCol, fieldCols: fieldCols, locale: i18n.language, timeZone: timeZone, currency: currency })) : null }), actionModal.action && (_jsx(ActionModalDispatcher, { open: !!actionModal.action, onOpenChange: (open) => {
312
- if (!open)
313
- setActionModal({ action: null, record: null });
314
- }, action: actionModal.action, model: model, record: actionModal.record ?? {}, endpoint: endpoint ?? `/data/${model}/me`, onSuccess: () => {
315
- setActionModal({ action: null, record: null });
316
- void fetchData();
317
- } }))] }));
348
+ return (_jsxs("div", { className: "flex flex-col gap-3", children: [_jsxs("div", { className: "flex flex-wrap items-center gap-2", "data-testid": "kanban-filters", children: [_jsxs("div", { className: "relative", children: [_jsx(Search, { className: "pointer-events-none absolute left-2.5 top-1/2 h-3.5 w-3.5 -translate-y-1/2 text-muted-foreground" }), _jsx(Input, { value: globalFilter, onChange: (e) => setGlobalFilter(e.target.value), placeholder: t('kanban.searchPlaceholder', { defaultValue: 'Buscar...' }), className: "h-8 w-52 pl-8 text-sm" })] }), filterFields.map((field) => (_jsx(ColumnFilterControl, { showLabel: true, label: field.label, filterKey: field.config.filterKey, filterType: field.config.filterType, filterOptions: field.config.options, filterLoading: field.config.loading, filterSearchEndpoint: field.config.searchEndpoint, selectedValues: field.config.selectedValues, onFilterChange: field.config.onFilterChange }, field.key))), activeFilterCount > 0 && (_jsxs(Button, { variant: "ghost", size: "sm", className: "h-8 gap-1 text-xs text-muted-foreground", onClick: clearAll, children: [_jsx(X, { className: "h-3.5 w-3.5" }), t('kanban.clearFilters', { defaultValue: 'Limpiar' }), ` (${activeFilterCount})`] }))] }), _jsxs(DndContext, { sensors: sensors, onDragStart: onDragStart, onDragEnd: onDragEnd, children: [_jsx("div", { className: "flex min-w-0 gap-4 overflow-x-auto p-1", "data-testid": "kanban-board", children: lanes.map((stage) => {
349
+ const cards = grouped.get(stage.key) ?? [];
350
+ const droppableAllowed = !activeId ||
351
+ stage.key === activeStage ||
352
+ isTransitionAllowed(transitions, activeStage, stage.key);
353
+ return (_jsx(KanbanLane, { stage: stage, count: cards.length, isDark: isDark, dimmed: !!activeId && !droppableAllowed, disabled: !!activeId && !droppableAllowed, children: loadingData && cards.length === 0 ? (_jsxs(_Fragment, { children: [_jsx(Skeleton, { className: "h-20 w-full" }), _jsx(Skeleton, { className: "h-20 w-full" })] })) : cards.length === 0 ? (_jsx("p", { className: "px-1 py-6 text-center text-xs text-muted-foreground", children: t('kanban.emptyLane', { defaultValue: 'Sin tarjetas' }) })) : (cards.map((card) => (_jsx(KanbanCard, { card: card, titleCol: titleCol, fieldCols: fieldCols, actions: rowActions, locale: i18n.language, timeZone: timeZone, currency: currency, onClick: onCardClick, onAction: handleInternalAction }, String(card.id))))) }, stage.key));
354
+ }) }), _jsx(DragOverlay, { children: activeCard ? (_jsx(CardPreview, { card: activeCard, titleCol: titleCol, fieldCols: fieldCols, locale: i18n.language, timeZone: timeZone, currency: currency })) : null }), rowActionDialogs] })] }));
318
355
  }
319
356
  function KanbanLane({ stage, count, isDark, dimmed, disabled, children }) {
320
357
  const { t } = useTranslation();
@@ -332,12 +369,12 @@ function KanbanCard({ card, titleCol, fieldCols, actions, locale, timeZone, curr
332
369
  const { attributes, listeners, setNodeRef, isDragging } = useDraggable({
333
370
  id: String(card.id),
334
371
  });
335
- const visibleActions = actions.filter((a) => isActionAllowedForRowState(a, card));
372
+ const visibleActions = actions.filter((a) => isRowActionVisible(a, card));
336
373
  return (_jsx(Card, { ref: setNodeRef, ...attributes, ...listeners, className: "w-full min-w-0 cursor-grab active:cursor-grabbing border-border/70 shadow-sm", style: { opacity: isDragging ? 0.4 : 1 }, onClick: () => onClick?.(card), "data-card-id": String(card.id), children: _jsxs(CardContent, { className: "space-y-1.5 p-3", children: [_jsxs("div", { className: "flex items-start justify-between gap-2", children: [_jsx("div", { className: "min-w-0 flex-1 break-words text-sm font-medium leading-snug", children: titleCol ? (_jsx(ActivityValueRenderer, { value: card[titleCol.key], col: titleCol, locale: locale, timeZone: timeZone, currency: currency })) : (_jsx("span", { className: "truncate", children: String(card.id) })) }), visibleActions.length > 0 && (_jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx(Button, { variant: "ghost", size: "icon", className: "h-6 w-6 shrink-0 -mr-1 -mt-1",
337
374
  // Don't start a drag / card click from the menu button.
338
375
  onPointerDown: (e) => e.stopPropagation(), onClick: (e) => e.stopPropagation(), children: _jsx(MoreHorizontal, { className: "h-4 w-4" }) }) }), _jsx(DropdownMenuContent, { align: "end", onClick: (e) => e.stopPropagation(), children: visibleActions.map((a) => (_jsxs(DropdownMenuItem, { onClick: (e) => {
339
376
  e.stopPropagation();
340
- onAction(a, card);
377
+ onAction(a.key, card);
341
378
  }, children: [_jsx(DynamicIcon, { name: a.icon || 'Zap', className: "mr-2 h-4 w-4" }), a.label] }, a.key))) })] }))] }), fieldCols.map((col) => (_jsxs("div", { className: "flex min-w-0 items-start gap-1.5 text-xs text-muted-foreground", children: [_jsxs("span", { className: "shrink-0 opacity-70", children: [col.label, ":"] }), _jsx("span", { className: "min-w-0 break-words", children: _jsx(ActivityValueRenderer, { value: card[col.key], col: col, locale: locale, timeZone: timeZone, currency: currency }) })] }, col.key)))] }) }));
342
379
  }
343
380
  // Static preview rendered inside the DragOverlay (no dnd hooks, no menu).
@@ -0,0 +1,36 @@
1
+ import type { TableMetadata } from './types';
2
+ export interface UseDynamicRowActionsParams {
3
+ /** Model key as registered on the backend (e.g. "issue"). */
4
+ model: string;
5
+ /**
6
+ * Data endpoint base. The per-record DELETE hits `<endpoint>/<id>`; when
7
+ * omitted it falls back to `/data/<model>/<id>`. Pass the SAME base the
8
+ * caller lists from (e.g. `/data/<model>/me`) so writes stay org-scoped.
9
+ */
10
+ endpoint?: string;
11
+ /** Raw model metadata — used to resolve link/custom action definitions. */
12
+ metadata: TableMetadata | null;
13
+ /**
14
+ * Host hook for `view`/`edit` (and any unhandled key). STRING contract:
15
+ * receives the action key, not the action object. When absent, `view`/`edit`
16
+ * fall back to the built-in record dialog.
17
+ */
18
+ onAction?: (action: string, row: any) => void;
19
+ /** Called after a successful delete / custom action to refetch the list. */
20
+ onRefresh: () => void;
21
+ }
22
+ export interface DynamicRowActions {
23
+ /** Dispatch a row action by its STRING key. */
24
+ handleInternalAction: (action: string, row: any) => Promise<void>;
25
+ /**
26
+ * The delete-confirm dialog + record dialog + action modal this handler
27
+ * drives. Render it ONCE in the consuming component's tree.
28
+ */
29
+ dialogs: React.ReactElement;
30
+ }
31
+ /**
32
+ * Owns the state + dialogs + dispatch logic for per-row actions, shared by
33
+ * DynamicTable and DynamicKanban so both behave identically.
34
+ */
35
+ export declare function useDynamicRowActions({ model, endpoint, metadata, onAction, onRefresh, }: UseDynamicRowActionsParams): DynamicRowActions;
36
+ //# sourceMappingURL=dynamic-row-actions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dynamic-row-actions.d.ts","sourceRoot":"","sources":["../src/dynamic-row-actions.tsx"],"names":[],"mappings":"AAoCA,OAAO,KAAK,EAAE,aAAa,EAAkB,MAAM,SAAS,CAAA;AAE5D,MAAM,WAAW,0BAA0B;IACvC,6DAA6D;IAC7D,KAAK,EAAE,MAAM,CAAA;IACb;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,2EAA2E;IAC3E,QAAQ,EAAE,aAAa,GAAG,IAAI,CAAA;IAC9B;;;;OAIG;IACH,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,KAAK,IAAI,CAAA;IAC7C,4EAA4E;IAC5E,SAAS,EAAE,MAAM,IAAI,CAAA;CACxB;AAED,MAAM,WAAW,iBAAiB;IAC9B,+CAA+C;IAC/C,oBAAoB,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IACjE;;;OAGG;IACH,OAAO,EAAE,KAAK,CAAC,YAAY,CAAA;CAC9B;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,EACjC,KAAK,EACL,QAAQ,EACR,QAAQ,EACR,QAAQ,EACR,SAAS,GACZ,EAAE,0BAA0B,GAAG,iBAAiB,CAmHhD"}
@@ -0,0 +1,110 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ // useDynamicRowActions — the single source of truth for what a per-row action
3
+ // (the "…" kebab → Ver / Editar / Eliminar / custom / link) DOES when clicked.
4
+ //
5
+ // Extracted verbatim from DynamicTable so the kanban board's per-card menu
6
+ // behaves IDENTICALLY to a table row (it used to forward the raw action object
7
+ // to the host and silently no-op). Both renderers call the returned
8
+ // `handleInternalAction(actionKey, row)` with the action's STRING key and mount
9
+ // the returned `dialogs` node once in their tree:
10
+ //
11
+ // delete → opens the SDK's own confirm dialog, then DELETEs.
12
+ // view / edit → host `onAction(action, row)` when provided (string
13
+ // contract), else the built-in record dialog.
14
+ // link action → navigate to the action's templated `linkUrl`.
15
+ // custom (fields/confirm/
16
+ // executable) action → opens the ActionModal via the dispatcher.
17
+ // anything else → host `onAction` + refresh (or just refresh).
18
+ //
19
+ // The host `onAction` contract is a STRING action key on purpose — the existing
20
+ // ops `handleAction(action: string, row)` keeps working unchanged.
21
+ import { useCallback, useState } from 'react';
22
+ import { useNavigate } from '@tanstack/react-router';
23
+ import { useTranslation } from 'react-i18next';
24
+ import { toast } from 'sonner';
25
+ import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, } from '@asteby/metacore-ui/primitives';
26
+ import { useApi } from './api-context';
27
+ import { ActionModalDispatcher } from './action-modal-dispatcher';
28
+ import { DynamicRecordDialog } from './dialogs/dynamic-record';
29
+ /**
30
+ * Owns the state + dialogs + dispatch logic for per-row actions, shared by
31
+ * DynamicTable and DynamicKanban so both behave identically.
32
+ */
33
+ export function useDynamicRowActions({ model, endpoint, metadata, onAction, onRefresh, }) {
34
+ const { t } = useTranslation();
35
+ const api = useApi();
36
+ const navigate = useNavigate();
37
+ const [recordDialog, setRecordDialog] = useState({ open: false, mode: 'view', recordId: null });
38
+ const [rowToDelete, setRowToDelete] = useState(null);
39
+ const [isDeleting, setIsDeleting] = useState(false);
40
+ const [actionModal, setActionModal] = useState({ open: false, action: null, record: null });
41
+ const handleInternalAction = useCallback(async (action, row) => {
42
+ if (action === 'delete') {
43
+ setRowToDelete(row);
44
+ return;
45
+ }
46
+ if (action === 'view' || action === 'edit') {
47
+ if (onAction)
48
+ await Promise.resolve(onAction(action, row));
49
+ else
50
+ setRecordDialog({ open: true, mode: action, recordId: row.id });
51
+ return;
52
+ }
53
+ const linkDef = metadata?.actions?.find((a) => a.key === action && a.type === 'link');
54
+ if (linkDef?.linkUrl) {
55
+ const url = linkDef.linkUrl.replace(/\{(\w+)\}/g, (_, field) => String(row[field] ?? ''));
56
+ navigate({ to: url });
57
+ return;
58
+ }
59
+ const actionDef = metadata?.actions?.find((a) => a.key === action);
60
+ if (actionDef && (actionDef.fields?.length || actionDef.confirm || actionDef.executable)) {
61
+ setActionModal({
62
+ open: true,
63
+ action: {
64
+ key: actionDef.key,
65
+ label: actionDef.label,
66
+ icon: actionDef.icon || 'Zap',
67
+ color: actionDef.color,
68
+ confirm: actionDef.confirm,
69
+ confirmMessage: actionDef.confirmMessage,
70
+ fields: actionDef.fields,
71
+ requiresState: actionDef.requiresState,
72
+ executable: actionDef.executable,
73
+ },
74
+ record: row,
75
+ });
76
+ return;
77
+ }
78
+ if (onAction) {
79
+ await Promise.resolve(onAction(action, row));
80
+ onRefresh();
81
+ }
82
+ else
83
+ onRefresh();
84
+ }, [onAction, onRefresh, metadata, navigate]);
85
+ const confirmDelete = async () => {
86
+ if (!rowToDelete)
87
+ return;
88
+ setIsDeleting(true);
89
+ try {
90
+ const deleteEndpoint = endpoint ? `${endpoint}/${rowToDelete.id}` : `/data/${model}/${rowToDelete.id}`;
91
+ const res = await api.delete(deleteEndpoint);
92
+ if (res.data.success) {
93
+ toast.success(res.data.message || 'Eliminado correctamente');
94
+ onRefresh();
95
+ }
96
+ else
97
+ toast.error(res.data.message || 'Error al eliminar');
98
+ }
99
+ catch (error) {
100
+ console.error('Error al eliminar', error);
101
+ toast.error('Error al eliminar el registro');
102
+ }
103
+ finally {
104
+ setIsDeleting(false);
105
+ setRowToDelete(null);
106
+ }
107
+ };
108
+ const dialogs = (_jsxs(_Fragment, { children: [_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(DynamicRecordDialog, { open: recordDialog.open, onOpenChange: (open) => setRecordDialog((prev) => ({ ...prev, open })), mode: recordDialog.mode, model: model, recordId: recordDialog.recordId, endpoint: endpoint, onSaved: onRefresh }), actionModal.action && (_jsx(ActionModalDispatcher, { open: actionModal.open, onOpenChange: (open) => setActionModal((prev) => ({ ...prev, open })), action: actionModal.action, model: model, record: actionModal.record, endpoint: endpoint, onSuccess: onRefresh }))] }));
109
+ return { handleInternalAction, dialogs };
110
+ }
@@ -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;AAWnF,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,+BAw5BnB"}
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;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,+BA2zBnB"}