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

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.js CHANGED
@@ -68,6 +68,7 @@ __export(src_exports, {
68
68
  DatePickerCell: () => DatePickerCell,
69
69
  LinkPickerCell: () => LinkPickerCell,
70
70
  PASTEL_PALETTES: () => PASTEL_PALETTES,
71
+ RelationFilterPopover: () => RelationFilterPopover,
71
72
  RelationPickerCell: () => RelationPickerCell,
72
73
  TEXT_REPRESENTABLE_TYPES: () => TEXT_REPRESENTABLE_TYPES,
73
74
  TableBlock: () => TableBlock,
@@ -224,7 +225,7 @@ var COLUMN_DEFAULT_INPUT_CONFIG = {
224
225
  NUMBER: { inputType: "number", placeholder: "\u05D4\u05D6\u05DF \u05DE\u05E1\u05E4\u05E8" },
225
226
  BOOLEAN: { inputType: "select" },
226
227
  DATE: { inputType: "date" },
227
- RELATION: { inputType: "text", placeholder: "\u05D4\u05D6\u05DF \u05E2\u05E8\u05DA \u05EA\u05E6\u05D5\u05D2\u05D4" },
228
+ RELATION: { inputType: "select", placeholder: "\u05D1\u05D7\u05E8 \u05E8\u05E9\u05D5\u05DE\u05D4 \u05DB\u05D1\u05E8\u05D9\u05E8\u05EA \u05DE\u05D7\u05D3\u05DC" },
228
229
  GOOGLE_DRIVE_FILE: { inputType: "text" },
229
230
  CURRENCY: { inputType: "number", placeholder: "\u05D4\u05D6\u05DF \u05DE\u05E1\u05E4\u05E8" },
230
231
  TIME: { inputType: "time" },
@@ -235,7 +236,7 @@ var COLUMN_DEFAULT_INPUT_CONFIG = {
235
236
  };
236
237
 
237
238
  // src/components/TableBlock/TableBlockClient.tsx
238
- var import_react12 = __toESM(require("react"));
239
+ var import_react14 = __toESM(require("react"));
239
240
 
240
241
  // src/hooks/useToast.ts
241
242
  var import_react2 = require("react");
@@ -1525,7 +1526,8 @@ function LinkPickerCell({ value, onChange, readOnly = false }) {
1525
1526
  }
1526
1527
 
1527
1528
  // src/components/TableBlock/fields/RelationPickerCell.tsx
1528
- var import_react7 = require("react");
1529
+ var import_react7 = __toESM(require("react"));
1530
+ var import_react_dom = require("react-dom");
1529
1531
  var import_lucide_react6 = require("lucide-react");
1530
1532
  var import_jsx_runtime6 = require("react/jsx-runtime");
1531
1533
  function isRawObjectId(str) {
@@ -1584,6 +1586,30 @@ function resolveRelationLabel(opt, column) {
1584
1586
  }
1585
1587
  return "";
1586
1588
  }
1589
+ var ITEM_HEIGHT = 35;
1590
+ var CONTAINER_HEIGHT = 200;
1591
+ var OVERSCAN = 5;
1592
+ var BATCH_SIZE = 50;
1593
+ var RelationPickerRow = import_react7.default.memo(function RelationPickerRow2({
1594
+ id,
1595
+ label,
1596
+ isSelected,
1597
+ onSelect,
1598
+ height
1599
+ }) {
1600
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
1601
+ "div",
1602
+ {
1603
+ onClick: () => onSelect(id),
1604
+ style: { height: `${height}px` },
1605
+ 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"}`,
1606
+ children: [
1607
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "truncate flex-1", children: label }),
1608
+ isSelected && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react6.Check, { className: "w-3.5 h-3.5 text-blue-600 shrink-0 mr-1" })
1609
+ ]
1610
+ }
1611
+ );
1612
+ });
1587
1613
  function RelationPickerCell({
1588
1614
  value,
1589
1615
  onChange,
@@ -1592,42 +1618,147 @@ function RelationPickerCell({
1592
1618
  rowId,
1593
1619
  readOnly = false
1594
1620
  }) {
1595
- var _a;
1621
+ var _a, _b, _c;
1596
1622
  const [isOpen, setIsOpen] = (0, import_react7.useState)(false);
1597
1623
  const [searchQuery, setSearchQuery] = (0, import_react7.useState)("");
1624
+ const [isRemoteSearching, setIsRemoteSearching] = (0, import_react7.useState)(false);
1625
+ const [isLoadingMore, setIsLoadingMore] = (0, import_react7.useState)(false);
1626
+ const [hasMore, setHasMore] = (0, import_react7.useState)(true);
1627
+ const [items, setItems] = (0, import_react7.useState)([]);
1628
+ const [skip, setSkip] = (0, import_react7.useState)(0);
1629
+ const [scrollTop, setScrollTop] = (0, import_react7.useState)(0);
1598
1630
  const containerRef = (0, import_react7.useRef)(null);
1631
+ const dropdownRef = (0, import_react7.useRef)(null);
1599
1632
  const searchInputRef = (0, import_react7.useRef)(null);
1633
+ const listContainerRef = (0, import_react7.useRef)(null);
1634
+ const sentinelRef = (0, import_react7.useRef)(null);
1635
+ const [dropdownCoords, setDropdownCoords] = (0, import_react7.useState)(null);
1636
+ const updateDropdownCoords = (0, import_react7.useCallback)(() => {
1637
+ if (!containerRef.current) return;
1638
+ const rect = containerRef.current.getBoundingClientRect();
1639
+ const dropdownHeight = 280;
1640
+ const dropdownWidth = Math.max(220, Math.min(320, rect.width || 220));
1641
+ let right = window.innerWidth - rect.right;
1642
+ if (right + dropdownWidth > window.innerWidth - 10) {
1643
+ right = window.innerWidth - dropdownWidth - 10;
1644
+ }
1645
+ if (right < 10) {
1646
+ right = 10;
1647
+ }
1648
+ const spaceBelow = window.innerHeight - rect.bottom;
1649
+ let top = rect.bottom + 4;
1650
+ if (spaceBelow < dropdownHeight && rect.top > dropdownHeight) {
1651
+ top = Math.max(10, rect.top - dropdownHeight - 4);
1652
+ } else {
1653
+ top = Math.min(window.innerHeight - dropdownHeight - 10, top);
1654
+ }
1655
+ setDropdownCoords({ top, right, width: dropdownWidth });
1656
+ }, []);
1657
+ (0, import_react7.useEffect)(() => {
1658
+ if (!isOpen) return;
1659
+ updateDropdownCoords();
1660
+ const handleScrollOrResize = () => updateDropdownCoords();
1661
+ window.addEventListener("scroll", handleScrollOrResize, true);
1662
+ window.addEventListener("resize", handleScrollOrResize);
1663
+ return () => {
1664
+ window.removeEventListener("scroll", handleScrollOrResize, true);
1665
+ window.removeEventListener("resize", handleScrollOrResize);
1666
+ };
1667
+ }, [isOpen, updateDropdownCoords]);
1668
+ const stableLabelCacheRef = (0, import_react7.useRef)(/* @__PURE__ */ new Map());
1669
+ const skipRef = (0, import_react7.useRef)(0);
1670
+ const isLoadingMoreRef = (0, import_react7.useRef)(false);
1600
1671
  const allowMultiple = Boolean((_a = column.config) == null ? void 0 : _a.allowMultiple);
1672
+ const referencedTableId = (_b = column.config) == null ? void 0 : _b.referencedTableId;
1673
+ const displayField = (_c = column.config) == null ? void 0 : _c.displayField;
1601
1674
  const selectedIds = (0, import_react7.useMemo)(() => normalizeRelationValue(value), [value]);
1602
1675
  const isStandalone = !context || context.relationOptions === void 0;
1603
1676
  const optionsLoaded = isStandalone || context.relationOptions[column.name] !== void 0;
1604
- const rawOptions = (0, import_react7.useMemo)(() => {
1677
+ const baseOptions = (0, import_react7.useMemo)(() => {
1605
1678
  var _a2;
1606
1679
  return ((_a2 = context == null ? void 0 : context.relationOptions) == null ? void 0 : _a2[column.name]) || [];
1607
1680
  }, [context == null ? void 0 : context.relationOptions, column.name]);
1608
1681
  const processedOptions = (0, import_react7.useMemo)(() => {
1609
- return rawOptions.map((opt) => {
1610
- const label = resolveRelationLabel(opt, column);
1611
- return {
1612
- id: String(opt.id),
1613
- _displayLabel: label
1614
- };
1615
- }).filter((opt) => opt._displayLabel && opt._displayLabel.trim() !== "" && !isRawObjectId(opt._displayLabel));
1616
- }, [rawOptions, column]);
1682
+ return items.map((opt) => ({
1683
+ id: String(opt.id),
1684
+ _displayLabel: resolveRelationLabel(opt, column) || opt.label || ""
1685
+ })).filter((opt) => opt._displayLabel && opt._displayLabel.trim() !== "" && !isRawObjectId(opt._displayLabel));
1686
+ }, [items, column]);
1617
1687
  const getDisplayForId = (0, import_react7.useCallback)((id) => {
1618
- const found = processedOptions.find((o) => String(o.id) === String(id));
1619
- if (found && found._displayLabel && !isRawObjectId(found._displayLabel)) {
1620
- return found._displayLabel;
1688
+ var _a2, _b2, _c2;
1689
+ if (!id) return "-";
1690
+ const strId = String(id).trim();
1691
+ if (!strId) return "-";
1692
+ if (stableLabelCacheRef.current.has(strId)) {
1693
+ const cached = stableLabelCacheRef.current.get(strId);
1694
+ if (cached && cached !== "-" && !isRawObjectId(cached)) {
1695
+ return cached;
1696
+ }
1697
+ }
1698
+ 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);
1699
+ if (dictOpt) {
1700
+ const lbl = resolveRelationLabel(dictOpt, column) || dictOpt.label || dictOpt.name;
1701
+ if (lbl && !isRawObjectId(String(lbl))) {
1702
+ stableLabelCacheRef.current.set(strId, String(lbl));
1703
+ return String(lbl);
1704
+ }
1705
+ }
1706
+ const foundInItems = items.find((o) => String(o.id) === strId);
1707
+ if (foundInItems) {
1708
+ const lbl = resolveRelationLabel(foundInItems, column) || foundInItems.label || foundInItems.name;
1709
+ if (lbl && !isRawObjectId(String(lbl))) {
1710
+ stableLabelCacheRef.current.set(strId, String(lbl));
1711
+ return String(lbl);
1712
+ }
1713
+ }
1714
+ const foundInBase = (baseOptions || []).find((o) => String(o.id) === strId);
1715
+ if (foundInBase) {
1716
+ const lbl = resolveRelationLabel(foundInBase, column) || foundInBase.label || foundInBase.name;
1717
+ if (lbl && !isRawObjectId(String(lbl))) {
1718
+ stableLabelCacheRef.current.set(strId, String(lbl));
1719
+ return String(lbl);
1720
+ }
1621
1721
  }
1622
1722
  return "-";
1623
- }, [processedOptions]);
1723
+ }, [items, baseOptions, column, context]);
1624
1724
  const handleOpen = (e) => {
1625
1725
  if (readOnly) return;
1626
1726
  e == null ? void 0 : e.stopPropagation();
1627
- setIsOpen((prev) => !prev);
1727
+ const nextOpen = !isOpen;
1728
+ if (nextOpen) {
1729
+ updateDropdownCoords();
1730
+ }
1731
+ setIsOpen(nextOpen);
1732
+ if (!nextOpen) return;
1628
1733
  setSearchQuery("");
1629
- if (context == null ? void 0 : context.refetchRelation) {
1630
- context.refetchRelation(column.name);
1734
+ setScrollTop(0);
1735
+ setSkip(0);
1736
+ skipRef.current = 0;
1737
+ setHasMore(true);
1738
+ 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;
1739
+ if (fetcher && referencedTableId) {
1740
+ setIsLoadingMore(true);
1741
+ isLoadingMoreRef.current = true;
1742
+ fetcher({
1743
+ referencedTableId,
1744
+ displayField,
1745
+ take: BATCH_SIZE,
1746
+ limit: BATCH_SIZE,
1747
+ skip: 0
1748
+ }).then((res) => {
1749
+ const newData = Array.isArray(res) ? res : (res == null ? void 0 : res.data) && Array.isArray(res.data) ? res.data : [];
1750
+ setItems(newData);
1751
+ setSkip(BATCH_SIZE);
1752
+ skipRef.current = BATCH_SIZE;
1753
+ if (newData.length < BATCH_SIZE) {
1754
+ setHasMore(false);
1755
+ }
1756
+ }).catch((err) => {
1757
+ console.warn("[RelationPickerCell] Initial fetch failed:", err);
1758
+ }).finally(() => {
1759
+ setIsLoadingMore(false);
1760
+ isLoadingMoreRef.current = false;
1761
+ });
1631
1762
  }
1632
1763
  };
1633
1764
  (0, import_react7.useEffect)(() => {
@@ -1638,7 +1769,105 @@ function RelationPickerCell({
1638
1769
  }, 50);
1639
1770
  }
1640
1771
  }, [isOpen]);
1641
- const handleSelectOption = (optId) => {
1772
+ (0, import_react7.useEffect)(() => {
1773
+ if (!isOpen) return;
1774
+ const query = searchQuery.trim();
1775
+ 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;
1776
+ if (!fetcher || !referencedTableId) return;
1777
+ setSkip(0);
1778
+ skipRef.current = 0;
1779
+ setHasMore(true);
1780
+ setScrollTop(0);
1781
+ if (listContainerRef.current) {
1782
+ listContainerRef.current.scrollTop = 0;
1783
+ }
1784
+ setIsRemoteSearching(true);
1785
+ const timer = setTimeout(() => {
1786
+ fetcher({
1787
+ referencedTableId,
1788
+ displayField,
1789
+ search: query,
1790
+ take: BATCH_SIZE,
1791
+ limit: BATCH_SIZE,
1792
+ skip: 0
1793
+ }).then((res) => {
1794
+ const newData = Array.isArray(res) ? res : (res == null ? void 0 : res.data) && Array.isArray(res.data) ? res.data : [];
1795
+ setItems(newData);
1796
+ setSkip(BATCH_SIZE);
1797
+ skipRef.current = BATCH_SIZE;
1798
+ if (newData.length < BATCH_SIZE) {
1799
+ setHasMore(false);
1800
+ }
1801
+ }).catch((err) => {
1802
+ console.warn("[RelationPickerCell] Remote search failed:", err);
1803
+ }).finally(() => {
1804
+ setIsRemoteSearching(false);
1805
+ });
1806
+ }, 250);
1807
+ return () => clearTimeout(timer);
1808
+ }, [searchQuery, isOpen, referencedTableId, displayField, context, column.name]);
1809
+ const handleLoadMore = (0, import_react7.useCallback)(async () => {
1810
+ if (isLoadingMoreRef.current || !hasMore || !referencedTableId) return;
1811
+ 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;
1812
+ if (!fetcher) return;
1813
+ isLoadingMoreRef.current = true;
1814
+ setIsLoadingMore(true);
1815
+ const currentQuery = searchQuery.trim();
1816
+ const currentSkip = skipRef.current;
1817
+ try {
1818
+ const res = await fetcher({
1819
+ referencedTableId,
1820
+ displayField,
1821
+ search: currentQuery,
1822
+ take: BATCH_SIZE,
1823
+ limit: BATCH_SIZE,
1824
+ skip: currentSkip
1825
+ });
1826
+ const newData = Array.isArray(res) ? res : (res == null ? void 0 : res.data) && Array.isArray(res.data) ? res.data : [];
1827
+ if (newData.length < BATCH_SIZE) {
1828
+ setHasMore(false);
1829
+ }
1830
+ if (newData.length > 0) {
1831
+ setItems((prev) => {
1832
+ const seen = new Set(prev.map((i) => String(i.id)));
1833
+ const unique = newData.filter((i) => !seen.has(String(i.id)));
1834
+ return [...prev, ...unique];
1835
+ });
1836
+ setSkip((prev) => prev + BATCH_SIZE);
1837
+ skipRef.current += BATCH_SIZE;
1838
+ }
1839
+ } catch (err) {
1840
+ console.warn("[RelationPickerCell] Load more failed:", err);
1841
+ } finally {
1842
+ isLoadingMoreRef.current = false;
1843
+ setIsLoadingMore(false);
1844
+ }
1845
+ }, [hasMore, referencedTableId, searchQuery, context, column.name, displayField]);
1846
+ (0, import_react7.useEffect)(() => {
1847
+ if (!isOpen || !hasMore) return;
1848
+ const sentinel = sentinelRef.current;
1849
+ if (!sentinel) return;
1850
+ const observer = new IntersectionObserver(
1851
+ (entries) => {
1852
+ var _a2;
1853
+ if (((_a2 = entries[0]) == null ? void 0 : _a2.isIntersecting) && !isLoadingMoreRef.current) {
1854
+ handleLoadMore();
1855
+ }
1856
+ },
1857
+ { root: listContainerRef.current, threshold: 0.1 }
1858
+ );
1859
+ observer.observe(sentinel);
1860
+ return () => observer.disconnect();
1861
+ }, [isOpen, hasMore, handleLoadMore]);
1862
+ const handleListScroll = (e) => {
1863
+ const currentScrollTop = e.currentTarget.scrollTop;
1864
+ setScrollTop(currentScrollTop);
1865
+ const { clientHeight, scrollHeight } = e.currentTarget;
1866
+ if (scrollHeight - (currentScrollTop + clientHeight) < 60 && hasMore && !isLoadingMoreRef.current) {
1867
+ handleLoadMore();
1868
+ }
1869
+ };
1870
+ const handleSelectOption = (0, import_react7.useCallback)((optId) => {
1642
1871
  if (!allowMultiple) {
1643
1872
  onChange([optId]);
1644
1873
  setIsOpen(false);
@@ -1649,7 +1878,7 @@ function RelationPickerCell({
1649
1878
  onChange([...selectedIds, optId]);
1650
1879
  }
1651
1880
  }
1652
- };
1881
+ }, [allowMultiple, onChange, selectedIds]);
1653
1882
  const handleRemove = (idToRemove) => {
1654
1883
  onChange(selectedIds.filter((id) => id !== idToRemove));
1655
1884
  };
@@ -1660,7 +1889,8 @@ function RelationPickerCell({
1660
1889
  (0, import_react7.useEffect)(() => {
1661
1890
  if (!isOpen) return;
1662
1891
  function handleClickOutside(event) {
1663
- if (containerRef.current && !containerRef.current.contains(event.target)) {
1892
+ const target = event.target;
1893
+ if (containerRef.current && !containerRef.current.contains(target) && dropdownRef.current && !dropdownRef.current.contains(target)) {
1664
1894
  setIsOpen(false);
1665
1895
  }
1666
1896
  }
@@ -1676,13 +1906,19 @@ function RelationPickerCell({
1676
1906
  document.removeEventListener("keydown", handleKeyDown);
1677
1907
  };
1678
1908
  }, [isOpen]);
1679
- const filteredOptions = (0, import_react7.useMemo)(() => {
1909
+ const displayedOptions = (0, import_react7.useMemo)(() => {
1680
1910
  const query = searchQuery.trim().toLowerCase();
1681
1911
  if (!query) return processedOptions;
1682
1912
  return processedOptions.filter((opt) => {
1683
1913
  return (opt._displayLabel || "").toLowerCase().includes(query);
1684
1914
  });
1685
1915
  }, [processedOptions, searchQuery]);
1916
+ const totalItems = displayedOptions.length;
1917
+ const totalHeight = totalItems * ITEM_HEIGHT;
1918
+ const startIndex = Math.max(0, Math.floor(scrollTop / ITEM_HEIGHT) - OVERSCAN);
1919
+ const endIndex = Math.min(totalItems, Math.ceil((scrollTop + CONTAINER_HEIGHT) / ITEM_HEIGHT) + OVERSCAN);
1920
+ const visibleOptions = displayedOptions.slice(startIndex, endIndex);
1921
+ const topPadding = startIndex * ITEM_HEIGHT;
1686
1922
  if (!optionsLoaded && selectedIds.length > 0) {
1687
1923
  return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "px-2 py-1 flex items-center h-full w-full", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "inline-block w-16 h-4 bg-slate-100 animate-pulse rounded" }) });
1688
1924
  }
@@ -1804,51 +2040,101 @@ function RelationPickerCell({
1804
2040
  )
1805
2041
  }
1806
2042
  ),
1807
- isOpen && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
1808
- "div",
1809
- {
1810
- id: `relation-dropdown-${column.name}-${rowId || "cell"}`,
1811
- dir: "rtl",
1812
- 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",
1813
- onClick: (e) => e.stopPropagation(),
1814
- children: [
1815
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "relative mb-1", children: [
1816
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react6.Search, { className: "w-3.5 h-3.5 text-slate-400 absolute right-2 top-2 pointer-events-none" }),
2043
+ isOpen && dropdownCoords && typeof document !== "undefined" && (0, import_react_dom.createPortal)(
2044
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
2045
+ "div",
2046
+ {
2047
+ ref: dropdownRef,
2048
+ id: `relation-dropdown-${column.name}-${rowId || "cell"}`,
2049
+ dir: "rtl",
2050
+ style: {
2051
+ position: "fixed",
2052
+ top: `${dropdownCoords.top}px`,
2053
+ right: `${dropdownCoords.right}px`,
2054
+ width: `${dropdownCoords.width}px`,
2055
+ zIndex: 99999
2056
+ },
2057
+ className: "bg-white rounded-md shadow-2xl border border-slate-200 p-1 animate-in fade-in duration-100 flex flex-col",
2058
+ onClick: (e) => e.stopPropagation(),
2059
+ onMouseDown: (e) => e.stopPropagation(),
2060
+ children: [
2061
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "relative mb-1", children: [
2062
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react6.Search, { className: "w-3.5 h-3.5 text-slate-400 absolute right-2 top-2 pointer-events-none" }),
2063
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2064
+ "input",
2065
+ {
2066
+ ref: searchInputRef,
2067
+ type: "text",
2068
+ placeholder: "\u05D7\u05E4\u05E9...",
2069
+ value: searchQuery,
2070
+ onChange: (e) => setSearchQuery(e.target.value),
2071
+ onKeyDown: (e) => {
2072
+ if (e.key === "Escape") {
2073
+ e.stopPropagation();
2074
+ setIsOpen(false);
2075
+ }
2076
+ },
2077
+ 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"
2078
+ }
2079
+ ),
2080
+ isRemoteSearching && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react6.Loader2, { className: "w-3.5 h-3.5 text-blue-500 animate-spin absolute left-2 top-2 pointer-events-none" })
2081
+ ] }),
1817
2082
  /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1818
- "input",
2083
+ "div",
1819
2084
  {
1820
- ref: searchInputRef,
1821
- type: "text",
1822
- placeholder: "\u05D7\u05E4\u05E9...",
1823
- value: searchQuery,
1824
- onChange: (e) => setSearchQuery(e.target.value),
1825
- onKeyDown: (e) => {
1826
- if (e.key === "Escape") {
1827
- e.stopPropagation();
1828
- setIsOpen(false);
1829
- }
1830
- },
1831
- 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"
2085
+ ref: listContainerRef,
2086
+ onScroll: handleListScroll,
2087
+ style: { maxHeight: `${CONTAINER_HEIGHT}px` },
2088
+ className: "overflow-y-auto relative",
2089
+ children: displayedOptions.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
2090
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: { height: `${totalHeight}px`, position: "relative", width: "100%" }, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2091
+ "div",
2092
+ {
2093
+ style: {
2094
+ position: "absolute",
2095
+ top: 0,
2096
+ left: 0,
2097
+ right: 0,
2098
+ transform: `translateY(${topPadding}px)`
2099
+ },
2100
+ children: visibleOptions.map((opt) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2101
+ RelationPickerRow,
2102
+ {
2103
+ id: opt.id,
2104
+ label: opt._displayLabel,
2105
+ isSelected: selectedIds.includes(opt.id),
2106
+ onSelect: handleSelectOption,
2107
+ height: ITEM_HEIGHT
2108
+ },
2109
+ opt.id
2110
+ ))
2111
+ }
2112
+ ) }),
2113
+ hasMore && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { ref: sentinelRef, className: "pt-1 pb-0.5 px-2 text-center", children: isLoadingMore ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex items-center justify-center gap-1.5 text-xs text-slate-400 py-1", children: [
2114
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react6.Loader2, { className: "w-3 h-3 text-blue-500 animate-spin shrink-0" }),
2115
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { children: "\u05D8\u05D5\u05E2\u05DF \u05E2\u05D5\u05D3 \u05E8\u05E9\u05D5\u05DE\u05D5\u05EA..." })
2116
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2117
+ "button",
2118
+ {
2119
+ type: "button",
2120
+ onClick: (e) => {
2121
+ e.stopPropagation();
2122
+ handleLoadMore();
2123
+ },
2124
+ className: "text-[11px] text-blue-600 hover:text-blue-700 hover:underline py-1 px-2 font-medium",
2125
+ children: "\u05D8\u05E2\u05DF \u05E2\u05D5\u05D3 \u05E8\u05E9\u05D5\u05DE\u05D5\u05EA..."
2126
+ }
2127
+ ) })
2128
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "py-2.5 px-2 text-center text-xs text-slate-400 select-none", children: isRemoteSearching ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex items-center justify-center gap-1.5 py-1", children: [
2129
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react6.Loader2, { className: "w-3 h-3 text-blue-500 animate-spin shrink-0" }),
2130
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { children: "\u05DE\u05D7\u05E4\u05E9 \u05E8\u05E9\u05D5\u05DE\u05D5\u05EA..." })
2131
+ ] }) : 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" })
1832
2132
  }
1833
2133
  )
1834
- ] }),
1835
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "overflow-y-auto max-h-[180px] space-y-0.5", children: filteredOptions.length > 0 ? filteredOptions.map((opt) => {
1836
- const isSelected = selectedIds.includes(opt.id);
1837
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
1838
- "div",
1839
- {
1840
- onClick: () => handleSelectOption(opt.id),
1841
- 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"}`,
1842
- children: [
1843
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "truncate flex-1", children: opt._displayLabel }),
1844
- isSelected && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react6.Check, { className: "w-3.5 h-3.5 text-blue-600 shrink-0 mr-1" })
1845
- ]
1846
- },
1847
- opt.id
1848
- );
1849
- }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("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" }) })
1850
- ]
1851
- }
2134
+ ]
2135
+ }
2136
+ ),
2137
+ document.body
1852
2138
  )
1853
2139
  ]
1854
2140
  }
@@ -2269,7 +2555,7 @@ var FORM_INPUTS = {
2269
2555
  };
2270
2556
 
2271
2557
  // src/components/TableBlock/fields/SubTableViewer.tsx
2272
- var import_react11 = require("react");
2558
+ var import_react12 = require("react");
2273
2559
 
2274
2560
  // src/utils/phone.ts
2275
2561
  function sanitizePhoneNumber(phone) {
@@ -2427,6 +2713,7 @@ function useColumnReorder({
2427
2713
  }
2428
2714
 
2429
2715
  // src/components/TableBlock/columnTitleUtils.tsx
2716
+ var import_react11 = require("react");
2430
2717
  var import_jsx_runtime8 = require("react/jsx-runtime");
2431
2718
  var canvas = null;
2432
2719
  function measureTextWidth(text, font = '600 14px system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif') {
@@ -2467,10 +2754,10 @@ function splitHeaderTitle(name) {
2467
2754
  }
2468
2755
  function calculateMinColumnWidth(name, isSubTable = false, colType) {
2469
2756
  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';
2470
- const chromeWidth = isSubTable ? 44 : 52;
2471
- let baseMin = isSubTable ? 50 : 60;
2757
+ const chromeWidth = isSubTable ? 24 : 26;
2758
+ let baseMin = isSubTable ? 30 : 36;
2472
2759
  if ((colType == null ? void 0 : colType.toUpperCase()) === "GOOGLE_CONTACT") {
2473
- baseMin = isSubTable ? 110 : 120;
2760
+ baseMin = isSubTable ? 100 : 110;
2474
2761
  }
2475
2762
  if (!name) return baseMin;
2476
2763
  const { isSingleWord, line1, line2 } = splitHeaderTitle(name);
@@ -2484,12 +2771,16 @@ function calculateMinColumnWidth(name, isSubTable = false, colType) {
2484
2771
  return Math.max(baseMin, Math.ceil(maxLine + chromeWidth));
2485
2772
  }
2486
2773
  function ColumnHeaderTitle({ name, width, isSubTable = false }) {
2774
+ const [isMounted, setIsMounted] = (0, import_react11.useState)(false);
2775
+ (0, import_react11.useEffect)(() => {
2776
+ setIsMounted(true);
2777
+ }, []);
2487
2778
  const { isSingleWord, line1, line2 } = splitHeaderTitle(name);
2488
- if (isSingleWord || !line2) {
2489
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "whitespace-nowrap select-none overflow-hidden text-right flex-1", title: name, children: line1 });
2779
+ if (!isMounted || isSingleWord || !line2) {
2780
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "whitespace-nowrap select-none overflow-hidden text-right flex-1", title: name, children: name });
2490
2781
  }
2491
2782
  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';
2492
- const chromeWidth = isSubTable ? 44 : 52;
2783
+ const chromeWidth = isSubTable ? 24 : 26;
2493
2784
  const fullTitleWidth = measureTextWidth(name, font) + chromeWidth;
2494
2785
  if (width !== void 0 && width >= fullTitleWidth) {
2495
2786
  return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "whitespace-nowrap select-none overflow-hidden text-right flex-1", title: name, children: name });
@@ -2623,18 +2914,18 @@ function SubTableCell({
2623
2914
  const isContact = colType === "GOOGLE_CONTACT";
2624
2915
  const InputComponent = FORM_INPUTS[colType] || FORM_INPUTS.DEFAULT;
2625
2916
  const serverValue = (_b = record.data[column.name]) != null ? _b : colType === "BOOLEAN" ? false : "";
2626
- const [draftValue, setDraftValue] = (0, import_react11.useState)(serverValue);
2627
- const [isDirty, setIsDirty] = (0, import_react11.useState)(false);
2628
- const [validationError, setValidationError] = (0, import_react11.useState)(null);
2629
- const cellRef = (0, import_react11.useRef)(null);
2630
- const draftRef = (0, import_react11.useRef)(draftValue);
2631
- const isDirtyRef = (0, import_react11.useRef)(isDirty);
2632
- const serverValueRef = (0, import_react11.useRef)(serverValue);
2633
- const recordIdRef = (0, import_react11.useRef)(record.id);
2634
- const columnRef = (0, import_react11.useRef)(column);
2635
- const onCommitRef = (0, import_react11.useRef)(onCommit);
2636
- const isCommittingRef = (0, import_react11.useRef)(false);
2637
- const lastFailedValRef = (0, import_react11.useRef)(void 0);
2917
+ const [draftValue, setDraftValue] = (0, import_react12.useState)(serverValue);
2918
+ const [isDirty, setIsDirty] = (0, import_react12.useState)(false);
2919
+ const [validationError, setValidationError] = (0, import_react12.useState)(null);
2920
+ const cellRef = (0, import_react12.useRef)(null);
2921
+ const draftRef = (0, import_react12.useRef)(draftValue);
2922
+ const isDirtyRef = (0, import_react12.useRef)(isDirty);
2923
+ const serverValueRef = (0, import_react12.useRef)(serverValue);
2924
+ const recordIdRef = (0, import_react12.useRef)(record.id);
2925
+ const columnRef = (0, import_react12.useRef)(column);
2926
+ const onCommitRef = (0, import_react12.useRef)(onCommit);
2927
+ const isCommittingRef = (0, import_react12.useRef)(false);
2928
+ const lastFailedValRef = (0, import_react12.useRef)(void 0);
2638
2929
  const { addToast } = useToast();
2639
2930
  draftRef.current = draftValue;
2640
2931
  isDirtyRef.current = isDirty;
@@ -2642,7 +2933,7 @@ function SubTableCell({
2642
2933
  recordIdRef.current = record.id;
2643
2934
  columnRef.current = column;
2644
2935
  onCommitRef.current = onCommit;
2645
- (0, import_react11.useEffect)(() => {
2936
+ (0, import_react12.useEffect)(() => {
2646
2937
  if (!isDirtyRef.current) {
2647
2938
  setDraftValue(serverValue);
2648
2939
  draftRef.current = serverValue;
@@ -2650,7 +2941,7 @@ function SubTableCell({
2650
2941
  lastFailedValRef.current = void 0;
2651
2942
  }
2652
2943
  }, [serverValue]);
2653
- const commit = (0, import_react11.useCallback)(async (valToCommit) => {
2944
+ const commit = (0, import_react12.useCallback)(async (valToCommit) => {
2654
2945
  if (isCommittingRef.current) return false;
2655
2946
  if (!isDirtyRef.current) return true;
2656
2947
  if (valToCommit === serverValueRef.current) {
@@ -2691,7 +2982,7 @@ function SubTableCell({
2691
2982
  isCommittingRef.current = false;
2692
2983
  }
2693
2984
  }, [addToast]);
2694
- const discard = (0, import_react11.useCallback)(() => {
2985
+ const discard = (0, import_react12.useCallback)(() => {
2695
2986
  setDraftValue(serverValueRef.current);
2696
2987
  draftRef.current = serverValueRef.current;
2697
2988
  setIsDirty(false);
@@ -2699,7 +2990,7 @@ function SubTableCell({
2699
2990
  setValidationError(null);
2700
2991
  lastFailedValRef.current = void 0;
2701
2992
  }, []);
2702
- (0, import_react11.useEffect)(() => {
2993
+ (0, import_react12.useEffect)(() => {
2703
2994
  return () => {
2704
2995
  if (isDirtyRef.current && !isCommittingRef.current) {
2705
2996
  const val = draftRef.current;
@@ -2801,7 +3092,7 @@ function SubTableViewer({ rowId, column, value, onChange, context }) {
2801
3092
  var _a, _b, _c, _d, _e, _f;
2802
3093
  const { addToast } = useToast();
2803
3094
  const entries = Array.isArray(value) ? value : [];
2804
- const [linkedRecords, setLinkedRecords] = (0, import_react11.useState)(() => {
3095
+ const [linkedRecords, setLinkedRecords] = (0, import_react12.useState)(() => {
2805
3096
  const initial = [];
2806
3097
  for (const entry of entries) {
2807
3098
  if (entry.recordId && entry._resolvedData) {
@@ -2810,25 +3101,25 @@ function SubTableViewer({ rowId, column, value, onChange, context }) {
2810
3101
  }
2811
3102
  return initial;
2812
3103
  });
2813
- const [targetSchema, setTargetSchema] = (0, import_react11.useState)(null);
2814
- const [isLoading, setIsLoading] = (0, import_react11.useState)(true);
2815
- const [isSearchOpen, setIsSearchOpen] = (0, import_react11.useState)(false);
2816
- const [searchQuery, setSearchQuery] = (0, import_react11.useState)("");
2817
- const [searchResults, setSearchResults] = (0, import_react11.useState)([]);
2818
- const [isSearching, setIsSearching] = (0, import_react11.useState)(false);
2819
- const [isCreating, setIsCreating] = (0, import_react11.useState)(false);
2820
- const [newRecordData, setNewRecordData] = (0, import_react11.useState)({});
2821
- const [conflictModalState, setConflictModalState] = (0, import_react11.useState)({
3104
+ const [targetSchema, setTargetSchema] = (0, import_react12.useState)(null);
3105
+ const [isLoading, setIsLoading] = (0, import_react12.useState)(true);
3106
+ const [isSearchOpen, setIsSearchOpen] = (0, import_react12.useState)(false);
3107
+ const [searchQuery, setSearchQuery] = (0, import_react12.useState)("");
3108
+ const [searchResults, setSearchResults] = (0, import_react12.useState)([]);
3109
+ const [isSearching, setIsSearching] = (0, import_react12.useState)(false);
3110
+ const [isCreating, setIsCreating] = (0, import_react12.useState)(false);
3111
+ const [newRecordData, setNewRecordData] = (0, import_react12.useState)({});
3112
+ const [conflictModalState, setConflictModalState] = (0, import_react12.useState)({
2822
3113
  isOpen: false,
2823
3114
  fieldName: "",
2824
3115
  matchingRecords: []
2825
3116
  });
2826
- const searchRef = (0, import_react11.useRef)(null);
2827
- const searchTimerRef = (0, import_react11.useRef)(null);
3117
+ const searchRef = (0, import_react12.useRef)(null);
3118
+ const searchTimerRef = (0, import_react12.useRef)(null);
2828
3119
  const executeAction = context == null ? void 0 : context.executeAction;
2829
3120
  const referencedTableId = ((_a = column.config) == null ? void 0 : _a.referencedTableId) || column.referencedTableId;
2830
- const fetchedIdsRef = (0, import_react11.useRef)(/* @__PURE__ */ new Set());
2831
- (0, import_react11.useEffect)(() => {
3121
+ const fetchedIdsRef = (0, import_react12.useRef)(/* @__PURE__ */ new Set());
3122
+ (0, import_react12.useEffect)(() => {
2832
3123
  if (entries.length > 0) {
2833
3124
  setLinkedRecords((prev) => {
2834
3125
  const existingIds = new Set(prev.map((r) => r.id));
@@ -2843,7 +3134,7 @@ function SubTableViewer({ rowId, column, value, onChange, context }) {
2843
3134
  });
2844
3135
  }
2845
3136
  }, [entries]);
2846
- (0, import_react11.useEffect)(() => {
3137
+ (0, import_react12.useEffect)(() => {
2847
3138
  if (!referencedTableId || !executeAction) {
2848
3139
  setIsLoading(false);
2849
3140
  return;
@@ -2870,7 +3161,7 @@ function SubTableViewer({ rowId, column, value, onChange, context }) {
2870
3161
  recordIdsToFetch.forEach((id) => fetchedIdsRef.current.delete(id));
2871
3162
  }).finally(() => setIsLoading(false));
2872
3163
  }, [referencedTableId, executeAction, entries, targetSchema]);
2873
- (0, import_react11.useEffect)(() => {
3164
+ (0, import_react12.useEffect)(() => {
2874
3165
  const handleClick = (e) => {
2875
3166
  if (searchRef.current && !searchRef.current.contains(e.target)) {
2876
3167
  setIsSearchOpen(false);
@@ -2879,7 +3170,7 @@ function SubTableViewer({ rowId, column, value, onChange, context }) {
2879
3170
  if (isSearchOpen) document.addEventListener("mousedown", handleClick);
2880
3171
  return () => document.removeEventListener("mousedown", handleClick);
2881
3172
  }, [isSearchOpen]);
2882
- const handleSearch = (0, import_react11.useCallback)((query) => {
3173
+ const handleSearch = (0, import_react12.useCallback)((query) => {
2883
3174
  setSearchQuery(query);
2884
3175
  if (searchTimerRef.current) clearTimeout(searchTimerRef.current);
2885
3176
  if (!query.trim()) {
@@ -2905,16 +3196,16 @@ function SubTableViewer({ rowId, column, value, onChange, context }) {
2905
3196
  }
2906
3197
  }, 300);
2907
3198
  }, [executeAction, referencedTableId, entries]);
2908
- const [localColumnOrder, setLocalColumnOrder] = (0, import_react11.useState)(null);
2909
- (0, import_react11.useEffect)(() => {
3199
+ const [localColumnOrder, setLocalColumnOrder] = (0, import_react12.useState)(null);
3200
+ (0, import_react12.useEffect)(() => {
2910
3201
  setLocalColumnOrder(null);
2911
3202
  }, [column.name, (_b = column.config) == null ? void 0 : _b.subTableColumnOrder]);
2912
- const rawTargetColumns = (0, import_react11.useMemo)(() => {
3203
+ const rawTargetColumns = (0, import_react12.useMemo)(() => {
2913
3204
  return ((targetSchema == null ? void 0 : targetSchema.columns) || []).filter(
2914
3205
  (c) => c.name !== "_id" && c.type !== "SUB_TABLE"
2915
3206
  );
2916
3207
  }, [targetSchema == null ? void 0 : targetSchema.columns]);
2917
- const targetColumns = (0, import_react11.useMemo)(() => {
3208
+ const targetColumns = (0, import_react12.useMemo)(() => {
2918
3209
  var _a2;
2919
3210
  const activeOrder = localColumnOrder || ((_a2 = column.config) == null ? void 0 : _a2.subTableColumnOrder);
2920
3211
  if (!activeOrder || !Array.isArray(activeOrder) || activeOrder.length === 0) {
@@ -2965,8 +3256,8 @@ function SubTableViewer({ rowId, column, value, onChange, context }) {
2965
3256
  return calculateMinColumnWidth(colName, true, col == null ? void 0 : col.type);
2966
3257
  }
2967
3258
  });
2968
- const [relationOptions, setRelationOptions] = (0, import_react11.useState)({});
2969
- (0, import_react11.useEffect)(() => {
3259
+ const [relationOptions, setRelationOptions] = (0, import_react12.useState)({});
3260
+ (0, import_react12.useEffect)(() => {
2970
3261
  if (!executeAction || !(targetSchema == null ? void 0 : targetSchema.columns) || targetSchema.columns.length === 0) return;
2971
3262
  const relationCols = targetSchema.columns.filter((c) => {
2972
3263
  var _a2, _b2;
@@ -2977,7 +3268,8 @@ function SubTableViewer({ rowId, column, value, onChange, context }) {
2977
3268
  try {
2978
3269
  const options = await executeAction("FETCH_RELATION", {
2979
3270
  referencedTableId: (_a2 = col.config) == null ? void 0 : _a2.referencedTableId,
2980
- displayField: (_b2 = col.config) == null ? void 0 : _b2.displayField
3271
+ displayField: (_b2 = col.config) == null ? void 0 : _b2.displayField,
3272
+ limit: 1e3
2981
3273
  });
2982
3274
  if (options && Array.isArray(options)) {
2983
3275
  setRelationOptions((prev) => __spreadProps(__spreadValues({}, prev), { [col.name]: options }));
@@ -2987,18 +3279,35 @@ function SubTableViewer({ rowId, column, value, onChange, context }) {
2987
3279
  }
2988
3280
  });
2989
3281
  }, [executeAction, targetColumns]);
2990
- const refetchRelation = (0, import_react11.useCallback)(async (colName) => {
2991
- var _a2, _b2, _c2;
3282
+ const refetchRelation = (0, import_react12.useCallback)(async (colName, params) => {
3283
+ var _a2, _b2, _c2, _d2, _e2, _f2;
2992
3284
  const col = targetColumns.find((c) => c.name === colName);
2993
- if (!col || ((_a2 = col.type) == null ? void 0 : _a2.toUpperCase()) !== "RELATION" || !((_b2 = col.config) == null ? void 0 : _b2.referencedTableId) || !executeAction) return;
3285
+ if (!col || ((_a2 = col.type) == null ? void 0 : _a2.toUpperCase()) !== "RELATION" || !((_b2 = col.config) == null ? void 0 : _b2.referencedTableId) || !executeAction) return [];
2994
3286
  try {
2995
- const options = await executeAction("FETCH_RELATION", { referencedTableId: col.config.referencedTableId, displayField: (_c2 = col.config) == null ? void 0 : _c2.displayField });
3287
+ const options = await executeAction("FETCH_RELATION", {
3288
+ referencedTableId: col.config.referencedTableId,
3289
+ displayField: (_c2 = col.config) == null ? void 0 : _c2.displayField,
3290
+ limit: (_d2 = params == null ? void 0 : params.limit) != null ? _d2 : 1e3,
3291
+ skip: (_e2 = params == null ? void 0 : params.skip) != null ? _e2 : 0,
3292
+ search: (_f2 = params == null ? void 0 : params.search) != null ? _f2 : ""
3293
+ });
2996
3294
  if (options && Array.isArray(options)) {
2997
- setRelationOptions((prev) => __spreadProps(__spreadValues({}, prev), { [col.name]: options }));
3295
+ if (params == null ? void 0 : params.append) {
3296
+ setRelationOptions((prev) => {
3297
+ const existing = prev[col.name] || [];
3298
+ const existingIds = new Set(existing.map((o) => String(o.id)));
3299
+ const uniqueNew = options.filter((o) => !existingIds.has(String(o.id)));
3300
+ return __spreadProps(__spreadValues({}, prev), { [col.name]: [...existing, ...uniqueNew] });
3301
+ });
3302
+ } else if (!(params == null ? void 0 : params.search)) {
3303
+ setRelationOptions((prev) => __spreadProps(__spreadValues({}, prev), { [col.name]: options }));
3304
+ }
3305
+ return options;
2998
3306
  }
2999
3307
  } catch (err) {
3000
3308
  console.warn(`[SubTableViewer] Could not refetch relation options for column ${col.name}:`, err);
3001
3309
  }
3310
+ return [];
3002
3311
  }, [targetColumns, executeAction]);
3003
3312
  const updateParentLinkage = async (updated) => {
3004
3313
  const isNewRow = rowId.startsWith("temp_");
@@ -3131,8 +3440,8 @@ function SubTableViewer({ rowId, column, value, onChange, context }) {
3131
3440
  );
3132
3441
  updateParentLinkage(updated);
3133
3442
  };
3134
- const isMountedRef = (0, import_react11.useRef)(true);
3135
- (0, import_react11.useEffect)(() => {
3443
+ const isMountedRef = (0, import_react12.useRef)(true);
3444
+ (0, import_react12.useEffect)(() => {
3136
3445
  isMountedRef.current = true;
3137
3446
  return () => {
3138
3447
  isMountedRef.current = false;
@@ -3219,7 +3528,7 @@ function SubTableViewer({ rowId, column, value, onChange, context }) {
3219
3528
  }
3220
3529
  };
3221
3530
  const handleRecordCellChange = handleCommitRecordCell;
3222
- const handleQuietSubTableCellChange = (0, import_react11.useCallback)((recordId, colName, value2) => {
3531
+ const handleQuietSubTableCellChange = (0, import_react12.useCallback)((recordId, colName, value2) => {
3223
3532
  setLinkedRecords(
3224
3533
  (prev) => prev.map((r) => r.id === recordId ? __spreadProps(__spreadValues({}, r), { data: __spreadProps(__spreadValues({}, r.data), { [colName]: value2 }) }) : r)
3225
3534
  );
@@ -3667,12 +3976,352 @@ function SubTableViewer({ rowId, column, value, onChange, context }) {
3667
3976
  }
3668
3977
 
3669
3978
  // src/components/TableBlock/TableBlockClient.tsx
3979
+ var import_lucide_react8 = require("lucide-react");
3980
+
3981
+ // src/components/TableBlock/RelationFilterPopover.tsx
3982
+ var import_react13 = require("react");
3670
3983
  var import_lucide_react7 = require("lucide-react");
3671
3984
  var import_jsx_runtime10 = require("react/jsx-runtime");
3985
+ function calculatePopoverCoords(rect) {
3986
+ if (!rect || typeof window === "undefined") return null;
3987
+ const popoverWidth = 260;
3988
+ const popoverHeight = 360;
3989
+ let right = window.innerWidth - rect.right;
3990
+ if (right + popoverWidth > window.innerWidth - 10) {
3991
+ right = window.innerWidth - popoverWidth - 10;
3992
+ }
3993
+ if (right < 10) {
3994
+ right = 10;
3995
+ }
3996
+ const spaceBelow = window.innerHeight - rect.bottom;
3997
+ let top = rect.bottom + 6;
3998
+ if (spaceBelow < popoverHeight && rect.top > popoverHeight) {
3999
+ top = Math.max(10, rect.top - popoverHeight - 6);
4000
+ } else {
4001
+ top = Math.min(window.innerHeight - popoverHeight - 10, top);
4002
+ }
4003
+ return { top, right };
4004
+ }
4005
+ function RelationFilterPopover({
4006
+ isOpen,
4007
+ onClose,
4008
+ column,
4009
+ triggerRect,
4010
+ options,
4011
+ filterValue,
4012
+ selectedValues,
4013
+ onSelectionChange,
4014
+ isLoading = false
4015
+ }) {
4016
+ const popoverRef = (0, import_react13.useRef)(null);
4017
+ const searchInputRef = (0, import_react13.useRef)(null);
4018
+ const selectAllRef = (0, import_react13.useRef)(null);
4019
+ const [searchQuery, setSearchQuery] = (0, import_react13.useState)("");
4020
+ const [coords, setCoords] = (0, import_react13.useState)(
4021
+ () => calculatePopoverCoords(triggerRect)
4022
+ );
4023
+ const [mode, setMode] = (0, import_react13.useState)("include");
4024
+ const [checkedSet, setCheckedSet] = (0, import_react13.useState)(/* @__PURE__ */ new Set());
4025
+ const [excludedSet, setExcludedSet] = (0, import_react13.useState)(/* @__PURE__ */ new Set());
4026
+ const prevIsOpenRef = (0, import_react13.useRef)(isOpen);
4027
+ (0, import_react13.useEffect)(() => {
4028
+ const justOpened = isOpen && !prevIsOpenRef.current;
4029
+ prevIsOpenRef.current = isOpen;
4030
+ if (justOpened) {
4031
+ const activeVal = filterValue != null ? filterValue : selectedValues;
4032
+ if (activeVal && typeof activeVal === "object" && !Array.isArray(activeVal) && "operator" in activeVal && activeVal.operator === "notIn") {
4033
+ setMode("exclude");
4034
+ setExcludedSet(new Set(activeVal.values || []));
4035
+ setCheckedSet(/* @__PURE__ */ new Set());
4036
+ } else if (Array.isArray(activeVal) && activeVal.length > 0) {
4037
+ setMode("include");
4038
+ setCheckedSet(new Set(activeVal));
4039
+ setExcludedSet(/* @__PURE__ */ new Set());
4040
+ } else {
4041
+ setMode("include");
4042
+ setCheckedSet(/* @__PURE__ */ new Set());
4043
+ setExcludedSet(/* @__PURE__ */ new Set());
4044
+ }
4045
+ }
4046
+ }, [isOpen, filterValue, selectedValues]);
4047
+ const updatePosition = (0, import_react13.useCallback)(() => {
4048
+ const next = calculatePopoverCoords(triggerRect);
4049
+ if (next) setCoords(next);
4050
+ }, [triggerRect]);
4051
+ (0, import_react13.useEffect)(() => {
4052
+ if (isOpen) {
4053
+ updatePosition();
4054
+ setTimeout(() => {
4055
+ var _a;
4056
+ return (_a = searchInputRef.current) == null ? void 0 : _a.focus();
4057
+ }, 50);
4058
+ } else {
4059
+ setSearchQuery("");
4060
+ }
4061
+ }, [isOpen, updatePosition]);
4062
+ (0, import_react13.useEffect)(() => {
4063
+ if (!isOpen) return;
4064
+ const handleScrollOrResize = () => updatePosition();
4065
+ window.addEventListener("scroll", handleScrollOrResize, true);
4066
+ window.addEventListener("resize", handleScrollOrResize);
4067
+ return () => {
4068
+ window.removeEventListener("scroll", handleScrollOrResize, true);
4069
+ window.removeEventListener("resize", handleScrollOrResize);
4070
+ };
4071
+ }, [isOpen, updatePosition]);
4072
+ (0, import_react13.useEffect)(() => {
4073
+ if (!isOpen) return;
4074
+ const handleMouseDown = (e) => {
4075
+ if (popoverRef.current && !popoverRef.current.contains(e.target)) {
4076
+ onClose();
4077
+ }
4078
+ };
4079
+ document.addEventListener("mousedown", handleMouseDown);
4080
+ return () => {
4081
+ document.removeEventListener("mousedown", handleMouseDown);
4082
+ };
4083
+ }, [isOpen, onClose]);
4084
+ (0, import_react13.useEffect)(() => {
4085
+ if (!isOpen) return;
4086
+ const handleKeyDown = (e) => {
4087
+ if (e.key === "Escape") {
4088
+ onClose();
4089
+ }
4090
+ };
4091
+ window.addEventListener("keydown", handleKeyDown);
4092
+ return () => {
4093
+ window.removeEventListener("keydown", handleKeyDown);
4094
+ };
4095
+ }, [isOpen, onClose]);
4096
+ const filteredOptions = (0, import_react13.useMemo)(() => {
4097
+ if (!searchQuery.trim()) return options;
4098
+ const q = searchQuery.trim().toLowerCase();
4099
+ return options.filter((opt) => opt.label.toLowerCase().includes(q));
4100
+ }, [options, searchQuery]);
4101
+ const isOptionChecked = (0, import_react13.useCallback)(
4102
+ (label) => {
4103
+ if (mode === "exclude") {
4104
+ return !excludedSet.has(label);
4105
+ }
4106
+ return checkedSet.has(label);
4107
+ },
4108
+ [mode, excludedSet, checkedSet]
4109
+ );
4110
+ const allFilteredSelected = (0, import_react13.useMemo)(() => {
4111
+ if (filteredOptions.length === 0) return false;
4112
+ return filteredOptions.every((opt) => isOptionChecked(opt.label));
4113
+ }, [filteredOptions, isOptionChecked]);
4114
+ const someFilteredSelected = (0, import_react13.useMemo)(() => {
4115
+ return filteredOptions.some((opt) => isOptionChecked(opt.label));
4116
+ }, [filteredOptions, isOptionChecked]);
4117
+ (0, import_react13.useEffect)(() => {
4118
+ if (selectAllRef.current) {
4119
+ selectAllRef.current.indeterminate = !allFilteredSelected && someFilteredSelected;
4120
+ }
4121
+ }, [allFilteredSelected, someFilteredSelected]);
4122
+ const handleToggleOption = (label) => {
4123
+ if (mode === "exclude") {
4124
+ const nextExcluded = new Set(excludedSet);
4125
+ if (nextExcluded.has(label)) {
4126
+ nextExcluded.delete(label);
4127
+ } else {
4128
+ nextExcluded.add(label);
4129
+ }
4130
+ setExcludedSet(nextExcluded);
4131
+ if (nextExcluded.size === 0) {
4132
+ onSelectionChange(void 0);
4133
+ } else {
4134
+ onSelectionChange({ operator: "notIn", values: Array.from(nextExcluded) });
4135
+ }
4136
+ } else {
4137
+ const nextChecked = new Set(checkedSet);
4138
+ if (nextChecked.has(label)) {
4139
+ nextChecked.delete(label);
4140
+ } else {
4141
+ nextChecked.add(label);
4142
+ }
4143
+ setCheckedSet(nextChecked);
4144
+ if (nextChecked.size === 0) {
4145
+ onSelectionChange(void 0);
4146
+ } else if (options.length > 0 && nextChecked.size >= options.length) {
4147
+ setMode("exclude");
4148
+ setExcludedSet(/* @__PURE__ */ new Set());
4149
+ onSelectionChange(void 0);
4150
+ } else {
4151
+ onSelectionChange(Array.from(nextChecked));
4152
+ }
4153
+ }
4154
+ };
4155
+ const handleToggleSelectAll = (checked) => {
4156
+ if (checked) {
4157
+ setMode("exclude");
4158
+ setExcludedSet(/* @__PURE__ */ new Set());
4159
+ setCheckedSet(/* @__PURE__ */ new Set());
4160
+ onSelectionChange(void 0);
4161
+ } else {
4162
+ setMode("include");
4163
+ setCheckedSet(/* @__PURE__ */ new Set());
4164
+ setExcludedSet(/* @__PURE__ */ new Set());
4165
+ onSelectionChange(void 0);
4166
+ }
4167
+ };
4168
+ const handleResetFilter = () => {
4169
+ setMode("include");
4170
+ setCheckedSet(/* @__PURE__ */ new Set());
4171
+ setExcludedSet(/* @__PURE__ */ new Set());
4172
+ setSearchQuery("");
4173
+ onSelectionChange(void 0);
4174
+ };
4175
+ if (!isOpen || !coords) return null;
4176
+ const selectedCount = (0, import_react13.useMemo)(() => {
4177
+ if (mode === "exclude") {
4178
+ return Math.max(0, options.length - excludedSet.size);
4179
+ }
4180
+ return checkedSet.size;
4181
+ }, [mode, options.length, excludedSet.size, checkedSet.size]);
4182
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
4183
+ "div",
4184
+ {
4185
+ ref: popoverRef,
4186
+ dir: "rtl",
4187
+ style: {
4188
+ top: `${coords.top}px`,
4189
+ right: `${coords.right}px`
4190
+ },
4191
+ 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",
4192
+ onClick: (e) => e.stopPropagation(),
4193
+ onMouseDown: (e) => e.stopPropagation(),
4194
+ children: [
4195
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex items-center justify-between border-b border-slate-100 pb-2 mb-2", children: [
4196
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex items-center gap-1.5 min-w-0", children: [
4197
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: "text-xs font-bold text-slate-700 truncate", children: [
4198
+ "\u05E1\u05D9\u05E0\u05D5\u05DF \u05DC\u05E4\u05D9 ",
4199
+ column.name
4200
+ ] }),
4201
+ mode === "exclude" && excludedSet.size > 0 ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: "text-[10px] text-amber-600 font-semibold", children: [
4202
+ "(\u05D4\u05DB\u05DC \u05DC\u05DE\u05E2\u05D8 ",
4203
+ excludedSet.size,
4204
+ ")"
4205
+ ] }) : mode === "exclude" && excludedSet.size === 0 ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "text-[10px] text-brand font-semibold", children: "(\u05D4\u05DB\u05DC \u05E0\u05D1\u05D7\u05E8)" }) : selectedCount > 0 ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: "text-[10px] text-brand font-semibold", children: [
4206
+ "(",
4207
+ selectedCount,
4208
+ " \u05E0\u05D1\u05D7\u05E8\u05D5)"
4209
+ ] }) : null
4210
+ ] }),
4211
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
4212
+ "button",
4213
+ {
4214
+ type: "button",
4215
+ onClick: onClose,
4216
+ className: "text-slate-400 hover:text-slate-600 p-0.5 rounded hover:bg-slate-100 transition-colors cursor-pointer",
4217
+ title: "\u05E1\u05D2\u05D5\u05E8",
4218
+ children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react7.X, { className: "w-3.5 h-3.5" })
4219
+ }
4220
+ )
4221
+ ] }),
4222
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "relative mb-2", children: [
4223
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react7.Search, { className: "w-3.5 h-3.5 text-slate-400 absolute right-2.5 top-1/2 -translate-y-1/2 pointer-events-none" }),
4224
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
4225
+ "input",
4226
+ {
4227
+ ref: searchInputRef,
4228
+ type: "text",
4229
+ placeholder: "\u05D7\u05D9\u05E4\u05D5\u05E9 \u05D0\u05E4\u05E9\u05E8\u05D5\u05D9\u05D5\u05EA...",
4230
+ value: searchQuery,
4231
+ onChange: (e) => setSearchQuery(e.target.value),
4232
+ 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"
4233
+ }
4234
+ ),
4235
+ searchQuery && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
4236
+ "button",
4237
+ {
4238
+ type: "button",
4239
+ onClick: () => setSearchQuery(""),
4240
+ className: "absolute left-1.5 top-1/2 -translate-y-1/2 p-0.5 text-slate-400 hover:text-slate-600 rounded",
4241
+ children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react7.X, { className: "w-3 h-3" })
4242
+ }
4243
+ )
4244
+ ] }),
4245
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("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: [
4246
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("label", { className: "flex items-center gap-2 cursor-pointer text-xs font-medium text-slate-700 flex-1", children: [
4247
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
4248
+ "input",
4249
+ {
4250
+ ref: selectAllRef,
4251
+ type: "checkbox",
4252
+ checked: allFilteredSelected,
4253
+ onChange: (e) => handleToggleSelectAll(e.target.checked),
4254
+ className: "w-3.5 h-3.5 rounded border-slate-300 text-brand focus:ring-brand cursor-pointer accent-[#0d9488]"
4255
+ }
4256
+ ),
4257
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { children: "\u05D1\u05D7\u05E8 \u05D4\u05DB\u05DC" })
4258
+ ] }),
4259
+ (mode === "exclude" || checkedSet.size > 0) && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
4260
+ "button",
4261
+ {
4262
+ type: "button",
4263
+ onClick: handleResetFilter,
4264
+ className: "text-[11px] text-blue-600 hover:text-blue-700 hover:underline flex items-center gap-1 cursor-pointer",
4265
+ title: "\u05E0\u05E7\u05D4 \u05E1\u05D9\u05E0\u05D5\u05DF \u05D5\u05D4\u05E6\u05D2 \u05D4\u05DB\u05DC",
4266
+ children: [
4267
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react7.RotateCcw, { className: "w-2.5 h-2.5" }),
4268
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { children: "\u05E0\u05E7\u05D4" })
4269
+ ]
4270
+ }
4271
+ )
4272
+ ] }),
4273
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "max-h-[250px] overflow-y-auto space-y-0.5 custom-scrollbar pr-0.5", children: isLoading ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex items-center justify-center py-6 text-slate-400 text-xs", children: [
4274
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "w-4 h-4 border-2 border-brand border-t-transparent rounded-full animate-spin ml-2" }),
4275
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { children: "\u05D8\u05D5\u05E2\u05DF \u05D0\u05E4\u05E9\u05E8\u05D5\u05D9\u05D5\u05EA..." })
4276
+ ] }) : filteredOptions.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("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) => {
4277
+ const isChecked = isOptionChecked(opt.label);
4278
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
4279
+ "label",
4280
+ {
4281
+ 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"}`,
4282
+ children: [
4283
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
4284
+ "input",
4285
+ {
4286
+ type: "checkbox",
4287
+ checked: isChecked,
4288
+ onChange: () => handleToggleOption(opt.label),
4289
+ className: "w-3.5 h-3.5 rounded border-slate-300 text-brand focus:ring-brand cursor-pointer accent-[#0d9488]"
4290
+ }
4291
+ ),
4292
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "truncate flex-1", title: opt.label, children: opt.label })
4293
+ ]
4294
+ },
4295
+ opt.id
4296
+ );
4297
+ }) }),
4298
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("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: [
4299
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { children: [
4300
+ filteredOptions.length,
4301
+ " \u05EA\u05D5\u05E6\u05D0\u05D5\u05EA"
4302
+ ] }),
4303
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
4304
+ "button",
4305
+ {
4306
+ type: "button",
4307
+ onClick: onClose,
4308
+ className: "text-slate-600 hover:text-slate-900 font-medium px-2 py-0.5 rounded hover:bg-slate-100 transition-colors cursor-pointer",
4309
+ children: "\u05E1\u05D2\u05D5\u05E8"
4310
+ }
4311
+ )
4312
+ ] })
4313
+ ]
4314
+ }
4315
+ );
4316
+ }
4317
+
4318
+ // src/components/TableBlock/TableBlockClient.tsx
4319
+ var import_jsx_runtime11 = require("react/jsx-runtime");
3672
4320
  function TableBlockClient({
3673
4321
  data: initialRecords,
3674
4322
  settings: schema,
3675
4323
  executeAction,
4324
+ exportAction,
3676
4325
  emitEvent,
3677
4326
  pageState,
3678
4327
  isLoading,
@@ -3685,6 +4334,7 @@ function TableBlockClient({
3685
4334
  "data-testid": dataTestId
3686
4335
  }) {
3687
4336
  const { showError, addToast } = useToast();
4337
+ const [isExporting, setIsExporting] = (0, import_react14.useState)(false);
3688
4338
  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";
3689
4339
  const { columnWidths, startResize } = useColumnResize({
3690
4340
  storageKey: `table_widths_${tableKey}`,
@@ -3695,14 +4345,18 @@ function TableBlockClient({
3695
4345
  return calculateMinColumnWidth(colName, false, col == null ? void 0 : col.type);
3696
4346
  }
3697
4347
  });
3698
- const [isMounted, setIsMounted] = (0, import_react12.useState)(false);
3699
- const [isInitialLoading, setIsInitialLoading] = (0, import_react12.useState)(true);
3700
- const [page, setPage] = (0, import_react12.useState)(1);
3701
- const [limit, setLimit] = (0, import_react12.useState)(50);
3702
- const [totalRecords, setTotalRecords] = (0, import_react12.useState)(0);
3703
- const [totalPages, setTotalPages] = (0, import_react12.useState)(1);
3704
- const [showSummary, setShowSummary] = (0, import_react12.useState)(false);
3705
- (0, import_react12.useEffect)(() => {
4348
+ const executeActionRef = (0, import_react14.useRef)(executeAction);
4349
+ (0, import_react14.useEffect)(() => {
4350
+ executeActionRef.current = executeAction;
4351
+ }, [executeAction]);
4352
+ const [isMounted, setIsMounted] = (0, import_react14.useState)(false);
4353
+ const [isInitialLoading, setIsInitialLoading] = (0, import_react14.useState)(true);
4354
+ const [page, setPage] = (0, import_react14.useState)(1);
4355
+ const [limit, setLimit] = (0, import_react14.useState)(50);
4356
+ const [totalRecords, setTotalRecords] = (0, import_react14.useState)(0);
4357
+ const [totalPages, setTotalPages] = (0, import_react14.useState)(1);
4358
+ const [showSummary, setShowSummary] = (0, import_react14.useState)(false);
4359
+ (0, import_react14.useEffect)(() => {
3706
4360
  if (typeof window !== "undefined") {
3707
4361
  const savedSummary = localStorage.getItem(`table_summary_${tableKey}`);
3708
4362
  if (savedSummary !== null) {
@@ -3751,7 +4405,7 @@ function TableBlockClient({
3751
4405
  return __spreadProps(__spreadValues({}, row), { id: String(row.id || ""), data: rowData });
3752
4406
  });
3753
4407
  };
3754
- const mergeColumnDefs = (0, import_react12.useCallback)((existingCols, incomingCols) => {
4408
+ const mergeColumnDefs = (0, import_react14.useCallback)((existingCols, incomingCols) => {
3755
4409
  if (!incomingCols || incomingCols.length === 0) return existingCols || [];
3756
4410
  if (!existingCols || existingCols.length === 0) return incomingCols;
3757
4411
  const existingMap = new Map(existingCols.map((c) => [c.name, c]));
@@ -3771,18 +4425,18 @@ function TableBlockClient({
3771
4425
  return ((_a = a.order) != null ? _a : 0) - ((_b = b.order) != null ? _b : 0);
3772
4426
  });
3773
4427
  }, []);
3774
- const [localColumns, setLocalColumns] = (0, import_react12.useState)(() => (schema == null ? void 0 : schema.columns) || []);
3775
- (0, import_react12.useEffect)(() => {
4428
+ const [localColumns, setLocalColumns] = (0, import_react14.useState)(() => (schema == null ? void 0 : schema.columns) || []);
4429
+ (0, import_react14.useEffect)(() => {
3776
4430
  if ((schema == null ? void 0 : schema.columns) && schema.columns.length > 0) {
3777
4431
  setLocalColumns((prev) => mergeColumnDefs(prev, schema.columns));
3778
4432
  }
3779
4433
  }, [schema == null ? void 0 : schema.columns, mergeColumnDefs]);
3780
- const [dirty, setDirty] = (0, import_react12.useState)({ added: [], modified: {}, deleted: [] });
3781
- const dirtyRef = (0, import_react12.useRef)(dirty);
3782
- (0, import_react12.useEffect)(() => {
4434
+ const [dirty, setDirty] = (0, import_react14.useState)({ added: [], modified: {}, deleted: [] });
4435
+ const dirtyRef = (0, import_react14.useRef)(dirty);
4436
+ (0, import_react14.useEffect)(() => {
3783
4437
  dirtyRef.current = dirty;
3784
4438
  }, [dirty]);
3785
- const mergeWithDirty = (0, import_react12.useCallback)((baseRecords) => {
4439
+ const mergeWithDirty = (0, import_react14.useCallback)((baseRecords) => {
3786
4440
  const { added, modified, deleted } = dirtyRef.current;
3787
4441
  const nonDeleted = (baseRecords || []).filter((r) => !deleted.includes(r.id));
3788
4442
  const modifiedRecords = nonDeleted.map((r) => {
@@ -3795,9 +4449,10 @@ function TableBlockClient({
3795
4449
  const uniqueAdded = added.filter((r) => !baseIds.has(r.id));
3796
4450
  return [...uniqueAdded, ...modifiedRecords];
3797
4451
  }, []);
3798
- const [data, setData] = (0, import_react12.useState)(() => normalizeRecords(initialRecords));
3799
- const [serverRecords, setServerRecords] = (0, import_react12.useState)(() => normalizeRecords(initialRecords));
3800
- (0, import_react12.useEffect)(() => {
4452
+ const [data, setData] = (0, import_react14.useState)(() => normalizeRecords(initialRecords));
4453
+ const [serverRecords, setServerRecords] = (0, import_react14.useState)(() => normalizeRecords(initialRecords));
4454
+ const filteredData = data;
4455
+ (0, import_react14.useEffect)(() => {
3801
4456
  if (initialRecords) {
3802
4457
  const norm = normalizeRecords(initialRecords);
3803
4458
  setServerRecords(norm);
@@ -3814,27 +4469,114 @@ function TableBlockClient({
3814
4469
  }
3815
4470
  return false;
3816
4471
  };
3817
- const [baseRecordsMap, setBaseRecordsMap] = (0, import_react12.useState)(() => {
4472
+ const [baseRecordsMap, setBaseRecordsMap] = (0, import_react14.useState)(() => {
3818
4473
  const map = /* @__PURE__ */ new Map();
3819
4474
  (normalizeRecords(initialRecords) || []).forEach((r) => map.set(r.id, __spreadValues({}, r.data)));
3820
4475
  return map;
3821
4476
  });
3822
- (0, import_react12.useEffect)(() => {
4477
+ (0, import_react14.useEffect)(() => {
3823
4478
  if (initialRecords && initialRecords.length > 0) {
3824
4479
  const map = /* @__PURE__ */ new Map();
3825
4480
  (normalizeRecords(initialRecords) || []).forEach((r) => map.set(r.id, __spreadValues({}, r.data)));
3826
4481
  setBaseRecordsMap(map);
3827
4482
  }
3828
4483
  }, [initialRecords]);
3829
- const refetchTableData = (0, import_react12.useCallback)((targetPage) => {
3830
- const tableId = (schema == null ? void 0 : schema.tableMetaId) || (schema == null ? void 0 : schema.tableId) || (schema == null ? void 0 : schema.id);
3831
- if (!tableId || !executeAction) return Promise.resolve();
3832
- const activePage = targetPage !== void 0 ? targetPage : page;
3833
- const skip = (activePage - 1) * limit;
3834
- return executeAction("FETCH_TABLE_DATA", { tableId, page: activePage, limit, skip }).then((res) => {
3835
- var _a;
3836
- if (res) {
3837
- if (((_a = res.schema) == null ? void 0 : _a.columns) && res.schema.columns.length > 0) {
4484
+ const [searchQuery, setSearchQuery] = (0, import_react14.useState)("");
4485
+ const [columnFilters, setColumnFilters] = (0, import_react14.useState)({});
4486
+ const [activeSearchCol, setActiveSearchCol] = (0, import_react14.useState)(null);
4487
+ const activeSearchRef = (0, import_react14.useRef)(null);
4488
+ const [activeRelationCol, setActiveRelationCol] = (0, import_react14.useState)(null);
4489
+ const [relationTriggerRect, setRelationTriggerRect] = (0, import_react14.useState)(null);
4490
+ const filterButtonRefs = (0, import_react14.useRef)({});
4491
+ const [relationOptions, setRelationOptions] = (0, import_react14.useState)({});
4492
+ const [relationFilterOptions, setRelationFilterOptions] = (0, import_react14.useState)({});
4493
+ const [loadingFilterCol, setLoadingFilterCol] = (0, import_react14.useState)(null);
4494
+ const relationDictionaryRef = (0, import_react14.useRef)({});
4495
+ const mergeRelationOptions = (0, import_react14.useCallback)((colName, newOptions) => {
4496
+ if (!Array.isArray(newOptions) || newOptions.length === 0) return;
4497
+ if (!relationDictionaryRef.current[colName]) {
4498
+ relationDictionaryRef.current[colName] = /* @__PURE__ */ new Map();
4499
+ }
4500
+ const dict = relationDictionaryRef.current[colName];
4501
+ let hasNew = false;
4502
+ for (const opt of newOptions) {
4503
+ if (!opt) continue;
4504
+ const id = String(opt.id || opt._id || "");
4505
+ if (!id) continue;
4506
+ const existing = dict.get(id);
4507
+ if (!existing || opt.label && !existing.label) {
4508
+ dict.set(id, opt);
4509
+ hasNew = true;
4510
+ }
4511
+ }
4512
+ if (hasNew) {
4513
+ setRelationOptions((prev) => __spreadProps(__spreadValues({}, prev), {
4514
+ [colName]: Array.from(dict.values())
4515
+ }));
4516
+ }
4517
+ }, []);
4518
+ (0, import_react14.useEffect)(() => {
4519
+ if (!activeSearchCol) return;
4520
+ const handleMouseDown = (e) => {
4521
+ if (activeSearchRef.current && !activeSearchRef.current.contains(e.target)) {
4522
+ setActiveSearchCol(null);
4523
+ }
4524
+ };
4525
+ document.addEventListener("mousedown", handleMouseDown);
4526
+ return () => {
4527
+ document.removeEventListener("mousedown", handleMouseDown);
4528
+ };
4529
+ }, [activeSearchCol]);
4530
+ const filtersKey = (0, import_react14.useMemo)(() => {
4531
+ const active = {};
4532
+ Object.entries(columnFilters).forEach(([k, v]) => {
4533
+ if (Array.isArray(v) && v.length > 0) active[k] = v;
4534
+ else if (v && typeof v === "object" && "operator" in v && Array.isArray(v.values) && v.values.length > 0) active[k] = v;
4535
+ else if (typeof v === "string" && v.trim()) active[k] = v.trim();
4536
+ });
4537
+ return JSON.stringify(active);
4538
+ }, [columnFilters]);
4539
+ const [debouncedSearch, setDebouncedSearch] = (0, import_react14.useState)(searchQuery);
4540
+ (0, import_react14.useEffect)(() => {
4541
+ const timer = setTimeout(() => {
4542
+ setDebouncedSearch(searchQuery.trim());
4543
+ }, 300);
4544
+ return () => clearTimeout(timer);
4545
+ }, [searchQuery]);
4546
+ const isSearchMountedRef = (0, import_react14.useRef)(false);
4547
+ (0, import_react14.useEffect)(() => {
4548
+ if (!isSearchMountedRef.current) {
4549
+ isSearchMountedRef.current = true;
4550
+ return;
4551
+ }
4552
+ setPage(1);
4553
+ }, [debouncedSearch]);
4554
+ const [isFetching, setIsFetching] = (0, import_react14.useState)(false);
4555
+ const fetchRequestIdRef = (0, import_react14.useRef)(0);
4556
+ const fetchTableData = (0, import_react14.useCallback)((targetPage, targetLimit, targetSearch, targetFiltersKey) => {
4557
+ const tableId = (schema == null ? void 0 : schema.tableMetaId) || (schema == null ? void 0 : schema.tableId) || (schema == null ? void 0 : schema.id);
4558
+ const action = executeActionRef.current;
4559
+ if (!tableId || !action) return Promise.resolve();
4560
+ const currentRequestId = ++fetchRequestIdRef.current;
4561
+ setIsFetching(true);
4562
+ let activeFilters = {};
4563
+ try {
4564
+ activeFilters = JSON.parse(targetFiltersKey);
4565
+ } catch (e) {
4566
+ }
4567
+ const skip = (targetPage - 1) * targetLimit;
4568
+ return action("FETCH_TABLE_DATA", {
4569
+ tableId,
4570
+ page: targetPage,
4571
+ limit: targetLimit,
4572
+ skip,
4573
+ search: targetSearch || void 0,
4574
+ columnFilters: Object.keys(activeFilters).length > 0 ? activeFilters : void 0
4575
+ }).then((res) => {
4576
+ var _a;
4577
+ if (currentRequestId !== fetchRequestIdRef.current) return;
4578
+ if (res) {
4579
+ if (((_a = res.schema) == null ? void 0 : _a.columns) && res.schema.columns.length > 0) {
3838
4580
  setLocalColumns((prev) => mergeColumnDefs(prev, res.schema.columns));
3839
4581
  }
3840
4582
  if (res.records && Array.isArray(res.records)) {
@@ -3847,37 +4589,50 @@ function TableBlockClient({
3847
4589
  }
3848
4590
  if (res.meta) {
3849
4591
  const total = typeof res.meta.totalRecords === "number" ? res.meta.totalRecords : 0;
3850
- const pages = typeof res.meta.totalPages === "number" ? res.meta.totalPages : Math.ceil(total / limit) || 1;
4592
+ const pages = typeof res.meta.totalPages === "number" ? res.meta.totalPages : Math.ceil(total / targetLimit) || 1;
3851
4593
  setTotalRecords(total);
3852
4594
  setTotalPages(pages);
3853
- if (activePage > pages && pages >= 1) {
3854
- setPage(pages);
3855
- }
3856
4595
  } else if (res.records && Array.isArray(res.records)) {
3857
4596
  setTotalRecords(res.records.length);
3858
- setTotalPages(Math.ceil(res.records.length / limit) || 1);
4597
+ setTotalPages(Math.ceil(res.records.length / targetLimit) || 1);
4598
+ }
4599
+ if (res.relationOptions && typeof res.relationOptions === "object") {
4600
+ for (const [colName, opts] of Object.entries(res.relationOptions)) {
4601
+ if (Array.isArray(opts)) {
4602
+ mergeRelationOptions(colName, opts);
4603
+ }
4604
+ }
3859
4605
  }
3860
4606
  }
3861
4607
  }).catch((err) => {
3862
- console.error("[TableBlock] Failed to auto-fetch table data:", err);
4608
+ if (currentRequestId === fetchRequestIdRef.current) {
4609
+ console.error("[TableBlock] Failed to fetch table data:", err);
4610
+ }
4611
+ }).finally(() => {
4612
+ if (currentRequestId === fetchRequestIdRef.current) {
4613
+ setIsFetching(false);
4614
+ setIsInitialLoading(false);
4615
+ }
3863
4616
  });
3864
- }, [schema == null ? void 0 : schema.tableMetaId, schema == null ? void 0 : schema.tableId, schema == null ? void 0 : schema.id, page, limit, executeAction, mergeColumnDefs, mergeWithDirty]);
3865
- (0, import_react12.useEffect)(() => {
3866
- let isMounted2 = true;
3867
- const fetchPromise = refetchTableData();
3868
- if (fetchPromise && typeof fetchPromise.finally === "function") {
3869
- fetchPromise.finally(() => {
3870
- if (isMounted2) {
3871
- setIsInitialLoading(false);
3872
- }
3873
- });
3874
- } else {
3875
- setIsInitialLoading(false);
3876
- }
3877
- return () => {
3878
- isMounted2 = false;
3879
- };
3880
- }, [refetchTableData]);
4617
+ }, [schema == null ? void 0 : schema.tableMetaId, schema == null ? void 0 : schema.tableId, schema == null ? void 0 : schema.id, mergeColumnDefs, mergeWithDirty, mergeRelationOptions]);
4618
+ (0, import_react14.useEffect)(() => {
4619
+ fetchTableData(page, limit, debouncedSearch, filtersKey);
4620
+ }, [page, limit, debouncedSearch, filtersKey, fetchTableData]);
4621
+ const refetchTableData = (0, import_react14.useCallback)(() => {
4622
+ return fetchTableData(page, limit, debouncedSearch, filtersKey);
4623
+ }, [page, limit, debouncedSearch, filtersKey, fetchTableData]);
4624
+ const handleApplyColumnFilter = (0, import_react14.useCallback)((colName, nextVal) => {
4625
+ setColumnFilters((prev) => {
4626
+ const next = __spreadValues({}, prev);
4627
+ 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) {
4628
+ delete next[colName];
4629
+ } else {
4630
+ next[colName] = nextVal;
4631
+ }
4632
+ return next;
4633
+ });
4634
+ setPage(1);
4635
+ }, []);
3881
4636
  const handleLimitChange = (newLimit) => {
3882
4637
  setLimit(newLimit);
3883
4638
  setPage(1);
@@ -3891,37 +4646,15 @@ function TableBlockClient({
3891
4646
  const handleNextPage = () => {
3892
4647
  setPage((prev) => Math.min(totalPages, prev + 1));
3893
4648
  };
3894
- (0, import_react12.useEffect)(() => {
3895
- if (error) {
3896
- showError(error, "\u05E9\u05D2\u05D9\u05D0\u05D4 \u05D1\u05E8\u05DB\u05D9\u05D1");
3897
- }
3898
- }, [error, showError]);
3899
- const [searchQuery, setSearchQuery] = (0, import_react12.useState)("");
3900
- const [columnFilters, setColumnFilters] = (0, import_react12.useState)({});
3901
- const [activeSearchCol, setActiveSearchCol] = (0, import_react12.useState)(null);
3902
- const activeSearchRef = (0, import_react12.useRef)(null);
3903
- (0, import_react12.useEffect)(() => {
3904
- if (!activeSearchCol) return;
3905
- const handleMouseDown = (e) => {
3906
- if (activeSearchRef.current && !activeSearchRef.current.contains(e.target)) {
3907
- setActiveSearchCol(null);
3908
- }
3909
- };
3910
- document.addEventListener("mousedown", handleMouseDown);
3911
- return () => {
3912
- document.removeEventListener("mousedown", handleMouseDown);
3913
- };
3914
- }, [activeSearchCol]);
3915
- const [selectedIds, setSelectedIds] = (0, import_react12.useState)(/* @__PURE__ */ new Set());
3916
- const [pendingDeletions, setPendingDeletions] = (0, import_react12.useState)([]);
3917
- const [isSaving, setIsSaving] = (0, import_react12.useState)(false);
4649
+ const [selectedIds, setSelectedIds] = (0, import_react14.useState)(/* @__PURE__ */ new Set());
4650
+ const [pendingDeletions, setPendingDeletions] = (0, import_react14.useState)([]);
4651
+ const [isSaving, setIsSaving] = (0, import_react14.useState)(false);
3918
4652
  const isUpdatingActive = Boolean(isUpdating || isSaving);
3919
- const [isSaveSuccess, setIsSaveSuccess] = (0, import_react12.useState)(false);
3920
- const [relationOptions, setRelationOptions] = (0, import_react12.useState)({});
3921
- const [expandedRowIds, setExpandedRowIds] = (0, import_react12.useState)(/* @__PURE__ */ new Set());
3922
- const schemaColsString = (0, import_react12.useMemo)(() => JSON.stringify(localColumns || []), [localColumns]);
3923
- const refetchRelation = (0, import_react12.useCallback)(async (colName) => {
3924
- var _a, _b, _c;
4653
+ const [isSaveSuccess, setIsSaveSuccess] = (0, import_react14.useState)(false);
4654
+ const [expandedRowIds, setExpandedRowIds] = (0, import_react14.useState)(/* @__PURE__ */ new Set());
4655
+ const schemaColsString = (0, import_react14.useMemo)(() => JSON.stringify(localColumns || []), [localColumns]);
4656
+ const refetchRelation = (0, import_react14.useCallback)(async (colName, params) => {
4657
+ var _a, _b, _c, _d, _e, _f, _g;
3925
4658
  let parsedCols = [];
3926
4659
  try {
3927
4660
  parsedCols = JSON.parse(schemaColsString);
@@ -3931,19 +4664,125 @@ function TableBlockClient({
3931
4664
  var _a2;
3932
4665
  return c.name === colName && ((_a2 = c.type) == null ? void 0 : _a2.toUpperCase()) === "RELATION";
3933
4666
  });
3934
- if (!col || !((_a = col.config) == null ? void 0 : _a.referencedTableId)) return;
4667
+ if (!col || !((_a = col.config) == null ? void 0 : _a.referencedTableId)) return [];
3935
4668
  try {
3936
4669
  if (executeAction) {
3937
- const options = await executeAction("FETCH_RELATION", { referencedTableId: (_b = col.config) == null ? void 0 : _b.referencedTableId, displayField: (_c = col.config) == null ? void 0 : _c.displayField });
3938
- if (options && Array.isArray(options)) {
3939
- setRelationOptions((prev) => __spreadProps(__spreadValues({}, prev), { [colName]: options }));
4670
+ const take = (_c = (_b = params == null ? void 0 : params.take) != null ? _b : params == null ? void 0 : params.limit) != null ? _c : 1e3;
4671
+ const payload = {
4672
+ referencedTableId: (_d = col.config) == null ? void 0 : _d.referencedTableId,
4673
+ displayField: (_e = col.config) == null ? void 0 : _e.displayField
4674
+ };
4675
+ if (params == null ? void 0 : params.recordIds) {
4676
+ payload.recordIds = params.recordIds;
4677
+ } else {
4678
+ payload.take = take;
4679
+ payload.limit = take;
4680
+ payload.skip = (_f = params == null ? void 0 : params.skip) != null ? _f : 0;
4681
+ payload.search = (_g = params == null ? void 0 : params.search) != null ? _g : "";
4682
+ }
4683
+ const options = await executeAction("FETCH_RELATION", payload);
4684
+ const list = Array.isArray(options) ? options : (options == null ? void 0 : options.data) && Array.isArray(options.data) ? options.data : [];
4685
+ if (list && Array.isArray(list)) {
4686
+ mergeRelationOptions(colName, list);
4687
+ return list;
3940
4688
  }
3941
4689
  }
3942
4690
  } catch (err) {
3943
4691
  console.warn(`[TableBlock] Could not fetch relation options for column ${colName}:`, err);
3944
4692
  }
3945
- }, [schemaColsString, executeAction]);
3946
- (0, import_react12.useEffect)(() => {
4693
+ return [];
4694
+ }, [schemaColsString, executeAction, mergeRelationOptions]);
4695
+ const fetchRelationFilterOptions = (0, import_react14.useCallback)(async (colName) => {
4696
+ var _a;
4697
+ let parsedCols = [];
4698
+ try {
4699
+ parsedCols = JSON.parse(schemaColsString);
4700
+ } catch (e) {
4701
+ }
4702
+ const col = parsedCols.find((c) => {
4703
+ var _a2;
4704
+ return c.name === colName && ((_a2 = c.type) == null ? void 0 : _a2.toUpperCase()) === "RELATION";
4705
+ });
4706
+ if (!col || !((_a = col.config) == null ? void 0 : _a.referencedTableId) || !executeAction) return;
4707
+ const currentTableId = (schema == null ? void 0 : schema.tableMetaId) || (schema == null ? void 0 : schema.tableId) || (schema == null ? void 0 : schema.id);
4708
+ setLoadingFilterCol(colName);
4709
+ try {
4710
+ const res = await executeAction("FETCH_RELATION", {
4711
+ referencedTableId: col.config.referencedTableId,
4712
+ currentTableId,
4713
+ columnName: colName,
4714
+ isFilter: true,
4715
+ displayField: col.config.displayField,
4716
+ take: 1e3
4717
+ });
4718
+ const list = Array.isArray(res) ? res : (res == null ? void 0 : res.data) && Array.isArray(res.data) ? res.data : [];
4719
+ setRelationFilterOptions((prev) => __spreadProps(__spreadValues({}, prev), {
4720
+ [colName]: list
4721
+ }));
4722
+ if (list.length > 0) {
4723
+ mergeRelationOptions(colName, list);
4724
+ }
4725
+ } catch (err) {
4726
+ console.warn(`[TableBlock] Failed to fetch distinct relation filter options for ${colName}:`, err);
4727
+ } finally {
4728
+ setLoadingFilterCol(null);
4729
+ }
4730
+ }, [schemaColsString, schema == null ? void 0 : schema.tableMetaId, schema == null ? void 0 : schema.tableId, schema == null ? void 0 : schema.id, executeAction, mergeRelationOptions]);
4731
+ const requestedRelationIdsRef = (0, import_react14.useRef)({});
4732
+ (0, import_react14.useEffect)(() => {
4733
+ if (!executeAction || !data || data.length === 0) return;
4734
+ let parsedCols = [];
4735
+ try {
4736
+ parsedCols = JSON.parse(schemaColsString);
4737
+ } catch (e) {
4738
+ }
4739
+ const relationCols = parsedCols.filter(
4740
+ (c) => {
4741
+ var _a;
4742
+ return ((_a = c.type) == null ? void 0 : _a.toUpperCase()) === "RELATION";
4743
+ }
4744
+ );
4745
+ if (relationCols.length === 0) return;
4746
+ relationCols.forEach(async (col) => {
4747
+ var _a, _b;
4748
+ const referencedTableId = (_a = col.config) == null ? void 0 : _a.referencedTableId;
4749
+ if (!referencedTableId) return;
4750
+ const extractedIds = /* @__PURE__ */ new Set();
4751
+ data.forEach((row) => {
4752
+ if (!(row == null ? void 0 : row.data)) return;
4753
+ const ids = normalizeRelationValue(row.data[col.name]);
4754
+ ids.forEach((id) => {
4755
+ if (/^[0-9a-fA-F]{24}$/.test(id)) {
4756
+ extractedIds.add(id);
4757
+ }
4758
+ });
4759
+ });
4760
+ if (extractedIds.size === 0) return;
4761
+ const existingOptions = relationOptions[col.name] || [];
4762
+ const existingIds = new Set(existingOptions.map((o) => String(o.id)));
4763
+ if (!requestedRelationIdsRef.current[col.name]) {
4764
+ requestedRelationIdsRef.current[col.name] = /* @__PURE__ */ new Set();
4765
+ }
4766
+ const inFlight = requestedRelationIdsRef.current[col.name];
4767
+ const missingIds = Array.from(extractedIds).filter((id) => !existingIds.has(id) && !inFlight.has(id));
4768
+ if (missingIds.length === 0) return;
4769
+ missingIds.forEach((id) => inFlight.add(id));
4770
+ try {
4771
+ const resolved = await executeAction("FETCH_RELATION", {
4772
+ referencedTableId,
4773
+ displayField: (_b = col.config) == null ? void 0 : _b.displayField,
4774
+ recordIds: missingIds
4775
+ });
4776
+ const items = Array.isArray(resolved) ? resolved : (resolved == null ? void 0 : resolved.data) && Array.isArray(resolved.data) ? resolved.data : [];
4777
+ if (items.length > 0) {
4778
+ mergeRelationOptions(col.name, items);
4779
+ }
4780
+ } catch (err) {
4781
+ console.warn(`[TableBlock] Failed to populate relations for ${col.name}:`, err);
4782
+ }
4783
+ });
4784
+ }, [data, schemaColsString, executeAction, relationOptions, mergeRelationOptions]);
4785
+ (0, import_react14.useEffect)(() => {
3947
4786
  let parsedCols = [];
3948
4787
  try {
3949
4788
  parsedCols = JSON.parse(schemaColsString);
@@ -3957,7 +4796,7 @@ function TableBlockClient({
3957
4796
  refetchRelation(col.name);
3958
4797
  });
3959
4798
  }, [schemaColsString, refetchRelation]);
3960
- const normalizedColumns = (0, import_react12.useMemo)(() => {
4799
+ const normalizedColumns = (0, import_react14.useMemo)(() => {
3961
4800
  return (localColumns || []).map((col, idx) => {
3962
4801
  const isRequired = col.isRequired === true || String(col.isRequired) === "true";
3963
4802
  const isUnique = col.isUnique === true || String(col.isUnique) === "true";
@@ -3971,17 +4810,17 @@ function TableBlockClient({
3971
4810
  return ((_a = a.order) != null ? _a : 0) - ((_b = b.order) != null ? _b : 0);
3972
4811
  });
3973
4812
  }, [localColumns]);
3974
- const filteredColumns = (0, import_react12.useMemo)(() => {
4813
+ const filteredColumns = (0, import_react14.useMemo)(() => {
3975
4814
  const systemFields = ["_id", "createdAt", "updatedAt", "orgId", "tableId"];
3976
4815
  return normalizedColumns.filter((col) => !systemFields.includes(col.name) && !col.isHidden);
3977
4816
  }, [normalizedColumns]);
3978
- const customizableColumns = (0, import_react12.useMemo)(() => {
4817
+ const customizableColumns = (0, import_react14.useMemo)(() => {
3979
4818
  const systemFields = ["_id", "createdAt", "updatedAt", "orgId", "tableId"];
3980
4819
  return normalizedColumns.filter((col) => !systemFields.includes(col.name));
3981
4820
  }, [normalizedColumns]);
3982
- const [isColumnsDropdownOpen, setIsColumnsDropdownOpen] = (0, import_react12.useState)(false);
3983
- const dropdownRef = (0, import_react12.useRef)(null);
3984
- (0, import_react12.useEffect)(() => {
4821
+ const [isColumnsDropdownOpen, setIsColumnsDropdownOpen] = (0, import_react14.useState)(false);
4822
+ const dropdownRef = (0, import_react14.useRef)(null);
4823
+ (0, import_react14.useEffect)(() => {
3985
4824
  const handleClickOutside = (e) => {
3986
4825
  if (dropdownRef.current && !dropdownRef.current.contains(e.target)) {
3987
4826
  setIsColumnsDropdownOpen(false);
@@ -4191,46 +5030,45 @@ function TableBlockClient({
4191
5030
  setData((prev) => [newRow, ...prev]);
4192
5031
  setDirty((prev) => __spreadProps(__spreadValues({}, prev), { added: [newRow, ...prev.added] }));
4193
5032
  };
4194
- const handleCellChange = (rowId, colName, value) => {
5033
+ const handleCellChange = (0, import_react14.useCallback)((rowId, colName, value) => {
4195
5034
  setData((prev) => prev.map(
4196
5035
  (row) => row.id === rowId ? __spreadProps(__spreadValues({}, row), { data: __spreadProps(__spreadValues({}, row.data), { [colName]: value }) }) : row
4197
5036
  ));
4198
- const isAdded = dirty.added.some((r) => r.id === rowId);
4199
- if (isAdded) {
4200
- setDirty((prev) => __spreadProps(__spreadValues({}, prev), {
4201
- added: prev.added.map(
4202
- (r) => r.id === rowId ? __spreadProps(__spreadValues({}, r), { data: __spreadProps(__spreadValues({}, r.data), { [colName]: value }) }) : r
4203
- )
4204
- }));
4205
- } else {
4206
- const origData = baseRecordsMap.get(rowId) || {};
4207
- const origValue = origData[colName];
4208
- setDirty((prev) => {
4209
- const currentMods = __spreadValues({}, prev.modified[rowId] || {});
4210
- if (isEqualValues(value, origValue)) {
4211
- delete currentMods[colName];
4212
- } else {
4213
- currentMods[colName] = value;
4214
- }
4215
- const nextModified = __spreadValues({}, prev.modified);
4216
- if (Object.keys(currentMods).length === 0) {
4217
- delete nextModified[rowId];
4218
- } else {
4219
- nextModified[rowId] = currentMods;
4220
- }
5037
+ setDirty((prev) => {
5038
+ const isAdded = prev.added.some((r) => r.id === rowId);
5039
+ if (isAdded) {
4221
5040
  return __spreadProps(__spreadValues({}, prev), {
4222
- modified: nextModified
5041
+ added: prev.added.map(
5042
+ (r) => r.id === rowId ? __spreadProps(__spreadValues({}, r), { data: __spreadProps(__spreadValues({}, r.data), { [colName]: value }) }) : r
5043
+ )
4223
5044
  });
5045
+ }
5046
+ const origData = baseRecordsMap.get(rowId) || {};
5047
+ const origValue = origData[colName];
5048
+ const currentMods = __spreadValues({}, prev.modified[rowId] || {});
5049
+ if (isEqualValues(value, origValue)) {
5050
+ delete currentMods[colName];
5051
+ } else {
5052
+ currentMods[colName] = value;
5053
+ }
5054
+ const nextModified = __spreadValues({}, prev.modified);
5055
+ if (Object.keys(currentMods).length === 0) {
5056
+ delete nextModified[rowId];
5057
+ } else {
5058
+ nextModified[rowId] = currentMods;
5059
+ }
5060
+ return __spreadProps(__spreadValues({}, prev), {
5061
+ modified: nextModified
4224
5062
  });
4225
- }
4226
- };
4227
- const triggerSaveSuccess = (0, import_react12.useCallback)(() => {
5063
+ });
5064
+ }, [baseRecordsMap]);
5065
+ const triggerSaveSuccess = (0, import_react14.useCallback)(() => {
4228
5066
  setIsSaveSuccess(true);
4229
5067
  setTimeout(() => {
4230
5068
  setIsSaveSuccess(false);
4231
5069
  }, 2500);
4232
5070
  }, []);
4233
- const handleQuietCellChange = (0, import_react12.useCallback)((rowId, colName, value) => {
5071
+ const handleQuietCellChange = (0, import_react14.useCallback)((rowId, colName, value) => {
4234
5072
  setData((prev) => prev.map(
4235
5073
  (row) => row.id === rowId ? __spreadProps(__spreadValues({}, row), { data: __spreadProps(__spreadValues({}, row.data), { [colName]: value }) }) : row
4236
5074
  ));
@@ -4254,22 +5092,28 @@ function TableBlockClient({
4254
5092
  });
4255
5093
  }
4256
5094
  }, []);
4257
- const toggleSelectAll = (checked) => {
4258
- const nextSelected = checked ? new Set(filteredData.map((r) => r.id)) : /* @__PURE__ */ new Set();
4259
- setSelectedIds(nextSelected);
4260
- if (emitEvent) {
4261
- emitEvent("SELECTION_CHANGE", { selectedIds: Array.from(nextSelected), componentId });
4262
- }
4263
- };
4264
- const toggleSelectRow = (rowId, checked) => {
4265
- const newSelected = new Set(selectedIds);
4266
- if (checked) newSelected.add(rowId);
4267
- else newSelected.delete(rowId);
4268
- setSelectedIds(newSelected);
4269
- if (emitEvent) {
4270
- emitEvent("SELECTION_CHANGE", { selectedIds: Array.from(newSelected), componentId });
4271
- }
4272
- };
5095
+ const toggleSelectAll = (0, import_react14.useCallback)((checked) => {
5096
+ setSelectedIds(checked ? new Set(filteredData.map((r) => r.id)) : /* @__PURE__ */ new Set());
5097
+ }, [filteredData]);
5098
+ const toggleSelectRow = (0, import_react14.useCallback)((rowId, checked) => {
5099
+ setSelectedIds((prev) => {
5100
+ const next = new Set(prev);
5101
+ if (checked) next.add(rowId);
5102
+ else next.delete(rowId);
5103
+ return next;
5104
+ });
5105
+ }, []);
5106
+ const handleToggleExpand = (0, import_react14.useCallback)((rowId) => {
5107
+ setExpandedRowIds((prev) => {
5108
+ const next = new Set(prev);
5109
+ if (next.has(rowId)) next.delete(rowId);
5110
+ else next.add(rowId);
5111
+ return next;
5112
+ });
5113
+ }, []);
5114
+ const handleMarkForDeletion = (0, import_react14.useCallback)((fileId) => {
5115
+ setPendingDeletions((prev) => [...prev, fileId]);
5116
+ }, []);
4273
5117
  const handleDeleteSelected = () => {
4274
5118
  const idsToDelete = Array.from(selectedIds);
4275
5119
  if (idsToDelete.length === 0) return;
@@ -4348,9 +5192,6 @@ function TableBlockClient({
4348
5192
  setData(serverRecords.map((r) => __spreadProps(__spreadValues({}, r), { data: __spreadValues({}, r.data) })));
4349
5193
  setSelectedIds(/* @__PURE__ */ new Set());
4350
5194
  setPendingDeletions([]);
4351
- if (emitEvent) {
4352
- emitEvent("SELECTION_CHANGE", { selectedIds: [], componentId });
4353
- }
4354
5195
  };
4355
5196
  const handleSave = async () => {
4356
5197
  var _a, _b;
@@ -4498,7 +5339,7 @@ function TableBlockClient({
4498
5339
  setIsSaving(false);
4499
5340
  }
4500
5341
  };
4501
- const getRowRelationLabels = (0, import_react12.useCallback)((rowVal, col) => {
5342
+ const getRowRelationLabels = (0, import_react14.useCallback)((rowVal, col) => {
4502
5343
  const ids = normalizeRelationValue(rowVal);
4503
5344
  if (ids.length === 0) return [];
4504
5345
  const options = relationOptions[col.name] || [];
@@ -4506,19 +5347,23 @@ function TableBlockClient({
4506
5347
  const opt = options.find((o) => o.id === id || o._id === id);
4507
5348
  if (opt) {
4508
5349
  const resolved = resolveRelationLabel(opt, col);
4509
- if (resolved) return resolved;
4510
- if (opt.label) return String(opt.label);
4511
- if (opt.name) return String(opt.name);
5350
+ if (resolved && !isRawObjectId(resolved)) return resolved;
5351
+ if (opt.label && !isRawObjectId(String(opt.label))) return String(opt.label);
5352
+ if (opt.name && !isRawObjectId(String(opt.name))) return String(opt.name);
4512
5353
  }
4513
5354
  if (typeof rowVal === "object" && rowVal !== null) {
4514
- if (rowVal._displayLabel) return String(rowVal._displayLabel);
4515
- if (rowVal.label) return String(rowVal.label);
5355
+ if (rowVal._displayLabel && !isRawObjectId(String(rowVal._displayLabel))) return String(rowVal._displayLabel);
5356
+ if (rowVal.label && !isRawObjectId(String(rowVal.label))) return String(rowVal.label);
4516
5357
  }
4517
- return id;
4518
- });
5358
+ return "";
5359
+ }).filter(Boolean);
4519
5360
  }, [relationOptions]);
4520
- const getUniqueRelationOptions = (0, import_react12.useCallback)((col) => {
5361
+ const getUniqueRelationOptions = (0, import_react14.useCallback)((col) => {
5362
+ if (relationFilterOptions[col.name]) {
5363
+ return relationFilterOptions[col.name];
5364
+ }
4521
5365
  const seenIds = /* @__PURE__ */ new Set();
5366
+ const seenLabels = /* @__PURE__ */ new Set();
4522
5367
  const results = [];
4523
5368
  const options = relationOptions[col.name] || [];
4524
5369
  data.forEach((row) => {
@@ -4529,58 +5374,23 @@ function TableBlockClient({
4529
5374
  seenIds.add(id);
4530
5375
  const opt = options.find((o) => o.id === id || o._id === id);
4531
5376
  let label = opt ? resolveRelationLabel(opt, col) : "";
4532
- if (!label && opt) label = opt.label || opt.name || opt.title || id;
4533
- if (!label) label = id;
4534
- results.push({ id, label });
4535
- }
4536
- });
4537
- });
4538
- return results.sort((a, b) => a.label.localeCompare(b.label));
4539
- }, [data, relationOptions]);
4540
- const filteredData = (0, import_react12.useMemo)(() => {
4541
- const hasGlobalSearch = Boolean(searchQuery && searchQuery.trim() !== "");
4542
- const activeFilters = Object.entries(columnFilters).filter(([, val]) => Boolean(val && val.trim() !== ""));
4543
- const hasColumnFilters = activeFilters.length > 0;
4544
- if (!hasGlobalSearch && !hasColumnFilters) return data;
4545
- const lowerGlobal = hasGlobalSearch ? searchQuery.trim().toLowerCase() : "";
4546
- return data.filter((row) => {
4547
- var _a;
4548
- if (!row || !row.data) return false;
4549
- if (hasGlobalSearch) {
4550
- const matchesGlobal = (localColumns || []).some((col) => {
4551
- var _a2;
4552
- const rawVal = row.data[col.name];
4553
- if (rawVal === void 0 || rawVal === null) return false;
4554
- if (((_a2 = col.type) == null ? void 0 : _a2.toUpperCase()) === "RELATION") {
4555
- const labels = getRowRelationLabels(rawVal, col);
4556
- return labels.some((l) => l.toLowerCase().includes(lowerGlobal));
5377
+ if (!label && opt) {
5378
+ const fallback = opt.label || opt.name || opt.title;
5379
+ if (fallback && typeof fallback === "string" && !isRawObjectId(fallback)) {
5380
+ label = fallback.trim();
5381
+ }
4557
5382
  }
4558
- if (typeof rawVal === "object") {
4559
- return JSON.stringify(rawVal).toLowerCase().includes(lowerGlobal);
5383
+ if (label && label.trim() && label !== id && !isRawObjectId(label) && !seenLabels.has(label.trim())) {
5384
+ seenLabels.add(label.trim());
5385
+ results.push({ id, label: label.trim() });
4560
5386
  }
4561
- return String(rawVal).toLowerCase().includes(lowerGlobal);
4562
- });
4563
- if (!matchesGlobal) return false;
4564
- }
4565
- for (const [colName, filterVal] of activeFilters) {
4566
- const lowerFilter = filterVal.trim().toLowerCase();
4567
- const col = (localColumns || []).find((c) => c.name === colName);
4568
- const rawVal = row.data[colName];
4569
- if (((_a = col == null ? void 0 : col.type) == null ? void 0 : _a.toUpperCase()) === "RELATION") {
4570
- const labels = getRowRelationLabels(rawVal, col);
4571
- const matches = labels.some((l) => l.toLowerCase().includes(lowerFilter));
4572
- if (!matches) return false;
4573
- } else {
4574
- if (rawVal === void 0 || rawVal === null) return false;
4575
- const strVal = typeof rawVal === "object" ? JSON.stringify(rawVal).toLowerCase() : String(rawVal).toLowerCase();
4576
- if (!strVal.includes(lowerFilter)) return false;
4577
5387
  }
4578
- }
4579
- return true;
5388
+ });
4580
5389
  });
4581
- }, [data, searchQuery, columnFilters, localColumns, getRowRelationLabels]);
5390
+ return results.sort((a, b) => a.label.localeCompare(b.label));
5391
+ }, [data, relationOptions, relationFilterOptions]);
4582
5392
  const errorMessage = error ? typeof error === "string" ? error : error.message || String(error) : null;
4583
- const columnTotals = (0, import_react12.useMemo)(() => {
5393
+ const columnTotals = (0, import_react14.useMemo)(() => {
4584
5394
  const totals = {};
4585
5395
  if (!showSummary) return totals;
4586
5396
  filteredColumns.forEach((col) => {
@@ -4598,42 +5408,120 @@ function TableBlockClient({
4598
5408
  });
4599
5409
  return totals;
4600
5410
  }, [filteredData, filteredColumns, showSummary]);
4601
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
5411
+ const hasSelectedRows = selectedIds.size > 0;
5412
+ const hasActiveSearchOrFilter = Boolean(searchQuery && searchQuery.trim() !== "") || Object.values(columnFilters).some(
5413
+ (v) => Array.isArray(v) ? v.length > 0 : v && typeof v === "object" && "values" in v ? v.values.length > 0 : typeof v === "string" && Boolean(v.trim())
5414
+ );
5415
+ let exportButtonText = "\u05D9\u05D9\u05E6\u05D0 \u05E0\u05EA\u05D5\u05E0\u05D9\u05DD";
5416
+ let ExportButtonIcon = import_lucide_react8.Download;
5417
+ if (hasSelectedRows) {
5418
+ exportButtonText = `\u05D9\u05D9\u05E6\u05D0 ${selectedIds.size} \u05E8\u05E9\u05D5\u05DE\u05D5\u05EA`;
5419
+ ExportButtonIcon = import_lucide_react8.Download;
5420
+ } else if (hasActiveSearchOrFilter) {
5421
+ exportButtonText = "\u05D9\u05D9\u05E6\u05D0 \u05EA\u05D5\u05E6\u05D0\u05D5\u05EA \u05E1\u05D9\u05E0\u05D5\u05DF";
5422
+ ExportButtonIcon = import_lucide_react8.Filter;
5423
+ }
5424
+ const handleExportCsv = async () => {
5425
+ if (isExporting) return;
5426
+ const systemFields = ["_id", "id", "createdAt", "updatedAt", "createdBy", "updatedBy", "orgId", "tableId"];
5427
+ const userHiddenColumns = normalizedColumns.filter((c) => c.isHidden && !systemFields.includes(c.name)).map((c) => c.name);
5428
+ if (userHiddenColumns.length > 0) {
5429
+ addToast({
5430
+ 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",
5431
+ type: "info",
5432
+ duration: 3e3
5433
+ });
5434
+ } else {
5435
+ addToast({
5436
+ message: "\u05DE\u05D9\u05D9\u05E6\u05D0 \u05E0\u05EA\u05D5\u05E0\u05D9\u05DD...",
5437
+ type: "info",
5438
+ duration: 3e3
5439
+ });
5440
+ }
5441
+ setIsExporting(true);
5442
+ try {
5443
+ const targetTableId = (schema == null ? void 0 : schema.tableMetaId) || (schema == null ? void 0 : schema.tableId) || (schema == null ? void 0 : schema.id);
5444
+ if (!targetTableId) {
5445
+ showError("\u05DE\u05D6\u05D4\u05D4 \u05D4\u05D8\u05D1\u05DC\u05D4 \u05D7\u05E1\u05E8 (tableId)", "\u05E9\u05D2\u05D9\u05D0\u05EA \u05D9\u05D9\u05E6\u05D5\u05D0");
5446
+ return;
5447
+ }
5448
+ const payload = {
5449
+ tableId: targetTableId,
5450
+ orgId,
5451
+ search: searchQuery.trim() || void 0,
5452
+ columnFilters: Object.keys(columnFilters).length > 0 ? columnFilters : void 0,
5453
+ selectedRowIds: hasSelectedRows ? Array.from(selectedIds) : [],
5454
+ hiddenColumnIds: userHiddenColumns
5455
+ };
5456
+ let res;
5457
+ if (exportAction) {
5458
+ res = await exportAction(payload);
5459
+ } else if (executeAction) {
5460
+ res = await executeAction("EXPORT_TABLE_TO_CSV", payload);
5461
+ } else {
5462
+ throw new Error("\u05E8\u05DB\u05D9\u05D1 \u05D4\u05EA\u05E7\u05E9\u05D5\u05E8\u05EA \u05DC\u05D0 \u05D0\u05D5\u05EA\u05D7\u05DC");
5463
+ }
5464
+ const result = (res == null ? void 0 : res.data) || res;
5465
+ if ((result == null ? void 0 : result.success) === false) {
5466
+ throw new Error(result.error || "\u05E9\u05D2\u05D9\u05D0\u05D4 \u05D1\u05D9\u05D9\u05E6\u05D5\u05D0 \u05D4\u05E0\u05EA\u05D5\u05E0\u05D9\u05DD");
5467
+ }
5468
+ const csvString = (result == null ? void 0 : result.csvString) || (result == null ? void 0 : result.csv);
5469
+ if (!csvString) {
5470
+ throw new Error("\u05DC\u05D0 \u05D4\u05EA\u05E7\u05D1\u05DC\u05D5 \u05E0\u05EA\u05D5\u05E0\u05D9 CSV \u05DE\u05D4\u05E9\u05E8\u05EA");
5471
+ }
5472
+ const fileName = (result == null ? void 0 : result.fileName) || `${((schema == null ? void 0 : schema.title) || (schema == null ? void 0 : schema.name) || "table").trim()}_export.csv`;
5473
+ const blob = new Blob([csvString], { type: "text/csv;charset=utf-8;" });
5474
+ const url = URL.createObjectURL(blob);
5475
+ const link = document.createElement("a");
5476
+ link.href = url;
5477
+ link.setAttribute("download", fileName);
5478
+ document.body.appendChild(link);
5479
+ link.click();
5480
+ document.body.removeChild(link);
5481
+ URL.revokeObjectURL(url);
5482
+ } catch (err) {
5483
+ console.error("[TableBlock] Export to CSV failed:", err);
5484
+ 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");
5485
+ } finally {
5486
+ setIsExporting(false);
5487
+ }
5488
+ };
5489
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
4602
5490
  "div",
4603
5491
  {
4604
5492
  id: componentId,
4605
5493
  "data-testid": dataTestId || (componentId ? `table-block-${componentId}` : void 0),
4606
- className: `flex flex-col w-full bg-white border border-slate-200 rounded-xl shadow-xs min-h-[350px] overflow-hidden ${className}`,
5494
+ className: `flex flex-col w-full bg-white border border-slate-200 rounded-xl shadow-xs flex-1 min-h-0 overflow-hidden ${className}`,
4607
5495
  dir: "rtl",
4608
5496
  children: [
4609
- errorMessage && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "p-3 bg-rose-50 border-b border-rose-200 text-rose-700 text-sm flex items-center justify-between", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex items-center gap-2", children: [
4610
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("svg", { className: "w-4 h-4 text-rose-500 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" }) }),
4611
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { children: errorMessage })
5497
+ errorMessage && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("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__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex items-center gap-2", children: [
5498
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("svg", { className: "w-4 h-4 text-rose-500 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" }) }),
5499
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { children: errorMessage })
4612
5500
  ] }) }),
4613
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("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: [
4614
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex flex-wrap items-center gap-2.5", children: [
4615
- ((schema == null ? void 0 : schema.title) || (schema == null ? void 0 : schema.name)) && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "font-bold text-slate-800 text-sm sm:text-base border-l border-slate-300 pl-3 ml-1", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { children: schema.title || schema.name }) }),
4616
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
5501
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("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: [
5502
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex flex-wrap items-center gap-2.5", children: [
5503
+ ((schema == null ? void 0 : schema.title) || (schema == null ? void 0 : schema.name)) && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "font-bold text-slate-800 text-sm sm:text-base border-l border-slate-300 pl-3 ml-1", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { children: schema.title || schema.name }) }),
5504
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
4617
5505
  "button",
4618
5506
  {
4619
5507
  onClick: handleAddRow,
4620
5508
  disabled: isInitialLoading || isLoading || isUpdatingActive,
4621
5509
  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"}`,
4622
5510
  title: isInitialLoading ? "\u05D8\u05D5\u05E2\u05DF \u05E0\u05EA\u05D5\u05E0\u05D9\u05DD..." : "\u05D4\u05D5\u05E1\u05E3 \u05E9\u05D5\u05E8\u05D4 \u05D7\u05D3\u05E9\u05D4",
4623
- children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("svg", { className: "w-4.5 h-4.5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2.5", d: "M12 4v16m8-8H4" }) })
5511
+ children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("svg", { className: "w-4.5 h-4.5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2.5", d: "M12 4v16m8-8H4" }) })
4624
5512
  }
4625
5513
  ),
4626
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
5514
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
4627
5515
  "button",
4628
5516
  {
4629
5517
  onClick: handleDuplicateRow,
4630
5518
  disabled: isInitialLoading || isLoading || isUpdatingActive || selectedIds.size !== 1,
4631
5519
  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",
4632
5520
  title: "\u05E9\u05DB\u05E4\u05DC \u05E9\u05D5\u05E8\u05D4 \u05E0\u05D1\u05D7\u05E8\u05EA",
4633
- children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react7.Copy, { className: "w-4 h-4 text-blue-600 shrink-0" })
5521
+ children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_lucide_react8.Copy, { className: "w-4 h-4 text-blue-600 shrink-0" })
4634
5522
  }
4635
5523
  ),
4636
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
5524
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
4637
5525
  "button",
4638
5526
  {
4639
5527
  onClick: handleDeleteSelected,
@@ -4641,12 +5529,12 @@ function TableBlockClient({
4641
5529
  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",
4642
5530
  title: "\u05DE\u05D7\u05E7 \u05E9\u05D5\u05E8\u05D5\u05EA \u05E0\u05D1\u05D7\u05E8\u05D5\u05EA",
4643
5531
  children: [
4644
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("svg", { className: "w-4.5 h-4.5 text-rose-600 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("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" }) }),
4645
- selectedIds.size > 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("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 })
5532
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("svg", { className: "w-4.5 h-4.5 text-rose-600 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("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" }) }),
5533
+ selectedIds.size > 0 && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("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 })
4646
5534
  ]
4647
5535
  }
4648
5536
  ),
4649
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
5537
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
4650
5538
  "button",
4651
5539
  {
4652
5540
  onClick: toggleSummary,
@@ -4654,13 +5542,13 @@ function TableBlockClient({
4654
5542
  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"}`,
4655
5543
  title: "\u05D4\u05E6\u05D2/\u05D4\u05E1\u05EA\u05E8 \u05E9\u05D5\u05E8\u05EA \u05E1\u05D9\u05DB\u05D5\u05DD",
4656
5544
  children: [
4657
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("svg", { className: "w-4 h-4 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M4 6h16M4 10h16M4 14h16M4 18h16" }) }),
4658
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "hidden sm:inline", children: "\u05E1\u05DB\u05D9\u05DE\u05D4" })
5545
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("svg", { className: "w-4 h-4 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M4 6h16M4 10h16M4 14h16M4 18h16" }) }),
5546
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "hidden sm:inline", children: "\u05E1\u05DB\u05D9\u05DE\u05D4" })
4659
5547
  ]
4660
5548
  }
4661
5549
  ),
4662
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "relative", ref: dropdownRef, children: [
4663
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
5550
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "relative", ref: dropdownRef, children: [
5551
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
4664
5552
  "button",
4665
5553
  {
4666
5554
  onClick: () => setIsColumnsDropdownOpen((prev) => !prev),
@@ -4668,16 +5556,16 @@ function TableBlockClient({
4668
5556
  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",
4669
5557
  title: "\u05D4\u05E6\u05D2/\u05D4\u05E1\u05EA\u05E8 \u05E2\u05DE\u05D5\u05D3\u05D5\u05EA",
4670
5558
  children: [
4671
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("svg", { className: "w-4 h-4 text-slate-600 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("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" }) }),
4672
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("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__ */ (0, import_jsx_runtime10.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M19 9l-7 7-7-7" }) })
5559
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("svg", { className: "w-4 h-4 text-slate-600 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("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" }) }),
5560
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("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__ */ (0, import_jsx_runtime11.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M19 9l-7 7-7-7" }) })
4673
5561
  ]
4674
5562
  }
4675
5563
  ),
4676
- isColumnsDropdownOpen && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("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: [
4677
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("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: [
4678
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex items-center gap-1.5", children: [
4679
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { children: "\u05D4\u05E6\u05D2\u05EA \u05E2\u05DE\u05D5\u05D3\u05D5\u05EA" }),
4680
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: "text-[10px] font-normal text-slate-400", children: [
5564
+ isColumnsDropdownOpen && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("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: [
5565
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("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: [
5566
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex items-center gap-1.5", children: [
5567
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { children: "\u05D4\u05E6\u05D2\u05EA \u05E2\u05DE\u05D5\u05D3\u05D5\u05EA" }),
5568
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { className: "text-[10px] font-normal text-slate-400", children: [
4681
5569
  "(",
4682
5570
  customizableColumns.filter((c) => !c.isHidden).length,
4683
5571
  "/",
@@ -4685,7 +5573,7 @@ function TableBlockClient({
4685
5573
  ")"
4686
5574
  ] })
4687
5575
  ] }),
4688
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
5576
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
4689
5577
  "button",
4690
5578
  {
4691
5579
  type: "button",
@@ -4695,7 +5583,7 @@ function TableBlockClient({
4695
5583
  }
4696
5584
  )
4697
5585
  ] }),
4698
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "max-h-60 overflow-y-auto space-y-0.5", children: customizableColumns.map((col) => {
5586
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "max-h-60 overflow-y-auto space-y-0.5", children: customizableColumns.map((col) => {
4699
5587
  const isRequired = col.isRequired === true || String(col.isRequired) === "true";
4700
5588
  const isUnique = col.isUnique === true || String(col.isUnique) === "true";
4701
5589
  const isProtected = isRequired || isUnique;
@@ -4709,7 +5597,7 @@ function TableBlockClient({
4709
5597
  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";
4710
5598
  }
4711
5599
  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";
4712
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
5600
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
4713
5601
  "div",
4714
5602
  {
4715
5603
  onClick: () => {
@@ -4720,8 +5608,8 @@ function TableBlockClient({
4720
5608
  title: isProtected ? protectedExplanation : void 0,
4721
5609
  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"}`,
4722
5610
  children: [
4723
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex items-center gap-2 min-w-0", children: [
4724
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
5611
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex items-center gap-2 min-w-0", children: [
5612
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
4725
5613
  "input",
4726
5614
  {
4727
5615
  type: "checkbox",
@@ -4732,16 +5620,16 @@ function TableBlockClient({
4732
5620
  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"
4733
5621
  }
4734
5622
  ),
4735
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: `font-medium truncate ${isProtected ? "text-slate-500" : "text-slate-700"}`, children: col.name })
5623
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: `font-medium truncate ${isProtected ? "text-slate-500" : "text-slate-700"}`, children: col.name })
4736
5624
  ] }),
4737
- isProtected && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
5625
+ isProtected && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
4738
5626
  "div",
4739
5627
  {
4740
5628
  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",
4741
5629
  title: protectedExplanation,
4742
5630
  children: [
4743
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("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__ */ (0, import_jsx_runtime10.jsx)("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" }) }),
4744
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { children: badgeLabel })
5631
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("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__ */ (0, import_jsx_runtime11.jsx)("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" }) }),
5632
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { children: badgeLabel })
4745
5633
  ]
4746
5634
  }
4747
5635
  )
@@ -4752,9 +5640,23 @@ function TableBlockClient({
4752
5640
  }) })
4753
5641
  ] })
4754
5642
  ] }),
4755
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "h-5 w-px bg-slate-300 mx-1 hidden sm:block" }),
4756
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "relative flex-1 sm:w-64 max-w-xs", children: [
4757
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
5643
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
5644
+ "button",
5645
+ {
5646
+ onClick: handleExportCsv,
5647
+ disabled: isLoading || isUpdatingActive || isExporting,
5648
+ 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"}`,
5649
+ title: exportButtonText,
5650
+ "data-testid": "export-csv-button",
5651
+ children: [
5652
+ isExporting ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_lucide_react8.Loader2, { className: "w-4 h-4 shrink-0 animate-spin text-slate-500" }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(ExportButtonIcon, { className: "w-4 h-4 shrink-0" }),
5653
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { children: isExporting ? "\u05DE\u05D9\u05D9\u05E6\u05D0..." : exportButtonText })
5654
+ ]
5655
+ }
5656
+ ),
5657
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "h-5 w-px bg-slate-300 mx-1 hidden sm:block" }),
5658
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "relative flex-1 sm:w-64 max-w-xs", children: [
5659
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
4758
5660
  "input",
4759
5661
  {
4760
5662
  placeholder: "\u05D7\u05D9\u05E4\u05D5\u05E9 \u05D1\u05E8\u05E9\u05D5\u05DE\u05D5\u05EA...",
@@ -4764,28 +5666,28 @@ function TableBlockClient({
4764
5666
  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"
4765
5667
  }
4766
5668
  ),
4767
- searchQuery ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
5669
+ searchQuery ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
4768
5670
  "button",
4769
5671
  {
4770
5672
  type: "button",
4771
5673
  onClick: () => setSearchQuery(""),
4772
5674
  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",
4773
5675
  title: "Clear search",
4774
- children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react7.X, { className: "w-3.5 h-3.5" })
5676
+ children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_lucide_react8.X, { className: "w-3.5 h-3.5" })
4775
5677
  }
4776
- ) : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("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__ */ (0, import_jsx_runtime10.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" }) })
5678
+ ) : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("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__ */ (0, import_jsx_runtime11.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" }) })
4777
5679
  ] })
4778
5680
  ] }),
4779
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex items-center gap-3", children: [
4780
- isUpdatingActive ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("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: [
4781
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "w-2 h-2 rounded-full bg-blue-500 inline-block" }),
5681
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex items-center gap-3", children: [
5682
+ isUpdatingActive ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("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: [
5683
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "w-2 h-2 rounded-full bg-blue-500 inline-block" }),
4782
5684
  "\u05DE\u05E2\u05D3\u05DB\u05DF..."
4783
- ] }) : isSaveSuccess ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("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: [
4784
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("svg", { className: "w-4 h-4 text-emerald-600 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2.5", d: "M5 13l4 4L19 7" }) }),
5685
+ ] }) : isSaveSuccess ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("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: [
5686
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("svg", { className: "w-4 h-4 text-emerald-600 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2.5", d: "M5 13l4 4L19 7" }) }),
4785
5687
  "\u05E2\u05D5\u05D3\u05DB\u05DF \u05D1\u05D4\u05E6\u05DC\u05D7\u05D4"
4786
- ] }) : hasChanges ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex items-center gap-1.5 animate-in fade-in", children: [
4787
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("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" }),
4788
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
5688
+ ] }) : hasChanges ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex items-center gap-1.5 animate-in fade-in", children: [
5689
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("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" }),
5690
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
4789
5691
  "button",
4790
5692
  {
4791
5693
  type: "button",
@@ -4794,30 +5696,31 @@ function TableBlockClient({
4794
5696
  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",
4795
5697
  title: "\u05D1\u05D8\u05DC \u05D0\u05EA \u05DB\u05DC \u05D4\u05E9\u05D9\u05E0\u05D5\u05D9\u05D9\u05DD \u05E9\u05DC\u05D0 \u05E0\u05E9\u05DE\u05E8\u05D5",
4796
5698
  "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",
4797
- children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react7.RotateCcw, { className: "w-3.5 h-3.5" })
5699
+ children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_lucide_react8.RotateCcw, { className: "w-3.5 h-3.5" })
4798
5700
  }
4799
5701
  )
4800
5702
  ] }) : null,
4801
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
5703
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
4802
5704
  "button",
4803
5705
  {
4804
5706
  onClick: handleSave,
4805
5707
  disabled: isUpdatingActive || isLoading || !hasChanges,
4806
5708
  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"}`,
4807
- children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { children: isUpdatingActive ? "\u05E9\u05D5\u05DE\u05E8..." : "\u05E9\u05DE\u05D9\u05E8\u05EA \u05E9\u05D9\u05E0\u05D5\u05D9\u05D9\u05DD" })
5709
+ children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { children: isUpdatingActive ? "\u05E9\u05D5\u05DE\u05E8..." : "\u05E9\u05DE\u05D9\u05E8\u05EA \u05E9\u05D9\u05E0\u05D5\u05D9\u05D9\u05DD" })
4808
5710
  }
4809
5711
  )
4810
5712
  ] })
4811
5713
  ] }),
4812
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: `overflow-x-auto relative min-h-[260px] flex-1 transition-opacity duration-200 ${isMounted ? "opacity-100" : "opacity-0"}`, children: [
4813
- isLoading && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "absolute inset-0 bg-white/80 backdrop-blur-xs z-20 flex flex-col items-center justify-center gap-2", children: [
4814
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "w-6 h-6 border-2 border-brand border-t-transparent rounded-full animate-spin" }),
4815
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "text-sm font-medium text-slate-600", children: "\u05D8\u05D5\u05E2\u05DF \u05E0\u05EA\u05D5\u05E0\u05D9\u05DD..." })
5714
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("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: [
5715
+ isFetching && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "absolute top-0 left-0 right-0 h-0.5 bg-blue-500/20 overflow-hidden z-30", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "w-full h-full bg-brand animate-pulse" }) }),
5716
+ isLoading && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "absolute inset-0 bg-white/80 backdrop-blur-xs z-20 flex flex-col items-center justify-center gap-2", children: [
5717
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "w-6 h-6 border-2 border-brand border-t-transparent rounded-full animate-spin" }),
5718
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "text-sm font-medium text-slate-600", children: "\u05D8\u05D5\u05E2\u05DF \u05E0\u05EA\u05D5\u05E0\u05D9\u05DD..." })
4816
5719
  ] }),
4817
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("table", { className: "w-full text-sm text-right border-collapse table-auto", children: [
4818
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("thead", { className: "bg-slate-100/80 text-slate-700 sticky top-0 z-10", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("tr", { className: "h-12 min-h-[48px]", children: [
4819
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("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__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex items-center justify-center gap-1.5", children: [
4820
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
5720
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("table", { className: "w-full text-sm text-right border-collapse table-auto", children: [
5721
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("thead", { className: "bg-white text-slate-700 sticky top-0 z-10 shadow-xs", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("tr", { className: "h-12 min-h-[48px]", children: [
5722
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("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__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex items-center justify-center gap-1.5", children: [
5723
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
4821
5724
  "input",
4822
5725
  {
4823
5726
  type: "checkbox",
@@ -4830,7 +5733,7 @@ function TableBlockClient({
4830
5733
  filteredColumns.some((c) => {
4831
5734
  var _a;
4832
5735
  return ((_a = c.type) == null ? void 0 : _a.toUpperCase()) === "SUB_TABLE";
4833
- }) && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "w-5 h-5 shrink-0" })
5736
+ }) && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "w-5 h-5 shrink-0" })
4834
5737
  ] }) }),
4835
5738
  filteredColumns.map((col) => {
4836
5739
  var _a, _b;
@@ -4841,16 +5744,25 @@ function TableBlockClient({
4841
5744
  const colMinWidth = calculateMinColumnWidth(col.name, false, col.type);
4842
5745
  const currentWidth = Math.max(colMinWidth, columnWidths[col.name] || 200);
4843
5746
  const isRelation = ((_a = col.type) == null ? void 0 : _a.toUpperCase()) === "RELATION";
4844
- const filterVal = columnFilters[col.name] || "";
4845
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
5747
+ const filterVal = columnFilters[col.name];
5748
+ const hasActiveFilter = Array.isArray(filterVal) ? filterVal.length > 0 : filterVal && typeof filterVal === "object" && "values" in filterVal ? filterVal.values.length > 0 : Boolean(filterVal && filterVal.trim() !== "");
5749
+ let filterTooltip = "\u05D7\u05E4\u05E9 \u05D5\u05E1\u05E0\u05DF \u05D1\u05E2\u05DE\u05D5\u05D3\u05D4 \u05D6\u05D5";
5750
+ if (Array.isArray(filterVal)) {
5751
+ 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`;
5752
+ } else if (filterVal && typeof filterVal === "object" && "operator" in filterVal && filterVal.operator === "notIn") {
5753
+ filterTooltip = `\u05DE\u05D5\u05D7\u05E8\u05D2\u05D9\u05DD: ${filterVal.values.length} \u05E4\u05E8\u05D9\u05D8\u05D9\u05DD (\u05D4\u05DB\u05DC \u05DC\u05DE\u05E2\u05D8)`;
5754
+ } else if (typeof filterVal === "string" && filterVal.trim()) {
5755
+ filterTooltip = `\u05DE\u05E1\u05D5\u05E0\u05DF \u05DC\u05E4\u05D9: "${filterVal}" (\u05DC\u05D7\u05E5 \u05DC\u05E2\u05E8\u05D9\u05DB\u05D4)`;
5756
+ }
5757
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
4846
5758
  "th",
4847
5759
  __spreadProps(__spreadValues({
4848
5760
  style: { width: currentWidth, minWidth: currentWidth, maxWidth: currentWidth },
4849
5761
  title: isSearching ? void 0 : col.name
4850
5762
  }, dragProps), {
4851
- 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" : ""}`,
5763
+ 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" : ""}`,
4852
5764
  children: [
4853
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
5765
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
4854
5766
  "div",
4855
5767
  {
4856
5768
  onMouseDown: (e) => {
@@ -4862,7 +5774,7 @@ function TableBlockClient({
4862
5774
  title: "\u05E9\u05E0\u05D4 \u05D2\u05D5\u05D3\u05DC \u05E2\u05DE\u05D5\u05D3\u05D4"
4863
5775
  }
4864
5776
  ),
4865
- isSearching ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
5777
+ isSearching && !isRelation ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
4866
5778
  "div",
4867
5779
  {
4868
5780
  ref: activeSearchRef,
@@ -4870,46 +5782,15 @@ function TableBlockClient({
4870
5782
  onClick: (e) => e.stopPropagation(),
4871
5783
  onMouseDown: (e) => e.stopPropagation(),
4872
5784
  children: [
4873
- isRelation ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "relative flex items-center w-full min-w-0", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
4874
- "select",
4875
- {
4876
- autoFocus: true,
4877
- value: filterVal,
4878
- onChange: (e) => {
4879
- const val = e.target.value;
4880
- setColumnFilters((prev) => {
4881
- const next = __spreadValues({}, prev);
4882
- if (val) next[col.name] = val;
4883
- else delete next[col.name];
4884
- return next;
4885
- });
4886
- },
4887
- onKeyDown: (e) => {
4888
- if (e.key === "Escape" || e.key === "Enter") {
4889
- setActiveSearchCol(null);
4890
- }
4891
- },
4892
- 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",
4893
- children: [
4894
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("option", { value: "", children: "\u05D4\u05DB\u05DC" }),
4895
- getUniqueRelationOptions(col).map((opt) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("option", { value: opt.label, children: opt.label }, opt.id))
4896
- ]
4897
- }
4898
- ) }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "relative flex items-center w-full min-w-0", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
5785
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "relative flex items-center w-full min-w-0", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
4899
5786
  "input",
4900
5787
  {
4901
5788
  autoFocus: true,
4902
5789
  type: "text",
4903
5790
  placeholder: `\u05D7\u05E4\u05E9 \u05D1-${col.name}...`,
4904
- value: filterVal,
5791
+ value: typeof filterVal === "string" ? filterVal : "",
4905
5792
  onChange: (e) => {
4906
- const val = e.target.value;
4907
- setColumnFilters((prev) => {
4908
- const next = __spreadValues({}, prev);
4909
- if (val) next[col.name] = val;
4910
- else delete next[col.name];
4911
- return next;
4912
- });
5793
+ handleApplyColumnFilter(col.name, e.target.value);
4913
5794
  },
4914
5795
  onKeyDown: (e) => {
4915
5796
  if (e.key === "Escape" || e.key === "Enter") {
@@ -4919,7 +5800,7 @@ function TableBlockClient({
4919
5800
  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"
4920
5801
  }
4921
5802
  ) }),
4922
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
5803
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
4923
5804
  "button",
4924
5805
  {
4925
5806
  type: "button",
@@ -4929,59 +5810,60 @@ function TableBlockClient({
4929
5810
  },
4930
5811
  onClick: (e) => {
4931
5812
  e.stopPropagation();
4932
- setColumnFilters((prev) => {
4933
- const next = __spreadValues({}, prev);
4934
- delete next[col.name];
4935
- return next;
4936
- });
5813
+ handleApplyColumnFilter(col.name, void 0);
4937
5814
  setActiveSearchCol(null);
4938
5815
  },
4939
5816
  className: "p-1 text-slate-400 hover:text-slate-700 hover:bg-slate-200/70 rounded transition-colors cursor-pointer shrink-0",
4940
5817
  title: "\u05E0\u05E7\u05D4 \u05D5\u05E1\u05D2\u05D5\u05E8 \u05D7\u05D9\u05E4\u05D5\u05E9",
4941
- children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react7.X, { className: "w-3.5 h-3.5" })
5818
+ children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_lucide_react8.X, { className: "w-3.5 h-3.5" })
4942
5819
  }
4943
5820
  )
4944
5821
  ]
4945
5822
  }
4946
- ) : /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex items-center justify-between gap-1.5 group overflow-hidden w-full", title: col.name, children: [
4947
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "flex items-center gap-1.5 min-w-0 flex-1 overflow-hidden", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ColumnHeaderTitle, { name: col.name, width: currentWidth, isSubTable: false }) }),
4948
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex items-center gap-1 shrink-0", children: [
4949
- ((_b = col.type) == null ? void 0 : _b.toUpperCase()) !== "SUB_TABLE" && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
4950
- "button",
4951
- {
4952
- type: "button",
4953
- onClick: (e) => {
4954
- e.stopPropagation();
4955
- e.preventDefault();
5823
+ ) : /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("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: [
5824
+ ((_b = col.type) == null ? void 0 : _b.toUpperCase()) !== "SUB_TABLE" && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
5825
+ "button",
5826
+ {
5827
+ ref: (el) => {
5828
+ filterButtonRefs.current[col.name] = el;
5829
+ },
5830
+ type: "button",
5831
+ onClick: (e) => {
5832
+ e.stopPropagation();
5833
+ e.preventDefault();
5834
+ if (isRelation) {
5835
+ if (activeRelationCol === col.name) {
5836
+ setActiveRelationCol(null);
5837
+ setRelationTriggerRect(null);
5838
+ } else {
5839
+ const btn = filterButtonRefs.current[col.name];
5840
+ if (btn) {
5841
+ setRelationTriggerRect(btn.getBoundingClientRect());
5842
+ }
5843
+ setActiveRelationCol(col.name);
5844
+ fetchRelationFilterOptions(col.name);
5845
+ }
5846
+ } else {
4956
5847
  setActiveSearchCol(col.name);
4957
- },
4958
- 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"}`,
4959
- 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",
4960
- children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react7.Search, { className: "w-3.5 h-3.5" })
4961
- }
4962
- ),
4963
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
4964
- "svg",
4965
- {
4966
- className: "w-3.5 h-3.5 text-slate-400 opacity-40 group-hover:opacity-100 transition-opacity shrink-0 cursor-grab",
4967
- fill: "none",
4968
- viewBox: "0 0 24 24",
4969
- stroke: "currentColor",
4970
- children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M8 9h.01M8 15h.01M16 9h.01M16 15h.01" })
4971
- }
4972
- )
4973
- ] })
5848
+ }
5849
+ },
5850
+ 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"}`,
5851
+ title: filterTooltip,
5852
+ children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_lucide_react8.Filter, { className: "w-3 h-3" })
5853
+ }
5854
+ ),
5855
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(ColumnHeaderTitle, { name: col.name, width: currentWidth, isSubTable: false })
4974
5856
  ] })
4975
5857
  ]
4976
5858
  }),
4977
5859
  col.name
4978
5860
  );
4979
5861
  }),
4980
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("th", { className: "w-full min-w-[50px] border-b border-slate-200 pointer-events-none h-12 min-h-[48px]" })
5862
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("th", { className: "w-full min-w-[50px] border-b border-slate-200 pointer-events-none h-12 min-h-[48px] bg-white" })
4981
5863
  ] }) }),
4982
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("tbody", { className: "bg-white", children: (isStateEmpty || filteredData.length === 0) && !isLoading ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("tr", { children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("td", { colSpan: filteredColumns.length + 2, className: "text-center py-12 text-slate-400", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex flex-col items-center justify-center gap-2", children: [
4983
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("svg", { className: "w-8 h-8 text-slate-300", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("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" }) }),
4984
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { children: "\u05D0\u05D9\u05DF \u05E8\u05E9\u05D5\u05DE\u05D5\u05EA \u05DC\u05D4\u05E6\u05D2\u05D4." })
5864
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("tbody", { className: `bg-white transition-opacity duration-150 ${isFetching ? "opacity-50 pointer-events-none" : "opacity-100"}`, children: (isStateEmpty || filteredData.length === 0) && !isLoading && !isFetching ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("tr", { children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("td", { colSpan: filteredColumns.length + 2, className: "text-center py-12 text-slate-400", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex flex-col items-center justify-center gap-2", children: [
5865
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("svg", { className: "w-8 h-8 text-slate-300", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("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" }) }),
5866
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { children: "\u05D0\u05D9\u05DF \u05E8\u05E9\u05D5\u05DE\u05D5\u05EA \u05DC\u05D4\u05E6\u05D2\u05D4." })
4985
5867
  ] }) }) }) : filteredData.map((row) => {
4986
5868
  const hasSubTableCols = filteredColumns.some((c) => {
4987
5869
  var _a;
@@ -4992,108 +5874,40 @@ function TableBlockClient({
4992
5874
  var _a;
4993
5875
  return ((_a = c.type) == null ? void 0 : _a.toUpperCase()) === "SUB_TABLE";
4994
5876
  });
4995
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react12.default.Fragment, { children: [
4996
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("tr", { className: "hover:bg-blue-50/30 transition-colors group", children: [
4997
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("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__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex items-center justify-center gap-1.5", children: [
4998
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
4999
- "input",
5000
- {
5001
- type: "checkbox",
5002
- checked: selectedIds.has(row.id),
5003
- onChange: (e) => toggleSelectRow(row.id, e.target.checked),
5004
- disabled: isLoading || isUpdatingActive,
5005
- className: "w-4 h-4 rounded border-slate-300 text-brand"
5006
- }
5007
- ),
5008
- hasSubTableCols && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
5009
- "button",
5010
- {
5011
- type: "button",
5012
- onClick: () => setExpandedRowIds((prev) => {
5013
- const next = new Set(prev);
5014
- if (next.has(row.id)) next.delete(row.id);
5015
- else next.add(row.id);
5016
- return next;
5017
- }),
5018
- 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",
5019
- title: isExpanded ? "\u05E1\u05D2\u05D5\u05E8 \u05EA\u05EA-\u05D8\u05D1\u05DC\u05D4" : "\u05E4\u05EA\u05D7 \u05EA\u05EA-\u05D8\u05D1\u05DC\u05D4",
5020
- children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("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__ */ (0, import_jsx_runtime10.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "3", d: "M9 5l7 7-7 7" }) })
5021
- }
5022
- )
5023
- ] }) }),
5024
- filteredColumns.map((col) => {
5025
- var _a;
5026
- const colType = ((_a = col.type) == null ? void 0 : _a.toUpperCase()) || "DEFAULT";
5027
- const InputComponent = FORM_INPUTS[colType] || FORM_INPUTS.DEFAULT;
5028
- const colMinWidth = calculateMinColumnWidth(col.name, false, col.type);
5029
- const currentWidth = Math.max(colMinWidth, columnWidths[col.name] || 200);
5030
- let value = (row == null ? void 0 : row.data) ? row.data[col.name] : void 0;
5031
- if (value === void 0 && col.defaultValue !== void 0) {
5032
- value = colType === "CURRENCY" || colType === "NUMBER" ? parseFloat(col.defaultValue) : col.defaultValue;
5033
- if (colType === "CURRENCY" || colType === "NUMBER") {
5034
- if (isNaN(value)) value = null;
5035
- }
5036
- }
5037
- if (value === void 0) value = null;
5038
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
5039
- "td",
5040
- {
5041
- className: `border-b border-l border-slate-200 p-0 relative ${colType === "RELATION" ? "overflow-visible" : "overflow-hidden"}`,
5042
- style: { width: currentWidth, minWidth: currentWidth, maxWidth: currentWidth },
5043
- children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
5044
- InputComponent,
5045
- {
5046
- value,
5047
- column: col,
5048
- rowId: row.id,
5049
- onChange: (v) => handleCellChange(row.id, col.name, v),
5050
- context: {
5051
- tableName: (schema == null ? void 0 : schema.name) || (schema == null ? void 0 : schema.tableName) || (schema == null ? void 0 : schema.title) || (schema == null ? void 0 : schema.id) || "Table",
5052
- tableId: (schema == null ? void 0 : schema.tableMetaId) || (schema == null ? void 0 : schema.tableId) || (schema == null ? void 0 : schema.id),
5053
- onMarkForDeletion: (fileId) => setPendingDeletions((prev) => [...prev, fileId]),
5054
- relationOptions,
5055
- refetchRelation,
5056
- executeAction,
5057
- emitEvent,
5058
- pageState,
5059
- componentId,
5060
- orgId,
5061
- updateQuietly: handleQuietCellChange,
5062
- triggerSaveSuccess,
5063
- rowData: row.data
5064
- }
5065
- }
5066
- )
5067
- },
5068
- col.name
5069
- );
5070
- }),
5071
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("td", { className: "border-b border-slate-200 bg-white pointer-events-none" })
5072
- ] }),
5073
- isExpanded && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
5074
- ExpandedSubTables,
5075
- {
5076
- rowId: row.id,
5077
- rowData: row.data,
5078
- subTableColumns,
5079
- filteredColumnsLength: filteredColumns.length,
5080
- handleCellChange,
5081
- context: {
5082
- executeAction,
5083
- orgId,
5084
- parentTableId: (schema == null ? void 0 : schema.tableMetaId) || (schema == null ? void 0 : schema.tableId) || (schema == null ? void 0 : schema.id),
5085
- tableId: (schema == null ? void 0 : schema.tableMetaId) || (schema == null ? void 0 : schema.tableId) || (schema == null ? void 0 : schema.id),
5086
- rowData: row.data,
5087
- updateQuietly: handleQuietCellChange,
5088
- triggerSaveSuccess,
5089
- onUpdateColumnConfig: handleUpdateColumnConfig
5090
- }
5091
- }
5092
- )
5093
- ] }, row.id);
5877
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
5878
+ TableRow,
5879
+ {
5880
+ row,
5881
+ isSelected: selectedIds.has(row.id),
5882
+ isExpanded,
5883
+ filteredColumns,
5884
+ columnWidths,
5885
+ hasSubTableCols,
5886
+ subTableColumns,
5887
+ isLoading: isLoading || isFetching,
5888
+ isUpdatingActive,
5889
+ onToggleSelect: toggleSelectRow,
5890
+ onToggleExpand: handleToggleExpand,
5891
+ handleCellChange,
5892
+ handleQuietCellChange,
5893
+ handleUpdateColumnConfig,
5894
+ onMarkForDeletion: handleMarkForDeletion,
5895
+ triggerSaveSuccess,
5896
+ schema,
5897
+ orgId,
5898
+ componentId,
5899
+ pageState,
5900
+ relationOptions,
5901
+ relationDictionaryRef,
5902
+ refetchRelation,
5903
+ executeAction,
5904
+ emitEvent
5905
+ },
5906
+ row.id
5907
+ );
5094
5908
  }) }),
5095
- showSummary && filteredData.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("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__ */ (0, import_jsx_runtime10.jsxs)("tr", { children: [
5096
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("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' }),
5909
+ showSummary && filteredData.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("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__ */ (0, import_jsx_runtime11.jsxs)("tr", { children: [
5910
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("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' }),
5097
5911
  filteredColumns.map((col) => {
5098
5912
  var _a, _b;
5099
5913
  const typeUpper = (_a = col.type) == null ? void 0 : _a.toUpperCase();
@@ -5107,16 +5921,16 @@ function TableBlockClient({
5107
5921
  displayVal = symbol ? `${symbol} ${displayVal}` : displayVal;
5108
5922
  }
5109
5923
  }
5110
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("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__ */ (0, import_jsx_runtime10.jsx)("div", { className: "flex items-center text-right justify-start", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "truncate", children: displayVal }) }) }, col.name);
5924
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("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__ */ (0, import_jsx_runtime11.jsx)("div", { className: "flex items-center text-right justify-start", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "truncate", children: displayVal }) }) }, col.name);
5111
5925
  }),
5112
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("td", { className: "border-b border-slate-200 bg-slate-50 pointer-events-none" })
5926
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("td", { className: "border-b border-slate-200 bg-slate-50 pointer-events-none" })
5113
5927
  ] }) })
5114
5928
  ] })
5115
5929
  ] }),
5116
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("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: [
5117
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex items-center gap-2", children: [
5118
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "font-medium text-slate-700", children: "\u05E9\u05D5\u05E8\u05D5\u05EA \u05DC\u05E2\u05DE\u05D5\u05D3:" }),
5119
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
5930
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("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: [
5931
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex items-center gap-2", children: [
5932
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "font-medium text-slate-700", children: "\u05E9\u05D5\u05E8\u05D5\u05EA \u05DC\u05E2\u05DE\u05D5\u05D3:" }),
5933
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
5120
5934
  "select",
5121
5935
  {
5122
5936
  value: limit,
@@ -5124,27 +5938,27 @@ function TableBlockClient({
5124
5938
  disabled: isLoading || isUpdatingActive,
5125
5939
  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",
5126
5940
  children: [
5127
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("option", { value: 20, children: "20" }),
5128
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("option", { value: 50, children: "50" }),
5129
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("option", { value: 100, children: "100" })
5941
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("option", { value: 20, children: "20" }),
5942
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("option", { value: 50, children: "50" }),
5943
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("option", { value: 100, children: "100" })
5130
5944
  ]
5131
5945
  }
5132
5946
  )
5133
5947
  ] }),
5134
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex items-center gap-4", children: [
5135
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: "font-medium text-slate-600", children: [
5948
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex items-center gap-4", children: [
5949
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { className: "font-medium text-slate-600", children: [
5136
5950
  "\u05E2\u05DE\u05D5\u05D3 ",
5137
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("strong", { className: "text-slate-900", children: page }),
5951
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("strong", { className: "text-slate-900", children: page }),
5138
5952
  " \u05DE\u05EA\u05D5\u05DA ",
5139
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("strong", { className: "text-slate-900", children: totalPages || 1 }),
5140
- totalRecords > 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: "text-slate-500 font-normal", children: [
5953
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("strong", { className: "text-slate-900", children: totalPages || 1 }),
5954
+ totalRecords > 0 && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { className: "text-slate-500 font-normal", children: [
5141
5955
  " (",
5142
5956
  totalRecords,
5143
5957
  ' \u05E8\u05E9\u05D5\u05DE\u05D5\u05EA \u05D1\u05E1\u05D4"\u05DB)'
5144
5958
  ] })
5145
5959
  ] }),
5146
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex items-center gap-1.5", children: [
5147
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
5960
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex items-center gap-1.5", children: [
5961
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
5148
5962
  "button",
5149
5963
  {
5150
5964
  onClick: handlePrevPage,
@@ -5154,7 +5968,7 @@ function TableBlockClient({
5154
5968
  children: "\u05D4\u05E7\u05D5\u05D3\u05DD"
5155
5969
  }
5156
5970
  ),
5157
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
5971
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
5158
5972
  "button",
5159
5973
  {
5160
5974
  onClick: handleNextPage,
@@ -5166,7 +5980,31 @@ function TableBlockClient({
5166
5980
  )
5167
5981
  ] })
5168
5982
  ] })
5169
- ] })
5983
+ ] }),
5984
+ activeRelationCol && (() => {
5985
+ const activeColDef = filteredColumns.find((c) => c.name === activeRelationCol);
5986
+ if (!activeColDef) return null;
5987
+ const rawSelected = columnFilters[activeRelationCol];
5988
+ const currentSelected = typeof rawSelected === "object" && rawSelected !== null ? rawSelected : void 0;
5989
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
5990
+ RelationFilterPopover,
5991
+ {
5992
+ isOpen: Boolean(activeRelationCol),
5993
+ onClose: () => {
5994
+ setActiveRelationCol(null);
5995
+ setRelationTriggerRect(null);
5996
+ },
5997
+ column: activeColDef,
5998
+ triggerRect: relationTriggerRect,
5999
+ options: getUniqueRelationOptions(activeColDef),
6000
+ filterValue: currentSelected,
6001
+ onSelectionChange: (newSelected) => {
6002
+ handleApplyColumnFilter(activeRelationCol, newSelected);
6003
+ },
6004
+ isLoading: loadingFilterCol === activeRelationCol
6005
+ }
6006
+ );
6007
+ })()
5170
6008
  ]
5171
6009
  }
5172
6010
  );
@@ -5180,11 +6018,11 @@ function ExpandedSubTables({
5180
6018
  context
5181
6019
  }) {
5182
6020
  var _a;
5183
- const [activeTab, setActiveTab] = (0, import_react12.useState)((_a = subTableColumns[0]) == null ? void 0 : _a.name);
6021
+ const [activeTab, setActiveTab] = (0, import_react14.useState)((_a = subTableColumns[0]) == null ? void 0 : _a.name);
5184
6022
  if (subTableColumns.length === 0) return null;
5185
6023
  if (subTableColumns.length === 1) {
5186
6024
  const stCol = subTableColumns[0];
5187
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("tr", { children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("td", { colSpan: filteredColumnsLength + 2, className: "p-0 border-b border-slate-200 bg-slate-50/50", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
6025
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("tr", { children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("td", { colSpan: filteredColumnsLength + 2, className: "p-0 border-b border-slate-200 bg-slate-50/50", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
5188
6026
  SubTableViewer,
5189
6027
  {
5190
6028
  rowId,
@@ -5196,8 +6034,8 @@ function ExpandedSubTables({
5196
6034
  ) }) });
5197
6035
  }
5198
6036
  const activeCol = subTableColumns.find((c) => c.name === activeTab) || subTableColumns[0];
5199
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("tr", { children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("td", { colSpan: filteredColumnsLength + 2, className: "p-0 border-b border-slate-200 bg-slate-50/50 overflow-hidden", children: [
5200
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("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__ */ (0, import_jsx_runtime10.jsx)(
6037
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("tr", { children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("td", { colSpan: filteredColumnsLength + 2, className: "p-0 border-b border-slate-200 bg-slate-50/50 overflow-hidden", children: [
6038
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("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__ */ (0, import_jsx_runtime11.jsx)(
5201
6039
  "button",
5202
6040
  {
5203
6041
  type: "button",
@@ -5207,7 +6045,7 @@ function ExpandedSubTables({
5207
6045
  },
5208
6046
  col.name
5209
6047
  )) }),
5210
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "bg-white", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
6048
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "bg-white", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
5211
6049
  SubTableViewer,
5212
6050
  {
5213
6051
  rowId,
@@ -5220,11 +6058,134 @@ function ExpandedSubTables({
5220
6058
  ) })
5221
6059
  ] }) });
5222
6060
  }
6061
+ var TableRow = import_react14.default.memo(function TableRow2({
6062
+ row,
6063
+ isSelected,
6064
+ isExpanded,
6065
+ filteredColumns,
6066
+ columnWidths,
6067
+ hasSubTableCols,
6068
+ subTableColumns,
6069
+ isLoading,
6070
+ isUpdatingActive,
6071
+ onToggleSelect,
6072
+ onToggleExpand,
6073
+ handleCellChange,
6074
+ handleQuietCellChange,
6075
+ handleUpdateColumnConfig,
6076
+ onMarkForDeletion,
6077
+ triggerSaveSuccess,
6078
+ schema,
6079
+ orgId,
6080
+ componentId,
6081
+ pageState,
6082
+ relationOptions,
6083
+ relationDictionaryRef,
6084
+ refetchRelation,
6085
+ executeAction,
6086
+ emitEvent
6087
+ }) {
6088
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_react14.default.Fragment, { children: [
6089
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("tr", { className: `hover:bg-blue-50/30 transition-colors group ${isSelected ? "bg-blue-50/40" : ""}`, children: [
6090
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("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__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex items-center justify-center gap-1.5", children: [
6091
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
6092
+ "input",
6093
+ {
6094
+ type: "checkbox",
6095
+ checked: isSelected,
6096
+ onChange: (e) => onToggleSelect(row.id, e.target.checked),
6097
+ disabled: isLoading || isUpdatingActive,
6098
+ className: "w-4 h-4 rounded border-slate-300 text-brand"
6099
+ }
6100
+ ),
6101
+ hasSubTableCols && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
6102
+ "button",
6103
+ {
6104
+ type: "button",
6105
+ onClick: () => onToggleExpand(row.id),
6106
+ 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",
6107
+ title: isExpanded ? "\u05E1\u05D2\u05D5\u05E8 \u05EA\u05EA-\u05D8\u05D1\u05DC\u05D4" : "\u05E4\u05EA\u05D7 \u05EA\u05EA-\u05D8\u05D1\u05DC\u05D4",
6108
+ children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("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__ */ (0, import_jsx_runtime11.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "3", d: "M9 5l7 7-7 7" }) })
6109
+ }
6110
+ )
6111
+ ] }) }),
6112
+ filteredColumns.map((col) => {
6113
+ var _a;
6114
+ const colType = ((_a = col.type) == null ? void 0 : _a.toUpperCase()) || "DEFAULT";
6115
+ const InputComponent = FORM_INPUTS[colType] || FORM_INPUTS.DEFAULT;
6116
+ const colMinWidth = calculateMinColumnWidth(col.name, false, col.type);
6117
+ const currentWidth = Math.max(colMinWidth, columnWidths[col.name] || 200);
6118
+ let value = (row == null ? void 0 : row.data) ? row.data[col.name] : void 0;
6119
+ if (value === void 0 && col.defaultValue !== void 0) {
6120
+ value = colType === "CURRENCY" || colType === "NUMBER" ? parseFloat(col.defaultValue) : col.defaultValue;
6121
+ if (colType === "CURRENCY" || colType === "NUMBER") {
6122
+ if (isNaN(value)) value = null;
6123
+ }
6124
+ }
6125
+ if (value === void 0) value = null;
6126
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
6127
+ "td",
6128
+ {
6129
+ className: `border-b border-l border-slate-200 p-0 relative ${colType === "RELATION" ? "overflow-visible" : "overflow-hidden"}`,
6130
+ style: { width: currentWidth, minWidth: currentWidth, maxWidth: currentWidth },
6131
+ children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
6132
+ InputComponent,
6133
+ {
6134
+ value,
6135
+ column: col,
6136
+ rowId: row.id,
6137
+ onChange: (v) => handleCellChange(row.id, col.name, v),
6138
+ context: {
6139
+ tableName: (schema == null ? void 0 : schema.name) || (schema == null ? void 0 : schema.tableName) || (schema == null ? void 0 : schema.title) || (schema == null ? void 0 : schema.id) || "Table",
6140
+ tableId: (schema == null ? void 0 : schema.tableMetaId) || (schema == null ? void 0 : schema.tableId) || (schema == null ? void 0 : schema.id),
6141
+ onMarkForDeletion,
6142
+ relationOptions,
6143
+ relationDictionaryRef,
6144
+ refetchRelation,
6145
+ executeAction,
6146
+ emitEvent,
6147
+ pageState,
6148
+ componentId,
6149
+ orgId,
6150
+ updateQuietly: handleQuietCellChange,
6151
+ triggerSaveSuccess,
6152
+ rowData: row.data
6153
+ }
6154
+ }
6155
+ )
6156
+ },
6157
+ col.name
6158
+ );
6159
+ }),
6160
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("td", { className: "border-b border-slate-200 bg-white pointer-events-none" })
6161
+ ] }),
6162
+ isExpanded && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
6163
+ ExpandedSubTables,
6164
+ {
6165
+ rowId: row.id,
6166
+ rowData: row.data,
6167
+ subTableColumns,
6168
+ filteredColumnsLength: filteredColumns.length,
6169
+ handleCellChange,
6170
+ context: {
6171
+ executeAction,
6172
+ orgId,
6173
+ parentTableId: (schema == null ? void 0 : schema.tableMetaId) || (schema == null ? void 0 : schema.tableId) || (schema == null ? void 0 : schema.id),
6174
+ tableId: (schema == null ? void 0 : schema.tableMetaId) || (schema == null ? void 0 : schema.tableId) || (schema == null ? void 0 : schema.id),
6175
+ rowData: row.data,
6176
+ updateQuietly: handleQuietCellChange,
6177
+ triggerSaveSuccess,
6178
+ onUpdateColumnConfig: handleUpdateColumnConfig
6179
+ }
6180
+ }
6181
+ )
6182
+ ] });
6183
+ });
5223
6184
 
5224
6185
  // src/components/TableBlock/TableBlock.tsx
5225
- var import_jsx_runtime11 = require("react/jsx-runtime");
6186
+ var import_jsx_runtime12 = require("react/jsx-runtime");
5226
6187
  function TableBlock(props) {
5227
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(TableBlockClient, __spreadValues({}, props));
6188
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(TableBlockClient, __spreadValues({}, props));
5228
6189
  }
5229
6190
 
5230
6191
  // src/registry.ts
@@ -5241,6 +6202,7 @@ var UNIVERSE_COMPONENTS = {
5241
6202
  DatePickerCell,
5242
6203
  LinkPickerCell,
5243
6204
  PASTEL_PALETTES,
6205
+ RelationFilterPopover,
5244
6206
  RelationPickerCell,
5245
6207
  TEXT_REPRESENTABLE_TYPES,
5246
6208
  TableBlock,