@open-mercato/ui 0.6.1-develop.3276.1.1fcd145078 → 0.6.1-develop.3278.1.a4d26475e4

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.
Files changed (62) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/dist/backend/DataTable.js +149 -53
  3. package/dist/backend/DataTable.js.map +2 -2
  4. package/dist/backend/filters/ActiveFilterChips.js +142 -0
  5. package/dist/backend/filters/ActiveFilterChips.js.map +7 -0
  6. package/dist/backend/filters/AdvancedFilterBuilder.js +689 -163
  7. package/dist/backend/filters/AdvancedFilterBuilder.js.map +2 -2
  8. package/dist/backend/filters/AdvancedFilterPanel.js +354 -0
  9. package/dist/backend/filters/AdvancedFilterPanel.js.map +7 -0
  10. package/dist/backend/filters/FilterEmptyState.js +41 -0
  11. package/dist/backend/filters/FilterEmptyState.js.map +7 -0
  12. package/dist/backend/filters/FilterFieldPicker.js +148 -0
  13. package/dist/backend/filters/FilterFieldPicker.js.map +7 -0
  14. package/dist/backend/filters/FilteredEmptyResults.js +26 -0
  15. package/dist/backend/filters/FilteredEmptyResults.js.map +7 -0
  16. package/dist/backend/filters/QuickFilters.js +41 -0
  17. package/dist/backend/filters/QuickFilters.js.map +7 -0
  18. package/dist/backend/filters/filterValidation.js +47 -0
  19. package/dist/backend/filters/filterValidation.js.map +7 -0
  20. package/dist/backend/filters/treeReducer.js +159 -0
  21. package/dist/backend/filters/treeReducer.js.map +7 -0
  22. package/dist/backend/hooks/useAdvancedFilter.js +82 -1
  23. package/dist/backend/hooks/useAdvancedFilter.js.map +2 -2
  24. package/dist/backend/utils/api.js +18 -1
  25. package/dist/backend/utils/api.js.map +2 -2
  26. package/dist/backend/utils/useAutoDiscoveredFields.js +1 -0
  27. package/dist/backend/utils/useAutoDiscoveredFields.js.map +2 -2
  28. package/dist/backend/utils/useCurrentUserId.js +31 -0
  29. package/dist/backend/utils/useCurrentUserId.js.map +7 -0
  30. package/dist/primitives/dialog.js +7 -5
  31. package/dist/primitives/dialog.js.map +2 -2
  32. package/dist/primitives/tag.js +4 -2
  33. package/dist/primitives/tag.js.map +2 -2
  34. package/package.json +3 -3
  35. package/src/backend/DataTable.tsx +307 -63
  36. package/src/backend/__tests__/DataTable.extensions.test.tsx +170 -0
  37. package/src/backend/filters/ActiveFilterChips.tsx +179 -0
  38. package/src/backend/filters/AdvancedFilterBuilder.tsx +840 -237
  39. package/src/backend/filters/AdvancedFilterPanel.tsx +456 -0
  40. package/src/backend/filters/FilterEmptyState.tsx +51 -0
  41. package/src/backend/filters/FilterFieldPicker.tsx +139 -0
  42. package/src/backend/filters/FilteredEmptyResults.tsx +40 -0
  43. package/src/backend/filters/QuickFilters.tsx +62 -0
  44. package/src/backend/filters/__tests__/ActiveFilterChips.test.tsx +75 -0
  45. package/src/backend/filters/__tests__/AdvancedFilterBuilder.test.tsx +210 -0
  46. package/src/backend/filters/__tests__/AdvancedFilterPanel.test.tsx +212 -0
  47. package/src/backend/filters/__tests__/FilterEmptyState.test.tsx +31 -0
  48. package/src/backend/filters/__tests__/FilterFieldPicker.test.tsx +61 -0
  49. package/src/backend/filters/__tests__/FilteredEmptyResults.test.tsx +35 -0
  50. package/src/backend/filters/__tests__/QuickFilters.test.tsx +34 -0
  51. package/src/backend/filters/__tests__/filterValidation.test.ts +69 -0
  52. package/src/backend/filters/__tests__/treeReducer.test.ts +189 -0
  53. package/src/backend/filters/filterValidation.ts +61 -0
  54. package/src/backend/filters/treeReducer.ts +201 -0
  55. package/src/backend/hooks/__tests__/useAdvancedFilter.test.tsx +213 -0
  56. package/src/backend/hooks/useAdvancedFilter.ts +130 -0
  57. package/src/backend/utils/api.ts +27 -2
  58. package/src/backend/utils/useAutoDiscoveredFields.ts +2 -0
  59. package/src/backend/utils/useCurrentUserId.ts +40 -0
  60. package/src/primitives/__tests__/zindex-overlay.test.tsx +22 -0
  61. package/src/primitives/dialog.tsx +18 -7
  62. package/src/primitives/tag.tsx +3 -1
@@ -1,3 +1,3 @@
1
1
  Generated lucide registry with 134 icons -> /home/runner/work/open-mercato/open-mercato/packages/ui/src/backend/icons/lucideRegistry.generated.tsx
2
- [build:ui] found 329 entry points
2
+ [build:ui] found 338 entry points
3
3
  [build:ui] built successfully
@@ -21,6 +21,7 @@ import { EmptyState } from "../primitives/empty-state.js";
21
21
  import { TooltipProvider } from "../primitives/tooltip.js";
22
22
  import { TruncatedCell } from "./TruncatedCell.js";
23
23
  import { FilterBar } from "./FilterBar.js";
24
+ import { FilteredEmptyResults } from "./filters/FilteredEmptyResults.js";
24
25
  import { useCustomFieldFilterDefs } from "./utils/customFieldFilters.js";
25
26
  import { fetchCustomFieldDefinitionsPayload } from "./utils/customFieldDefs.js";
26
27
  import { RowActions } from "./RowActions.js";
@@ -41,7 +42,15 @@ import { useConfirmDialog } from "./confirm-dialog/index.js";
41
42
  import { ComponentReplacementHandles } from "@open-mercato/shared/modules/widgets/component-registry";
42
43
  import { insertByInjectionPlacement } from "@open-mercato/shared/modules/widgets/injection-position";
43
44
  import { useVirtualizer } from "@tanstack/react-virtual";
44
- import { createEmptyCondition, getDefaultOperator } from "@open-mercato/shared/lib/query/advanced-filter";
45
+ import { getDefaultOperator, isAdvancedFilterState, flatToTree } from "@open-mercato/shared/lib/query/advanced-filter";
46
+ import {
47
+ createEmptyTree,
48
+ serializeTreeForPersist,
49
+ deserializeTreeFromPersist,
50
+ isPersistedFilterTree,
51
+ treeToFlat
52
+ } from "@open-mercato/shared/lib/query/advanced-filter-tree";
53
+ import { treeReducer } from "./filters/treeReducer.js";
45
54
  import { AdvancedFilterBuilder } from "./filters/AdvancedFilterBuilder.js";
46
55
  import { useAutoDiscoveredFields } from "./utils/useAutoDiscoveredFields.js";
47
56
  import { useCustomFieldDefs } from "./utils/customFieldDefs.js";
@@ -635,8 +644,10 @@ function DataTable({
635
644
  virtualized = false,
636
645
  virtualizedMaxHeight,
637
646
  virtualizedOverscan = 10,
638
- advancedFilter,
639
- columnChooser
647
+ advancedFilter: advancedFilterInput,
648
+ columnChooser,
649
+ activeFilterChips,
650
+ filterAwareEmptyState
640
651
  }) {
641
652
  const t = useT();
642
653
  const { confirm, ConfirmDialogElement } = useConfirmDialog();
@@ -645,6 +656,28 @@ function DataTable({
645
656
  const containerRef = React.useRef(null);
646
657
  const lastScopeRef = React.useRef(null);
647
658
  const hasInitializedScopeRef = React.useRef(false);
659
+ const legacyAdvancedFilterWarnedRef = React.useRef(false);
660
+ const advancedFilter = React.useMemo(() => {
661
+ if (!advancedFilterInput) return void 0;
662
+ if (!isAdvancedFilterState(advancedFilterInput.value)) {
663
+ return advancedFilterInput;
664
+ }
665
+ if (!legacyAdvancedFilterWarnedRef.current && process.env.NODE_ENV !== "production") {
666
+ legacyAdvancedFilterWarnedRef.current = true;
667
+ console.warn(
668
+ "[DataTable] `advancedFilter.value` was passed as the legacy `AdvancedFilterState` shape. This bridge will be removed in the next minor version \u2014 migrate to the tree shape (`AdvancedFilterTree`, see `@open-mercato/shared/lib/query/advanced-filter-tree`)."
669
+ );
670
+ }
671
+ const legacy = advancedFilterInput;
672
+ return {
673
+ fields: legacy.fields,
674
+ auto: legacy.auto,
675
+ value: flatToTree(legacy.value),
676
+ onChange: (next) => legacy.onChange(treeToFlat(next)),
677
+ onApply: legacy.onApply,
678
+ onClear: legacy.onClear
679
+ };
680
+ }, [advancedFilterInput]);
648
681
  React.useEffect(() => {
649
682
  return subscribeOrganizationScopeChanged((detail) => {
650
683
  const prev = lastScopeRef.current;
@@ -1091,20 +1124,27 @@ function DataTable({
1091
1124
  visibility[key] = value;
1092
1125
  }
1093
1126
  }
1094
- const filtersRecord = {};
1095
- for (const [key, value] of Object.entries(filterValues ?? {})) {
1096
- if (typeof key === "string") filtersRecord[key] = value;
1127
+ let filtersPayload;
1128
+ if (advancedFilter) {
1129
+ const persisted = serializeTreeForPersist(advancedFilter.value);
1130
+ filtersPayload = persisted.root.children.length > 0 ? persisted : void 0;
1131
+ } else {
1132
+ const filtersRecord = {};
1133
+ for (const [key, value] of Object.entries(filterValues ?? {})) {
1134
+ if (typeof key === "string") filtersRecord[key] = value;
1135
+ }
1136
+ if (Object.keys(filtersRecord).length) filtersPayload = filtersRecord;
1097
1137
  }
1098
1138
  const candidate = {
1099
1139
  columnOrder,
1100
1140
  columnVisibility: visibility,
1101
1141
  sorting,
1102
- filters: filtersRecord,
1142
+ filters: filtersPayload,
1103
1143
  searchValue
1104
1144
  };
1105
1145
  return sanitizePerspectiveSettings(candidate) ?? {};
1106
- }, [columnOrder, columnVisibility, sorting, filterValues, searchValue]);
1107
- const applyPerspectiveSettings = React.useCallback((settings, nextId) => {
1146
+ }, [columnOrder, columnVisibility, sorting, filterValues, searchValue, advancedFilter]);
1147
+ const applyPerspectiveSettings = React.useCallback((settings, nextId, options) => {
1108
1148
  const normalized = sanitizePerspectiveSettings(settings) ?? {};
1109
1149
  if (normalized.columnOrder && normalized.columnOrder.length) {
1110
1150
  setColumnOrder(normalized.columnOrder);
@@ -1125,8 +1165,15 @@ function DataTable({
1125
1165
  setSorting([]);
1126
1166
  onSortingChange?.([]);
1127
1167
  }
1128
- if (onFiltersApply) {
1129
- onFiltersApply(normalized.filters ?? {});
1168
+ if (!options?.preserveAdvancedFilter) {
1169
+ const restoredTree = isPersistedFilterTree(normalized.filters) ? deserializeTreeFromPersist(normalized.filters) : null;
1170
+ if (advancedFilter?.onApplyTree) {
1171
+ advancedFilter.onApplyTree(restoredTree ?? createEmptyTree());
1172
+ if (onFiltersApply) onFiltersApply({});
1173
+ } else if (onFiltersApply) {
1174
+ const legacy = restoredTree ? {} : normalized.filters ?? {};
1175
+ onFiltersApply(legacy);
1176
+ }
1130
1177
  }
1131
1178
  if (onSearchChange) {
1132
1179
  onSearchChange(normalized.searchValue ?? "");
@@ -1143,7 +1190,7 @@ function DataTable({
1143
1190
  initialSnapshotRef.current = null;
1144
1191
  }
1145
1192
  }
1146
- }, [onFiltersApply, onSearchChange, onSortingChange, perspectiveTableId, table]);
1193
+ }, [onFiltersApply, onSearchChange, onSortingChange, perspectiveTableId, table, advancedFilter]);
1147
1194
  React.useLayoutEffect(() => {
1148
1195
  if (!perspectiveTableId) return;
1149
1196
  if (snapshotHydratedTableRef.current === perspectiveTableId) return;
@@ -1151,9 +1198,14 @@ function DataTable({
1151
1198
  const snapshot = readPerspectiveSnapshot(perspectiveTableId);
1152
1199
  if (!snapshot) return;
1153
1200
  initialSnapshotRef.current = snapshot;
1154
- applyPerspectiveSettings(snapshot.settings, snapshot.perspectiveId ?? null);
1201
+ const preserveAdvancedFilter = !!advancedFilter?.onApplyTree;
1202
+ applyPerspectiveSettings(
1203
+ snapshot.settings,
1204
+ snapshot.perspectiveId ?? null,
1205
+ { preserveAdvancedFilter }
1206
+ );
1155
1207
  initialPerspectiveAppliedRef.current = true;
1156
- }, [perspectiveTableId, applyPerspectiveSettings]);
1208
+ }, [perspectiveTableId, applyPerspectiveSettings, advancedFilter]);
1157
1209
  const perspectiveQueryKey = ["table-perspectives", perspectiveTableId];
1158
1210
  const savePerspectiveMutation = useMutation({
1159
1211
  mutationFn: async (input) => {
@@ -1366,7 +1418,7 @@ function DataTable({
1366
1418
  if (!canUsePerspectives) return;
1367
1419
  if (!perspectiveTableId) return;
1368
1420
  if (initialSnapshotRef.current) return;
1369
- if (initialPerspectiveAppliedRef.current && activePerspectiveId != null) return;
1421
+ if (initialPerspectiveAppliedRef.current) return;
1370
1422
  const source = perspectiveData ?? perspectiveConfig?.initialState?.response;
1371
1423
  if (!source) return;
1372
1424
  const tryResolve = (id) => {
@@ -1603,6 +1655,18 @@ function DataTable({
1603
1655
  customFieldDefs: needsAutoDiscovery ? autoDiscoveryDefs : []
1604
1656
  });
1605
1657
  const resolvedAdvancedFilterFields = isAutoAdvancedFilter ? autoDiscovered.advancedFilterFields : advancedFilter?.fields ?? [];
1658
+ const advancedFilterRuleCount = React.useMemo(() => {
1659
+ if (!advancedFilter) return 0;
1660
+ function countRules(group) {
1661
+ let n = 0;
1662
+ for (const c of group.children) {
1663
+ if (c.type === "rule") n += 1;
1664
+ else n += countRules(c);
1665
+ }
1666
+ return n;
1667
+ }
1668
+ return countRules(advancedFilter.value.root);
1669
+ }, [advancedFilter]);
1606
1670
  const resolvedColumnChooserFields = isAutoColumnChooser ? autoDiscovered.columnChooserFields : columnChooser?.availableColumns ?? [];
1607
1671
  const effectiveColumnChooserFields = React.useMemo(() => {
1608
1672
  if (resolvedColumnChooserFields.length > 0) return resolvedColumnChooserFields;
@@ -1722,14 +1786,56 @@ function DataTable({
1722
1786
  const builtToolbar = React.useMemo(() => {
1723
1787
  if (toolbar) return toolbar;
1724
1788
  const anySearch = onSearchChange != null;
1725
- const anyFilters = baseFilters && baseFilters.length > 0 || cfFilters && cfFilters.length > 0 || injectedFilters.length > 0;
1789
+ const suppressFilterBarFilters = !!(advancedFilter && advancedFilter.externalPopover);
1790
+ const effectiveBaseFilters = suppressFilterBarFilters ? [] : baseFilters;
1791
+ const effectiveCfFilters = suppressFilterBarFilters ? [] : cfFilters;
1792
+ const effectiveInjectedFilters = suppressFilterBarFilters ? [] : injectedFilters;
1793
+ const anyFilters = effectiveBaseFilters && effectiveBaseFilters.length > 0 || effectiveCfFilters && effectiveCfFilters.length > 0 || effectiveInjectedFilters.length > 0;
1726
1794
  const hasBulkButtons = hasInjectedBulkActions || hasPropBulkActions;
1727
- if (!anySearch && !anyFilters && !hasBulkButtons) return null;
1728
- const baseList = baseFilters || [];
1795
+ const hasAdvancedFilterButton = Boolean(advancedFilter);
1796
+ const hasPerspectiveButton = canUsePerspectives;
1797
+ if (!anySearch && !anyFilters && !hasBulkButtons && !hasAdvancedFilterButton && !hasPerspectiveButton) return null;
1798
+ const baseList = effectiveBaseFilters || [];
1729
1799
  const existing = new Set(baseList.map((f) => f.id));
1730
- const cfOnly = (cfFilters || []).filter((f) => !existing.has(f.id));
1731
- const injectedOnly = injectedFilters.filter((f) => !existing.has(f.id) && !cfOnly.some((cf) => cf.id === f.id));
1800
+ const cfOnly = (effectiveCfFilters || []).filter((f) => !existing.has(f.id));
1801
+ const injectedOnly = effectiveInjectedFilters.filter((f) => !existing.has(f.id) && !cfOnly.some((cf) => cf.id === f.id));
1732
1802
  const combined = [...baseList, ...cfOnly, ...injectedOnly];
1803
+ const advancedFilterButton = advancedFilter ? /* @__PURE__ */ jsxs(
1804
+ Button,
1805
+ {
1806
+ ref: advancedFilter.triggerRef,
1807
+ type: "button",
1808
+ variant: advancedFilterRuleCount > 0 ? "default" : "outline",
1809
+ size: "default",
1810
+ className: advancedFilterRuleCount > 0 ? "bg-foreground text-background hover:bg-foreground/90" : "",
1811
+ onClick: () => {
1812
+ if (advancedFilter.externalPopover) {
1813
+ advancedFilter.onTriggerClick?.();
1814
+ return;
1815
+ }
1816
+ const opening = !isAdvancedFilterOpen;
1817
+ if (opening && advancedFilterRuleCount === 0) {
1818
+ const defaultField = resolvedAdvancedFilterFields[0];
1819
+ const seeded = treeReducer(advancedFilter.value, {
1820
+ type: "addRule",
1821
+ groupId: advancedFilter.value.root.id,
1822
+ defaultField: defaultField?.key,
1823
+ defaultOperator: defaultField ? getDefaultOperator(defaultField.type) : void 0
1824
+ });
1825
+ advancedFilter.onChange(seeded);
1826
+ }
1827
+ setAdvancedFilterOpen(opening);
1828
+ },
1829
+ "aria-label": t("ui.advancedFilter.toggle", "Advanced filters"),
1830
+ title: t("ui.advancedFilter.toggle", "Advanced filters"),
1831
+ "data-testid": "advanced-filter-trigger",
1832
+ children: [
1833
+ /* @__PURE__ */ jsx(Filter, { className: "h-4 w-4" }),
1834
+ /* @__PURE__ */ jsx("span", { children: t("ui.dataTable.filters", "Filters") }),
1835
+ advancedFilterRuleCount > 0 ? /* @__PURE__ */ jsx("span", { className: "ml-1 inline-flex h-5 min-w-5 px-1.5 items-center justify-center rounded-full bg-muted-foreground/30 text-background text-xs", children: advancedFilterRuleCount }) : null
1836
+ ]
1837
+ }
1838
+ ) : null;
1733
1839
  const perspectiveButton = canUsePerspectives ? /* @__PURE__ */ jsx(
1734
1840
  ViewSwitcherDropdown,
1735
1841
  {
@@ -1756,7 +1862,10 @@ function DataTable({
1756
1862
  }
1757
1863
  )
1758
1864
  ] }) : null;
1759
- const leadingItems = perspectiveButton ? /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2", children: perspectiveButton }) : null;
1865
+ const leadingItems = advancedFilterButton || perspectiveButton ? /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
1866
+ advancedFilterButton,
1867
+ perspectiveButton
1868
+ ] }) : null;
1760
1869
  const trailingItems = hasBulkButtons ? /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
1761
1870
  selectedRows.length > 0 ? /* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground", children: t("ui.dataTable.bulkAction.selectedCount", "{count} selected", { count: selectedRows.length }) }) : null,
1762
1871
  injectedBulkActions.map((action) => {
@@ -1845,7 +1954,11 @@ function DataTable({
1845
1954
  runBulkAction,
1846
1955
  runPropBulkAction,
1847
1956
  searchTrailingInjectionSpotId,
1848
- resolvedInjectionContext
1957
+ resolvedInjectionContext,
1958
+ advancedFilter,
1959
+ advancedFilterRuleCount,
1960
+ isAdvancedFilterOpen,
1961
+ resolvedAdvancedFilterFields
1849
1962
  ]);
1850
1963
  const hasTitle = title != null;
1851
1964
  const hasActions = actions !== void 0 && actions !== null && actions !== false;
@@ -1857,7 +1970,7 @@ function DataTable({
1857
1970
  const hasRefreshButton = Boolean(refreshButtonConfig);
1858
1971
  const hasToolbar = builtToolbar != null;
1859
1972
  const hasToolbarInjection = Boolean(toolbarInjectionSpotId);
1860
- const shouldRenderActionsWrapper = hasActions || hasRefreshButton || shouldReserveActionsSpace || hasExport || hasToolbarInjection || Boolean(advancedFilter);
1973
+ const shouldRenderActionsWrapper = hasActions || hasRefreshButton || shouldReserveActionsSpace || hasExport || hasToolbarInjection;
1861
1974
  const renderToolbarInline = embedded && hasToolbar;
1862
1975
  const shouldRenderToolbarBelow = hasToolbar && !renderToolbarInline;
1863
1976
  const shouldRenderHeader = hasTitle || renderToolbarInline || shouldRenderActionsWrapper || shouldRenderToolbarBelow;
@@ -1900,32 +2013,6 @@ function DataTable({
1900
2013
  ]
1901
2014
  }
1902
2015
  ) : null,
1903
- advancedFilter ? /* @__PURE__ */ jsxs(
1904
- Button,
1905
- {
1906
- type: "button",
1907
- variant: advancedFilter.value.conditions.length > 0 ? "secondary" : "ghost",
1908
- size: "icon",
1909
- onClick: () => {
1910
- const opening = !isAdvancedFilterOpen;
1911
- if (opening && advancedFilter.value.conditions.length === 0) {
1912
- const newCondition = createEmptyCondition();
1913
- if (resolvedAdvancedFilterFields.length > 0) {
1914
- newCondition.field = resolvedAdvancedFilterFields[0].key;
1915
- newCondition.operator = getDefaultOperator(resolvedAdvancedFilterFields[0].type);
1916
- }
1917
- advancedFilter.onChange({ ...advancedFilter.value, conditions: [newCondition] });
1918
- }
1919
- setAdvancedFilterOpen(opening);
1920
- },
1921
- "aria-label": t("ui.advancedFilter.toggle", "Advanced filters"),
1922
- title: t("ui.advancedFilter.toggle", "Advanced filters"),
1923
- children: [
1924
- /* @__PURE__ */ jsx(Filter, { className: "h-4 w-4" }),
1925
- advancedFilter.value.conditions.length > 0 ? /* @__PURE__ */ jsx("span", { className: "absolute -top-1 -right-1 flex h-4 w-4 items-center justify-center rounded-full bg-primary text-overline text-primary-foreground", children: advancedFilter.value.conditions.length }) : null
1926
- ]
1927
- }
1928
- ) : null,
1929
2016
  canUsePerspectives ? /* @__PURE__ */ jsxs(
1930
2017
  Button,
1931
2018
  {
@@ -1949,7 +2036,7 @@ function DataTable({
1949
2036
  shouldRenderToolbarBelow ? /* @__PURE__ */ jsx("div", { className: toolbarWrapperClassName, children: builtToolbar }) : null,
1950
2037
  headerInjectionSpotId ? /* @__PURE__ */ jsx("div", { className: embedded ? "mt-2" : "mt-3", children: /* @__PURE__ */ jsx(InjectionSpot, { spotId: headerInjectionSpotId, context: resolvedInjectionContext }) }) : null
1951
2038
  ] }),
1952
- advancedFilter && isAdvancedFilterOpen ? /* @__PURE__ */ jsx("div", { className: "border-b", children: /* @__PURE__ */ jsx(
2039
+ advancedFilter && !advancedFilter.externalPopover && isAdvancedFilterOpen ? /* @__PURE__ */ jsx("div", { className: "border-b", children: /* @__PURE__ */ jsx(
1953
2040
  AdvancedFilterBuilder,
1954
2041
  {
1955
2042
  fields: resolvedAdvancedFilterFields,
@@ -1965,11 +2052,12 @@ function DataTable({
1965
2052
  }
1966
2053
  }
1967
2054
  ) }) : null,
1968
- advancedFilter && advancedFilter.value.conditions.length > 0 && !isAdvancedFilterOpen ? /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 flex-wrap px-4 py-2 border-b text-sm", children: [
1969
- /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: t("ui.advancedFilter.activeCount", "{count} active filters", { count: advancedFilter.value.conditions.length }) }),
2055
+ advancedFilter && !advancedFilter.externalPopover && advancedFilterRuleCount > 0 && !isAdvancedFilterOpen ? /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 flex-wrap px-4 py-2 border-b text-sm", children: [
2056
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: t("ui.advancedFilter.activeCount", "{count} active filters", { count: advancedFilterRuleCount }) }),
1970
2057
  /* @__PURE__ */ jsx(Button, { type: "button", variant: "ghost", size: "sm", className: "h-auto px-1 py-0.5 text-xs", onClick: () => setAdvancedFilterOpen(true), children: t("ui.advancedFilter.edit", "Edit") }),
1971
2058
  /* @__PURE__ */ jsx(Button, { type: "button", variant: "ghost", size: "sm", className: "h-auto px-1 py-0.5 text-xs text-muted-foreground", onClick: advancedFilter.onClear, children: t("ui.advancedFilter.clearAll", "Clear all") })
1972
2059
  ] }) : null,
2060
+ activeFilterChips,
1973
2061
  /* @__PURE__ */ jsx(
1974
2062
  HeaderDndWrapper,
1975
2063
  {
@@ -2120,7 +2208,15 @@ function DataTable({
2120
2208
  const bottomPadding = lastItem ? rowVirtualizer.getTotalSize() - lastItem.end : 0;
2121
2209
  return bottomPadding > 0 ? /* @__PURE__ */ jsx("tr", { style: { height: `${bottomPadding}px` } }) : null;
2122
2210
  })() : null
2123
- ] }) : /* @__PURE__ */ jsx(TableRow, { children: /* @__PURE__ */ jsx(TableCell, { colSpan: mergedColumns.length + (rowActions || injectedRowActions.length > 0 ? 1 : 0) + (hasInjectedBulkActions ? 1 : 0), className: "py-6", children: emptyState && typeof emptyState !== "string" ? emptyState : /* @__PURE__ */ jsx(
2211
+ ] }) : /* @__PURE__ */ jsx(TableRow, { children: /* @__PURE__ */ jsx(TableCell, { colSpan: mergedColumns.length + (rowActions || injectedRowActions.length > 0 ? 1 : 0) + (hasInjectedBulkActions ? 1 : 0), className: "py-6", children: filterAwareEmptyState?.active ? /* @__PURE__ */ jsx(
2212
+ FilteredEmptyResults,
2213
+ {
2214
+ entityNamePlural: filterAwareEmptyState.entityNamePlural,
2215
+ canRemoveLast: filterAwareEmptyState.canRemoveLast,
2216
+ onClearAll: filterAwareEmptyState.onClearAll,
2217
+ onRemoveLast: filterAwareEmptyState.onRemoveLast
2218
+ }
2219
+ ) : emptyState && typeof emptyState !== "string" ? emptyState : /* @__PURE__ */ jsx(
2124
2220
  EmptyState,
2125
2221
  {
2126
2222
  size: "sm",