@universe-platform/ui 0.1.0-beta.10 → 0.1.0-beta.11

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/dist/index.mjs CHANGED
@@ -159,7 +159,7 @@ var COLUMN_DEFAULT_INPUT_CONFIG = {
159
159
  NUMBER: { inputType: "number", placeholder: "\u05D4\u05D6\u05DF \u05DE\u05E1\u05E4\u05E8" },
160
160
  BOOLEAN: { inputType: "select" },
161
161
  DATE: { inputType: "date" },
162
- RELATION: { inputType: "text", placeholder: "\u05D4\u05D6\u05DF \u05E2\u05E8\u05DA \u05EA\u05E6\u05D5\u05D2\u05D4" },
162
+ RELATION: { inputType: "select", placeholder: "\u05D1\u05D7\u05E8 \u05E8\u05E9\u05D5\u05DE\u05D4 \u05DB\u05D1\u05E8\u05D9\u05E8\u05EA \u05DE\u05D7\u05D3\u05DC" },
163
163
  GOOGLE_DRIVE_FILE: { inputType: "text" },
164
164
  CURRENCY: { inputType: "number", placeholder: "\u05D4\u05D6\u05DF \u05DE\u05E1\u05E4\u05E8" },
165
165
  TIME: { inputType: "time" },
@@ -170,7 +170,7 @@ var COLUMN_DEFAULT_INPUT_CONFIG = {
170
170
  };
171
171
 
172
172
  // src/components/TableBlock/TableBlockClient.tsx
173
- import React9, { useState as useState10, useMemo as useMemo5, useEffect as useEffect8, useCallback as useCallback9, useRef as useRef7 } from "react";
173
+ import React11, { useState as useState12, useMemo as useMemo6, useEffect as useEffect10, useCallback as useCallback10, useRef as useRef8 } from "react";
174
174
 
175
175
  // src/hooks/useToast.ts
176
176
  import { useContext as useContext2 } from "react";
@@ -1460,9 +1460,10 @@ function LinkPickerCell({ value, onChange, readOnly = false }) {
1460
1460
  }
1461
1461
 
1462
1462
  // src/components/TableBlock/fields/RelationPickerCell.tsx
1463
- import { useState as useState6, useRef as useRef5, useEffect as useEffect5, useCallback as useCallback5, useMemo as useMemo3 } from "react";
1464
- import { X as X6, Search, Check as Check3, ChevronDown } from "lucide-react";
1465
- import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
1463
+ import React6, { useState as useState6, useRef as useRef5, useEffect as useEffect5, useCallback as useCallback5, useMemo as useMemo3 } from "react";
1464
+ import { createPortal } from "react-dom";
1465
+ import { X as X6, Search, Check as Check3, ChevronDown, Loader2 } from "lucide-react";
1466
+ import { Fragment as Fragment2, jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
1466
1467
  function isRawObjectId(str) {
1467
1468
  if (typeof str !== "string") return false;
1468
1469
  const trimmed = str.trim();
@@ -1519,6 +1520,30 @@ function resolveRelationLabel(opt, column) {
1519
1520
  }
1520
1521
  return "";
1521
1522
  }
1523
+ var ITEM_HEIGHT = 35;
1524
+ var CONTAINER_HEIGHT = 200;
1525
+ var OVERSCAN = 5;
1526
+ var BATCH_SIZE = 50;
1527
+ var RelationPickerRow = React6.memo(function RelationPickerRow2({
1528
+ id,
1529
+ label,
1530
+ isSelected,
1531
+ onSelect,
1532
+ height
1533
+ }) {
1534
+ return /* @__PURE__ */ jsxs6(
1535
+ "div",
1536
+ {
1537
+ onClick: () => onSelect(id),
1538
+ style: { height: `${height}px` },
1539
+ className: `flex items-center justify-between px-2.5 rounded cursor-pointer text-xs transition-colors ${isSelected ? "bg-blue-50 text-blue-900 font-medium" : "hover:bg-slate-50 text-slate-700"}`,
1540
+ children: [
1541
+ /* @__PURE__ */ jsx6("span", { className: "truncate flex-1", children: label }),
1542
+ isSelected && /* @__PURE__ */ jsx6(Check3, { className: "w-3.5 h-3.5 text-blue-600 shrink-0 mr-1" })
1543
+ ]
1544
+ }
1545
+ );
1546
+ });
1522
1547
  function RelationPickerCell({
1523
1548
  value,
1524
1549
  onChange,
@@ -1527,42 +1552,147 @@ function RelationPickerCell({
1527
1552
  rowId,
1528
1553
  readOnly = false
1529
1554
  }) {
1530
- var _a;
1555
+ var _a, _b, _c;
1531
1556
  const [isOpen, setIsOpen] = useState6(false);
1532
1557
  const [searchQuery, setSearchQuery] = useState6("");
1558
+ const [isRemoteSearching, setIsRemoteSearching] = useState6(false);
1559
+ const [isLoadingMore, setIsLoadingMore] = useState6(false);
1560
+ const [hasMore, setHasMore] = useState6(true);
1561
+ const [items, setItems] = useState6([]);
1562
+ const [skip, setSkip] = useState6(0);
1563
+ const [scrollTop, setScrollTop] = useState6(0);
1533
1564
  const containerRef = useRef5(null);
1565
+ const dropdownRef = useRef5(null);
1534
1566
  const searchInputRef = useRef5(null);
1567
+ const listContainerRef = useRef5(null);
1568
+ const sentinelRef = useRef5(null);
1569
+ const [dropdownCoords, setDropdownCoords] = useState6(null);
1570
+ const updateDropdownCoords = useCallback5(() => {
1571
+ if (!containerRef.current) return;
1572
+ const rect = containerRef.current.getBoundingClientRect();
1573
+ const dropdownHeight = 280;
1574
+ const dropdownWidth = Math.max(220, Math.min(320, rect.width || 220));
1575
+ let right = window.innerWidth - rect.right;
1576
+ if (right + dropdownWidth > window.innerWidth - 10) {
1577
+ right = window.innerWidth - dropdownWidth - 10;
1578
+ }
1579
+ if (right < 10) {
1580
+ right = 10;
1581
+ }
1582
+ const spaceBelow = window.innerHeight - rect.bottom;
1583
+ let top = rect.bottom + 4;
1584
+ if (spaceBelow < dropdownHeight && rect.top > dropdownHeight) {
1585
+ top = Math.max(10, rect.top - dropdownHeight - 4);
1586
+ } else {
1587
+ top = Math.min(window.innerHeight - dropdownHeight - 10, top);
1588
+ }
1589
+ setDropdownCoords({ top, right, width: dropdownWidth });
1590
+ }, []);
1591
+ useEffect5(() => {
1592
+ if (!isOpen) return;
1593
+ updateDropdownCoords();
1594
+ const handleScrollOrResize = () => updateDropdownCoords();
1595
+ window.addEventListener("scroll", handleScrollOrResize, true);
1596
+ window.addEventListener("resize", handleScrollOrResize);
1597
+ return () => {
1598
+ window.removeEventListener("scroll", handleScrollOrResize, true);
1599
+ window.removeEventListener("resize", handleScrollOrResize);
1600
+ };
1601
+ }, [isOpen, updateDropdownCoords]);
1602
+ const stableLabelCacheRef = useRef5(/* @__PURE__ */ new Map());
1603
+ const skipRef = useRef5(0);
1604
+ const isLoadingMoreRef = useRef5(false);
1535
1605
  const allowMultiple = Boolean((_a = column.config) == null ? void 0 : _a.allowMultiple);
1606
+ const referencedTableId = (_b = column.config) == null ? void 0 : _b.referencedTableId;
1607
+ const displayField = (_c = column.config) == null ? void 0 : _c.displayField;
1536
1608
  const selectedIds = useMemo3(() => normalizeRelationValue(value), [value]);
1537
1609
  const isStandalone = !context || context.relationOptions === void 0;
1538
1610
  const optionsLoaded = isStandalone || context.relationOptions[column.name] !== void 0;
1539
- const rawOptions = useMemo3(() => {
1611
+ const baseOptions = useMemo3(() => {
1540
1612
  var _a2;
1541
1613
  return ((_a2 = context == null ? void 0 : context.relationOptions) == null ? void 0 : _a2[column.name]) || [];
1542
1614
  }, [context == null ? void 0 : context.relationOptions, column.name]);
1543
1615
  const processedOptions = useMemo3(() => {
1544
- return rawOptions.map((opt) => {
1545
- const label = resolveRelationLabel(opt, column);
1546
- return {
1547
- id: String(opt.id),
1548
- _displayLabel: label
1549
- };
1550
- }).filter((opt) => opt._displayLabel && opt._displayLabel.trim() !== "" && !isRawObjectId(opt._displayLabel));
1551
- }, [rawOptions, column]);
1616
+ return items.map((opt) => ({
1617
+ id: String(opt.id),
1618
+ _displayLabel: resolveRelationLabel(opt, column) || opt.label || ""
1619
+ })).filter((opt) => opt._displayLabel && opt._displayLabel.trim() !== "" && !isRawObjectId(opt._displayLabel));
1620
+ }, [items, column]);
1552
1621
  const getDisplayForId = useCallback5((id) => {
1553
- const found = processedOptions.find((o) => String(o.id) === String(id));
1554
- if (found && found._displayLabel && !isRawObjectId(found._displayLabel)) {
1555
- return found._displayLabel;
1622
+ var _a2, _b2, _c2;
1623
+ if (!id) return "-";
1624
+ const strId = String(id).trim();
1625
+ if (!strId) return "-";
1626
+ if (stableLabelCacheRef.current.has(strId)) {
1627
+ const cached = stableLabelCacheRef.current.get(strId);
1628
+ if (cached && cached !== "-" && !isRawObjectId(cached)) {
1629
+ return cached;
1630
+ }
1631
+ }
1632
+ const dictOpt = (_c2 = (_b2 = (_a2 = context == null ? void 0 : context.relationDictionaryRef) == null ? void 0 : _a2.current) == null ? void 0 : _b2[column.name]) == null ? void 0 : _c2.get(strId);
1633
+ if (dictOpt) {
1634
+ const lbl = resolveRelationLabel(dictOpt, column) || dictOpt.label || dictOpt.name;
1635
+ if (lbl && !isRawObjectId(String(lbl))) {
1636
+ stableLabelCacheRef.current.set(strId, String(lbl));
1637
+ return String(lbl);
1638
+ }
1639
+ }
1640
+ const foundInItems = items.find((o) => String(o.id) === strId);
1641
+ if (foundInItems) {
1642
+ const lbl = resolveRelationLabel(foundInItems, column) || foundInItems.label || foundInItems.name;
1643
+ if (lbl && !isRawObjectId(String(lbl))) {
1644
+ stableLabelCacheRef.current.set(strId, String(lbl));
1645
+ return String(lbl);
1646
+ }
1647
+ }
1648
+ const foundInBase = (baseOptions || []).find((o) => String(o.id) === strId);
1649
+ if (foundInBase) {
1650
+ const lbl = resolveRelationLabel(foundInBase, column) || foundInBase.label || foundInBase.name;
1651
+ if (lbl && !isRawObjectId(String(lbl))) {
1652
+ stableLabelCacheRef.current.set(strId, String(lbl));
1653
+ return String(lbl);
1654
+ }
1556
1655
  }
1557
1656
  return "-";
1558
- }, [processedOptions]);
1657
+ }, [items, baseOptions, column, context]);
1559
1658
  const handleOpen = (e) => {
1560
1659
  if (readOnly) return;
1561
1660
  e == null ? void 0 : e.stopPropagation();
1562
- setIsOpen((prev) => !prev);
1661
+ const nextOpen = !isOpen;
1662
+ if (nextOpen) {
1663
+ updateDropdownCoords();
1664
+ }
1665
+ setIsOpen(nextOpen);
1666
+ if (!nextOpen) return;
1563
1667
  setSearchQuery("");
1564
- if (context == null ? void 0 : context.refetchRelation) {
1565
- context.refetchRelation(column.name);
1668
+ setScrollTop(0);
1669
+ setSkip(0);
1670
+ skipRef.current = 0;
1671
+ setHasMore(true);
1672
+ const fetcher = (context == null ? void 0 : context.executeAction) ? (p) => context.executeAction("FETCH_RELATION", p) : (context == null ? void 0 : context.refetchRelation) ? (p) => context.refetchRelation(column.name, p) : null;
1673
+ if (fetcher && referencedTableId) {
1674
+ setIsLoadingMore(true);
1675
+ isLoadingMoreRef.current = true;
1676
+ fetcher({
1677
+ referencedTableId,
1678
+ displayField,
1679
+ take: BATCH_SIZE,
1680
+ limit: BATCH_SIZE,
1681
+ skip: 0
1682
+ }).then((res) => {
1683
+ const newData = Array.isArray(res) ? res : (res == null ? void 0 : res.data) && Array.isArray(res.data) ? res.data : [];
1684
+ setItems(newData);
1685
+ setSkip(BATCH_SIZE);
1686
+ skipRef.current = BATCH_SIZE;
1687
+ if (newData.length < BATCH_SIZE) {
1688
+ setHasMore(false);
1689
+ }
1690
+ }).catch((err) => {
1691
+ console.warn("[RelationPickerCell] Initial fetch failed:", err);
1692
+ }).finally(() => {
1693
+ setIsLoadingMore(false);
1694
+ isLoadingMoreRef.current = false;
1695
+ });
1566
1696
  }
1567
1697
  };
1568
1698
  useEffect5(() => {
@@ -1573,7 +1703,105 @@ function RelationPickerCell({
1573
1703
  }, 50);
1574
1704
  }
1575
1705
  }, [isOpen]);
1576
- const handleSelectOption = (optId) => {
1706
+ useEffect5(() => {
1707
+ if (!isOpen) return;
1708
+ const query = searchQuery.trim();
1709
+ const fetcher = (context == null ? void 0 : context.executeAction) ? (p) => context.executeAction("FETCH_RELATION", p) : (context == null ? void 0 : context.refetchRelation) ? (p) => context.refetchRelation(column.name, p) : null;
1710
+ if (!fetcher || !referencedTableId) return;
1711
+ setSkip(0);
1712
+ skipRef.current = 0;
1713
+ setHasMore(true);
1714
+ setScrollTop(0);
1715
+ if (listContainerRef.current) {
1716
+ listContainerRef.current.scrollTop = 0;
1717
+ }
1718
+ setIsRemoteSearching(true);
1719
+ const timer = setTimeout(() => {
1720
+ fetcher({
1721
+ referencedTableId,
1722
+ displayField,
1723
+ search: query,
1724
+ take: BATCH_SIZE,
1725
+ limit: BATCH_SIZE,
1726
+ skip: 0
1727
+ }).then((res) => {
1728
+ const newData = Array.isArray(res) ? res : (res == null ? void 0 : res.data) && Array.isArray(res.data) ? res.data : [];
1729
+ setItems(newData);
1730
+ setSkip(BATCH_SIZE);
1731
+ skipRef.current = BATCH_SIZE;
1732
+ if (newData.length < BATCH_SIZE) {
1733
+ setHasMore(false);
1734
+ }
1735
+ }).catch((err) => {
1736
+ console.warn("[RelationPickerCell] Remote search failed:", err);
1737
+ }).finally(() => {
1738
+ setIsRemoteSearching(false);
1739
+ });
1740
+ }, 250);
1741
+ return () => clearTimeout(timer);
1742
+ }, [searchQuery, isOpen, referencedTableId, displayField, context, column.name]);
1743
+ const handleLoadMore = useCallback5(async () => {
1744
+ if (isLoadingMoreRef.current || !hasMore || !referencedTableId) return;
1745
+ const fetcher = (context == null ? void 0 : context.executeAction) ? (p) => context.executeAction("FETCH_RELATION", p) : (context == null ? void 0 : context.refetchRelation) ? (p) => context.refetchRelation(column.name, p) : null;
1746
+ if (!fetcher) return;
1747
+ isLoadingMoreRef.current = true;
1748
+ setIsLoadingMore(true);
1749
+ const currentQuery = searchQuery.trim();
1750
+ const currentSkip = skipRef.current;
1751
+ try {
1752
+ const res = await fetcher({
1753
+ referencedTableId,
1754
+ displayField,
1755
+ search: currentQuery,
1756
+ take: BATCH_SIZE,
1757
+ limit: BATCH_SIZE,
1758
+ skip: currentSkip
1759
+ });
1760
+ const newData = Array.isArray(res) ? res : (res == null ? void 0 : res.data) && Array.isArray(res.data) ? res.data : [];
1761
+ if (newData.length < BATCH_SIZE) {
1762
+ setHasMore(false);
1763
+ }
1764
+ if (newData.length > 0) {
1765
+ setItems((prev) => {
1766
+ const seen = new Set(prev.map((i) => String(i.id)));
1767
+ const unique = newData.filter((i) => !seen.has(String(i.id)));
1768
+ return [...prev, ...unique];
1769
+ });
1770
+ setSkip((prev) => prev + BATCH_SIZE);
1771
+ skipRef.current += BATCH_SIZE;
1772
+ }
1773
+ } catch (err) {
1774
+ console.warn("[RelationPickerCell] Load more failed:", err);
1775
+ } finally {
1776
+ isLoadingMoreRef.current = false;
1777
+ setIsLoadingMore(false);
1778
+ }
1779
+ }, [hasMore, referencedTableId, searchQuery, context, column.name, displayField]);
1780
+ useEffect5(() => {
1781
+ if (!isOpen || !hasMore) return;
1782
+ const sentinel = sentinelRef.current;
1783
+ if (!sentinel) return;
1784
+ const observer = new IntersectionObserver(
1785
+ (entries) => {
1786
+ var _a2;
1787
+ if (((_a2 = entries[0]) == null ? void 0 : _a2.isIntersecting) && !isLoadingMoreRef.current) {
1788
+ handleLoadMore();
1789
+ }
1790
+ },
1791
+ { root: listContainerRef.current, threshold: 0.1 }
1792
+ );
1793
+ observer.observe(sentinel);
1794
+ return () => observer.disconnect();
1795
+ }, [isOpen, hasMore, handleLoadMore]);
1796
+ const handleListScroll = (e) => {
1797
+ const currentScrollTop = e.currentTarget.scrollTop;
1798
+ setScrollTop(currentScrollTop);
1799
+ const { clientHeight, scrollHeight } = e.currentTarget;
1800
+ if (scrollHeight - (currentScrollTop + clientHeight) < 60 && hasMore && !isLoadingMoreRef.current) {
1801
+ handleLoadMore();
1802
+ }
1803
+ };
1804
+ const handleSelectOption = useCallback5((optId) => {
1577
1805
  if (!allowMultiple) {
1578
1806
  onChange([optId]);
1579
1807
  setIsOpen(false);
@@ -1584,7 +1812,7 @@ function RelationPickerCell({
1584
1812
  onChange([...selectedIds, optId]);
1585
1813
  }
1586
1814
  }
1587
- };
1815
+ }, [allowMultiple, onChange, selectedIds]);
1588
1816
  const handleRemove = (idToRemove) => {
1589
1817
  onChange(selectedIds.filter((id) => id !== idToRemove));
1590
1818
  };
@@ -1595,7 +1823,8 @@ function RelationPickerCell({
1595
1823
  useEffect5(() => {
1596
1824
  if (!isOpen) return;
1597
1825
  function handleClickOutside(event) {
1598
- if (containerRef.current && !containerRef.current.contains(event.target)) {
1826
+ const target = event.target;
1827
+ if (containerRef.current && !containerRef.current.contains(target) && dropdownRef.current && !dropdownRef.current.contains(target)) {
1599
1828
  setIsOpen(false);
1600
1829
  }
1601
1830
  }
@@ -1611,13 +1840,19 @@ function RelationPickerCell({
1611
1840
  document.removeEventListener("keydown", handleKeyDown);
1612
1841
  };
1613
1842
  }, [isOpen]);
1614
- const filteredOptions = useMemo3(() => {
1843
+ const displayedOptions = useMemo3(() => {
1615
1844
  const query = searchQuery.trim().toLowerCase();
1616
1845
  if (!query) return processedOptions;
1617
1846
  return processedOptions.filter((opt) => {
1618
1847
  return (opt._displayLabel || "").toLowerCase().includes(query);
1619
1848
  });
1620
1849
  }, [processedOptions, searchQuery]);
1850
+ const totalItems = displayedOptions.length;
1851
+ const totalHeight = totalItems * ITEM_HEIGHT;
1852
+ const startIndex = Math.max(0, Math.floor(scrollTop / ITEM_HEIGHT) - OVERSCAN);
1853
+ const endIndex = Math.min(totalItems, Math.ceil((scrollTop + CONTAINER_HEIGHT) / ITEM_HEIGHT) + OVERSCAN);
1854
+ const visibleOptions = displayedOptions.slice(startIndex, endIndex);
1855
+ const topPadding = startIndex * ITEM_HEIGHT;
1621
1856
  if (!optionsLoaded && selectedIds.length > 0) {
1622
1857
  return /* @__PURE__ */ jsx6("div", { className: "px-2 py-1 flex items-center h-full w-full", children: /* @__PURE__ */ jsx6("span", { className: "inline-block w-16 h-4 bg-slate-100 animate-pulse rounded" }) });
1623
1858
  }
@@ -1739,51 +1974,101 @@ function RelationPickerCell({
1739
1974
  )
1740
1975
  }
1741
1976
  ),
1742
- isOpen && /* @__PURE__ */ jsxs6(
1743
- "div",
1744
- {
1745
- id: `relation-dropdown-${column.name}-${rowId || "cell"}`,
1746
- dir: "rtl",
1747
- className: "absolute top-full right-0 mt-1 z-[100] bg-white rounded-md shadow-lg border border-slate-200 p-1 min-w-[200px] w-full max-w-[300px] animate-in fade-in duration-100 flex flex-col",
1748
- onClick: (e) => e.stopPropagation(),
1749
- children: [
1750
- /* @__PURE__ */ jsxs6("div", { className: "relative mb-1", children: [
1751
- /* @__PURE__ */ jsx6(Search, { className: "w-3.5 h-3.5 text-slate-400 absolute right-2 top-2 pointer-events-none" }),
1977
+ isOpen && dropdownCoords && typeof document !== "undefined" && createPortal(
1978
+ /* @__PURE__ */ jsxs6(
1979
+ "div",
1980
+ {
1981
+ ref: dropdownRef,
1982
+ id: `relation-dropdown-${column.name}-${rowId || "cell"}`,
1983
+ dir: "rtl",
1984
+ style: {
1985
+ position: "fixed",
1986
+ top: `${dropdownCoords.top}px`,
1987
+ right: `${dropdownCoords.right}px`,
1988
+ width: `${dropdownCoords.width}px`,
1989
+ zIndex: 99999
1990
+ },
1991
+ className: "bg-white rounded-md shadow-2xl border border-slate-200 p-1 animate-in fade-in duration-100 flex flex-col",
1992
+ onClick: (e) => e.stopPropagation(),
1993
+ onMouseDown: (e) => e.stopPropagation(),
1994
+ children: [
1995
+ /* @__PURE__ */ jsxs6("div", { className: "relative mb-1", children: [
1996
+ /* @__PURE__ */ jsx6(Search, { className: "w-3.5 h-3.5 text-slate-400 absolute right-2 top-2 pointer-events-none" }),
1997
+ /* @__PURE__ */ jsx6(
1998
+ "input",
1999
+ {
2000
+ ref: searchInputRef,
2001
+ type: "text",
2002
+ placeholder: "\u05D7\u05E4\u05E9...",
2003
+ value: searchQuery,
2004
+ onChange: (e) => setSearchQuery(e.target.value),
2005
+ onKeyDown: (e) => {
2006
+ if (e.key === "Escape") {
2007
+ e.stopPropagation();
2008
+ setIsOpen(false);
2009
+ }
2010
+ },
2011
+ className: "w-full h-7 pr-7 pl-7 bg-slate-50 border border-slate-200 rounded text-xs text-slate-800 placeholder-slate-400 focus:bg-white focus:outline-none focus:ring-1 focus:ring-blue-500 focus:border-blue-500 transition-colors"
2012
+ }
2013
+ ),
2014
+ isRemoteSearching && /* @__PURE__ */ jsx6(Loader2, { className: "w-3.5 h-3.5 text-blue-500 animate-spin absolute left-2 top-2 pointer-events-none" })
2015
+ ] }),
1752
2016
  /* @__PURE__ */ jsx6(
1753
- "input",
2017
+ "div",
1754
2018
  {
1755
- ref: searchInputRef,
1756
- type: "text",
1757
- placeholder: "\u05D7\u05E4\u05E9...",
1758
- value: searchQuery,
1759
- onChange: (e) => setSearchQuery(e.target.value),
1760
- onKeyDown: (e) => {
1761
- if (e.key === "Escape") {
1762
- e.stopPropagation();
1763
- setIsOpen(false);
1764
- }
1765
- },
1766
- className: "w-full h-7 pr-7 pl-2 bg-slate-50 border border-slate-200 rounded text-xs text-slate-800 placeholder-slate-400 focus:bg-white focus:outline-none focus:ring-1 focus:ring-blue-500 focus:border-blue-500 transition-colors"
2019
+ ref: listContainerRef,
2020
+ onScroll: handleListScroll,
2021
+ style: { maxHeight: `${CONTAINER_HEIGHT}px` },
2022
+ className: "overflow-y-auto relative",
2023
+ children: displayedOptions.length > 0 ? /* @__PURE__ */ jsxs6(Fragment2, { children: [
2024
+ /* @__PURE__ */ jsx6("div", { style: { height: `${totalHeight}px`, position: "relative", width: "100%" }, children: /* @__PURE__ */ jsx6(
2025
+ "div",
2026
+ {
2027
+ style: {
2028
+ position: "absolute",
2029
+ top: 0,
2030
+ left: 0,
2031
+ right: 0,
2032
+ transform: `translateY(${topPadding}px)`
2033
+ },
2034
+ children: visibleOptions.map((opt) => /* @__PURE__ */ jsx6(
2035
+ RelationPickerRow,
2036
+ {
2037
+ id: opt.id,
2038
+ label: opt._displayLabel,
2039
+ isSelected: selectedIds.includes(opt.id),
2040
+ onSelect: handleSelectOption,
2041
+ height: ITEM_HEIGHT
2042
+ },
2043
+ opt.id
2044
+ ))
2045
+ }
2046
+ ) }),
2047
+ hasMore && /* @__PURE__ */ jsx6("div", { ref: sentinelRef, className: "pt-1 pb-0.5 px-2 text-center", children: isLoadingMore ? /* @__PURE__ */ jsxs6("div", { className: "flex items-center justify-center gap-1.5 text-xs text-slate-400 py-1", children: [
2048
+ /* @__PURE__ */ jsx6(Loader2, { className: "w-3 h-3 text-blue-500 animate-spin shrink-0" }),
2049
+ /* @__PURE__ */ jsx6("span", { children: "\u05D8\u05D5\u05E2\u05DF \u05E2\u05D5\u05D3 \u05E8\u05E9\u05D5\u05DE\u05D5\u05EA..." })
2050
+ ] }) : /* @__PURE__ */ jsx6(
2051
+ "button",
2052
+ {
2053
+ type: "button",
2054
+ onClick: (e) => {
2055
+ e.stopPropagation();
2056
+ handleLoadMore();
2057
+ },
2058
+ className: "text-[11px] text-blue-600 hover:text-blue-700 hover:underline py-1 px-2 font-medium",
2059
+ children: "\u05D8\u05E2\u05DF \u05E2\u05D5\u05D3 \u05E8\u05E9\u05D5\u05DE\u05D5\u05EA..."
2060
+ }
2061
+ ) })
2062
+ ] }) : /* @__PURE__ */ jsx6("div", { className: "py-2.5 px-2 text-center text-xs text-slate-400 select-none", children: isRemoteSearching ? /* @__PURE__ */ jsxs6("div", { className: "flex items-center justify-center gap-1.5 py-1", children: [
2063
+ /* @__PURE__ */ jsx6(Loader2, { className: "w-3 h-3 text-blue-500 animate-spin shrink-0" }),
2064
+ /* @__PURE__ */ jsx6("span", { children: "\u05DE\u05D7\u05E4\u05E9 \u05E8\u05E9\u05D5\u05DE\u05D5\u05EA..." })
2065
+ ] }) : items.length === 0 ? "\u05D0\u05D9\u05DF \u05E8\u05E9\u05D5\u05DE\u05D5\u05EA \u05D6\u05DE\u05D9\u05E0\u05D5\u05EA" : "\u05DC\u05D0 \u05E0\u05DE\u05E6\u05D0\u05D5 \u05EA\u05D5\u05E6\u05D0\u05D5\u05EA" })
1767
2066
  }
1768
2067
  )
1769
- ] }),
1770
- /* @__PURE__ */ jsx6("div", { className: "overflow-y-auto max-h-[180px] space-y-0.5", children: filteredOptions.length > 0 ? filteredOptions.map((opt) => {
1771
- const isSelected = selectedIds.includes(opt.id);
1772
- return /* @__PURE__ */ jsxs6(
1773
- "div",
1774
- {
1775
- onClick: () => handleSelectOption(opt.id),
1776
- className: `flex items-center justify-between px-2.5 py-1.5 rounded cursor-pointer text-xs transition-colors ${isSelected ? "bg-blue-50 text-blue-900 font-medium" : "hover:bg-slate-50 text-slate-700"}`,
1777
- children: [
1778
- /* @__PURE__ */ jsx6("span", { className: "truncate flex-1", children: opt._displayLabel }),
1779
- isSelected && /* @__PURE__ */ jsx6(Check3, { className: "w-3.5 h-3.5 text-blue-600 shrink-0 mr-1" })
1780
- ]
1781
- },
1782
- opt.id
1783
- );
1784
- }) : /* @__PURE__ */ jsx6("div", { className: "py-2.5 px-2 text-center text-xs text-slate-400 select-none", children: processedOptions.length === 0 ? "\u05D0\u05D9\u05DF \u05E8\u05E9\u05D5\u05DE\u05D5\u05EA \u05D6\u05DE\u05D9\u05E0\u05D5\u05EA" : "\u05DC\u05D0 \u05E0\u05DE\u05E6\u05D0\u05D5 \u05EA\u05D5\u05E6\u05D0\u05D5\u05EA" }) })
1785
- ]
1786
- }
2068
+ ]
2069
+ }
2070
+ ),
2071
+ document.body
1787
2072
  )
1788
2073
  ]
1789
2074
  }
@@ -2204,7 +2489,7 @@ var FORM_INPUTS = {
2204
2489
  };
2205
2490
 
2206
2491
  // src/components/TableBlock/fields/SubTableViewer.tsx
2207
- import { useState as useState9, useEffect as useEffect7, useRef as useRef6, useCallback as useCallback8, useMemo as useMemo4 } from "react";
2492
+ import { useState as useState10, useEffect as useEffect8, useRef as useRef6, useCallback as useCallback8, useMemo as useMemo4 } from "react";
2208
2493
 
2209
2494
  // src/utils/phone.ts
2210
2495
  function sanitizePhoneNumber(phone) {
@@ -2362,6 +2647,7 @@ function useColumnReorder({
2362
2647
  }
2363
2648
 
2364
2649
  // src/components/TableBlock/columnTitleUtils.tsx
2650
+ import { useState as useState9, useEffect as useEffect7 } from "react";
2365
2651
  import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
2366
2652
  var canvas = null;
2367
2653
  function measureTextWidth(text, font = '600 14px system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif') {
@@ -2402,10 +2688,10 @@ function splitHeaderTitle(name) {
2402
2688
  }
2403
2689
  function calculateMinColumnWidth(name, isSubTable = false, colType) {
2404
2690
  const font = isSubTable ? '600 12px system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif' : '600 14px system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif';
2405
- const chromeWidth = isSubTable ? 44 : 52;
2406
- let baseMin = isSubTable ? 50 : 60;
2691
+ const chromeWidth = isSubTable ? 24 : 26;
2692
+ let baseMin = isSubTable ? 30 : 36;
2407
2693
  if ((colType == null ? void 0 : colType.toUpperCase()) === "GOOGLE_CONTACT") {
2408
- baseMin = isSubTable ? 110 : 120;
2694
+ baseMin = isSubTable ? 100 : 110;
2409
2695
  }
2410
2696
  if (!name) return baseMin;
2411
2697
  const { isSingleWord, line1, line2 } = splitHeaderTitle(name);
@@ -2419,12 +2705,16 @@ function calculateMinColumnWidth(name, isSubTable = false, colType) {
2419
2705
  return Math.max(baseMin, Math.ceil(maxLine + chromeWidth));
2420
2706
  }
2421
2707
  function ColumnHeaderTitle({ name, width, isSubTable = false }) {
2708
+ const [isMounted, setIsMounted] = useState9(false);
2709
+ useEffect7(() => {
2710
+ setIsMounted(true);
2711
+ }, []);
2422
2712
  const { isSingleWord, line1, line2 } = splitHeaderTitle(name);
2423
- if (isSingleWord || !line2) {
2424
- return /* @__PURE__ */ jsx8("span", { className: "whitespace-nowrap select-none overflow-hidden text-right flex-1", title: name, children: line1 });
2713
+ if (!isMounted || isSingleWord || !line2) {
2714
+ return /* @__PURE__ */ jsx8("span", { className: "whitespace-nowrap select-none overflow-hidden text-right flex-1", title: name, children: name });
2425
2715
  }
2426
2716
  const font = isSubTable ? '600 12px system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif' : '600 14px system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif';
2427
- const chromeWidth = isSubTable ? 44 : 52;
2717
+ const chromeWidth = isSubTable ? 24 : 26;
2428
2718
  const fullTitleWidth = measureTextWidth(name, font) + chromeWidth;
2429
2719
  if (width !== void 0 && width >= fullTitleWidth) {
2430
2720
  return /* @__PURE__ */ jsx8("span", { className: "whitespace-nowrap select-none overflow-hidden text-right flex-1", title: name, children: name });
@@ -2558,9 +2848,9 @@ function SubTableCell({
2558
2848
  const isContact = colType === "GOOGLE_CONTACT";
2559
2849
  const InputComponent = FORM_INPUTS[colType] || FORM_INPUTS.DEFAULT;
2560
2850
  const serverValue = (_b = record.data[column.name]) != null ? _b : colType === "BOOLEAN" ? false : "";
2561
- const [draftValue, setDraftValue] = useState9(serverValue);
2562
- const [isDirty, setIsDirty] = useState9(false);
2563
- const [validationError, setValidationError] = useState9(null);
2851
+ const [draftValue, setDraftValue] = useState10(serverValue);
2852
+ const [isDirty, setIsDirty] = useState10(false);
2853
+ const [validationError, setValidationError] = useState10(null);
2564
2854
  const cellRef = useRef6(null);
2565
2855
  const draftRef = useRef6(draftValue);
2566
2856
  const isDirtyRef = useRef6(isDirty);
@@ -2577,7 +2867,7 @@ function SubTableCell({
2577
2867
  recordIdRef.current = record.id;
2578
2868
  columnRef.current = column;
2579
2869
  onCommitRef.current = onCommit;
2580
- useEffect7(() => {
2870
+ useEffect8(() => {
2581
2871
  if (!isDirtyRef.current) {
2582
2872
  setDraftValue(serverValue);
2583
2873
  draftRef.current = serverValue;
@@ -2634,7 +2924,7 @@ function SubTableCell({
2634
2924
  setValidationError(null);
2635
2925
  lastFailedValRef.current = void 0;
2636
2926
  }, []);
2637
- useEffect7(() => {
2927
+ useEffect8(() => {
2638
2928
  return () => {
2639
2929
  if (isDirtyRef.current && !isCommittingRef.current) {
2640
2930
  const val = draftRef.current;
@@ -2736,7 +3026,7 @@ function SubTableViewer({ rowId, column, value, onChange, context }) {
2736
3026
  var _a, _b, _c, _d, _e, _f;
2737
3027
  const { addToast } = useToast();
2738
3028
  const entries = Array.isArray(value) ? value : [];
2739
- const [linkedRecords, setLinkedRecords] = useState9(() => {
3029
+ const [linkedRecords, setLinkedRecords] = useState10(() => {
2740
3030
  const initial = [];
2741
3031
  for (const entry of entries) {
2742
3032
  if (entry.recordId && entry._resolvedData) {
@@ -2745,15 +3035,15 @@ function SubTableViewer({ rowId, column, value, onChange, context }) {
2745
3035
  }
2746
3036
  return initial;
2747
3037
  });
2748
- const [targetSchema, setTargetSchema] = useState9(null);
2749
- const [isLoading, setIsLoading] = useState9(true);
2750
- const [isSearchOpen, setIsSearchOpen] = useState9(false);
2751
- const [searchQuery, setSearchQuery] = useState9("");
2752
- const [searchResults, setSearchResults] = useState9([]);
2753
- const [isSearching, setIsSearching] = useState9(false);
2754
- const [isCreating, setIsCreating] = useState9(false);
2755
- const [newRecordData, setNewRecordData] = useState9({});
2756
- const [conflictModalState, setConflictModalState] = useState9({
3038
+ const [targetSchema, setTargetSchema] = useState10(null);
3039
+ const [isLoading, setIsLoading] = useState10(true);
3040
+ const [isSearchOpen, setIsSearchOpen] = useState10(false);
3041
+ const [searchQuery, setSearchQuery] = useState10("");
3042
+ const [searchResults, setSearchResults] = useState10([]);
3043
+ const [isSearching, setIsSearching] = useState10(false);
3044
+ const [isCreating, setIsCreating] = useState10(false);
3045
+ const [newRecordData, setNewRecordData] = useState10({});
3046
+ const [conflictModalState, setConflictModalState] = useState10({
2757
3047
  isOpen: false,
2758
3048
  fieldName: "",
2759
3049
  matchingRecords: []
@@ -2763,7 +3053,7 @@ function SubTableViewer({ rowId, column, value, onChange, context }) {
2763
3053
  const executeAction = context == null ? void 0 : context.executeAction;
2764
3054
  const referencedTableId = ((_a = column.config) == null ? void 0 : _a.referencedTableId) || column.referencedTableId;
2765
3055
  const fetchedIdsRef = useRef6(/* @__PURE__ */ new Set());
2766
- useEffect7(() => {
3056
+ useEffect8(() => {
2767
3057
  if (entries.length > 0) {
2768
3058
  setLinkedRecords((prev) => {
2769
3059
  const existingIds = new Set(prev.map((r) => r.id));
@@ -2778,7 +3068,7 @@ function SubTableViewer({ rowId, column, value, onChange, context }) {
2778
3068
  });
2779
3069
  }
2780
3070
  }, [entries]);
2781
- useEffect7(() => {
3071
+ useEffect8(() => {
2782
3072
  if (!referencedTableId || !executeAction) {
2783
3073
  setIsLoading(false);
2784
3074
  return;
@@ -2805,7 +3095,7 @@ function SubTableViewer({ rowId, column, value, onChange, context }) {
2805
3095
  recordIdsToFetch.forEach((id) => fetchedIdsRef.current.delete(id));
2806
3096
  }).finally(() => setIsLoading(false));
2807
3097
  }, [referencedTableId, executeAction, entries, targetSchema]);
2808
- useEffect7(() => {
3098
+ useEffect8(() => {
2809
3099
  const handleClick = (e) => {
2810
3100
  if (searchRef.current && !searchRef.current.contains(e.target)) {
2811
3101
  setIsSearchOpen(false);
@@ -2840,8 +3130,8 @@ function SubTableViewer({ rowId, column, value, onChange, context }) {
2840
3130
  }
2841
3131
  }, 300);
2842
3132
  }, [executeAction, referencedTableId, entries]);
2843
- const [localColumnOrder, setLocalColumnOrder] = useState9(null);
2844
- useEffect7(() => {
3133
+ const [localColumnOrder, setLocalColumnOrder] = useState10(null);
3134
+ useEffect8(() => {
2845
3135
  setLocalColumnOrder(null);
2846
3136
  }, [column.name, (_b = column.config) == null ? void 0 : _b.subTableColumnOrder]);
2847
3137
  const rawTargetColumns = useMemo4(() => {
@@ -2900,8 +3190,8 @@ function SubTableViewer({ rowId, column, value, onChange, context }) {
2900
3190
  return calculateMinColumnWidth(colName, true, col == null ? void 0 : col.type);
2901
3191
  }
2902
3192
  });
2903
- const [relationOptions, setRelationOptions] = useState9({});
2904
- useEffect7(() => {
3193
+ const [relationOptions, setRelationOptions] = useState10({});
3194
+ useEffect8(() => {
2905
3195
  if (!executeAction || !(targetSchema == null ? void 0 : targetSchema.columns) || targetSchema.columns.length === 0) return;
2906
3196
  const relationCols = targetSchema.columns.filter((c) => {
2907
3197
  var _a2, _b2;
@@ -2912,7 +3202,8 @@ function SubTableViewer({ rowId, column, value, onChange, context }) {
2912
3202
  try {
2913
3203
  const options = await executeAction("FETCH_RELATION", {
2914
3204
  referencedTableId: (_a2 = col.config) == null ? void 0 : _a2.referencedTableId,
2915
- displayField: (_b2 = col.config) == null ? void 0 : _b2.displayField
3205
+ displayField: (_b2 = col.config) == null ? void 0 : _b2.displayField,
3206
+ limit: 1e3
2916
3207
  });
2917
3208
  if (options && Array.isArray(options)) {
2918
3209
  setRelationOptions((prev) => __spreadProps(__spreadValues({}, prev), { [col.name]: options }));
@@ -2922,18 +3213,35 @@ function SubTableViewer({ rowId, column, value, onChange, context }) {
2922
3213
  }
2923
3214
  });
2924
3215
  }, [executeAction, targetColumns]);
2925
- const refetchRelation = useCallback8(async (colName) => {
2926
- var _a2, _b2, _c2;
3216
+ const refetchRelation = useCallback8(async (colName, params) => {
3217
+ var _a2, _b2, _c2, _d2, _e2, _f2;
2927
3218
  const col = targetColumns.find((c) => c.name === colName);
2928
- if (!col || ((_a2 = col.type) == null ? void 0 : _a2.toUpperCase()) !== "RELATION" || !((_b2 = col.config) == null ? void 0 : _b2.referencedTableId) || !executeAction) return;
3219
+ if (!col || ((_a2 = col.type) == null ? void 0 : _a2.toUpperCase()) !== "RELATION" || !((_b2 = col.config) == null ? void 0 : _b2.referencedTableId) || !executeAction) return [];
2929
3220
  try {
2930
- const options = await executeAction("FETCH_RELATION", { referencedTableId: col.config.referencedTableId, displayField: (_c2 = col.config) == null ? void 0 : _c2.displayField });
3221
+ const options = await executeAction("FETCH_RELATION", {
3222
+ referencedTableId: col.config.referencedTableId,
3223
+ displayField: (_c2 = col.config) == null ? void 0 : _c2.displayField,
3224
+ limit: (_d2 = params == null ? void 0 : params.limit) != null ? _d2 : 1e3,
3225
+ skip: (_e2 = params == null ? void 0 : params.skip) != null ? _e2 : 0,
3226
+ search: (_f2 = params == null ? void 0 : params.search) != null ? _f2 : ""
3227
+ });
2931
3228
  if (options && Array.isArray(options)) {
2932
- setRelationOptions((prev) => __spreadProps(__spreadValues({}, prev), { [col.name]: options }));
3229
+ if (params == null ? void 0 : params.append) {
3230
+ setRelationOptions((prev) => {
3231
+ const existing = prev[col.name] || [];
3232
+ const existingIds = new Set(existing.map((o) => String(o.id)));
3233
+ const uniqueNew = options.filter((o) => !existingIds.has(String(o.id)));
3234
+ return __spreadProps(__spreadValues({}, prev), { [col.name]: [...existing, ...uniqueNew] });
3235
+ });
3236
+ } else if (!(params == null ? void 0 : params.search)) {
3237
+ setRelationOptions((prev) => __spreadProps(__spreadValues({}, prev), { [col.name]: options }));
3238
+ }
3239
+ return options;
2933
3240
  }
2934
3241
  } catch (err) {
2935
3242
  console.warn(`[SubTableViewer] Could not refetch relation options for column ${col.name}:`, err);
2936
3243
  }
3244
+ return [];
2937
3245
  }, [targetColumns, executeAction]);
2938
3246
  const updateParentLinkage = async (updated) => {
2939
3247
  const isNewRow = rowId.startsWith("temp_");
@@ -3067,7 +3375,7 @@ function SubTableViewer({ rowId, column, value, onChange, context }) {
3067
3375
  updateParentLinkage(updated);
3068
3376
  };
3069
3377
  const isMountedRef = useRef6(true);
3070
- useEffect7(() => {
3378
+ useEffect8(() => {
3071
3379
  isMountedRef.current = true;
3072
3380
  return () => {
3073
3381
  isMountedRef.current = false;
@@ -3602,12 +3910,352 @@ function SubTableViewer({ rowId, column, value, onChange, context }) {
3602
3910
  }
3603
3911
 
3604
3912
  // src/components/TableBlock/TableBlockClient.tsx
3605
- import { X as X7, Copy as Copy2, Search as Search2, RotateCcw } from "lucide-react";
3913
+ import { X as X8, Copy as Copy2, RotateCcw as RotateCcw2, Download, Filter, Loader2 as Loader22 } from "lucide-react";
3914
+
3915
+ // src/components/TableBlock/RelationFilterPopover.tsx
3916
+ import { useState as useState11, useEffect as useEffect9, useRef as useRef7, useMemo as useMemo5, useCallback as useCallback9 } from "react";
3917
+ import { Search as Search2, X as X7, RotateCcw } from "lucide-react";
3606
3918
  import { jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
3919
+ function calculatePopoverCoords(rect) {
3920
+ if (!rect || typeof window === "undefined") return null;
3921
+ const popoverWidth = 260;
3922
+ const popoverHeight = 360;
3923
+ let right = window.innerWidth - rect.right;
3924
+ if (right + popoverWidth > window.innerWidth - 10) {
3925
+ right = window.innerWidth - popoverWidth - 10;
3926
+ }
3927
+ if (right < 10) {
3928
+ right = 10;
3929
+ }
3930
+ const spaceBelow = window.innerHeight - rect.bottom;
3931
+ let top = rect.bottom + 6;
3932
+ if (spaceBelow < popoverHeight && rect.top > popoverHeight) {
3933
+ top = Math.max(10, rect.top - popoverHeight - 6);
3934
+ } else {
3935
+ top = Math.min(window.innerHeight - popoverHeight - 10, top);
3936
+ }
3937
+ return { top, right };
3938
+ }
3939
+ function RelationFilterPopover({
3940
+ isOpen,
3941
+ onClose,
3942
+ column,
3943
+ triggerRect,
3944
+ options,
3945
+ filterValue,
3946
+ selectedValues,
3947
+ onSelectionChange,
3948
+ isLoading = false
3949
+ }) {
3950
+ const popoverRef = useRef7(null);
3951
+ const searchInputRef = useRef7(null);
3952
+ const selectAllRef = useRef7(null);
3953
+ const [searchQuery, setSearchQuery] = useState11("");
3954
+ const [coords, setCoords] = useState11(
3955
+ () => calculatePopoverCoords(triggerRect)
3956
+ );
3957
+ const [mode, setMode] = useState11("include");
3958
+ const [checkedSet, setCheckedSet] = useState11(/* @__PURE__ */ new Set());
3959
+ const [excludedSet, setExcludedSet] = useState11(/* @__PURE__ */ new Set());
3960
+ const prevIsOpenRef = useRef7(isOpen);
3961
+ useEffect9(() => {
3962
+ const justOpened = isOpen && !prevIsOpenRef.current;
3963
+ prevIsOpenRef.current = isOpen;
3964
+ if (justOpened) {
3965
+ const activeVal = filterValue != null ? filterValue : selectedValues;
3966
+ if (activeVal && typeof activeVal === "object" && !Array.isArray(activeVal) && "operator" in activeVal && activeVal.operator === "notIn") {
3967
+ setMode("exclude");
3968
+ setExcludedSet(new Set(activeVal.values || []));
3969
+ setCheckedSet(/* @__PURE__ */ new Set());
3970
+ } else if (Array.isArray(activeVal) && activeVal.length > 0) {
3971
+ setMode("include");
3972
+ setCheckedSet(new Set(activeVal));
3973
+ setExcludedSet(/* @__PURE__ */ new Set());
3974
+ } else {
3975
+ setMode("include");
3976
+ setCheckedSet(/* @__PURE__ */ new Set());
3977
+ setExcludedSet(/* @__PURE__ */ new Set());
3978
+ }
3979
+ }
3980
+ }, [isOpen, filterValue, selectedValues]);
3981
+ const updatePosition = useCallback9(() => {
3982
+ const next = calculatePopoverCoords(triggerRect);
3983
+ if (next) setCoords(next);
3984
+ }, [triggerRect]);
3985
+ useEffect9(() => {
3986
+ if (isOpen) {
3987
+ updatePosition();
3988
+ setTimeout(() => {
3989
+ var _a;
3990
+ return (_a = searchInputRef.current) == null ? void 0 : _a.focus();
3991
+ }, 50);
3992
+ } else {
3993
+ setSearchQuery("");
3994
+ }
3995
+ }, [isOpen, updatePosition]);
3996
+ useEffect9(() => {
3997
+ if (!isOpen) return;
3998
+ const handleScrollOrResize = () => updatePosition();
3999
+ window.addEventListener("scroll", handleScrollOrResize, true);
4000
+ window.addEventListener("resize", handleScrollOrResize);
4001
+ return () => {
4002
+ window.removeEventListener("scroll", handleScrollOrResize, true);
4003
+ window.removeEventListener("resize", handleScrollOrResize);
4004
+ };
4005
+ }, [isOpen, updatePosition]);
4006
+ useEffect9(() => {
4007
+ if (!isOpen) return;
4008
+ const handleMouseDown = (e) => {
4009
+ if (popoverRef.current && !popoverRef.current.contains(e.target)) {
4010
+ onClose();
4011
+ }
4012
+ };
4013
+ document.addEventListener("mousedown", handleMouseDown);
4014
+ return () => {
4015
+ document.removeEventListener("mousedown", handleMouseDown);
4016
+ };
4017
+ }, [isOpen, onClose]);
4018
+ useEffect9(() => {
4019
+ if (!isOpen) return;
4020
+ const handleKeyDown = (e) => {
4021
+ if (e.key === "Escape") {
4022
+ onClose();
4023
+ }
4024
+ };
4025
+ window.addEventListener("keydown", handleKeyDown);
4026
+ return () => {
4027
+ window.removeEventListener("keydown", handleKeyDown);
4028
+ };
4029
+ }, [isOpen, onClose]);
4030
+ const filteredOptions = useMemo5(() => {
4031
+ if (!searchQuery.trim()) return options;
4032
+ const q = searchQuery.trim().toLowerCase();
4033
+ return options.filter((opt) => opt.label.toLowerCase().includes(q));
4034
+ }, [options, searchQuery]);
4035
+ const isOptionChecked = useCallback9(
4036
+ (label) => {
4037
+ if (mode === "exclude") {
4038
+ return !excludedSet.has(label);
4039
+ }
4040
+ return checkedSet.has(label);
4041
+ },
4042
+ [mode, excludedSet, checkedSet]
4043
+ );
4044
+ const allFilteredSelected = useMemo5(() => {
4045
+ if (filteredOptions.length === 0) return false;
4046
+ return filteredOptions.every((opt) => isOptionChecked(opt.label));
4047
+ }, [filteredOptions, isOptionChecked]);
4048
+ const someFilteredSelected = useMemo5(() => {
4049
+ return filteredOptions.some((opt) => isOptionChecked(opt.label));
4050
+ }, [filteredOptions, isOptionChecked]);
4051
+ useEffect9(() => {
4052
+ if (selectAllRef.current) {
4053
+ selectAllRef.current.indeterminate = !allFilteredSelected && someFilteredSelected;
4054
+ }
4055
+ }, [allFilteredSelected, someFilteredSelected]);
4056
+ const handleToggleOption = (label) => {
4057
+ if (mode === "exclude") {
4058
+ const nextExcluded = new Set(excludedSet);
4059
+ if (nextExcluded.has(label)) {
4060
+ nextExcluded.delete(label);
4061
+ } else {
4062
+ nextExcluded.add(label);
4063
+ }
4064
+ setExcludedSet(nextExcluded);
4065
+ if (nextExcluded.size === 0) {
4066
+ onSelectionChange(void 0);
4067
+ } else {
4068
+ onSelectionChange({ operator: "notIn", values: Array.from(nextExcluded) });
4069
+ }
4070
+ } else {
4071
+ const nextChecked = new Set(checkedSet);
4072
+ if (nextChecked.has(label)) {
4073
+ nextChecked.delete(label);
4074
+ } else {
4075
+ nextChecked.add(label);
4076
+ }
4077
+ setCheckedSet(nextChecked);
4078
+ if (nextChecked.size === 0) {
4079
+ onSelectionChange(void 0);
4080
+ } else if (options.length > 0 && nextChecked.size >= options.length) {
4081
+ setMode("exclude");
4082
+ setExcludedSet(/* @__PURE__ */ new Set());
4083
+ onSelectionChange(void 0);
4084
+ } else {
4085
+ onSelectionChange(Array.from(nextChecked));
4086
+ }
4087
+ }
4088
+ };
4089
+ const handleToggleSelectAll = (checked) => {
4090
+ if (checked) {
4091
+ setMode("exclude");
4092
+ setExcludedSet(/* @__PURE__ */ new Set());
4093
+ setCheckedSet(/* @__PURE__ */ new Set());
4094
+ onSelectionChange(void 0);
4095
+ } else {
4096
+ setMode("include");
4097
+ setCheckedSet(/* @__PURE__ */ new Set());
4098
+ setExcludedSet(/* @__PURE__ */ new Set());
4099
+ onSelectionChange(void 0);
4100
+ }
4101
+ };
4102
+ const handleResetFilter = () => {
4103
+ setMode("include");
4104
+ setCheckedSet(/* @__PURE__ */ new Set());
4105
+ setExcludedSet(/* @__PURE__ */ new Set());
4106
+ setSearchQuery("");
4107
+ onSelectionChange(void 0);
4108
+ };
4109
+ if (!isOpen || !coords) return null;
4110
+ const selectedCount = useMemo5(() => {
4111
+ if (mode === "exclude") {
4112
+ return Math.max(0, options.length - excludedSet.size);
4113
+ }
4114
+ return checkedSet.size;
4115
+ }, [mode, options.length, excludedSet.size, checkedSet.size]);
4116
+ return /* @__PURE__ */ jsxs10(
4117
+ "div",
4118
+ {
4119
+ ref: popoverRef,
4120
+ dir: "rtl",
4121
+ style: {
4122
+ top: `${coords.top}px`,
4123
+ right: `${coords.right}px`
4124
+ },
4125
+ className: "fixed z-[99999] w-[260px] bg-white rounded-xl shadow-2xl border border-slate-200 p-2.5 text-right select-none animate-in fade-in duration-100",
4126
+ onClick: (e) => e.stopPropagation(),
4127
+ onMouseDown: (e) => e.stopPropagation(),
4128
+ children: [
4129
+ /* @__PURE__ */ jsxs10("div", { className: "flex items-center justify-between border-b border-slate-100 pb-2 mb-2", children: [
4130
+ /* @__PURE__ */ jsxs10("div", { className: "flex items-center gap-1.5 min-w-0", children: [
4131
+ /* @__PURE__ */ jsxs10("span", { className: "text-xs font-bold text-slate-700 truncate", children: [
4132
+ "\u05E1\u05D9\u05E0\u05D5\u05DF \u05DC\u05E4\u05D9 ",
4133
+ column.name
4134
+ ] }),
4135
+ mode === "exclude" && excludedSet.size > 0 ? /* @__PURE__ */ jsxs10("span", { className: "text-[10px] text-amber-600 font-semibold", children: [
4136
+ "(\u05D4\u05DB\u05DC \u05DC\u05DE\u05E2\u05D8 ",
4137
+ excludedSet.size,
4138
+ ")"
4139
+ ] }) : mode === "exclude" && excludedSet.size === 0 ? /* @__PURE__ */ jsx10("span", { className: "text-[10px] text-brand font-semibold", children: "(\u05D4\u05DB\u05DC \u05E0\u05D1\u05D7\u05E8)" }) : selectedCount > 0 ? /* @__PURE__ */ jsxs10("span", { className: "text-[10px] text-brand font-semibold", children: [
4140
+ "(",
4141
+ selectedCount,
4142
+ " \u05E0\u05D1\u05D7\u05E8\u05D5)"
4143
+ ] }) : null
4144
+ ] }),
4145
+ /* @__PURE__ */ jsx10(
4146
+ "button",
4147
+ {
4148
+ type: "button",
4149
+ onClick: onClose,
4150
+ className: "text-slate-400 hover:text-slate-600 p-0.5 rounded hover:bg-slate-100 transition-colors cursor-pointer",
4151
+ title: "\u05E1\u05D2\u05D5\u05E8",
4152
+ children: /* @__PURE__ */ jsx10(X7, { className: "w-3.5 h-3.5" })
4153
+ }
4154
+ )
4155
+ ] }),
4156
+ /* @__PURE__ */ jsxs10("div", { className: "relative mb-2", children: [
4157
+ /* @__PURE__ */ jsx10(Search2, { className: "w-3.5 h-3.5 text-slate-400 absolute right-2.5 top-1/2 -translate-y-1/2 pointer-events-none" }),
4158
+ /* @__PURE__ */ jsx10(
4159
+ "input",
4160
+ {
4161
+ ref: searchInputRef,
4162
+ type: "text",
4163
+ placeholder: "\u05D7\u05D9\u05E4\u05D5\u05E9 \u05D0\u05E4\u05E9\u05E8\u05D5\u05D9\u05D5\u05EA...",
4164
+ value: searchQuery,
4165
+ onChange: (e) => setSearchQuery(e.target.value),
4166
+ className: "h-7 text-xs pr-7 pl-6 w-full rounded-md border border-slate-200 bg-slate-50 focus:bg-white focus:border-brand focus:ring-1 focus:ring-brand text-slate-800 transition-all placeholder:text-slate-400"
4167
+ }
4168
+ ),
4169
+ searchQuery && /* @__PURE__ */ jsx10(
4170
+ "button",
4171
+ {
4172
+ type: "button",
4173
+ onClick: () => setSearchQuery(""),
4174
+ className: "absolute left-1.5 top-1/2 -translate-y-1/2 p-0.5 text-slate-400 hover:text-slate-600 rounded",
4175
+ children: /* @__PURE__ */ jsx10(X7, { className: "w-3 h-3" })
4176
+ }
4177
+ )
4178
+ ] }),
4179
+ /* @__PURE__ */ jsxs10("div", { className: "flex items-center justify-between px-1.5 py-1 mb-1 rounded hover:bg-slate-50 transition-colors border-b border-slate-100 pb-1.5", children: [
4180
+ /* @__PURE__ */ jsxs10("label", { className: "flex items-center gap-2 cursor-pointer text-xs font-medium text-slate-700 flex-1", children: [
4181
+ /* @__PURE__ */ jsx10(
4182
+ "input",
4183
+ {
4184
+ ref: selectAllRef,
4185
+ type: "checkbox",
4186
+ checked: allFilteredSelected,
4187
+ onChange: (e) => handleToggleSelectAll(e.target.checked),
4188
+ className: "w-3.5 h-3.5 rounded border-slate-300 text-brand focus:ring-brand cursor-pointer accent-[#0d9488]"
4189
+ }
4190
+ ),
4191
+ /* @__PURE__ */ jsx10("span", { children: "\u05D1\u05D7\u05E8 \u05D4\u05DB\u05DC" })
4192
+ ] }),
4193
+ (mode === "exclude" || checkedSet.size > 0) && /* @__PURE__ */ jsxs10(
4194
+ "button",
4195
+ {
4196
+ type: "button",
4197
+ onClick: handleResetFilter,
4198
+ className: "text-[11px] text-blue-600 hover:text-blue-700 hover:underline flex items-center gap-1 cursor-pointer",
4199
+ title: "\u05E0\u05E7\u05D4 \u05E1\u05D9\u05E0\u05D5\u05DF \u05D5\u05D4\u05E6\u05D2 \u05D4\u05DB\u05DC",
4200
+ children: [
4201
+ /* @__PURE__ */ jsx10(RotateCcw, { className: "w-2.5 h-2.5" }),
4202
+ /* @__PURE__ */ jsx10("span", { children: "\u05E0\u05E7\u05D4" })
4203
+ ]
4204
+ }
4205
+ )
4206
+ ] }),
4207
+ /* @__PURE__ */ jsx10("div", { className: "max-h-[250px] overflow-y-auto space-y-0.5 custom-scrollbar pr-0.5", children: isLoading ? /* @__PURE__ */ jsxs10("div", { className: "flex items-center justify-center py-6 text-slate-400 text-xs", children: [
4208
+ /* @__PURE__ */ jsx10("div", { className: "w-4 h-4 border-2 border-brand border-t-transparent rounded-full animate-spin ml-2" }),
4209
+ /* @__PURE__ */ jsx10("span", { children: "\u05D8\u05D5\u05E2\u05DF \u05D0\u05E4\u05E9\u05E8\u05D5\u05D9\u05D5\u05EA..." })
4210
+ ] }) : filteredOptions.length === 0 ? /* @__PURE__ */ jsx10("div", { className: "py-6 text-center text-xs text-slate-400", children: "\u05DC\u05D0 \u05E0\u05DE\u05E6\u05D0\u05D5 \u05D0\u05E4\u05E9\u05E8\u05D5\u05D9\u05D5\u05EA" }) : filteredOptions.map((opt) => {
4211
+ const isChecked = isOptionChecked(opt.label);
4212
+ return /* @__PURE__ */ jsxs10(
4213
+ "label",
4214
+ {
4215
+ className: `flex items-center gap-2 px-2 py-1 rounded cursor-pointer transition-colors text-xs ${isChecked ? "text-slate-800 font-medium bg-slate-50/60" : "text-slate-500 hover:bg-slate-50"}`,
4216
+ children: [
4217
+ /* @__PURE__ */ jsx10(
4218
+ "input",
4219
+ {
4220
+ type: "checkbox",
4221
+ checked: isChecked,
4222
+ onChange: () => handleToggleOption(opt.label),
4223
+ className: "w-3.5 h-3.5 rounded border-slate-300 text-brand focus:ring-brand cursor-pointer accent-[#0d9488]"
4224
+ }
4225
+ ),
4226
+ /* @__PURE__ */ jsx10("span", { className: "truncate flex-1", title: opt.label, children: opt.label })
4227
+ ]
4228
+ },
4229
+ opt.id
4230
+ );
4231
+ }) }),
4232
+ /* @__PURE__ */ jsxs10("div", { className: "border-t border-slate-100 pt-1.5 mt-1 flex items-center justify-between text-[11px] text-slate-400 px-1", children: [
4233
+ /* @__PURE__ */ jsxs10("span", { children: [
4234
+ filteredOptions.length,
4235
+ " \u05EA\u05D5\u05E6\u05D0\u05D5\u05EA"
4236
+ ] }),
4237
+ /* @__PURE__ */ jsx10(
4238
+ "button",
4239
+ {
4240
+ type: "button",
4241
+ onClick: onClose,
4242
+ className: "text-slate-600 hover:text-slate-900 font-medium px-2 py-0.5 rounded hover:bg-slate-100 transition-colors cursor-pointer",
4243
+ children: "\u05E1\u05D2\u05D5\u05E8"
4244
+ }
4245
+ )
4246
+ ] })
4247
+ ]
4248
+ }
4249
+ );
4250
+ }
4251
+
4252
+ // src/components/TableBlock/TableBlockClient.tsx
4253
+ import { jsx as jsx11, jsxs as jsxs11 } from "react/jsx-runtime";
3607
4254
  function TableBlockClient({
3608
4255
  data: initialRecords,
3609
4256
  settings: schema,
3610
4257
  executeAction,
4258
+ exportAction,
3611
4259
  emitEvent,
3612
4260
  pageState,
3613
4261
  isLoading,
@@ -3620,6 +4268,7 @@ function TableBlockClient({
3620
4268
  "data-testid": dataTestId
3621
4269
  }) {
3622
4270
  const { showError, addToast } = useToast();
4271
+ const [isExporting, setIsExporting] = useState12(false);
3623
4272
  const tableKey = (schema == null ? void 0 : schema.tableMetaId) || (schema == null ? void 0 : schema.tableId) || (schema == null ? void 0 : schema.id) || (schema == null ? void 0 : schema.name) || "default";
3624
4273
  const { columnWidths, startResize } = useColumnResize({
3625
4274
  storageKey: `table_widths_${tableKey}`,
@@ -3630,14 +4279,14 @@ function TableBlockClient({
3630
4279
  return calculateMinColumnWidth(colName, false, col == null ? void 0 : col.type);
3631
4280
  }
3632
4281
  });
3633
- const [isMounted, setIsMounted] = useState10(false);
3634
- const [isInitialLoading, setIsInitialLoading] = useState10(true);
3635
- const [page, setPage] = useState10(1);
3636
- const [limit, setLimit] = useState10(50);
3637
- const [totalRecords, setTotalRecords] = useState10(0);
3638
- const [totalPages, setTotalPages] = useState10(1);
3639
- const [showSummary, setShowSummary] = useState10(false);
3640
- useEffect8(() => {
4282
+ const [isMounted, setIsMounted] = useState12(false);
4283
+ const [isInitialLoading, setIsInitialLoading] = useState12(true);
4284
+ const [page, setPage] = useState12(1);
4285
+ const [limit, setLimit] = useState12(50);
4286
+ const [totalRecords, setTotalRecords] = useState12(0);
4287
+ const [totalPages, setTotalPages] = useState12(1);
4288
+ const [showSummary, setShowSummary] = useState12(false);
4289
+ useEffect10(() => {
3641
4290
  if (typeof window !== "undefined") {
3642
4291
  const savedSummary = localStorage.getItem(`table_summary_${tableKey}`);
3643
4292
  if (savedSummary !== null) {
@@ -3686,7 +4335,7 @@ function TableBlockClient({
3686
4335
  return __spreadProps(__spreadValues({}, row), { id: String(row.id || ""), data: rowData });
3687
4336
  });
3688
4337
  };
3689
- const mergeColumnDefs = useCallback9((existingCols, incomingCols) => {
4338
+ const mergeColumnDefs = useCallback10((existingCols, incomingCols) => {
3690
4339
  if (!incomingCols || incomingCols.length === 0) return existingCols || [];
3691
4340
  if (!existingCols || existingCols.length === 0) return incomingCols;
3692
4341
  const existingMap = new Map(existingCols.map((c) => [c.name, c]));
@@ -3706,18 +4355,18 @@ function TableBlockClient({
3706
4355
  return ((_a = a.order) != null ? _a : 0) - ((_b = b.order) != null ? _b : 0);
3707
4356
  });
3708
4357
  }, []);
3709
- const [localColumns, setLocalColumns] = useState10(() => (schema == null ? void 0 : schema.columns) || []);
3710
- useEffect8(() => {
4358
+ const [localColumns, setLocalColumns] = useState12(() => (schema == null ? void 0 : schema.columns) || []);
4359
+ useEffect10(() => {
3711
4360
  if ((schema == null ? void 0 : schema.columns) && schema.columns.length > 0) {
3712
4361
  setLocalColumns((prev) => mergeColumnDefs(prev, schema.columns));
3713
4362
  }
3714
4363
  }, [schema == null ? void 0 : schema.columns, mergeColumnDefs]);
3715
- const [dirty, setDirty] = useState10({ added: [], modified: {}, deleted: [] });
3716
- const dirtyRef = useRef7(dirty);
3717
- useEffect8(() => {
4364
+ const [dirty, setDirty] = useState12({ added: [], modified: {}, deleted: [] });
4365
+ const dirtyRef = useRef8(dirty);
4366
+ useEffect10(() => {
3718
4367
  dirtyRef.current = dirty;
3719
4368
  }, [dirty]);
3720
- const mergeWithDirty = useCallback9((baseRecords) => {
4369
+ const mergeWithDirty = useCallback10((baseRecords) => {
3721
4370
  const { added, modified, deleted } = dirtyRef.current;
3722
4371
  const nonDeleted = (baseRecords || []).filter((r) => !deleted.includes(r.id));
3723
4372
  const modifiedRecords = nonDeleted.map((r) => {
@@ -3730,9 +4379,9 @@ function TableBlockClient({
3730
4379
  const uniqueAdded = added.filter((r) => !baseIds.has(r.id));
3731
4380
  return [...uniqueAdded, ...modifiedRecords];
3732
4381
  }, []);
3733
- const [data, setData] = useState10(() => normalizeRecords(initialRecords));
3734
- const [serverRecords, setServerRecords] = useState10(() => normalizeRecords(initialRecords));
3735
- useEffect8(() => {
4382
+ const [data, setData] = useState12(() => normalizeRecords(initialRecords));
4383
+ const [serverRecords, setServerRecords] = useState12(() => normalizeRecords(initialRecords));
4384
+ useEffect10(() => {
3736
4385
  if (initialRecords) {
3737
4386
  const norm = normalizeRecords(initialRecords);
3738
4387
  setServerRecords(norm);
@@ -3749,25 +4398,109 @@ function TableBlockClient({
3749
4398
  }
3750
4399
  return false;
3751
4400
  };
3752
- const [baseRecordsMap, setBaseRecordsMap] = useState10(() => {
4401
+ const [baseRecordsMap, setBaseRecordsMap] = useState12(() => {
3753
4402
  const map = /* @__PURE__ */ new Map();
3754
4403
  (normalizeRecords(initialRecords) || []).forEach((r) => map.set(r.id, __spreadValues({}, r.data)));
3755
4404
  return map;
3756
4405
  });
3757
- useEffect8(() => {
4406
+ useEffect10(() => {
3758
4407
  if (initialRecords && initialRecords.length > 0) {
3759
4408
  const map = /* @__PURE__ */ new Map();
3760
4409
  (normalizeRecords(initialRecords) || []).forEach((r) => map.set(r.id, __spreadValues({}, r.data)));
3761
4410
  setBaseRecordsMap(map);
3762
4411
  }
3763
4412
  }, [initialRecords]);
3764
- const refetchTableData = useCallback9((targetPage) => {
4413
+ const [searchQuery, setSearchQuery] = useState12("");
4414
+ const [columnFilters, setColumnFilters] = useState12({});
4415
+ const [activeSearchCol, setActiveSearchCol] = useState12(null);
4416
+ const activeSearchRef = useRef8(null);
4417
+ const [activeRelationCol, setActiveRelationCol] = useState12(null);
4418
+ const [relationTriggerRect, setRelationTriggerRect] = useState12(null);
4419
+ const filterButtonRefs = useRef8({});
4420
+ const [relationOptions, setRelationOptions] = useState12({});
4421
+ const relationDictionaryRef = useRef8({});
4422
+ const mergeRelationOptions = useCallback10((colName, newOptions) => {
4423
+ if (!Array.isArray(newOptions) || newOptions.length === 0) return;
4424
+ if (!relationDictionaryRef.current[colName]) {
4425
+ relationDictionaryRef.current[colName] = /* @__PURE__ */ new Map();
4426
+ }
4427
+ const dict = relationDictionaryRef.current[colName];
4428
+ let hasNew = false;
4429
+ for (const opt of newOptions) {
4430
+ if (!opt) continue;
4431
+ const id = String(opt.id || opt._id || "");
4432
+ if (!id) continue;
4433
+ const existing = dict.get(id);
4434
+ if (!existing || opt.label && !existing.label) {
4435
+ dict.set(id, opt);
4436
+ hasNew = true;
4437
+ }
4438
+ }
4439
+ if (hasNew) {
4440
+ setRelationOptions((prev) => __spreadProps(__spreadValues({}, prev), {
4441
+ [colName]: Array.from(dict.values())
4442
+ }));
4443
+ }
4444
+ }, []);
4445
+ useEffect10(() => {
4446
+ if (!activeSearchCol) return;
4447
+ const handleMouseDown = (e) => {
4448
+ if (activeSearchRef.current && !activeSearchRef.current.contains(e.target)) {
4449
+ setActiveSearchCol(null);
4450
+ }
4451
+ };
4452
+ document.addEventListener("mousedown", handleMouseDown);
4453
+ return () => {
4454
+ document.removeEventListener("mousedown", handleMouseDown);
4455
+ };
4456
+ }, [activeSearchCol]);
4457
+ const filtersKey = useMemo6(() => {
4458
+ const active = {};
4459
+ Object.entries(columnFilters).forEach(([k, v]) => {
4460
+ if (Array.isArray(v) && v.length > 0) active[k] = v;
4461
+ else if (v && typeof v === "object" && "operator" in v && Array.isArray(v.values) && v.values.length > 0) active[k] = v;
4462
+ else if (typeof v === "string" && v.trim()) active[k] = v.trim();
4463
+ });
4464
+ return JSON.stringify(active);
4465
+ }, [columnFilters]);
4466
+ const [debouncedSearch, setDebouncedSearch] = useState12(searchQuery);
4467
+ useEffect10(() => {
4468
+ const timer = setTimeout(() => {
4469
+ setDebouncedSearch(searchQuery.trim());
4470
+ }, 300);
4471
+ return () => clearTimeout(timer);
4472
+ }, [searchQuery]);
4473
+ const isSearchMountedRef = useRef8(false);
4474
+ useEffect10(() => {
4475
+ if (!isSearchMountedRef.current) {
4476
+ isSearchMountedRef.current = true;
4477
+ return;
4478
+ }
4479
+ setPage(1);
4480
+ }, [debouncedSearch]);
4481
+ const [isFetching, setIsFetching] = useState12(false);
4482
+ const fetchRequestIdRef = useRef8(0);
4483
+ const fetchTableData = useCallback10((targetPage, targetLimit, targetSearch, targetFiltersKey) => {
3765
4484
  const tableId = (schema == null ? void 0 : schema.tableMetaId) || (schema == null ? void 0 : schema.tableId) || (schema == null ? void 0 : schema.id);
3766
4485
  if (!tableId || !executeAction) return Promise.resolve();
3767
- const activePage = targetPage !== void 0 ? targetPage : page;
3768
- const skip = (activePage - 1) * limit;
3769
- return executeAction("FETCH_TABLE_DATA", { tableId, page: activePage, limit, skip }).then((res) => {
4486
+ const currentRequestId = ++fetchRequestIdRef.current;
4487
+ setIsFetching(true);
4488
+ let activeFilters = {};
4489
+ try {
4490
+ activeFilters = JSON.parse(targetFiltersKey);
4491
+ } catch (e) {
4492
+ }
4493
+ const skip = (targetPage - 1) * targetLimit;
4494
+ return executeAction("FETCH_TABLE_DATA", {
4495
+ tableId,
4496
+ page: targetPage,
4497
+ limit: targetLimit,
4498
+ skip,
4499
+ search: targetSearch || void 0,
4500
+ columnFilters: Object.keys(activeFilters).length > 0 ? activeFilters : void 0
4501
+ }).then((res) => {
3770
4502
  var _a;
4503
+ if (currentRequestId !== fetchRequestIdRef.current) return;
3771
4504
  if (res) {
3772
4505
  if (((_a = res.schema) == null ? void 0 : _a.columns) && res.schema.columns.length > 0) {
3773
4506
  setLocalColumns((prev) => mergeColumnDefs(prev, res.schema.columns));
@@ -3782,37 +4515,50 @@ function TableBlockClient({
3782
4515
  }
3783
4516
  if (res.meta) {
3784
4517
  const total = typeof res.meta.totalRecords === "number" ? res.meta.totalRecords : 0;
3785
- const pages = typeof res.meta.totalPages === "number" ? res.meta.totalPages : Math.ceil(total / limit) || 1;
4518
+ const pages = typeof res.meta.totalPages === "number" ? res.meta.totalPages : Math.ceil(total / targetLimit) || 1;
3786
4519
  setTotalRecords(total);
3787
4520
  setTotalPages(pages);
3788
- if (activePage > pages && pages >= 1) {
3789
- setPage(pages);
3790
- }
3791
4521
  } else if (res.records && Array.isArray(res.records)) {
3792
4522
  setTotalRecords(res.records.length);
3793
- setTotalPages(Math.ceil(res.records.length / limit) || 1);
4523
+ setTotalPages(Math.ceil(res.records.length / targetLimit) || 1);
4524
+ }
4525
+ if (res.relationOptions && typeof res.relationOptions === "object") {
4526
+ for (const [colName, opts] of Object.entries(res.relationOptions)) {
4527
+ if (Array.isArray(opts)) {
4528
+ mergeRelationOptions(colName, opts);
4529
+ }
4530
+ }
3794
4531
  }
3795
4532
  }
3796
4533
  }).catch((err) => {
3797
- console.error("[TableBlock] Failed to auto-fetch table data:", err);
4534
+ if (currentRequestId === fetchRequestIdRef.current) {
4535
+ console.error("[TableBlock] Failed to fetch table data:", err);
4536
+ }
4537
+ }).finally(() => {
4538
+ if (currentRequestId === fetchRequestIdRef.current) {
4539
+ setIsFetching(false);
4540
+ setIsInitialLoading(false);
4541
+ }
3798
4542
  });
3799
- }, [schema == null ? void 0 : schema.tableMetaId, schema == null ? void 0 : schema.tableId, schema == null ? void 0 : schema.id, page, limit, executeAction, mergeColumnDefs, mergeWithDirty]);
3800
- useEffect8(() => {
3801
- let isMounted2 = true;
3802
- const fetchPromise = refetchTableData();
3803
- if (fetchPromise && typeof fetchPromise.finally === "function") {
3804
- fetchPromise.finally(() => {
3805
- if (isMounted2) {
3806
- setIsInitialLoading(false);
3807
- }
3808
- });
3809
- } else {
3810
- setIsInitialLoading(false);
3811
- }
3812
- return () => {
3813
- isMounted2 = false;
3814
- };
3815
- }, [refetchTableData]);
4543
+ }, [schema == null ? void 0 : schema.tableMetaId, schema == null ? void 0 : schema.tableId, schema == null ? void 0 : schema.id, executeAction, mergeColumnDefs, mergeWithDirty, mergeRelationOptions]);
4544
+ useEffect10(() => {
4545
+ fetchTableData(page, limit, debouncedSearch, filtersKey);
4546
+ }, [page, limit, debouncedSearch, filtersKey, fetchTableData]);
4547
+ const refetchTableData = useCallback10(() => {
4548
+ return fetchTableData(page, limit, debouncedSearch, filtersKey);
4549
+ }, [page, limit, debouncedSearch, filtersKey, fetchTableData]);
4550
+ const handleApplyColumnFilter = useCallback10((colName, nextVal) => {
4551
+ setColumnFilters((prev) => {
4552
+ const next = __spreadValues({}, prev);
4553
+ if (nextVal === void 0 || Array.isArray(nextVal) && nextVal.length === 0 || typeof nextVal === "string" && !nextVal.trim() || typeof nextVal === "object" && "values" in nextVal && Array.isArray(nextVal.values) && nextVal.values.length === 0) {
4554
+ delete next[colName];
4555
+ } else {
4556
+ next[colName] = nextVal;
4557
+ }
4558
+ return next;
4559
+ });
4560
+ setPage(1);
4561
+ }, []);
3816
4562
  const handleLimitChange = (newLimit) => {
3817
4563
  setLimit(newLimit);
3818
4564
  setPage(1);
@@ -3826,37 +4572,15 @@ function TableBlockClient({
3826
4572
  const handleNextPage = () => {
3827
4573
  setPage((prev) => Math.min(totalPages, prev + 1));
3828
4574
  };
3829
- useEffect8(() => {
3830
- if (error) {
3831
- showError(error, "\u05E9\u05D2\u05D9\u05D0\u05D4 \u05D1\u05E8\u05DB\u05D9\u05D1");
3832
- }
3833
- }, [error, showError]);
3834
- const [searchQuery, setSearchQuery] = useState10("");
3835
- const [columnFilters, setColumnFilters] = useState10({});
3836
- const [activeSearchCol, setActiveSearchCol] = useState10(null);
3837
- const activeSearchRef = useRef7(null);
3838
- useEffect8(() => {
3839
- if (!activeSearchCol) return;
3840
- const handleMouseDown = (e) => {
3841
- if (activeSearchRef.current && !activeSearchRef.current.contains(e.target)) {
3842
- setActiveSearchCol(null);
3843
- }
3844
- };
3845
- document.addEventListener("mousedown", handleMouseDown);
3846
- return () => {
3847
- document.removeEventListener("mousedown", handleMouseDown);
3848
- };
3849
- }, [activeSearchCol]);
3850
- const [selectedIds, setSelectedIds] = useState10(/* @__PURE__ */ new Set());
3851
- const [pendingDeletions, setPendingDeletions] = useState10([]);
3852
- const [isSaving, setIsSaving] = useState10(false);
4575
+ const [selectedIds, setSelectedIds] = useState12(/* @__PURE__ */ new Set());
4576
+ const [pendingDeletions, setPendingDeletions] = useState12([]);
4577
+ const [isSaving, setIsSaving] = useState12(false);
3853
4578
  const isUpdatingActive = Boolean(isUpdating || isSaving);
3854
- const [isSaveSuccess, setIsSaveSuccess] = useState10(false);
3855
- const [relationOptions, setRelationOptions] = useState10({});
3856
- const [expandedRowIds, setExpandedRowIds] = useState10(/* @__PURE__ */ new Set());
3857
- const schemaColsString = useMemo5(() => JSON.stringify(localColumns || []), [localColumns]);
3858
- const refetchRelation = useCallback9(async (colName) => {
3859
- var _a, _b, _c;
4579
+ const [isSaveSuccess, setIsSaveSuccess] = useState12(false);
4580
+ const [expandedRowIds, setExpandedRowIds] = useState12(/* @__PURE__ */ new Set());
4581
+ const schemaColsString = useMemo6(() => JSON.stringify(localColumns || []), [localColumns]);
4582
+ const refetchRelation = useCallback10(async (colName, params) => {
4583
+ var _a, _b, _c, _d, _e, _f, _g;
3860
4584
  let parsedCols = [];
3861
4585
  try {
3862
4586
  parsedCols = JSON.parse(schemaColsString);
@@ -3866,19 +4590,89 @@ function TableBlockClient({
3866
4590
  var _a2;
3867
4591
  return c.name === colName && ((_a2 = c.type) == null ? void 0 : _a2.toUpperCase()) === "RELATION";
3868
4592
  });
3869
- if (!col || !((_a = col.config) == null ? void 0 : _a.referencedTableId)) return;
4593
+ if (!col || !((_a = col.config) == null ? void 0 : _a.referencedTableId)) return [];
3870
4594
  try {
3871
4595
  if (executeAction) {
3872
- const options = await executeAction("FETCH_RELATION", { referencedTableId: (_b = col.config) == null ? void 0 : _b.referencedTableId, displayField: (_c = col.config) == null ? void 0 : _c.displayField });
3873
- if (options && Array.isArray(options)) {
3874
- setRelationOptions((prev) => __spreadProps(__spreadValues({}, prev), { [colName]: options }));
4596
+ const take = (_c = (_b = params == null ? void 0 : params.take) != null ? _b : params == null ? void 0 : params.limit) != null ? _c : 1e3;
4597
+ const payload = {
4598
+ referencedTableId: (_d = col.config) == null ? void 0 : _d.referencedTableId,
4599
+ displayField: (_e = col.config) == null ? void 0 : _e.displayField
4600
+ };
4601
+ if (params == null ? void 0 : params.recordIds) {
4602
+ payload.recordIds = params.recordIds;
4603
+ } else {
4604
+ payload.take = take;
4605
+ payload.limit = take;
4606
+ payload.skip = (_f = params == null ? void 0 : params.skip) != null ? _f : 0;
4607
+ payload.search = (_g = params == null ? void 0 : params.search) != null ? _g : "";
4608
+ }
4609
+ const options = await executeAction("FETCH_RELATION", payload);
4610
+ const list = Array.isArray(options) ? options : (options == null ? void 0 : options.data) && Array.isArray(options.data) ? options.data : [];
4611
+ if (list && Array.isArray(list)) {
4612
+ mergeRelationOptions(colName, list);
4613
+ return list;
3875
4614
  }
3876
4615
  }
3877
4616
  } catch (err) {
3878
4617
  console.warn(`[TableBlock] Could not fetch relation options for column ${colName}:`, err);
3879
4618
  }
3880
- }, [schemaColsString, executeAction]);
3881
- useEffect8(() => {
4619
+ return [];
4620
+ }, [schemaColsString, executeAction, mergeRelationOptions]);
4621
+ const requestedRelationIdsRef = useRef8({});
4622
+ useEffect10(() => {
4623
+ if (!executeAction || !data || data.length === 0) return;
4624
+ let parsedCols = [];
4625
+ try {
4626
+ parsedCols = JSON.parse(schemaColsString);
4627
+ } catch (e) {
4628
+ }
4629
+ const relationCols = parsedCols.filter(
4630
+ (c) => {
4631
+ var _a;
4632
+ return ((_a = c.type) == null ? void 0 : _a.toUpperCase()) === "RELATION";
4633
+ }
4634
+ );
4635
+ if (relationCols.length === 0) return;
4636
+ relationCols.forEach(async (col) => {
4637
+ var _a, _b;
4638
+ const referencedTableId = (_a = col.config) == null ? void 0 : _a.referencedTableId;
4639
+ if (!referencedTableId) return;
4640
+ const extractedIds = /* @__PURE__ */ new Set();
4641
+ data.forEach((row) => {
4642
+ if (!(row == null ? void 0 : row.data)) return;
4643
+ const ids = normalizeRelationValue(row.data[col.name]);
4644
+ ids.forEach((id) => {
4645
+ if (/^[0-9a-fA-F]{24}$/.test(id)) {
4646
+ extractedIds.add(id);
4647
+ }
4648
+ });
4649
+ });
4650
+ if (extractedIds.size === 0) return;
4651
+ const existingOptions = relationOptions[col.name] || [];
4652
+ const existingIds = new Set(existingOptions.map((o) => String(o.id)));
4653
+ if (!requestedRelationIdsRef.current[col.name]) {
4654
+ requestedRelationIdsRef.current[col.name] = /* @__PURE__ */ new Set();
4655
+ }
4656
+ const inFlight = requestedRelationIdsRef.current[col.name];
4657
+ const missingIds = Array.from(extractedIds).filter((id) => !existingIds.has(id) && !inFlight.has(id));
4658
+ if (missingIds.length === 0) return;
4659
+ missingIds.forEach((id) => inFlight.add(id));
4660
+ try {
4661
+ const resolved = await executeAction("FETCH_RELATION", {
4662
+ referencedTableId,
4663
+ displayField: (_b = col.config) == null ? void 0 : _b.displayField,
4664
+ recordIds: missingIds
4665
+ });
4666
+ const items = Array.isArray(resolved) ? resolved : (resolved == null ? void 0 : resolved.data) && Array.isArray(resolved.data) ? resolved.data : [];
4667
+ if (items.length > 0) {
4668
+ mergeRelationOptions(col.name, items);
4669
+ }
4670
+ } catch (err) {
4671
+ console.warn(`[TableBlock] Failed to populate relations for ${col.name}:`, err);
4672
+ }
4673
+ });
4674
+ }, [data, schemaColsString, executeAction, relationOptions, mergeRelationOptions]);
4675
+ useEffect10(() => {
3882
4676
  let parsedCols = [];
3883
4677
  try {
3884
4678
  parsedCols = JSON.parse(schemaColsString);
@@ -3892,7 +4686,7 @@ function TableBlockClient({
3892
4686
  refetchRelation(col.name);
3893
4687
  });
3894
4688
  }, [schemaColsString, refetchRelation]);
3895
- const normalizedColumns = useMemo5(() => {
4689
+ const normalizedColumns = useMemo6(() => {
3896
4690
  return (localColumns || []).map((col, idx) => {
3897
4691
  const isRequired = col.isRequired === true || String(col.isRequired) === "true";
3898
4692
  const isUnique = col.isUnique === true || String(col.isUnique) === "true";
@@ -3906,17 +4700,17 @@ function TableBlockClient({
3906
4700
  return ((_a = a.order) != null ? _a : 0) - ((_b = b.order) != null ? _b : 0);
3907
4701
  });
3908
4702
  }, [localColumns]);
3909
- const filteredColumns = useMemo5(() => {
4703
+ const filteredColumns = useMemo6(() => {
3910
4704
  const systemFields = ["_id", "createdAt", "updatedAt", "orgId", "tableId"];
3911
4705
  return normalizedColumns.filter((col) => !systemFields.includes(col.name) && !col.isHidden);
3912
4706
  }, [normalizedColumns]);
3913
- const customizableColumns = useMemo5(() => {
4707
+ const customizableColumns = useMemo6(() => {
3914
4708
  const systemFields = ["_id", "createdAt", "updatedAt", "orgId", "tableId"];
3915
4709
  return normalizedColumns.filter((col) => !systemFields.includes(col.name));
3916
4710
  }, [normalizedColumns]);
3917
- const [isColumnsDropdownOpen, setIsColumnsDropdownOpen] = useState10(false);
3918
- const dropdownRef = useRef7(null);
3919
- useEffect8(() => {
4711
+ const [isColumnsDropdownOpen, setIsColumnsDropdownOpen] = useState12(false);
4712
+ const dropdownRef = useRef8(null);
4713
+ useEffect10(() => {
3920
4714
  const handleClickOutside = (e) => {
3921
4715
  if (dropdownRef.current && !dropdownRef.current.contains(e.target)) {
3922
4716
  setIsColumnsDropdownOpen(false);
@@ -4159,13 +4953,13 @@ function TableBlockClient({
4159
4953
  });
4160
4954
  }
4161
4955
  };
4162
- const triggerSaveSuccess = useCallback9(() => {
4956
+ const triggerSaveSuccess = useCallback10(() => {
4163
4957
  setIsSaveSuccess(true);
4164
4958
  setTimeout(() => {
4165
4959
  setIsSaveSuccess(false);
4166
4960
  }, 2500);
4167
4961
  }, []);
4168
- const handleQuietCellChange = useCallback9((rowId, colName, value) => {
4962
+ const handleQuietCellChange = useCallback10((rowId, colName, value) => {
4169
4963
  setData((prev) => prev.map(
4170
4964
  (row) => row.id === rowId ? __spreadProps(__spreadValues({}, row), { data: __spreadProps(__spreadValues({}, row.data), { [colName]: value }) }) : row
4171
4965
  ));
@@ -4433,7 +5227,7 @@ function TableBlockClient({
4433
5227
  setIsSaving(false);
4434
5228
  }
4435
5229
  };
4436
- const getRowRelationLabels = useCallback9((rowVal, col) => {
5230
+ const getRowRelationLabels = useCallback10((rowVal, col) => {
4437
5231
  const ids = normalizeRelationValue(rowVal);
4438
5232
  if (ids.length === 0) return [];
4439
5233
  const options = relationOptions[col.name] || [];
@@ -4441,21 +5235,38 @@ function TableBlockClient({
4441
5235
  const opt = options.find((o) => o.id === id || o._id === id);
4442
5236
  if (opt) {
4443
5237
  const resolved = resolveRelationLabel(opt, col);
4444
- if (resolved) return resolved;
4445
- if (opt.label) return String(opt.label);
4446
- if (opt.name) return String(opt.name);
5238
+ if (resolved && !isRawObjectId(resolved)) return resolved;
5239
+ if (opt.label && !isRawObjectId(String(opt.label))) return String(opt.label);
5240
+ if (opt.name && !isRawObjectId(String(opt.name))) return String(opt.name);
4447
5241
  }
4448
5242
  if (typeof rowVal === "object" && rowVal !== null) {
4449
- if (rowVal._displayLabel) return String(rowVal._displayLabel);
4450
- if (rowVal.label) return String(rowVal.label);
5243
+ if (rowVal._displayLabel && !isRawObjectId(String(rowVal._displayLabel))) return String(rowVal._displayLabel);
5244
+ if (rowVal.label && !isRawObjectId(String(rowVal.label))) return String(rowVal.label);
4451
5245
  }
4452
- return id;
4453
- });
5246
+ return "";
5247
+ }).filter(Boolean);
4454
5248
  }, [relationOptions]);
4455
- const getUniqueRelationOptions = useCallback9((col) => {
5249
+ const getUniqueRelationOptions = useCallback10((col) => {
4456
5250
  const seenIds = /* @__PURE__ */ new Set();
5251
+ const seenLabels = /* @__PURE__ */ new Set();
4457
5252
  const results = [];
4458
5253
  const options = relationOptions[col.name] || [];
5254
+ options.forEach((opt) => {
5255
+ const id = String(opt.id || opt._id || "");
5256
+ if (!id) return;
5257
+ let label = resolveRelationLabel(opt, col);
5258
+ if (!label) {
5259
+ const fallback = opt.label || opt.name || opt.title;
5260
+ if (fallback && typeof fallback === "string" && !isRawObjectId(fallback)) {
5261
+ label = fallback.trim();
5262
+ }
5263
+ }
5264
+ if (label && label.trim() && !isRawObjectId(label) && !seenLabels.has(label.trim())) {
5265
+ seenIds.add(id);
5266
+ seenLabels.add(label.trim());
5267
+ results.push({ id, label: label.trim() });
5268
+ }
5269
+ });
4459
5270
  data.forEach((row) => {
4460
5271
  if (!(row == null ? void 0 : row.data)) return;
4461
5272
  const ids = normalizeRelationValue(row.data[col.name]);
@@ -4464,58 +5275,24 @@ function TableBlockClient({
4464
5275
  seenIds.add(id);
4465
5276
  const opt = options.find((o) => o.id === id || o._id === id);
4466
5277
  let label = opt ? resolveRelationLabel(opt, col) : "";
4467
- if (!label && opt) label = opt.label || opt.name || opt.title || id;
4468
- if (!label) label = id;
4469
- results.push({ id, label });
5278
+ if (!label && opt) {
5279
+ const fallback = opt.label || opt.name || opt.title;
5280
+ if (fallback && typeof fallback === "string" && !isRawObjectId(fallback)) {
5281
+ label = fallback.trim();
5282
+ }
5283
+ }
5284
+ if (label && label.trim() && label !== id && !isRawObjectId(label) && !seenLabels.has(label.trim())) {
5285
+ seenLabels.add(label.trim());
5286
+ results.push({ id, label: label.trim() });
5287
+ }
4470
5288
  }
4471
5289
  });
4472
5290
  });
4473
5291
  return results.sort((a, b) => a.label.localeCompare(b.label));
4474
5292
  }, [data, relationOptions]);
4475
- const filteredData = useMemo5(() => {
4476
- const hasGlobalSearch = Boolean(searchQuery && searchQuery.trim() !== "");
4477
- const activeFilters = Object.entries(columnFilters).filter(([, val]) => Boolean(val && val.trim() !== ""));
4478
- const hasColumnFilters = activeFilters.length > 0;
4479
- if (!hasGlobalSearch && !hasColumnFilters) return data;
4480
- const lowerGlobal = hasGlobalSearch ? searchQuery.trim().toLowerCase() : "";
4481
- return data.filter((row) => {
4482
- var _a;
4483
- if (!row || !row.data) return false;
4484
- if (hasGlobalSearch) {
4485
- const matchesGlobal = (localColumns || []).some((col) => {
4486
- var _a2;
4487
- const rawVal = row.data[col.name];
4488
- if (rawVal === void 0 || rawVal === null) return false;
4489
- if (((_a2 = col.type) == null ? void 0 : _a2.toUpperCase()) === "RELATION") {
4490
- const labels = getRowRelationLabels(rawVal, col);
4491
- return labels.some((l) => l.toLowerCase().includes(lowerGlobal));
4492
- }
4493
- if (typeof rawVal === "object") {
4494
- return JSON.stringify(rawVal).toLowerCase().includes(lowerGlobal);
4495
- }
4496
- return String(rawVal).toLowerCase().includes(lowerGlobal);
4497
- });
4498
- if (!matchesGlobal) return false;
4499
- }
4500
- for (const [colName, filterVal] of activeFilters) {
4501
- const lowerFilter = filterVal.trim().toLowerCase();
4502
- const col = (localColumns || []).find((c) => c.name === colName);
4503
- const rawVal = row.data[colName];
4504
- if (((_a = col == null ? void 0 : col.type) == null ? void 0 : _a.toUpperCase()) === "RELATION") {
4505
- const labels = getRowRelationLabels(rawVal, col);
4506
- const matches = labels.some((l) => l.toLowerCase().includes(lowerFilter));
4507
- if (!matches) return false;
4508
- } else {
4509
- if (rawVal === void 0 || rawVal === null) return false;
4510
- const strVal = typeof rawVal === "object" ? JSON.stringify(rawVal).toLowerCase() : String(rawVal).toLowerCase();
4511
- if (!strVal.includes(lowerFilter)) return false;
4512
- }
4513
- }
4514
- return true;
4515
- });
4516
- }, [data, searchQuery, columnFilters, localColumns, getRowRelationLabels]);
5293
+ const filteredData = data;
4517
5294
  const errorMessage = error ? typeof error === "string" ? error : error.message || String(error) : null;
4518
- const columnTotals = useMemo5(() => {
5295
+ const columnTotals = useMemo6(() => {
4519
5296
  const totals = {};
4520
5297
  if (!showSummary) return totals;
4521
5298
  filteredColumns.forEach((col) => {
@@ -4533,42 +5310,120 @@ function TableBlockClient({
4533
5310
  });
4534
5311
  return totals;
4535
5312
  }, [filteredData, filteredColumns, showSummary]);
4536
- return /* @__PURE__ */ jsxs10(
5313
+ const hasSelectedRows = selectedIds.size > 0;
5314
+ const hasActiveSearchOrFilter = Boolean(searchQuery && searchQuery.trim() !== "") || Object.values(columnFilters).some(
5315
+ (v) => Array.isArray(v) ? v.length > 0 : v && typeof v === "object" && "values" in v ? v.values.length > 0 : typeof v === "string" && Boolean(v.trim())
5316
+ );
5317
+ let exportButtonText = "\u05D9\u05D9\u05E6\u05D0 \u05E0\u05EA\u05D5\u05E0\u05D9\u05DD";
5318
+ let ExportButtonIcon = Download;
5319
+ if (hasSelectedRows) {
5320
+ exportButtonText = `\u05D9\u05D9\u05E6\u05D0 ${selectedIds.size} \u05E8\u05E9\u05D5\u05DE\u05D5\u05EA`;
5321
+ ExportButtonIcon = Download;
5322
+ } else if (hasActiveSearchOrFilter) {
5323
+ exportButtonText = "\u05D9\u05D9\u05E6\u05D0 \u05EA\u05D5\u05E6\u05D0\u05D5\u05EA \u05E1\u05D9\u05E0\u05D5\u05DF";
5324
+ ExportButtonIcon = Filter;
5325
+ }
5326
+ const handleExportCsv = async () => {
5327
+ if (isExporting) return;
5328
+ const systemFields = ["_id", "id", "createdAt", "updatedAt", "createdBy", "updatedBy", "orgId", "tableId"];
5329
+ const userHiddenColumns = normalizedColumns.filter((c) => c.isHidden && !systemFields.includes(c.name)).map((c) => c.name);
5330
+ if (userHiddenColumns.length > 0) {
5331
+ addToast({
5332
+ message: "\u05DE\u05D9\u05D9\u05E6\u05D0 \u05E0\u05EA\u05D5\u05E0\u05D9\u05DD... \u05E9\u05D9\u05DD \u05DC\u05D1: \u05E2\u05DE\u05D5\u05D3\u05D5\u05EA \u05DE\u05D5\u05E1\u05EA\u05E8\u05D5\u05EA \u05DC\u05D0 \u05D9\u05D9\u05DB\u05DC\u05DC\u05D5 \u05D1\u05E7\u05D5\u05D1\u05E5",
5333
+ type: "info",
5334
+ duration: 3e3
5335
+ });
5336
+ } else {
5337
+ addToast({
5338
+ message: "\u05DE\u05D9\u05D9\u05E6\u05D0 \u05E0\u05EA\u05D5\u05E0\u05D9\u05DD...",
5339
+ type: "info",
5340
+ duration: 3e3
5341
+ });
5342
+ }
5343
+ setIsExporting(true);
5344
+ try {
5345
+ const targetTableId = (schema == null ? void 0 : schema.tableMetaId) || (schema == null ? void 0 : schema.tableId) || (schema == null ? void 0 : schema.id);
5346
+ if (!targetTableId) {
5347
+ showError("\u05DE\u05D6\u05D4\u05D4 \u05D4\u05D8\u05D1\u05DC\u05D4 \u05D7\u05E1\u05E8 (tableId)", "\u05E9\u05D2\u05D9\u05D0\u05EA \u05D9\u05D9\u05E6\u05D5\u05D0");
5348
+ return;
5349
+ }
5350
+ const payload = {
5351
+ tableId: targetTableId,
5352
+ orgId,
5353
+ search: searchQuery.trim() || void 0,
5354
+ columnFilters: Object.keys(columnFilters).length > 0 ? columnFilters : void 0,
5355
+ selectedRowIds: hasSelectedRows ? Array.from(selectedIds) : [],
5356
+ hiddenColumnIds: userHiddenColumns
5357
+ };
5358
+ let res;
5359
+ if (exportAction) {
5360
+ res = await exportAction(payload);
5361
+ } else if (executeAction) {
5362
+ res = await executeAction("EXPORT_TABLE_TO_CSV", payload);
5363
+ } else {
5364
+ throw new Error("\u05E8\u05DB\u05D9\u05D1 \u05D4\u05EA\u05E7\u05E9\u05D5\u05E8\u05EA \u05DC\u05D0 \u05D0\u05D5\u05EA\u05D7\u05DC");
5365
+ }
5366
+ const result = (res == null ? void 0 : res.data) || res;
5367
+ if ((result == null ? void 0 : result.success) === false) {
5368
+ throw new Error(result.error || "\u05E9\u05D2\u05D9\u05D0\u05D4 \u05D1\u05D9\u05D9\u05E6\u05D5\u05D0 \u05D4\u05E0\u05EA\u05D5\u05E0\u05D9\u05DD");
5369
+ }
5370
+ const csvString = (result == null ? void 0 : result.csvString) || (result == null ? void 0 : result.csv);
5371
+ if (!csvString) {
5372
+ throw new Error("\u05DC\u05D0 \u05D4\u05EA\u05E7\u05D1\u05DC\u05D5 \u05E0\u05EA\u05D5\u05E0\u05D9 CSV \u05DE\u05D4\u05E9\u05E8\u05EA");
5373
+ }
5374
+ const fileName = (result == null ? void 0 : result.fileName) || `${((schema == null ? void 0 : schema.title) || (schema == null ? void 0 : schema.name) || "table").trim()}_export.csv`;
5375
+ const blob = new Blob([csvString], { type: "text/csv;charset=utf-8;" });
5376
+ const url = URL.createObjectURL(blob);
5377
+ const link = document.createElement("a");
5378
+ link.href = url;
5379
+ link.setAttribute("download", fileName);
5380
+ document.body.appendChild(link);
5381
+ link.click();
5382
+ document.body.removeChild(link);
5383
+ URL.revokeObjectURL(url);
5384
+ } catch (err) {
5385
+ console.error("[TableBlock] Export to CSV failed:", err);
5386
+ showError((err == null ? void 0 : err.message) || String(err), "\u05E9\u05D2\u05D9\u05D0\u05D4 \u05D1\u05D9\u05D9\u05E6\u05D5\u05D0 \u05D4\u05E0\u05EA\u05D5\u05E0\u05D9\u05DD");
5387
+ } finally {
5388
+ setIsExporting(false);
5389
+ }
5390
+ };
5391
+ return /* @__PURE__ */ jsxs11(
4537
5392
  "div",
4538
5393
  {
4539
5394
  id: componentId,
4540
5395
  "data-testid": dataTestId || (componentId ? `table-block-${componentId}` : void 0),
4541
- className: `flex flex-col w-full bg-white border border-slate-200 rounded-xl shadow-xs min-h-[350px] overflow-hidden ${className}`,
5396
+ className: `flex flex-col w-full bg-white border border-slate-200 rounded-xl shadow-xs flex-1 min-h-0 overflow-hidden ${className}`,
4542
5397
  dir: "rtl",
4543
5398
  children: [
4544
- errorMessage && /* @__PURE__ */ jsx10("div", { className: "p-3 bg-rose-50 border-b border-rose-200 text-rose-700 text-sm flex items-center justify-between", children: /* @__PURE__ */ jsxs10("div", { className: "flex items-center gap-2", children: [
4545
- /* @__PURE__ */ jsx10("svg", { className: "w-4 h-4 text-rose-500 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx10("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" }) }),
4546
- /* @__PURE__ */ jsx10("span", { children: errorMessage })
5399
+ errorMessage && /* @__PURE__ */ jsx11("div", { className: "p-3 bg-rose-50 border-b border-rose-200 text-rose-700 text-sm flex items-center justify-between shrink-0", children: /* @__PURE__ */ jsxs11("div", { className: "flex items-center gap-2", children: [
5400
+ /* @__PURE__ */ jsx11("svg", { className: "w-4 h-4 text-rose-500 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx11("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" }) }),
5401
+ /* @__PURE__ */ jsx11("span", { children: errorMessage })
4547
5402
  ] }) }),
4548
- /* @__PURE__ */ jsxs10("div", { className: "flex flex-wrap items-center justify-between gap-3 p-3.5 sm:p-4 bg-slate-50 border-b border-slate-200", children: [
4549
- /* @__PURE__ */ jsxs10("div", { className: "flex flex-wrap items-center gap-2.5", children: [
4550
- ((schema == null ? void 0 : schema.title) || (schema == null ? void 0 : schema.name)) && /* @__PURE__ */ jsx10("div", { className: "font-bold text-slate-800 text-sm sm:text-base border-l border-slate-300 pl-3 ml-1", children: /* @__PURE__ */ jsx10("span", { children: schema.title || schema.name }) }),
4551
- /* @__PURE__ */ jsx10(
5403
+ /* @__PURE__ */ jsxs11("div", { className: "flex flex-wrap items-center justify-between gap-3 p-3.5 sm:p-4 bg-slate-50 border-b border-slate-200 shrink-0", children: [
5404
+ /* @__PURE__ */ jsxs11("div", { className: "flex flex-wrap items-center gap-2.5", children: [
5405
+ ((schema == null ? void 0 : schema.title) || (schema == null ? void 0 : schema.name)) && /* @__PURE__ */ jsx11("div", { className: "font-bold text-slate-800 text-sm sm:text-base border-l border-slate-300 pl-3 ml-1", children: /* @__PURE__ */ jsx11("span", { children: schema.title || schema.name }) }),
5406
+ /* @__PURE__ */ jsx11(
4552
5407
  "button",
4553
5408
  {
4554
5409
  onClick: handleAddRow,
4555
5410
  disabled: isInitialLoading || isLoading || isUpdatingActive,
4556
5411
  className: `w-9 h-9 text-white rounded-lg shadow-xs flex items-center justify-center transition-all ${isInitialLoading || isLoading || isUpdatingActive ? "bg-emerald-950/80 text-emerald-400/60 pointer-events-none cursor-not-allowed" : "bg-emerald-600 hover:bg-emerald-700 active:bg-emerald-800 cursor-pointer"}`,
4557
5412
  title: isInitialLoading ? "\u05D8\u05D5\u05E2\u05DF \u05E0\u05EA\u05D5\u05E0\u05D9\u05DD..." : "\u05D4\u05D5\u05E1\u05E3 \u05E9\u05D5\u05E8\u05D4 \u05D7\u05D3\u05E9\u05D4",
4558
- children: /* @__PURE__ */ jsx10("svg", { className: "w-4.5 h-4.5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx10("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2.5", d: "M12 4v16m8-8H4" }) })
5413
+ children: /* @__PURE__ */ jsx11("svg", { className: "w-4.5 h-4.5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx11("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2.5", d: "M12 4v16m8-8H4" }) })
4559
5414
  }
4560
5415
  ),
4561
- /* @__PURE__ */ jsx10(
5416
+ /* @__PURE__ */ jsx11(
4562
5417
  "button",
4563
5418
  {
4564
5419
  onClick: handleDuplicateRow,
4565
5420
  disabled: isInitialLoading || isLoading || isUpdatingActive || selectedIds.size !== 1,
4566
5421
  className: "w-9 h-9 bg-blue-50 hover:bg-blue-100 border border-blue-200 text-blue-700 rounded-lg shadow-2xs flex items-center justify-center transition-all disabled:opacity-40 disabled:pointer-events-none cursor-pointer",
4567
5422
  title: "\u05E9\u05DB\u05E4\u05DC \u05E9\u05D5\u05E8\u05D4 \u05E0\u05D1\u05D7\u05E8\u05EA",
4568
- children: /* @__PURE__ */ jsx10(Copy2, { className: "w-4 h-4 text-blue-600 shrink-0" })
5423
+ children: /* @__PURE__ */ jsx11(Copy2, { className: "w-4 h-4 text-blue-600 shrink-0" })
4569
5424
  }
4570
5425
  ),
4571
- /* @__PURE__ */ jsxs10(
5426
+ /* @__PURE__ */ jsxs11(
4572
5427
  "button",
4573
5428
  {
4574
5429
  onClick: handleDeleteSelected,
@@ -4576,12 +5431,12 @@ function TableBlockClient({
4576
5431
  className: "w-9 h-9 bg-rose-50 hover:bg-rose-100 border border-rose-200 text-rose-700 rounded-lg shadow-2xs flex items-center justify-center relative transition-all disabled:opacity-40 disabled:pointer-events-none cursor-pointer",
4577
5432
  title: "\u05DE\u05D7\u05E7 \u05E9\u05D5\u05E8\u05D5\u05EA \u05E0\u05D1\u05D7\u05E8\u05D5\u05EA",
4578
5433
  children: [
4579
- /* @__PURE__ */ jsx10("svg", { className: "w-4.5 h-4.5 text-rose-600 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx10("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" }) }),
4580
- selectedIds.size > 0 && /* @__PURE__ */ jsx10("span", { className: "absolute -top-1.5 -right-1.5 bg-rose-600 text-white min-w-[18px] h-[18px] px-1 rounded-full text-[10px] font-bold flex items-center justify-center shadow-xs", children: selectedIds.size })
5434
+ /* @__PURE__ */ jsx11("svg", { className: "w-4.5 h-4.5 text-rose-600 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx11("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" }) }),
5435
+ selectedIds.size > 0 && /* @__PURE__ */ jsx11("span", { className: "absolute -top-1.5 -right-1.5 bg-rose-600 text-white min-w-[18px] h-[18px] px-1 rounded-full text-[10px] font-bold flex items-center justify-center shadow-xs", children: selectedIds.size })
4581
5436
  ]
4582
5437
  }
4583
5438
  ),
4584
- /* @__PURE__ */ jsxs10(
5439
+ /* @__PURE__ */ jsxs11(
4585
5440
  "button",
4586
5441
  {
4587
5442
  onClick: toggleSummary,
@@ -4589,13 +5444,13 @@ function TableBlockClient({
4589
5444
  className: `h-9 px-3 border font-semibold rounded-lg shadow-2xs flex items-center gap-1.5 text-xs transition-all disabled:opacity-40 disabled:pointer-events-none cursor-pointer ${showSummary ? "bg-indigo-50 border-indigo-200 text-indigo-700 hover:bg-indigo-100" : "bg-white border-slate-300 text-slate-700 hover:bg-slate-100"}`,
4590
5445
  title: "\u05D4\u05E6\u05D2/\u05D4\u05E1\u05EA\u05E8 \u05E9\u05D5\u05E8\u05EA \u05E1\u05D9\u05DB\u05D5\u05DD",
4591
5446
  children: [
4592
- /* @__PURE__ */ jsx10("svg", { className: "w-4 h-4 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx10("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M4 6h16M4 10h16M4 14h16M4 18h16" }) }),
4593
- /* @__PURE__ */ jsx10("span", { className: "hidden sm:inline", children: "\u05E1\u05DB\u05D9\u05DE\u05D4" })
5447
+ /* @__PURE__ */ jsx11("svg", { className: "w-4 h-4 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx11("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M4 6h16M4 10h16M4 14h16M4 18h16" }) }),
5448
+ /* @__PURE__ */ jsx11("span", { className: "hidden sm:inline", children: "\u05E1\u05DB\u05D9\u05DE\u05D4" })
4594
5449
  ]
4595
5450
  }
4596
5451
  ),
4597
- /* @__PURE__ */ jsxs10("div", { className: "relative", ref: dropdownRef, children: [
4598
- /* @__PURE__ */ jsxs10(
5452
+ /* @__PURE__ */ jsxs11("div", { className: "relative", ref: dropdownRef, children: [
5453
+ /* @__PURE__ */ jsxs11(
4599
5454
  "button",
4600
5455
  {
4601
5456
  onClick: () => setIsColumnsDropdownOpen((prev) => !prev),
@@ -4603,16 +5458,16 @@ function TableBlockClient({
4603
5458
  className: "h-9 px-3 bg-white hover:bg-slate-100 border border-slate-300 text-slate-700 font-semibold rounded-lg shadow-2xs flex items-center gap-1.5 text-xs transition-all disabled:opacity-40 disabled:pointer-events-none cursor-pointer",
4604
5459
  title: "\u05D4\u05E6\u05D2/\u05D4\u05E1\u05EA\u05E8 \u05E2\u05DE\u05D5\u05D3\u05D5\u05EA",
4605
5460
  children: [
4606
- /* @__PURE__ */ jsx10("svg", { className: "w-4 h-4 text-slate-600 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx10("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M9 17V7m0 10a2 2 0 01-2 2H5a2 2 0 01-2-2V7a2 2 0 012-2h2a2 2 0 012 2m0 10a2 2 0 002 2h2a2 2 0 002-2M9 7a2 2 0 012-2h2a2 2 0 012 2m0 10V7m0 10a2 2 0 002 2h2a2 2 0 002-2V7a2 2 0 00-2-2h-2a2 2 0 00-2 2" }) }),
4607
- /* @__PURE__ */ jsx10("svg", { className: `w-3.5 h-3.5 text-slate-500 transition-transform ${isColumnsDropdownOpen ? "rotate-180" : ""}`, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx10("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M19 9l-7 7-7-7" }) })
5461
+ /* @__PURE__ */ jsx11("svg", { className: "w-4 h-4 text-slate-600 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx11("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M9 17V7m0 10a2 2 0 01-2 2H5a2 2 0 01-2-2V7a2 2 0 012-2h2a2 2 0 012 2m0 10a2 2 0 002 2h2a2 2 0 002-2M9 7a2 2 0 012-2h2a2 2 0 012 2m0 10V7m0 10a2 2 0 002 2h2a2 2 0 002-2V7a2 2 0 00-2-2h-2a2 2 0 00-2 2" }) }),
5462
+ /* @__PURE__ */ jsx11("svg", { className: `w-3.5 h-3.5 text-slate-500 transition-transform ${isColumnsDropdownOpen ? "rotate-180" : ""}`, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx11("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M19 9l-7 7-7-7" }) })
4608
5463
  ]
4609
5464
  }
4610
5465
  ),
4611
- isColumnsDropdownOpen && /* @__PURE__ */ jsxs10("div", { className: "absolute right-0 top-full mt-1.5 w-56 bg-white border border-slate-200 rounded-xl shadow-xl z-50 p-1.5 dir-rtl animate-in fade-in slide-in-from-top-2 duration-150", children: [
4612
- /* @__PURE__ */ jsxs10("div", { className: "px-2 py-1.5 text-xs font-bold text-slate-500 border-b border-slate-100 mb-1 flex items-center justify-between", children: [
4613
- /* @__PURE__ */ jsxs10("div", { className: "flex items-center gap-1.5", children: [
4614
- /* @__PURE__ */ jsx10("span", { children: "\u05D4\u05E6\u05D2\u05EA \u05E2\u05DE\u05D5\u05D3\u05D5\u05EA" }),
4615
- /* @__PURE__ */ jsxs10("span", { className: "text-[10px] font-normal text-slate-400", children: [
5466
+ isColumnsDropdownOpen && /* @__PURE__ */ jsxs11("div", { className: "absolute right-0 top-full mt-1.5 w-56 bg-white border border-slate-200 rounded-xl shadow-xl z-50 p-1.5 dir-rtl animate-in fade-in slide-in-from-top-2 duration-150", children: [
5467
+ /* @__PURE__ */ jsxs11("div", { className: "px-2 py-1.5 text-xs font-bold text-slate-500 border-b border-slate-100 mb-1 flex items-center justify-between", children: [
5468
+ /* @__PURE__ */ jsxs11("div", { className: "flex items-center gap-1.5", children: [
5469
+ /* @__PURE__ */ jsx11("span", { children: "\u05D4\u05E6\u05D2\u05EA \u05E2\u05DE\u05D5\u05D3\u05D5\u05EA" }),
5470
+ /* @__PURE__ */ jsxs11("span", { className: "text-[10px] font-normal text-slate-400", children: [
4616
5471
  "(",
4617
5472
  customizableColumns.filter((c) => !c.isHidden).length,
4618
5473
  "/",
@@ -4620,7 +5475,7 @@ function TableBlockClient({
4620
5475
  ")"
4621
5476
  ] })
4622
5477
  ] }),
4623
- /* @__PURE__ */ jsx10(
5478
+ /* @__PURE__ */ jsx11(
4624
5479
  "button",
4625
5480
  {
4626
5481
  type: "button",
@@ -4630,7 +5485,7 @@ function TableBlockClient({
4630
5485
  }
4631
5486
  )
4632
5487
  ] }),
4633
- /* @__PURE__ */ jsx10("div", { className: "max-h-60 overflow-y-auto space-y-0.5", children: customizableColumns.map((col) => {
5488
+ /* @__PURE__ */ jsx11("div", { className: "max-h-60 overflow-y-auto space-y-0.5", children: customizableColumns.map((col) => {
4634
5489
  const isRequired = col.isRequired === true || String(col.isRequired) === "true";
4635
5490
  const isUnique = col.isUnique === true || String(col.isUnique) === "true";
4636
5491
  const isProtected = isRequired || isUnique;
@@ -4644,7 +5499,7 @@ function TableBlockClient({
4644
5499
  protectedExplanation = "\u05E9\u05D3\u05D4 \u05D9\u05D9\u05D7\u05D5\u05D3\u05D9 - \u05DC\u05D0 \u05E0\u05D9\u05EA\u05DF \u05DC\u05D4\u05D5\u05E8\u05D9\u05D3 \u05E2\u05DE\u05D5\u05D3\u05D4 \u05D6\u05D5 \u05DE\u05D4\u05EA\u05E6\u05D5\u05D2\u05D4";
4645
5500
  }
4646
5501
  const badgeLabel = isRequired && isUnique ? "\u05D7\u05D5\u05D1\u05D4 + \u05D9\u05D9\u05D7\u05D5\u05D3\u05D9" : isRequired ? "\u05E9\u05D3\u05D4 \u05D7\u05D5\u05D1\u05D4" : "\u05E9\u05D3\u05D4 \u05D9\u05D9\u05D7\u05D5\u05D3\u05D9";
4647
- return /* @__PURE__ */ jsxs10(
5502
+ return /* @__PURE__ */ jsxs11(
4648
5503
  "div",
4649
5504
  {
4650
5505
  onClick: () => {
@@ -4655,8 +5510,8 @@ function TableBlockClient({
4655
5510
  title: isProtected ? protectedExplanation : void 0,
4656
5511
  className: `group flex items-center justify-between px-2.5 py-1.5 rounded-lg text-xs transition-colors select-none ${isProtected ? "opacity-75 bg-slate-50 border border-slate-100/70 cursor-not-allowed" : "hover:bg-slate-100 active:bg-slate-200 cursor-pointer"}`,
4657
5512
  children: [
4658
- /* @__PURE__ */ jsxs10("div", { className: "flex items-center gap-2 min-w-0", children: [
4659
- /* @__PURE__ */ jsx10(
5513
+ /* @__PURE__ */ jsxs11("div", { className: "flex items-center gap-2 min-w-0", children: [
5514
+ /* @__PURE__ */ jsx11(
4660
5515
  "input",
4661
5516
  {
4662
5517
  type: "checkbox",
@@ -4667,16 +5522,16 @@ function TableBlockClient({
4667
5522
  className: "w-3.5 h-3.5 rounded border-slate-300 text-brand focus:ring-brand/20 cursor-pointer disabled:cursor-not-allowed disabled:opacity-60"
4668
5523
  }
4669
5524
  ),
4670
- /* @__PURE__ */ jsx10("span", { className: `font-medium truncate ${isProtected ? "text-slate-500" : "text-slate-700"}`, children: col.name })
5525
+ /* @__PURE__ */ jsx11("span", { className: `font-medium truncate ${isProtected ? "text-slate-500" : "text-slate-700"}`, children: col.name })
4671
5526
  ] }),
4672
- isProtected && /* @__PURE__ */ jsxs10(
5527
+ isProtected && /* @__PURE__ */ jsxs11(
4673
5528
  "div",
4674
5529
  {
4675
5530
  className: "flex items-center gap-1 px-1.5 py-0.5 rounded text-[10px] font-semibold bg-amber-50 text-amber-800 border border-amber-200/80 cursor-help",
4676
5531
  title: protectedExplanation,
4677
5532
  children: [
4678
- /* @__PURE__ */ jsx10("svg", { className: "w-3 h-3 text-amber-600 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: "2.2", children: /* @__PURE__ */ jsx10("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z" }) }),
4679
- /* @__PURE__ */ jsx10("span", { children: badgeLabel })
5533
+ /* @__PURE__ */ jsx11("svg", { className: "w-3 h-3 text-amber-600 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: "2.2", children: /* @__PURE__ */ jsx11("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z" }) }),
5534
+ /* @__PURE__ */ jsx11("span", { children: badgeLabel })
4680
5535
  ]
4681
5536
  }
4682
5537
  )
@@ -4687,9 +5542,23 @@ function TableBlockClient({
4687
5542
  }) })
4688
5543
  ] })
4689
5544
  ] }),
4690
- /* @__PURE__ */ jsx10("div", { className: "h-5 w-px bg-slate-300 mx-1 hidden sm:block" }),
4691
- /* @__PURE__ */ jsxs10("div", { className: "relative flex-1 sm:w-64 max-w-xs", children: [
4692
- /* @__PURE__ */ jsx10(
5545
+ /* @__PURE__ */ jsxs11(
5546
+ "button",
5547
+ {
5548
+ onClick: handleExportCsv,
5549
+ disabled: isLoading || isUpdatingActive || isExporting,
5550
+ className: `h-9 px-3 font-semibold rounded-lg shadow-2xs flex items-center gap-1.5 text-xs transition-all disabled:opacity-40 disabled:pointer-events-none cursor-pointer border ${hasSelectedRows ? "bg-blue-50 hover:bg-blue-100 border-blue-200 text-blue-700" : hasActiveSearchOrFilter ? "bg-amber-50 hover:bg-amber-100 border-amber-200 text-amber-800" : "bg-white hover:bg-slate-100 border-slate-300 text-slate-700"}`,
5551
+ title: exportButtonText,
5552
+ "data-testid": "export-csv-button",
5553
+ children: [
5554
+ isExporting ? /* @__PURE__ */ jsx11(Loader22, { className: "w-4 h-4 shrink-0 animate-spin text-slate-500" }) : /* @__PURE__ */ jsx11(ExportButtonIcon, { className: "w-4 h-4 shrink-0" }),
5555
+ /* @__PURE__ */ jsx11("span", { children: isExporting ? "\u05DE\u05D9\u05D9\u05E6\u05D0..." : exportButtonText })
5556
+ ]
5557
+ }
5558
+ ),
5559
+ /* @__PURE__ */ jsx11("div", { className: "h-5 w-px bg-slate-300 mx-1 hidden sm:block" }),
5560
+ /* @__PURE__ */ jsxs11("div", { className: "relative flex-1 sm:w-64 max-w-xs", children: [
5561
+ /* @__PURE__ */ jsx11(
4693
5562
  "input",
4694
5563
  {
4695
5564
  placeholder: "\u05D7\u05D9\u05E4\u05D5\u05E9 \u05D1\u05E8\u05E9\u05D5\u05DE\u05D5\u05EA...",
@@ -4699,28 +5568,28 @@ function TableBlockClient({
4699
5568
  className: "w-full h-9 px-3 pr-9 text-xs border border-slate-300 rounded-lg bg-white shadow-2xs focus:outline-none focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 text-slate-800 disabled:opacity-50"
4700
5569
  }
4701
5570
  ),
4702
- searchQuery ? /* @__PURE__ */ jsx10(
5571
+ searchQuery ? /* @__PURE__ */ jsx11(
4703
5572
  "button",
4704
5573
  {
4705
5574
  type: "button",
4706
5575
  onClick: () => setSearchQuery(""),
4707
5576
  className: "absolute right-2.5 top-2.5 text-slate-400 hover:text-slate-600 transition-colors p-0.5 rounded-full hover:bg-slate-100 cursor-pointer",
4708
5577
  title: "Clear search",
4709
- children: /* @__PURE__ */ jsx10(X7, { className: "w-3.5 h-3.5" })
5578
+ children: /* @__PURE__ */ jsx11(X8, { className: "w-3.5 h-3.5" })
4710
5579
  }
4711
- ) : /* @__PURE__ */ jsx10("svg", { className: "w-4 h-4 text-slate-400 absolute right-2.5 top-2.5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx10("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" }) })
5580
+ ) : /* @__PURE__ */ jsx11("svg", { className: "w-4 h-4 text-slate-400 absolute right-2.5 top-2.5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx11("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" }) })
4712
5581
  ] })
4713
5582
  ] }),
4714
- /* @__PURE__ */ jsxs10("div", { className: "flex items-center gap-3", children: [
4715
- isUpdatingActive ? /* @__PURE__ */ jsxs10("span", { className: "text-xs text-blue-600 font-semibold flex items-center gap-1.5 bg-blue-50 border border-blue-200 px-3 py-1.5 rounded-lg animate-pulse", children: [
4716
- /* @__PURE__ */ jsx10("span", { className: "w-2 h-2 rounded-full bg-blue-500 inline-block" }),
5583
+ /* @__PURE__ */ jsxs11("div", { className: "flex items-center gap-3", children: [
5584
+ isUpdatingActive ? /* @__PURE__ */ jsxs11("span", { className: "text-xs text-blue-600 font-semibold flex items-center gap-1.5 bg-blue-50 border border-blue-200 px-3 py-1.5 rounded-lg animate-pulse", children: [
5585
+ /* @__PURE__ */ jsx11("span", { className: "w-2 h-2 rounded-full bg-blue-500 inline-block" }),
4717
5586
  "\u05DE\u05E2\u05D3\u05DB\u05DF..."
4718
- ] }) : isSaveSuccess ? /* @__PURE__ */ jsxs10("span", { className: "text-xs text-emerald-700 font-semibold flex items-center gap-1.5 bg-emerald-50 border border-emerald-200 px-3 py-1.5 rounded-lg animate-in fade-in duration-200", children: [
4719
- /* @__PURE__ */ jsx10("svg", { className: "w-4 h-4 text-emerald-600 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx10("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2.5", d: "M5 13l4 4L19 7" }) }),
5587
+ ] }) : isSaveSuccess ? /* @__PURE__ */ jsxs11("span", { className: "text-xs text-emerald-700 font-semibold flex items-center gap-1.5 bg-emerald-50 border border-emerald-200 px-3 py-1.5 rounded-lg animate-in fade-in duration-200", children: [
5588
+ /* @__PURE__ */ jsx11("svg", { className: "w-4 h-4 text-emerald-600 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx11("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2.5", d: "M5 13l4 4L19 7" }) }),
4720
5589
  "\u05E2\u05D5\u05D3\u05DB\u05DF \u05D1\u05D4\u05E6\u05DC\u05D7\u05D4"
4721
- ] }) : hasChanges ? /* @__PURE__ */ jsxs10("div", { className: "flex items-center gap-1.5 animate-in fade-in", children: [
4722
- /* @__PURE__ */ jsx10("span", { className: "text-xs font-semibold text-amber-700", children: "\u05E9\u05D9\u05E0\u05D5\u05D9\u05D9\u05DD \u05E9\u05DC\u05D0 \u05E0\u05E9\u05DE\u05E8\u05D5" }),
4723
- /* @__PURE__ */ jsx10(
5590
+ ] }) : hasChanges ? /* @__PURE__ */ jsxs11("div", { className: "flex items-center gap-1.5 animate-in fade-in", children: [
5591
+ /* @__PURE__ */ jsx11("span", { className: "text-xs font-semibold text-amber-700", children: "\u05E9\u05D9\u05E0\u05D5\u05D9\u05D9\u05DD \u05E9\u05DC\u05D0 \u05E0\u05E9\u05DE\u05E8\u05D5" }),
5592
+ /* @__PURE__ */ jsx11(
4724
5593
  "button",
4725
5594
  {
4726
5595
  type: "button",
@@ -4729,30 +5598,31 @@ function TableBlockClient({
4729
5598
  className: "p-1 text-amber-700 hover:text-amber-900 hover:bg-amber-100/80 active:bg-amber-200/80 rounded-md transition-colors cursor-pointer disabled:opacity-50 disabled:pointer-events-none",
4730
5599
  title: "\u05D1\u05D8\u05DC \u05D0\u05EA \u05DB\u05DC \u05D4\u05E9\u05D9\u05E0\u05D5\u05D9\u05D9\u05DD \u05E9\u05DC\u05D0 \u05E0\u05E9\u05DE\u05E8\u05D5",
4731
5600
  "aria-label": "\u05D1\u05D8\u05DC \u05D0\u05EA \u05DB\u05DC \u05D4\u05E9\u05D9\u05E0\u05D5\u05D9\u05D9\u05DD \u05E9\u05DC\u05D0 \u05E0\u05E9\u05DE\u05E8\u05D5",
4732
- children: /* @__PURE__ */ jsx10(RotateCcw, { className: "w-3.5 h-3.5" })
5601
+ children: /* @__PURE__ */ jsx11(RotateCcw2, { className: "w-3.5 h-3.5" })
4733
5602
  }
4734
5603
  )
4735
5604
  ] }) : null,
4736
- /* @__PURE__ */ jsx10(
5605
+ /* @__PURE__ */ jsx11(
4737
5606
  "button",
4738
5607
  {
4739
5608
  onClick: handleSave,
4740
5609
  disabled: isUpdatingActive || isLoading || !hasChanges,
4741
5610
  className: `h-9 px-4 text-xs font-bold rounded-lg shadow-2xs transition-all flex items-center justify-center cursor-pointer ${hasChanges && !isUpdatingActive && !isLoading ? "bg-brand hover:bg-brand-hover active:bg-[#00897b] text-white shadow-teal-500/20" : "opacity-50 grayscale bg-slate-200 text-slate-400 cursor-not-allowed"}`,
4742
- children: /* @__PURE__ */ jsx10("span", { children: isUpdatingActive ? "\u05E9\u05D5\u05DE\u05E8..." : "\u05E9\u05DE\u05D9\u05E8\u05EA \u05E9\u05D9\u05E0\u05D5\u05D9\u05D9\u05DD" })
5611
+ children: /* @__PURE__ */ jsx11("span", { children: isUpdatingActive ? "\u05E9\u05D5\u05DE\u05E8..." : "\u05E9\u05DE\u05D9\u05E8\u05EA \u05E9\u05D9\u05E0\u05D5\u05D9\u05D9\u05DD" })
4743
5612
  }
4744
5613
  )
4745
5614
  ] })
4746
5615
  ] }),
4747
- /* @__PURE__ */ jsxs10("div", { className: `overflow-x-auto relative min-h-[260px] flex-1 transition-opacity duration-200 ${isMounted ? "opacity-100" : "opacity-0"}`, children: [
4748
- isLoading && /* @__PURE__ */ jsxs10("div", { className: "absolute inset-0 bg-white/80 backdrop-blur-xs z-20 flex flex-col items-center justify-center gap-2", children: [
4749
- /* @__PURE__ */ jsx10("div", { className: "w-6 h-6 border-2 border-brand border-t-transparent rounded-full animate-spin" }),
4750
- /* @__PURE__ */ jsx10("span", { className: "text-sm font-medium text-slate-600", children: "\u05D8\u05D5\u05E2\u05DF \u05E0\u05EA\u05D5\u05E0\u05D9\u05DD..." })
5616
+ /* @__PURE__ */ jsxs11("div", { className: `overflow-x-auto overflow-y-auto relative max-h-[calc(100vh-240px)] min-h-[260px] flex-1 transition-opacity duration-200 ${isMounted ? "opacity-100" : "opacity-0"}`, children: [
5617
+ isFetching && /* @__PURE__ */ jsx11("div", { className: "absolute top-0 left-0 right-0 h-0.5 bg-blue-500/20 overflow-hidden z-30", children: /* @__PURE__ */ jsx11("div", { className: "w-full h-full bg-brand animate-pulse" }) }),
5618
+ isLoading && /* @__PURE__ */ jsxs11("div", { className: "absolute inset-0 bg-white/80 backdrop-blur-xs z-20 flex flex-col items-center justify-center gap-2", children: [
5619
+ /* @__PURE__ */ jsx11("div", { className: "w-6 h-6 border-2 border-brand border-t-transparent rounded-full animate-spin" }),
5620
+ /* @__PURE__ */ jsx11("span", { className: "text-sm font-medium text-slate-600", children: "\u05D8\u05D5\u05E2\u05DF \u05E0\u05EA\u05D5\u05E0\u05D9\u05DD..." })
4751
5621
  ] }),
4752
- /* @__PURE__ */ jsxs10("table", { className: "w-full text-sm text-right border-collapse table-auto", children: [
4753
- /* @__PURE__ */ jsx10("thead", { className: "bg-slate-100/80 text-slate-700 sticky top-0 z-10", children: /* @__PURE__ */ jsxs10("tr", { className: "h-12 min-h-[48px]", children: [
4754
- /* @__PURE__ */ jsx10("th", { className: "border-b border-l border-slate-200 p-1.5 text-center shrink-0 h-12 min-h-[48px] align-middle", style: { width: 72, minWidth: 72, maxWidth: 72 }, children: /* @__PURE__ */ jsxs10("div", { className: "flex items-center justify-center gap-1.5", children: [
4755
- /* @__PURE__ */ jsx10(
5622
+ /* @__PURE__ */ jsxs11("table", { className: "w-full text-sm text-right border-collapse table-auto", children: [
5623
+ /* @__PURE__ */ jsx11("thead", { className: "bg-white text-slate-700 sticky top-0 z-10 shadow-xs", children: /* @__PURE__ */ jsxs11("tr", { className: "h-12 min-h-[48px]", children: [
5624
+ /* @__PURE__ */ jsx11("th", { className: "border-b border-l border-slate-200 p-1.5 text-center shrink-0 h-12 min-h-[48px] align-middle bg-white", style: { width: 72, minWidth: 72, maxWidth: 72 }, children: /* @__PURE__ */ jsxs11("div", { className: "flex items-center justify-center gap-1.5", children: [
5625
+ /* @__PURE__ */ jsx11(
4756
5626
  "input",
4757
5627
  {
4758
5628
  type: "checkbox",
@@ -4765,7 +5635,7 @@ function TableBlockClient({
4765
5635
  filteredColumns.some((c) => {
4766
5636
  var _a;
4767
5637
  return ((_a = c.type) == null ? void 0 : _a.toUpperCase()) === "SUB_TABLE";
4768
- }) && /* @__PURE__ */ jsx10("div", { className: "w-5 h-5 shrink-0" })
5638
+ }) && /* @__PURE__ */ jsx11("div", { className: "w-5 h-5 shrink-0" })
4769
5639
  ] }) }),
4770
5640
  filteredColumns.map((col) => {
4771
5641
  var _a, _b;
@@ -4776,16 +5646,25 @@ function TableBlockClient({
4776
5646
  const colMinWidth = calculateMinColumnWidth(col.name, false, col.type);
4777
5647
  const currentWidth = Math.max(colMinWidth, columnWidths[col.name] || 200);
4778
5648
  const isRelation = ((_a = col.type) == null ? void 0 : _a.toUpperCase()) === "RELATION";
4779
- const filterVal = columnFilters[col.name] || "";
4780
- return /* @__PURE__ */ jsxs10(
5649
+ const filterVal = columnFilters[col.name];
5650
+ const hasActiveFilter = Array.isArray(filterVal) ? filterVal.length > 0 : filterVal && typeof filterVal === "object" && "values" in filterVal ? filterVal.values.length > 0 : Boolean(filterVal && filterVal.trim() !== "");
5651
+ let filterTooltip = "\u05D7\u05E4\u05E9 \u05D5\u05E1\u05E0\u05DF \u05D1\u05E2\u05DE\u05D5\u05D3\u05D4 \u05D6\u05D5";
5652
+ if (Array.isArray(filterVal)) {
5653
+ filterTooltip = `\u05DE\u05E1\u05D5\u05E0\u05DF \u05DC\u05E4\u05D9: ${filterVal.length} \u05D0\u05E4\u05E9\u05E8\u05D5\u05D9\u05D5\u05EA \u05E0\u05D1\u05D7\u05E8\u05D5\u05EA`;
5654
+ } else if (filterVal && typeof filterVal === "object" && "operator" in filterVal && filterVal.operator === "notIn") {
5655
+ filterTooltip = `\u05DE\u05D5\u05D7\u05E8\u05D2\u05D9\u05DD: ${filterVal.values.length} \u05E4\u05E8\u05D9\u05D8\u05D9\u05DD (\u05D4\u05DB\u05DC \u05DC\u05DE\u05E2\u05D8)`;
5656
+ } else if (typeof filterVal === "string" && filterVal.trim()) {
5657
+ filterTooltip = `\u05DE\u05E1\u05D5\u05E0\u05DF \u05DC\u05E4\u05D9: "${filterVal}" (\u05DC\u05D7\u05E5 \u05DC\u05E2\u05E8\u05D9\u05DB\u05D4)`;
5658
+ }
5659
+ return /* @__PURE__ */ jsxs11(
4781
5660
  "th",
4782
5661
  __spreadProps(__spreadValues({
4783
5662
  style: { width: currentWidth, minWidth: currentWidth, maxWidth: currentWidth },
4784
5663
  title: isSearching ? void 0 : col.name
4785
5664
  }, dragProps), {
4786
- className: `relative border-b border-l border-slate-200 px-2.5 py-1.5 font-semibold text-slate-700 select-none transition-colors h-12 min-h-[48px] align-middle ${isSearching ? "cursor-default bg-blue-50/40" : "cursor-grab active:cursor-grabbing hover:bg-slate-200/60"} ${isDragging ? "opacity-40 bg-slate-200 border-dashed border-2 border-brand" : ""} ${isDragOver ? "bg-blue-50 border-r-4 border-r-brand text-brand font-bold" : ""}`,
5665
+ className: `group relative border-b border-l border-slate-200 px-2 py-1 font-semibold text-slate-700 select-none transition-colors h-12 min-h-[48px] align-middle bg-white ${isSearching ? "cursor-default bg-blue-50/40" : "cursor-grab active:cursor-grabbing hover:bg-slate-100"} ${isDragging ? "opacity-40 bg-slate-200 border-dashed border-2 border-brand" : ""} ${isDragOver ? "bg-blue-50 border-r-4 border-r-brand text-brand font-bold" : ""}`,
4787
5666
  children: [
4788
- /* @__PURE__ */ jsx10(
5667
+ /* @__PURE__ */ jsx11(
4789
5668
  "div",
4790
5669
  {
4791
5670
  onMouseDown: (e) => {
@@ -4797,7 +5676,7 @@ function TableBlockClient({
4797
5676
  title: "\u05E9\u05E0\u05D4 \u05D2\u05D5\u05D3\u05DC \u05E2\u05DE\u05D5\u05D3\u05D4"
4798
5677
  }
4799
5678
  ),
4800
- isSearching ? /* @__PURE__ */ jsxs10(
5679
+ isSearching && !isRelation ? /* @__PURE__ */ jsxs11(
4801
5680
  "div",
4802
5681
  {
4803
5682
  ref: activeSearchRef,
@@ -4805,46 +5684,15 @@ function TableBlockClient({
4805
5684
  onClick: (e) => e.stopPropagation(),
4806
5685
  onMouseDown: (e) => e.stopPropagation(),
4807
5686
  children: [
4808
- isRelation ? /* @__PURE__ */ jsx10("div", { className: "relative flex items-center w-full min-w-0", children: /* @__PURE__ */ jsxs10(
4809
- "select",
4810
- {
4811
- autoFocus: true,
4812
- value: filterVal,
4813
- onChange: (e) => {
4814
- const val = e.target.value;
4815
- setColumnFilters((prev) => {
4816
- const next = __spreadValues({}, prev);
4817
- if (val) next[col.name] = val;
4818
- else delete next[col.name];
4819
- return next;
4820
- });
4821
- },
4822
- onKeyDown: (e) => {
4823
- if (e.key === "Escape" || e.key === "Enter") {
4824
- setActiveSearchCol(null);
4825
- }
4826
- },
4827
- className: "h-7 text-xs px-1.5 w-full rounded border border-blue-400 bg-white text-slate-800 focus:outline-none focus:ring-1 focus:ring-blue-400 cursor-pointer truncate",
4828
- children: [
4829
- /* @__PURE__ */ jsx10("option", { value: "", children: "\u05D4\u05DB\u05DC" }),
4830
- getUniqueRelationOptions(col).map((opt) => /* @__PURE__ */ jsx10("option", { value: opt.label, children: opt.label }, opt.id))
4831
- ]
4832
- }
4833
- ) }) : /* @__PURE__ */ jsx10("div", { className: "relative flex items-center w-full min-w-0", children: /* @__PURE__ */ jsx10(
5687
+ /* @__PURE__ */ jsx11("div", { className: "relative flex items-center w-full min-w-0", children: /* @__PURE__ */ jsx11(
4834
5688
  "input",
4835
5689
  {
4836
5690
  autoFocus: true,
4837
5691
  type: "text",
4838
5692
  placeholder: `\u05D7\u05E4\u05E9 \u05D1-${col.name}...`,
4839
- value: filterVal,
5693
+ value: typeof filterVal === "string" ? filterVal : "",
4840
5694
  onChange: (e) => {
4841
- const val = e.target.value;
4842
- setColumnFilters((prev) => {
4843
- const next = __spreadValues({}, prev);
4844
- if (val) next[col.name] = val;
4845
- else delete next[col.name];
4846
- return next;
4847
- });
5695
+ handleApplyColumnFilter(col.name, e.target.value);
4848
5696
  },
4849
5697
  onKeyDown: (e) => {
4850
5698
  if (e.key === "Escape" || e.key === "Enter") {
@@ -4854,7 +5702,7 @@ function TableBlockClient({
4854
5702
  className: "h-7 text-xs px-2 w-full rounded border border-blue-400 bg-white text-slate-800 focus:outline-none focus:ring-1 focus:ring-blue-400"
4855
5703
  }
4856
5704
  ) }),
4857
- /* @__PURE__ */ jsx10(
5705
+ /* @__PURE__ */ jsx11(
4858
5706
  "button",
4859
5707
  {
4860
5708
  type: "button",
@@ -4864,59 +5712,62 @@ function TableBlockClient({
4864
5712
  },
4865
5713
  onClick: (e) => {
4866
5714
  e.stopPropagation();
4867
- setColumnFilters((prev) => {
4868
- const next = __spreadValues({}, prev);
4869
- delete next[col.name];
4870
- return next;
4871
- });
5715
+ handleApplyColumnFilter(col.name, void 0);
4872
5716
  setActiveSearchCol(null);
4873
5717
  },
4874
5718
  className: "p-1 text-slate-400 hover:text-slate-700 hover:bg-slate-200/70 rounded transition-colors cursor-pointer shrink-0",
4875
5719
  title: "\u05E0\u05E7\u05D4 \u05D5\u05E1\u05D2\u05D5\u05E8 \u05D7\u05D9\u05E4\u05D5\u05E9",
4876
- children: /* @__PURE__ */ jsx10(X7, { className: "w-3.5 h-3.5" })
5720
+ children: /* @__PURE__ */ jsx11(X8, { className: "w-3.5 h-3.5" })
4877
5721
  }
4878
5722
  )
4879
5723
  ]
4880
5724
  }
4881
- ) : /* @__PURE__ */ jsxs10("div", { className: "flex items-center justify-between gap-1.5 group overflow-hidden w-full", title: col.name, children: [
4882
- /* @__PURE__ */ jsx10("div", { className: "flex items-center gap-1.5 min-w-0 flex-1 overflow-hidden", children: /* @__PURE__ */ jsx10(ColumnHeaderTitle, { name: col.name, width: currentWidth, isSubTable: false }) }),
4883
- /* @__PURE__ */ jsxs10("div", { className: "flex items-center gap-1 shrink-0", children: [
4884
- ((_b = col.type) == null ? void 0 : _b.toUpperCase()) !== "SUB_TABLE" && /* @__PURE__ */ jsx10(
4885
- "button",
4886
- {
4887
- type: "button",
4888
- onClick: (e) => {
4889
- e.stopPropagation();
4890
- e.preventDefault();
5725
+ ) : /* @__PURE__ */ jsxs11("div", { className: "flex flex-col items-center justify-center w-full h-full min-w-0 select-none py-0.5", title: col.name, children: [
5726
+ ((_b = col.type) == null ? void 0 : _b.toUpperCase()) !== "SUB_TABLE" && /* @__PURE__ */ jsx11(
5727
+ "button",
5728
+ {
5729
+ ref: (el) => {
5730
+ filterButtonRefs.current[col.name] = el;
5731
+ },
5732
+ type: "button",
5733
+ onClick: (e) => {
5734
+ e.stopPropagation();
5735
+ e.preventDefault();
5736
+ if (isRelation) {
5737
+ if (activeRelationCol === col.name) {
5738
+ setActiveRelationCol(null);
5739
+ setRelationTriggerRect(null);
5740
+ } else {
5741
+ const btn = filterButtonRefs.current[col.name];
5742
+ if (btn) {
5743
+ setRelationTriggerRect(btn.getBoundingClientRect());
5744
+ }
5745
+ setActiveRelationCol(col.name);
5746
+ if (!relationOptions[col.name] || relationOptions[col.name].length < 100) {
5747
+ refetchRelation(col.name, { take: 1e3 });
5748
+ }
5749
+ }
5750
+ } else {
4891
5751
  setActiveSearchCol(col.name);
4892
- },
4893
- className: `p-1 rounded transition-all cursor-pointer ${filterVal ? "opacity-100 text-blue-600 bg-blue-100 hover:bg-blue-200" : "opacity-0 group-hover:opacity-100 text-slate-400 hover:text-slate-600 hover:bg-slate-200/60"}`,
4894
- title: filterVal ? `\u05DE\u05E1\u05D5\u05E0\u05DF \u05DC\u05E4\u05D9: "${filterVal}" (\u05DC\u05D7\u05E5 \u05DC\u05E2\u05E8\u05D9\u05DB\u05D4)` : "\u05D7\u05E4\u05E9 \u05D5\u05E1\u05E0\u05DF \u05D1\u05E2\u05DE\u05D5\u05D3\u05D4 \u05D6\u05D5",
4895
- children: /* @__PURE__ */ jsx10(Search2, { className: "w-3.5 h-3.5" })
4896
- }
4897
- ),
4898
- /* @__PURE__ */ jsx10(
4899
- "svg",
4900
- {
4901
- className: "w-3.5 h-3.5 text-slate-400 opacity-40 group-hover:opacity-100 transition-opacity shrink-0 cursor-grab",
4902
- fill: "none",
4903
- viewBox: "0 0 24 24",
4904
- stroke: "currentColor",
4905
- children: /* @__PURE__ */ jsx10("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M8 9h.01M8 15h.01M16 9h.01M16 15h.01" })
4906
- }
4907
- )
4908
- ] })
5752
+ }
5753
+ },
5754
+ className: `p-0.5 rounded transition-colors cursor-pointer mb-0.5 shrink-0 ${hasActiveFilter ? "opacity-100 text-blue-600 bg-blue-100 hover:bg-blue-200" : activeRelationCol === col.name ? "opacity-100 text-blue-600 bg-blue-100" : "opacity-0 group-hover:opacity-100 text-slate-400 hover:text-slate-600 hover:bg-slate-200/60"}`,
5755
+ title: filterTooltip,
5756
+ children: /* @__PURE__ */ jsx11(Filter, { className: "w-3 h-3" })
5757
+ }
5758
+ ),
5759
+ /* @__PURE__ */ jsx11(ColumnHeaderTitle, { name: col.name, width: currentWidth, isSubTable: false })
4909
5760
  ] })
4910
5761
  ]
4911
5762
  }),
4912
5763
  col.name
4913
5764
  );
4914
5765
  }),
4915
- /* @__PURE__ */ jsx10("th", { className: "w-full min-w-[50px] border-b border-slate-200 pointer-events-none h-12 min-h-[48px]" })
5766
+ /* @__PURE__ */ jsx11("th", { className: "w-full min-w-[50px] border-b border-slate-200 pointer-events-none h-12 min-h-[48px] bg-white" })
4916
5767
  ] }) }),
4917
- /* @__PURE__ */ jsx10("tbody", { className: "bg-white", children: (isStateEmpty || filteredData.length === 0) && !isLoading ? /* @__PURE__ */ jsx10("tr", { children: /* @__PURE__ */ jsx10("td", { colSpan: filteredColumns.length + 2, className: "text-center py-12 text-slate-400", children: /* @__PURE__ */ jsxs10("div", { className: "flex flex-col items-center justify-center gap-2", children: [
4918
- /* @__PURE__ */ jsx10("svg", { className: "w-8 h-8 text-slate-300", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx10("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "1.5", d: "M20 13V6a2 2 0 00-2-2H6a2 2 0 00-2 2v7m16 0v5a2 2 0 01-2 2H6a2 2 0 01-2-2v-5m16 0h-2.586a1 1 0 00-.707.293l-2.414 2.414a1 1 0 01-.707.293h-3.172a1 1 0 01-.707-.293l-2.414-2.414A1 1 0 006.586 13H4" }) }),
4919
- /* @__PURE__ */ jsx10("span", { children: "\u05D0\u05D9\u05DF \u05E8\u05E9\u05D5\u05DE\u05D5\u05EA \u05DC\u05D4\u05E6\u05D2\u05D4." })
5768
+ /* @__PURE__ */ jsx11("tbody", { className: `bg-white transition-opacity duration-150 ${isFetching ? "opacity-50 pointer-events-none" : "opacity-100"}`, children: (isStateEmpty || filteredData.length === 0) && !isLoading && !isFetching ? /* @__PURE__ */ jsx11("tr", { children: /* @__PURE__ */ jsx11("td", { colSpan: filteredColumns.length + 2, className: "text-center py-12 text-slate-400", children: /* @__PURE__ */ jsxs11("div", { className: "flex flex-col items-center justify-center gap-2", children: [
5769
+ /* @__PURE__ */ jsx11("svg", { className: "w-8 h-8 text-slate-300", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx11("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "1.5", d: "M20 13V6a2 2 0 00-2-2H6a2 2 0 00-2 2v7m16 0v5a2 2 0 01-2 2H6a2 2 0 01-2-2v-5m16 0h-2.586a1 1 0 00-.707.293l-2.414 2.414a1 1 0 01-.707.293h-3.172a1 1 0 01-.707-.293l-2.414-2.414A1 1 0 006.586 13H4" }) }),
5770
+ /* @__PURE__ */ jsx11("span", { children: "\u05D0\u05D9\u05DF \u05E8\u05E9\u05D5\u05DE\u05D5\u05EA \u05DC\u05D4\u05E6\u05D2\u05D4." })
4920
5771
  ] }) }) }) : filteredData.map((row) => {
4921
5772
  const hasSubTableCols = filteredColumns.some((c) => {
4922
5773
  var _a;
@@ -4927,10 +5778,10 @@ function TableBlockClient({
4927
5778
  var _a;
4928
5779
  return ((_a = c.type) == null ? void 0 : _a.toUpperCase()) === "SUB_TABLE";
4929
5780
  });
4930
- return /* @__PURE__ */ jsxs10(React9.Fragment, { children: [
4931
- /* @__PURE__ */ jsxs10("tr", { className: "hover:bg-blue-50/30 transition-colors group", children: [
4932
- /* @__PURE__ */ jsx10("td", { className: "border-b border-l border-slate-200 p-1.5 text-center bg-white group-hover:bg-transparent", style: { width: 72, minWidth: 72, maxWidth: 72 }, children: /* @__PURE__ */ jsxs10("div", { className: "flex items-center justify-center gap-1.5", children: [
4933
- /* @__PURE__ */ jsx10(
5781
+ return /* @__PURE__ */ jsxs11(React11.Fragment, { children: [
5782
+ /* @__PURE__ */ jsxs11("tr", { className: "hover:bg-blue-50/30 transition-colors group", children: [
5783
+ /* @__PURE__ */ jsx11("td", { className: "border-b border-l border-slate-200 p-1.5 text-center bg-white group-hover:bg-transparent", style: { width: 72, minWidth: 72, maxWidth: 72 }, children: /* @__PURE__ */ jsxs11("div", { className: "flex items-center justify-center gap-1.5", children: [
5784
+ /* @__PURE__ */ jsx11(
4934
5785
  "input",
4935
5786
  {
4936
5787
  type: "checkbox",
@@ -4940,7 +5791,7 @@ function TableBlockClient({
4940
5791
  className: "w-4 h-4 rounded border-slate-300 text-brand"
4941
5792
  }
4942
5793
  ),
4943
- hasSubTableCols && /* @__PURE__ */ jsx10(
5794
+ hasSubTableCols && /* @__PURE__ */ jsx11(
4944
5795
  "button",
4945
5796
  {
4946
5797
  type: "button",
@@ -4952,7 +5803,7 @@ function TableBlockClient({
4952
5803
  }),
4953
5804
  className: "w-5 h-5 rounded-full bg-slate-500 hover:bg-slate-600 text-white flex items-center justify-center transition-colors cursor-pointer shrink-0 shadow-sm",
4954
5805
  title: isExpanded ? "\u05E1\u05D2\u05D5\u05E8 \u05EA\u05EA-\u05D8\u05D1\u05DC\u05D4" : "\u05E4\u05EA\u05D7 \u05EA\u05EA-\u05D8\u05D1\u05DC\u05D4",
4955
- children: /* @__PURE__ */ jsx10("svg", { className: `w-3 h-3 transition-transform duration-150 ${isExpanded ? "rotate-90" : "rotate-180"}`, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx10("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "3", d: "M9 5l7 7-7 7" }) })
5806
+ children: /* @__PURE__ */ jsx11("svg", { className: `w-3 h-3 transition-transform duration-150 ${isExpanded ? "rotate-90" : "rotate-180"}`, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx11("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "3", d: "M9 5l7 7-7 7" }) })
4956
5807
  }
4957
5808
  )
4958
5809
  ] }) }),
@@ -4970,12 +5821,12 @@ function TableBlockClient({
4970
5821
  }
4971
5822
  }
4972
5823
  if (value === void 0) value = null;
4973
- return /* @__PURE__ */ jsx10(
5824
+ return /* @__PURE__ */ jsx11(
4974
5825
  "td",
4975
5826
  {
4976
5827
  className: `border-b border-l border-slate-200 p-0 relative ${colType === "RELATION" ? "overflow-visible" : "overflow-hidden"}`,
4977
5828
  style: { width: currentWidth, minWidth: currentWidth, maxWidth: currentWidth },
4978
- children: /* @__PURE__ */ jsx10(
5829
+ children: /* @__PURE__ */ jsx11(
4979
5830
  InputComponent,
4980
5831
  {
4981
5832
  value,
@@ -4987,6 +5838,7 @@ function TableBlockClient({
4987
5838
  tableId: (schema == null ? void 0 : schema.tableMetaId) || (schema == null ? void 0 : schema.tableId) || (schema == null ? void 0 : schema.id),
4988
5839
  onMarkForDeletion: (fileId) => setPendingDeletions((prev) => [...prev, fileId]),
4989
5840
  relationOptions,
5841
+ relationDictionaryRef,
4990
5842
  refetchRelation,
4991
5843
  executeAction,
4992
5844
  emitEvent,
@@ -5003,9 +5855,9 @@ function TableBlockClient({
5003
5855
  col.name
5004
5856
  );
5005
5857
  }),
5006
- /* @__PURE__ */ jsx10("td", { className: "border-b border-slate-200 bg-white pointer-events-none" })
5858
+ /* @__PURE__ */ jsx11("td", { className: "border-b border-slate-200 bg-white pointer-events-none" })
5007
5859
  ] }),
5008
- isExpanded && /* @__PURE__ */ jsx10(
5860
+ isExpanded && /* @__PURE__ */ jsx11(
5009
5861
  ExpandedSubTables,
5010
5862
  {
5011
5863
  rowId: row.id,
@@ -5027,8 +5879,8 @@ function TableBlockClient({
5027
5879
  )
5028
5880
  ] }, row.id);
5029
5881
  }) }),
5030
- showSummary && filteredData.length > 0 && /* @__PURE__ */ jsx10("tfoot", { className: "bg-slate-50 border-t-2 border-slate-300 sticky bottom-0 z-10 shadow-[0_-2px_4px_rgba(0,0,0,0.02)]", children: /* @__PURE__ */ jsxs10("tr", { children: [
5031
- /* @__PURE__ */ jsx10("td", { className: "border-b border-l border-slate-200 p-1.5 text-center font-bold text-slate-600 text-xs", children: '\u05E1\u05D4"\u05DB' }),
5882
+ showSummary && filteredData.length > 0 && /* @__PURE__ */ jsx11("tfoot", { className: "bg-slate-50 border-t-2 border-slate-300 sticky bottom-0 z-10 shadow-[0_-2px_4px_rgba(0,0,0,0.02)]", children: /* @__PURE__ */ jsxs11("tr", { children: [
5883
+ /* @__PURE__ */ jsx11("td", { className: "border-b border-l border-slate-200 p-1.5 text-center font-bold text-slate-600 text-xs", children: '\u05E1\u05D4"\u05DB' }),
5032
5884
  filteredColumns.map((col) => {
5033
5885
  var _a, _b;
5034
5886
  const typeUpper = (_a = col.type) == null ? void 0 : _a.toUpperCase();
@@ -5042,16 +5894,16 @@ function TableBlockClient({
5042
5894
  displayVal = symbol ? `${symbol} ${displayVal}` : displayVal;
5043
5895
  }
5044
5896
  }
5045
- return /* @__PURE__ */ jsx10("td", { className: "border-b border-l border-slate-200 p-2 text-sm font-semibold text-slate-700 bg-slate-50 relative", children: isNumeric && /* @__PURE__ */ jsx10("div", { className: "flex items-center text-right justify-start", children: /* @__PURE__ */ jsx10("span", { className: "truncate", children: displayVal }) }) }, col.name);
5897
+ return /* @__PURE__ */ jsx11("td", { className: "border-b border-l border-slate-200 p-2 text-sm font-semibold text-slate-700 bg-slate-50 relative", children: isNumeric && /* @__PURE__ */ jsx11("div", { className: "flex items-center text-right justify-start", children: /* @__PURE__ */ jsx11("span", { className: "truncate", children: displayVal }) }) }, col.name);
5046
5898
  }),
5047
- /* @__PURE__ */ jsx10("td", { className: "border-b border-slate-200 bg-slate-50 pointer-events-none" })
5899
+ /* @__PURE__ */ jsx11("td", { className: "border-b border-slate-200 bg-slate-50 pointer-events-none" })
5048
5900
  ] }) })
5049
5901
  ] })
5050
5902
  ] }),
5051
- /* @__PURE__ */ jsxs10("div", { className: "flex flex-col sm:flex-row items-center justify-between gap-3 px-4 py-3 bg-slate-50 border-t border-slate-200 text-xs text-slate-600 rounded-b-xl", children: [
5052
- /* @__PURE__ */ jsxs10("div", { className: "flex items-center gap-2", children: [
5053
- /* @__PURE__ */ jsx10("span", { className: "font-medium text-slate-700", children: "\u05E9\u05D5\u05E8\u05D5\u05EA \u05DC\u05E2\u05DE\u05D5\u05D3:" }),
5054
- /* @__PURE__ */ jsxs10(
5903
+ /* @__PURE__ */ jsxs11("div", { className: "flex flex-col sm:flex-row items-center justify-between gap-3 px-4 py-3 bg-slate-50 border-t border-slate-200 text-xs text-slate-600 rounded-b-xl shrink-0", children: [
5904
+ /* @__PURE__ */ jsxs11("div", { className: "flex items-center gap-2", children: [
5905
+ /* @__PURE__ */ jsx11("span", { className: "font-medium text-slate-700", children: "\u05E9\u05D5\u05E8\u05D5\u05EA \u05DC\u05E2\u05DE\u05D5\u05D3:" }),
5906
+ /* @__PURE__ */ jsxs11(
5055
5907
  "select",
5056
5908
  {
5057
5909
  value: limit,
@@ -5059,27 +5911,27 @@ function TableBlockClient({
5059
5911
  disabled: isLoading || isUpdatingActive,
5060
5912
  className: "bg-white border border-slate-300 rounded-lg px-2.5 py-1 text-slate-700 font-semibold shadow-2xs cursor-pointer focus:outline-none focus:ring-2 focus:ring-brand disabled:opacity-50",
5061
5913
  children: [
5062
- /* @__PURE__ */ jsx10("option", { value: 20, children: "20" }),
5063
- /* @__PURE__ */ jsx10("option", { value: 50, children: "50" }),
5064
- /* @__PURE__ */ jsx10("option", { value: 100, children: "100" })
5914
+ /* @__PURE__ */ jsx11("option", { value: 20, children: "20" }),
5915
+ /* @__PURE__ */ jsx11("option", { value: 50, children: "50" }),
5916
+ /* @__PURE__ */ jsx11("option", { value: 100, children: "100" })
5065
5917
  ]
5066
5918
  }
5067
5919
  )
5068
5920
  ] }),
5069
- /* @__PURE__ */ jsxs10("div", { className: "flex items-center gap-4", children: [
5070
- /* @__PURE__ */ jsxs10("span", { className: "font-medium text-slate-600", children: [
5921
+ /* @__PURE__ */ jsxs11("div", { className: "flex items-center gap-4", children: [
5922
+ /* @__PURE__ */ jsxs11("span", { className: "font-medium text-slate-600", children: [
5071
5923
  "\u05E2\u05DE\u05D5\u05D3 ",
5072
- /* @__PURE__ */ jsx10("strong", { className: "text-slate-900", children: page }),
5924
+ /* @__PURE__ */ jsx11("strong", { className: "text-slate-900", children: page }),
5073
5925
  " \u05DE\u05EA\u05D5\u05DA ",
5074
- /* @__PURE__ */ jsx10("strong", { className: "text-slate-900", children: totalPages || 1 }),
5075
- totalRecords > 0 && /* @__PURE__ */ jsxs10("span", { className: "text-slate-500 font-normal", children: [
5926
+ /* @__PURE__ */ jsx11("strong", { className: "text-slate-900", children: totalPages || 1 }),
5927
+ totalRecords > 0 && /* @__PURE__ */ jsxs11("span", { className: "text-slate-500 font-normal", children: [
5076
5928
  " (",
5077
5929
  totalRecords,
5078
5930
  ' \u05E8\u05E9\u05D5\u05DE\u05D5\u05EA \u05D1\u05E1\u05D4"\u05DB)'
5079
5931
  ] })
5080
5932
  ] }),
5081
- /* @__PURE__ */ jsxs10("div", { className: "flex items-center gap-1.5", children: [
5082
- /* @__PURE__ */ jsx10(
5933
+ /* @__PURE__ */ jsxs11("div", { className: "flex items-center gap-1.5", children: [
5934
+ /* @__PURE__ */ jsx11(
5083
5935
  "button",
5084
5936
  {
5085
5937
  onClick: handlePrevPage,
@@ -5089,7 +5941,7 @@ function TableBlockClient({
5089
5941
  children: "\u05D4\u05E7\u05D5\u05D3\u05DD"
5090
5942
  }
5091
5943
  ),
5092
- /* @__PURE__ */ jsx10(
5944
+ /* @__PURE__ */ jsx11(
5093
5945
  "button",
5094
5946
  {
5095
5947
  onClick: handleNextPage,
@@ -5101,7 +5953,30 @@ function TableBlockClient({
5101
5953
  )
5102
5954
  ] })
5103
5955
  ] })
5104
- ] })
5956
+ ] }),
5957
+ activeRelationCol && (() => {
5958
+ const activeColDef = filteredColumns.find((c) => c.name === activeRelationCol);
5959
+ if (!activeColDef) return null;
5960
+ const rawSelected = columnFilters[activeRelationCol];
5961
+ const currentSelected = typeof rawSelected === "object" && rawSelected !== null ? rawSelected : void 0;
5962
+ return /* @__PURE__ */ jsx11(
5963
+ RelationFilterPopover,
5964
+ {
5965
+ isOpen: Boolean(activeRelationCol),
5966
+ onClose: () => {
5967
+ setActiveRelationCol(null);
5968
+ setRelationTriggerRect(null);
5969
+ },
5970
+ column: activeColDef,
5971
+ triggerRect: relationTriggerRect,
5972
+ options: getUniqueRelationOptions(activeColDef),
5973
+ filterValue: currentSelected,
5974
+ onSelectionChange: (newSelected) => {
5975
+ handleApplyColumnFilter(activeRelationCol, newSelected);
5976
+ }
5977
+ }
5978
+ );
5979
+ })()
5105
5980
  ]
5106
5981
  }
5107
5982
  );
@@ -5115,11 +5990,11 @@ function ExpandedSubTables({
5115
5990
  context
5116
5991
  }) {
5117
5992
  var _a;
5118
- const [activeTab, setActiveTab] = useState10((_a = subTableColumns[0]) == null ? void 0 : _a.name);
5993
+ const [activeTab, setActiveTab] = useState12((_a = subTableColumns[0]) == null ? void 0 : _a.name);
5119
5994
  if (subTableColumns.length === 0) return null;
5120
5995
  if (subTableColumns.length === 1) {
5121
5996
  const stCol = subTableColumns[0];
5122
- return /* @__PURE__ */ jsx10("tr", { children: /* @__PURE__ */ jsx10("td", { colSpan: filteredColumnsLength + 2, className: "p-0 border-b border-slate-200 bg-slate-50/50", children: /* @__PURE__ */ jsx10(
5997
+ return /* @__PURE__ */ jsx11("tr", { children: /* @__PURE__ */ jsx11("td", { colSpan: filteredColumnsLength + 2, className: "p-0 border-b border-slate-200 bg-slate-50/50", children: /* @__PURE__ */ jsx11(
5123
5998
  SubTableViewer,
5124
5999
  {
5125
6000
  rowId,
@@ -5131,8 +6006,8 @@ function ExpandedSubTables({
5131
6006
  ) }) });
5132
6007
  }
5133
6008
  const activeCol = subTableColumns.find((c) => c.name === activeTab) || subTableColumns[0];
5134
- return /* @__PURE__ */ jsx10("tr", { children: /* @__PURE__ */ jsxs10("td", { colSpan: filteredColumnsLength + 2, className: "p-0 border-b border-slate-200 bg-slate-50/50 overflow-hidden", children: [
5135
- /* @__PURE__ */ jsx10("div", { className: "flex border-b border-slate-200 bg-slate-100/50 px-2 pt-2 gap-1 overflow-hidden", children: subTableColumns.map((col) => /* @__PURE__ */ jsx10(
6009
+ return /* @__PURE__ */ jsx11("tr", { children: /* @__PURE__ */ jsxs11("td", { colSpan: filteredColumnsLength + 2, className: "p-0 border-b border-slate-200 bg-slate-50/50 overflow-hidden", children: [
6010
+ /* @__PURE__ */ jsx11("div", { className: "flex border-b border-slate-200 bg-slate-100/50 px-2 pt-2 gap-1 overflow-hidden", children: subTableColumns.map((col) => /* @__PURE__ */ jsx11(
5136
6011
  "button",
5137
6012
  {
5138
6013
  type: "button",
@@ -5142,7 +6017,7 @@ function ExpandedSubTables({
5142
6017
  },
5143
6018
  col.name
5144
6019
  )) }),
5145
- /* @__PURE__ */ jsx10("div", { className: "bg-white", children: /* @__PURE__ */ jsx10(
6020
+ /* @__PURE__ */ jsx11("div", { className: "bg-white", children: /* @__PURE__ */ jsx11(
5146
6021
  SubTableViewer,
5147
6022
  {
5148
6023
  rowId,
@@ -5157,9 +6032,9 @@ function ExpandedSubTables({
5157
6032
  }
5158
6033
 
5159
6034
  // src/components/TableBlock/TableBlock.tsx
5160
- import { jsx as jsx11 } from "react/jsx-runtime";
6035
+ import { jsx as jsx12 } from "react/jsx-runtime";
5161
6036
  function TableBlock(props) {
5162
- return /* @__PURE__ */ jsx11(TableBlockClient, __spreadValues({}, props));
6037
+ return /* @__PURE__ */ jsx12(TableBlockClient, __spreadValues({}, props));
5163
6038
  }
5164
6039
 
5165
6040
  // src/registry.ts
@@ -5175,6 +6050,7 @@ export {
5175
6050
  DatePickerCell,
5176
6051
  LinkPickerCell,
5177
6052
  PASTEL_PALETTES,
6053
+ RelationFilterPopover,
5178
6054
  RelationPickerCell,
5179
6055
  TEXT_REPRESENTABLE_TYPES,
5180
6056
  TableBlock,