@evergis/react 4.0.76 → 4.0.78

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.
@@ -18,4 +18,6 @@ export declare const useTreeFilter: (type: WidgetType, filter: ConfigContainerCh
18
18
  onClose: () => void;
19
19
  onToggleSelect: (item: any) => void;
20
20
  onReset: () => void;
21
+ onSave: () => void;
22
+ dirty: boolean;
21
23
  };
@@ -7,5 +7,6 @@ export declare const useTreeFilterData: (type: WidgetType, filterName: string) =
7
7
  loadLevelOne: () => Promise<TreeItemProps[]>;
8
8
  loadChildren: (item: TreeItemProps) => Promise<PartialLoadData<TreeNodeData>>;
9
9
  searchNodes: (query: string) => Promise<TreeItemProps[]>;
10
- loadByIds: (ids: TreeId[]) => Promise<TreeItemProps[]>;
10
+ loadByNames: (names: TreeId[]) => Promise<TreeItemProps[]>;
11
+ loadByValues: (values: TreeId[]) => Promise<TreeItemProps[]>;
11
12
  };
@@ -1,9 +1,9 @@
1
1
  import { TreeId, TreeItemProps } from '@evergis/uilib-gl';
2
2
  type UseTreeFilterSearchParams = {
3
3
  searchNodes: (query: string) => Promise<TreeItemProps[]>;
4
- loadByIds: (ids: TreeId[]) => Promise<TreeItemProps[]>;
4
+ loadByNames: (names: TreeId[]) => Promise<TreeItemProps[]>;
5
5
  };
6
- export declare const useTreeFilterSearch: ({ searchNodes, loadByIds }: UseTreeFilterSearchParams) => {
6
+ export declare const useTreeFilterSearch: ({ searchNodes, loadByNames }: UseTreeFilterSearchParams) => {
7
7
  searchValue: string;
8
8
  isSearchActive: boolean;
9
9
  searching: boolean;
@@ -4,6 +4,8 @@ export declare const useTreeFilterSelection: (type: WidgetType, filterName: stri
4
4
  selected: Map<TreeId, number>;
5
5
  selectedIds: Set<TreeId>;
6
6
  selectedLabel: string;
7
+ dirty: boolean;
7
8
  onToggleSelect: (item: TreeItemProps, multiSelect?: boolean) => void;
8
9
  onReset: () => void;
10
+ onSave: () => void;
9
11
  };
@@ -2,9 +2,10 @@ import { TreeId, TreeItemProps } from '@evergis/uilib-gl';
2
2
  type UseTreeFilterTreeParams = {
3
3
  selected: Map<TreeId, number>;
4
4
  loadLevelOne: () => Promise<TreeItemProps[]>;
5
- loadByIds: (ids: TreeId[]) => Promise<TreeItemProps[]>;
5
+ loadByValues: (values: TreeId[]) => Promise<TreeItemProps[]>;
6
+ loadByNames: (names: TreeId[]) => Promise<TreeItemProps[]>;
6
7
  };
7
- export declare const useTreeFilterTree: ({ selected, loadLevelOne, loadByIds }: UseTreeFilterTreeParams) => {
8
+ export declare const useTreeFilterTree: ({ selected, loadLevelOne, loadByValues, loadByNames }: UseTreeFilterTreeParams) => {
8
9
  treeData: TreeItemProps[];
9
10
  setTreeData: import('react').Dispatch<import('react').SetStateAction<TreeItemProps[]>>;
10
11
  treeExpanded: TreeId[];
@@ -6,9 +6,14 @@ export type FilterOption = {
6
6
  min: string | number;
7
7
  max: string | number;
8
8
  };
9
- /** Доменные данные узла иерархического фильтра "tree", хранятся в `TreeItemProps.data`. */
9
+ /**
10
+ * Доменные данные узла иерархического фильтра "tree", хранятся в `TreeItemProps.data`.
11
+ * `name`/`parentName` — служебная связь дерева (по `attributeName`/`attributeParentName`);
12
+ * идентичность/значение узла лежит в `TreeItemProps.id` (по `attributeValue`).
13
+ */
10
14
  export type TreeNodeData = {
11
- parentId: TreeId | null;
15
+ name: TreeId;
16
+ parentName: TreeId | null;
12
17
  level: number;
13
18
  };
14
19
  export type WidgetFilterProps = {
@@ -1,9 +1,12 @@
1
1
  import { TreeId, TreeItemProps } from '@evergis/uilib-gl';
2
2
  import { TreeFilterValue } from '../../../types';
3
3
  export declare const buildLevelOneCondition: (attributeLevel: string) => string;
4
- export declare const buildChildrenCondition: (attributeParentValue: string, parentId: TreeId) => string;
4
+ export declare const buildChildrenCondition: (attributeParentName: string, parentName: TreeId) => string;
5
5
  export declare const buildSearchCondition: (attributeAlias: string, query: string) => string;
6
- export declare const buildIdsCondition: (attributeValue: string, ids: Array<string | number>) => string;
6
+ /** Запрос пачки записей по их именам (`attributeName`) для достройки предков. */
7
+ export declare const buildNamesCondition: (attributeName: string, names: Array<string | number>) => string;
8
+ /** Запрос пачки записей по их значениям (`attributeValue`) — для восстановления `defaultValue`. */
9
+ export declare const buildValuesCondition: (attributeValue: string, values: Array<string | number>) => string;
7
10
  /** Группирует выбранные id по уровню в объектное значение фильтра `{ l{N}: [ids] }`. */
8
11
  export declare const buildFilterValue: (selected: Map<TreeId, number>) => TreeFilterValue;
9
12
  /** Разбирает объектное значение фильтра в карту `id → level`. */
@@ -11,13 +14,15 @@ export declare const parseFilterValue: (value?: TreeFilterValue) => Map<TreeId,
11
14
  /** Стабильная сериализация выбора для сравнения (порядок не важен). */
12
15
  export declare const serializeSelection: (selected: Map<TreeId, number>) => string;
13
16
  /**
14
- * Дозапрашивает цепочку предков вверх по `parentId` уровень за уровнем (батч `id in (...)`),
15
- * пока не достигнет уровня 1. Возвращает исходные узлы вместе с предками.
17
+ * Дозапрашивает цепочку предков вверх по `parentName` уровень за уровнем (батч `attributeName in
18
+ * (...)`), пока не достигнет уровня 1. Связь идёт по именам (`name`/`parentName`), т.к. `node.id`
19
+ * хранит значение (`attributeValue`). Возвращает исходные узлы вместе с предками.
16
20
  */
17
- export declare const collectAncestors: (nodes: TreeItemProps[], loadByIds: (ids: TreeId[]) => Promise<TreeItemProps[]>) => Promise<TreeItemProps[]>;
21
+ export declare const collectAncestors: (nodes: TreeItemProps[], loadByNames: (names: TreeId[]) => Promise<TreeItemProps[]>) => Promise<TreeItemProps[]>;
18
22
  /**
19
- * Собирает плоский набор узлов в дерево по `parentId`. Узлы с подгруженными потомками
20
- * раскрываются; листья-папки без потомков получают `children = null` (ленивая подгрузка).
23
+ * Собирает плоский набор узлов в дерево по связи `parentName` ↔ `name`. Узлы с подгруженными
24
+ * потомками раскрываются (`expanded` хранит `node.id` = значение); листья-папки без потомков
25
+ * получают `children = null` (ленивая подгрузка).
21
26
  */
22
27
  export declare const assembleTree: (nodes: TreeItemProps[]) => {
23
28
  roots: TreeItemProps[];
@@ -326,11 +326,18 @@ export interface ConfigFilter {
326
326
  relatedDataSource?: string;
327
327
  defaultValue?: SelectedFilter["value"];
328
328
  attributeAlias?: string;
329
+ /**
330
+ * Атрибут хранимого значения фильтра — то, что фильтр отдаёт потребителям (плейсхолдеры
331
+ * `%name`, для "tree" — `%name.lN`). Для "tree" служит ещё и идентичностью узла дерева
332
+ * (`TreeItemProps.id`). Если не задан — фолбэк на {@link ConfigFilter.attributeName}.
333
+ */
329
334
  attributeValue?: string;
330
335
  attributeMin?: string;
331
336
  attributeMax?: string;
332
- /** Атрибут id родителя для иерархического фильтра "tree". */
333
- attributeParentValue?: string;
337
+ /** Атрибут-имя записислужебная связь дерева (`child.attributeParentName == parent.attributeName`); для "tree". */
338
+ attributeName?: string;
339
+ /** Атрибут-имя родителя — служебная связь дерева; для "tree". */
340
+ attributeParentName?: string;
334
341
  /** Атрибут числового уровня (корень = 1) — для "tree". */
335
342
  attributeLevel?: string;
336
343
  /** Атрибут-флаг наличия детей (показ шеврона) — для "tree". */
package/dist/index.js CHANGED
@@ -11446,9 +11446,12 @@ function getIconFromAttribute(option, iconAttribute) {
11446
11446
 
11447
11447
  const MAX_ANCESTOR_DEPTH = 50;
11448
11448
  const buildLevelOneCondition = (attributeLevel) => `${attributeLevel} = 1`;
11449
- const buildChildrenCondition = (attributeParentValue, parentId) => `${attributeParentValue} = ${formatConditionValue({ value: parentId })}`;
11449
+ const buildChildrenCondition = (attributeParentName, parentName) => `${attributeParentName} = ${formatConditionValue({ value: parentName })}`;
11450
11450
  const buildSearchCondition = (attributeAlias, query) => `${attributeAlias} LIKE '%${query.replace(/'/g, "''")}%'`;
11451
- const buildIdsCondition = (attributeValue, ids) => `${attributeValue} in ${formatConditionValue({ value: ids })}`;
11451
+ /** Запрос пачки записей по их именам (`attributeName`) для достройки предков. */
11452
+ const buildNamesCondition = (attributeName, names) => `${attributeName} in ${formatConditionValue({ value: names })}`;
11453
+ /** Запрос пачки записей по их значениям (`attributeValue`) — для восстановления `defaultValue`. */
11454
+ const buildValuesCondition = (attributeValue, values) => `${attributeValue} in ${formatConditionValue({ value: values })}`;
11452
11455
  /** Группирует выбранные id по уровню в объектное значение фильтра `{ l{N}: [ids] }`. */
11453
11456
  const buildFilterValue = (selected) => {
11454
11457
  const result = {};
@@ -11473,54 +11476,62 @@ const parseFilterValue = (value) => {
11473
11476
  });
11474
11477
  return result;
11475
11478
  };
11479
+ /** Стабильная сериализация выбора для сравнения (порядок не важен). */
11480
+ const serializeSelection = (selected) => [...selected.entries()]
11481
+ .map(([id, level]) => `${id}:${level}`)
11482
+ .sort()
11483
+ .join(",");
11476
11484
  /**
11477
- * Дозапрашивает цепочку предков вверх по `parentId` уровень за уровнем (батч `id in (...)`),
11478
- * пока не достигнет уровня 1. Возвращает исходные узлы вместе с предками.
11485
+ * Дозапрашивает цепочку предков вверх по `parentName` уровень за уровнем (батч `attributeName in
11486
+ * (...)`), пока не достигнет уровня 1. Связь идёт по именам (`name`/`parentName`), т.к. `node.id`
11487
+ * хранит значение (`attributeValue`). Возвращает исходные узлы вместе с предками.
11479
11488
  */
11480
- const collectAncestors = async (nodes, loadByIds) => {
11481
- const byId = new Map();
11482
- nodes.forEach(node => byId.set(node.id, node));
11489
+ const collectAncestors = async (nodes, loadByNames) => {
11490
+ const byName = new Map();
11491
+ nodes.forEach(node => byName.set(node.data.name, node));
11483
11492
  let frontier = nodes;
11484
11493
  for (let depth = 0; depth < MAX_ANCESTOR_DEPTH; depth++) {
11485
11494
  const missingParents = new Set();
11486
11495
  frontier.forEach(node => {
11487
- const { parentId, level } = node.data ?? {};
11488
- if (parentId != null && level > 1 && !byId.has(parentId)) {
11489
- missingParents.add(parentId);
11496
+ const { parentName, level } = node.data ?? {};
11497
+ if (parentName != null && level > 1 && !byName.has(parentName)) {
11498
+ missingParents.add(parentName);
11490
11499
  }
11491
11500
  });
11492
11501
  if (!missingParents.size) {
11493
11502
  break;
11494
11503
  }
11495
- const parents = await loadByIds([...missingParents]);
11504
+ const parents = await loadByNames([...missingParents]);
11496
11505
  if (!parents.length) {
11497
11506
  break;
11498
11507
  }
11499
- parents.forEach(parent => byId.set(parent.id, parent));
11508
+ parents.forEach(parent => byName.set(parent.data.name, parent));
11500
11509
  frontier = parents;
11501
11510
  }
11502
- return [...byId.values()];
11511
+ return [...byName.values()];
11503
11512
  };
11504
11513
  /**
11505
- * Собирает плоский набор узлов в дерево по `parentId`. Узлы с подгруженными потомками
11506
- * раскрываются; листья-папки без потомков получают `children = null` (ленивая подгрузка).
11514
+ * Собирает плоский набор узлов в дерево по связи `parentName` ↔ `name`. Узлы с подгруженными
11515
+ * потомками раскрываются (`expanded` хранит `node.id` = значение); листья-папки без потомков
11516
+ * получают `children = null` (ленивая подгрузка).
11507
11517
  */
11508
11518
  const assembleTree = (nodes) => {
11509
- const nodesById = new Map();
11510
- nodes.forEach(node => nodesById.set(node.id, node));
11519
+ const nodesByName = new Map();
11520
+ nodes.forEach(node => nodesByName.set(node.data.name, node));
11511
11521
  const childrenMap = new Map();
11512
- nodesById.forEach(node => {
11513
- const parentId = node.data?.parentId;
11514
- if (parentId != null && nodesById.has(parentId)) {
11515
- const siblings = childrenMap.get(parentId) ?? [];
11522
+ nodesByName.forEach(node => {
11523
+ const parentName = node.data?.parentName;
11524
+ if (parentName != null && nodesByName.has(parentName)) {
11525
+ const siblings = childrenMap.get(parentName) ?? [];
11516
11526
  siblings.push(node);
11517
- childrenMap.set(parentId, siblings);
11527
+ childrenMap.set(parentName, siblings);
11518
11528
  }
11519
11529
  });
11520
11530
  const roots = [];
11521
11531
  const expanded = [];
11522
- nodesById.forEach(node => {
11523
- const kids = childrenMap.get(node.id);
11532
+ nodesByName.forEach(node => {
11533
+ const { name, parentName } = node.data;
11534
+ const kids = childrenMap.get(name);
11524
11535
  if (kids?.length) {
11525
11536
  node.children = kids;
11526
11537
  expanded.push(node.id);
@@ -11528,8 +11539,7 @@ const assembleTree = (nodes) => {
11528
11539
  else if (node.isLeaf) {
11529
11540
  node.children = null;
11530
11541
  }
11531
- const parentId = node.data?.parentId;
11532
- if (parentId == null || !nodesById.has(parentId)) {
11542
+ if (parentName == null || !nodesByName.has(parentName)) {
11533
11543
  roots.push(node);
11534
11544
  }
11535
11545
  });
@@ -11540,22 +11550,24 @@ const useTreeFilterData = (type, filterName) => {
11540
11550
  const { api } = useGlobalContext();
11541
11551
  const { currentPage } = useWidgetPage(type);
11542
11552
  const configFilter = React.useMemo(() => getConfigFilter(filterName, currentPage?.filters), [filterName, currentPage?.filters]);
11543
- const { relatedDataSource, attributeValue = DEFAULT_ATTRIBUTE_NAME, attributeAlias = DEFAULT_ATTRIBUTE_NAME, attributeParentValue, attributeLevel, attributeHasChildren, limit = DEFAULT_DATA_SOURCE_LIMIT, } = configFilter ?? {};
11553
+ const { relatedDataSource, attributeName = DEFAULT_ATTRIBUTE_NAME, attributeValue, attributeAlias = DEFAULT_ATTRIBUTE_NAME, attributeParentName, attributeLevel, attributeHasChildren, limit = DEFAULT_DATA_SOURCE_LIMIT, } = configFilter ?? {};
11554
+ const valueAttribute = attributeValue ?? attributeName;
11544
11555
  const layerName = React.useMemo(() => currentPage?.dataSources?.find(({ name }) => name === relatedDataSource)?.layerName, [currentPage?.dataSources, relatedDataSource]);
11545
11556
  const mapNode = React.useCallback(({ properties }) => {
11546
11557
  const hasChildren = attributeHasChildren ? !!properties[attributeHasChildren] : false;
11547
11558
  const data = {
11548
- parentId: attributeParentValue ? properties[attributeParentValue] ?? null : null,
11559
+ name: properties[attributeName],
11560
+ parentName: attributeParentName ? properties[attributeParentName] ?? null : null,
11549
11561
  level: attributeLevel ? Number(properties[attributeLevel]) : 1,
11550
11562
  };
11551
11563
  return {
11552
- id: properties[attributeValue],
11564
+ id: properties[valueAttribute],
11553
11565
  text: String(properties[attributeAlias] ?? ""),
11554
11566
  isLeaf: hasChildren,
11555
11567
  children: hasChildren ? null : undefined,
11556
11568
  data,
11557
11569
  };
11558
- }, [attributeValue, attributeAlias, attributeParentValue, attributeLevel, attributeHasChildren]);
11570
+ }, [valueAttribute, attributeName, attributeAlias, attributeParentName, attributeLevel, attributeHasChildren]);
11559
11571
  const runQuery = React.useCallback(async (condition) => {
11560
11572
  if (!layerName) {
11561
11573
  return [];
@@ -11571,29 +11583,36 @@ const useTreeFilterData = (type, filterName) => {
11571
11583
  return features.map(mapNode);
11572
11584
  }, [attributeLevel, runQuery, mapNode]);
11573
11585
  const loadChildren = React.useCallback(async (item) => {
11574
- if (!attributeParentValue) {
11586
+ if (!attributeParentName) {
11575
11587
  return { children: [] };
11576
11588
  }
11577
- const features = await runQuery(buildChildrenCondition(attributeParentValue, item.id));
11589
+ const features = await runQuery(buildChildrenCondition(attributeParentName, item.data.name));
11578
11590
  return { children: features.map(mapNode) };
11579
- }, [attributeParentValue, runQuery, mapNode]);
11591
+ }, [attributeParentName, runQuery, mapNode]);
11580
11592
  const searchNodes = React.useCallback(async (query) => {
11581
11593
  const features = await runQuery(buildSearchCondition(attributeAlias, query));
11582
11594
  return features.map(mapNode);
11583
11595
  }, [attributeAlias, runQuery, mapNode]);
11584
- const loadByIds = React.useCallback(async (ids) => {
11585
- if (!ids.length) {
11596
+ const loadByNames = React.useCallback(async (names) => {
11597
+ if (!names.length) {
11586
11598
  return [];
11587
11599
  }
11588
- const features = await runQuery(buildIdsCondition(attributeValue, ids));
11600
+ const features = await runQuery(buildNamesCondition(attributeName, names));
11589
11601
  return features.map(mapNode);
11590
- }, [attributeValue, runQuery, mapNode]);
11591
- return { configFilter, layerName, loadLevelOne, loadChildren, searchNodes, loadByIds };
11602
+ }, [attributeName, runQuery, mapNode]);
11603
+ const loadByValues = React.useCallback(async (values) => {
11604
+ if (!values.length) {
11605
+ return [];
11606
+ }
11607
+ const features = await runQuery(buildValuesCondition(valueAttribute, values));
11608
+ return features.map(mapNode);
11609
+ }, [valueAttribute, runQuery, mapNode]);
11610
+ return { configFilter, layerName, loadLevelOne, loadChildren, searchNodes, loadByNames, loadByValues };
11592
11611
  };
11593
11612
 
11594
11613
  const SEARCH_MIN_LENGTH = 3;
11595
11614
  const SEARCH_DEBOUNCE = 300;
11596
- const useTreeFilterSearch = ({ searchNodes, loadByIds }) => {
11615
+ const useTreeFilterSearch = ({ searchNodes, loadByNames }) => {
11597
11616
  const [searchValue, setSearchValue] = React.useState("");
11598
11617
  const [searchData, setSearchData] = React.useState([]);
11599
11618
  const [searchExpanded, setSearchExpanded] = React.useState([]);
@@ -11606,7 +11625,7 @@ const useTreeFilterSearch = ({ searchNodes, loadByIds }) => {
11606
11625
  setSearching(true);
11607
11626
  try {
11608
11627
  const results = await searchNodes(query);
11609
- const withAncestors = await collectAncestors(results, loadByIds);
11628
+ const withAncestors = await collectAncestors(results, loadByNames);
11610
11629
  const { roots, expanded } = assembleTree(withAncestors);
11611
11630
  if (id !== requestId.current) {
11612
11631
  return;
@@ -11619,7 +11638,7 @@ const useTreeFilterSearch = ({ searchNodes, loadByIds }) => {
11619
11638
  setSearching(false);
11620
11639
  }
11621
11640
  }
11622
- }, [searchNodes, loadByIds]);
11641
+ }, [searchNodes, loadByNames]);
11623
11642
  const clearSearchState = React.useCallback(() => {
11624
11643
  requestId.current++;
11625
11644
  setSearchData([]);
@@ -11663,6 +11682,9 @@ const useTreeFilterSelection = (type, filterName, configFilter) => {
11663
11682
  const [selected, setSelected] = React.useState(() => parseFilterValue(configFilter?.defaultValue));
11664
11683
  const [selectedLabel, setSelectedLabel] = React.useState();
11665
11684
  const selectedIds = React.useMemo(() => new Set(selected.keys()), [selected]);
11685
+ /** Уже применённый (в redux) выбор — база для `dirty`. */
11686
+ const committed = React.useMemo(() => parseFilterValue((filters[filterName]?.value ?? configFilter?.defaultValue)), [filters, filterName, configFilter?.defaultValue]);
11687
+ const dirty = React.useMemo(() => serializeSelection(selected) !== serializeSelection(committed), [selected, committed]);
11666
11688
  const commit = React.useCallback((next) => {
11667
11689
  setSelected(next);
11668
11690
  changeFilters({ [filterName]: { value: buildFilterValue(next) } }, configFilter?.resetFilters);
@@ -11683,8 +11705,17 @@ const useTreeFilterSelection = (type, filterName, configFilter) => {
11683
11705
  }
11684
11706
  next.set(item.id, level);
11685
11707
  }
11686
- commit(next);
11708
+ // Мультивыбор не коммитит в redux — сохранение по кнопке (onSave). Single — сразу.
11709
+ if (multiSelect) {
11710
+ setSelected(next);
11711
+ }
11712
+ else {
11713
+ commit(next);
11714
+ }
11687
11715
  }, [selected, commit]);
11716
+ const onSave = React.useCallback(() => {
11717
+ changeFilters({ [filterName]: { value: buildFilterValue(selected) } }, configFilter?.resetFilters);
11718
+ }, [changeFilters, filterName, selected, configFilter?.resetFilters]);
11688
11719
  const onReset = React.useCallback(() => {
11689
11720
  setSelectedLabel(undefined);
11690
11721
  commit(new Map());
@@ -11699,10 +11730,10 @@ const useTreeFilterSelection = (type, filterName, configFilter) => {
11699
11730
  changeFilters({ [filterName]: { value: buildFilterValue(selected) } });
11700
11731
  }
11701
11732
  }, [filters, filterName, changeFilters, selected]);
11702
- return { selected, selectedIds, selectedLabel, onToggleSelect, onReset };
11733
+ return { selected, selectedIds, selectedLabel, dirty, onToggleSelect, onReset, onSave };
11703
11734
  };
11704
11735
 
11705
- const useTreeFilterTree = ({ selected, loadLevelOne, loadByIds }) => {
11736
+ const useTreeFilterTree = ({ selected, loadLevelOne, loadByValues, loadByNames }) => {
11706
11737
  const [treeData, setTreeData] = React.useState([]);
11707
11738
  const [treeExpanded, setTreeExpanded] = React.useState([]);
11708
11739
  const [loading, setLoading] = React.useState(false);
@@ -11722,8 +11753,8 @@ const useTreeFilterTree = ({ selected, loadLevelOne, loadByIds }) => {
11722
11753
  setTreeData(roots);
11723
11754
  return;
11724
11755
  }
11725
- const selectedNodes = await loadByIds(preselected);
11726
- const withAncestors = await collectAncestors([...roots, ...selectedNodes], loadByIds);
11756
+ const selectedNodes = await loadByValues(preselected);
11757
+ const withAncestors = await collectAncestors([...roots, ...selectedNodes], loadByNames);
11727
11758
  const { roots: assembled, expanded } = assembleTree(withAncestors);
11728
11759
  setTreeData(assembled);
11729
11760
  setTreeExpanded(expanded);
@@ -11731,20 +11762,21 @@ const useTreeFilterTree = ({ selected, loadLevelOne, loadByIds }) => {
11731
11762
  finally {
11732
11763
  setLoading(false);
11733
11764
  }
11734
- }, [loadLevelOne, loadByIds]);
11765
+ }, [loadLevelOne, loadByValues, loadByNames]);
11735
11766
  return { treeData, setTreeData, treeExpanded, setTreeExpanded, loading, onOpen };
11736
11767
  };
11737
11768
 
11738
11769
  const useTreeFilter = (type, filter) => {
11739
11770
  const { filterName, multiSelect, placeholder, width } = filter.options ?? {};
11740
- const { configFilter, loadLevelOne, loadChildren, searchNodes, loadByIds } = useTreeFilterData(type, filterName ?? "");
11741
- const { selected, selectedIds, selectedLabel, onToggleSelect: toggleSelect, onReset } = useTreeFilterSelection(type, filterName ?? "", configFilter);
11771
+ const { configFilter, loadLevelOne, loadChildren, searchNodes, loadByNames, loadByValues } = useTreeFilterData(type, filterName ?? "");
11772
+ const { selected, selectedIds, selectedLabel, dirty, onToggleSelect: toggleSelect, onReset, onSave, } = useTreeFilterSelection(type, filterName ?? "", configFilter);
11742
11773
  const { treeData, setTreeData, treeExpanded, setTreeExpanded, loading, onOpen } = useTreeFilterTree({
11743
11774
  selected,
11744
11775
  loadLevelOne,
11745
- loadByIds,
11776
+ loadByValues,
11777
+ loadByNames,
11746
11778
  });
11747
- const search = useTreeFilterSearch({ searchNodes, loadByIds });
11779
+ const search = useTreeFilterSearch({ searchNodes, loadByNames });
11748
11780
  const onToggleSelect = React.useCallback(item => toggleSelect(item, multiSelect), [toggleSelect, multiSelect]);
11749
11781
  const onClose = React.useCallback(() => search.resetSearch(), [search]);
11750
11782
  const view = React.useMemo(() => search.isSearchActive
@@ -11769,12 +11801,14 @@ const useTreeFilter = (type, filter) => {
11769
11801
  onClose,
11770
11802
  onToggleSelect,
11771
11803
  onReset,
11804
+ onSave,
11805
+ dirty,
11772
11806
  };
11773
11807
  };
11774
11808
 
11775
11809
  const TreeFilter = ({ type, filter }) => {
11776
- const { width, placeholder, multiSelect, loading, data, setData, expanded, setExpanded, onLoadChildren, selectedIds, selectedCount, selectedLabel, searchValue, onSearchChange, onOpen, onClose, onToggleSelect, onReset, } = useTreeFilter(type, filter);
11777
- return (jsxRuntime.jsx(uilibGl.TreeDropdown, { width: width, placeholder: placeholder, multiSelect: multiSelect, loading: loading, data: data, setData: setData, expanded: expanded, setExpanded: setExpanded, onLoadChildren: onLoadChildren, selectedIds: selectedIds, selectedCount: selectedCount, selectedLabel: selectedLabel, searchValue: searchValue, onSearchChange: onSearchChange, onOpen: onOpen, onClose: onClose, onToggleSelect: onToggleSelect, onReset: onReset }));
11810
+ const { width, placeholder, multiSelect, loading, data, setData, expanded, setExpanded, onLoadChildren, selectedIds, selectedCount, selectedLabel, searchValue, onSearchChange, onOpen, onClose, onToggleSelect, onReset, onSave, dirty, } = useTreeFilter(type, filter);
11811
+ return (jsxRuntime.jsx(uilibGl.TreeDropdown, { zIndex: 100, width: width, placeholder: placeholder, multiSelect: multiSelect, loading: loading, data: data, setData: setData, expanded: expanded, setExpanded: setExpanded, onLoadChildren: onLoadChildren, selectedIds: selectedIds, selectedCount: selectedCount, selectedLabel: selectedLabel, searchValue: searchValue, onSearchChange: onSearchChange, onOpen: onOpen, onClose: onClose, onToggleSelect: onToggleSelect, onReset: onReset, onSave: onSave, dirty: dirty }));
11778
11812
  };
11779
11813
 
11780
11814
  const getFilterComponent = (filterType) => {