Skip to content

Commit

Permalink
Add option to disable button based filtering (#840)
Browse files Browse the repository at this point in the history
* disable button based filtering implementation

* extract-api

* change

* adjustments

* extract-api

* Update packages/hierarchies-react/src/test/itwinui/Tree.test.tsx

Co-authored-by: Grigas <[email protected]>

* documentation change

* updated change

* Documentation adjustment 3rd try

---------

Co-authored-by: Grigas <[email protected]>
  • Loading branch information
MartynasStrazdas and grigasp authored Jan 16, 2025
1 parent f8863a6 commit f94dcdd
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 5 deletions.
8 changes: 8 additions & 0 deletions .changeset/little-vans-sell.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
"@itwin/presentation-hierarchies-react": minor
---

Added `filterButtonsVisibility` to `treeNodeRenderer`. Which allows configuring filter buttons visibility for the whole tree.

- `show-on-hover` - default value, shows filter buttons on node hover or focus.
- `hide` - hides filter buttons on focus and hover, but will continue to show buttons on nodes in which filter is applied. Reaching hierarchy limit will continue to provide a way to filter nodes.
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ export const TreeNodeRenderer: React.ForwardRefExoticComponent<TreeNodeRendererP
// @public (undocumented)
interface TreeNodeRendererOwnProps {
actionButtonsClassName?: string;
filterButtonsVisibility?: "show-on-hover" | "hide";
getIcon?: (node: PresentationHierarchyNode) => ReactElement | undefined;
getLabel?: (node: PresentationHierarchyNode) => ReactElement | undefined;
getSublabel?: (node: PresentationHierarchyNode) => ReactElement | undefined;
Expand All @@ -192,7 +193,7 @@ type TreeNodeRendererProps_2 = ComponentPropsWithoutRef<typeof TreeNodeRenderer>
type TreeProps = ComponentPropsWithoutRef<typeof Tree<RenderedTreeNode>>;

// @public
export function TreeRenderer({ rootNodes, expandNode, selectNodes, isNodeSelected, onFilterClick, getIcon, getLabel, getSublabel, getHierarchyLevelDetails, reloadTree, selectionMode, localizedStrings, size, ...treeProps }: TreeRendererProps): JSX_3.Element;
export function TreeRenderer({ rootNodes, expandNode, selectNodes, isNodeSelected, onFilterClick, getIcon, getLabel, getSublabel, getHierarchyLevelDetails, reloadTree, selectionMode, localizedStrings, size, filterButtonsVisibility, ...treeProps }: TreeRendererProps): JSX_3.Element;

// @public (undocumented)
interface TreeRendererOwnProps {
Expand All @@ -201,7 +202,7 @@ interface TreeRendererOwnProps {
}

// @public (undocumented)
type TreeRendererProps = Pick<ReturnType<typeof useTree>, "rootNodes" | "expandNode"> & Partial<Pick<ReturnType<typeof useTree>, "selectNodes" | "isNodeSelected" | "getHierarchyLevelDetails" | "reloadTree">> & Pick<TreeNodeRendererProps_2, "onFilterClick" | "getIcon" | "getLabel" | "getSublabel"> & TreeRendererOwnProps & Omit<TreeProps, "data" | "nodeRenderer" | "getNode" | "enableVirtualization"> & ComponentPropsWithoutRef<typeof LocalizationContextProvider>;
type TreeRendererProps = Pick<ReturnType<typeof useTree>, "rootNodes" | "expandNode"> & Partial<Pick<ReturnType<typeof useTree>, "selectNodes" | "isNodeSelected" | "getHierarchyLevelDetails" | "reloadTree">> & Pick<TreeNodeRendererProps_2, "onFilterClick" | "getIcon" | "getLabel" | "getSublabel" | "filterButtonsVisibility"> & TreeRendererOwnProps & Omit<TreeProps, "data" | "nodeRenderer" | "getNode" | "enableVirtualization"> & ComponentPropsWithoutRef<typeof LocalizationContextProvider>;

// @public
export function UnifiedSelectionProvider({ storage, children }: PropsWithChildren<{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,16 @@ interface TreeNodeRendererOwnProps {
actionButtonsClassName?: string;
/** Tree node size. Should match the size passed to `TreeRenderer` component. */
size?: "default" | "small";
/**
* Configures filter buttons visibility.
*
* Options:
* - `show-on-hover` - show filter buttons when hovering over node, or the node is in focus.
* - `hide` - hide filter buttons, but will show them if the filter is applied.
*
* Default value: `show-on-hover`
*/
filterButtonsVisibility?: "show-on-hover" | "hide";
}

/** @public */
Expand Down Expand Up @@ -71,6 +81,7 @@ export const TreeNodeRenderer: React.ForwardRefExoticComponent<TreeNodeRendererP
getHierarchyLevelDetails,
reloadTree,
size,
filterButtonsVisibility,
...treeNodeProps
},
forwardedRef,
Expand Down Expand Up @@ -121,7 +132,7 @@ export const TreeNodeRenderer: React.ForwardRefExoticComponent<TreeNodeRendererP
<SvgRemove />
</IconButton>
) : null}
{onFilterClick && node.isFilterable ? (
{onFilterClick && node.isFilterable && (filterButtonsVisibility !== "hide" || node.isFiltered) ? (
<IconButton
ref={applyFilterButtonRef}
className="filtering-action-button"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ interface TreeRendererOwnProps {
/** @public */
type TreeRendererProps = Pick<ReturnType<typeof useTree>, "rootNodes" | "expandNode"> &
Partial<Pick<ReturnType<typeof useTree>, "selectNodes" | "isNodeSelected" | "getHierarchyLevelDetails" | "reloadTree">> &
Pick<TreeNodeRendererProps, "onFilterClick" | "getIcon" | "getLabel" | "getSublabel"> &
Pick<TreeNodeRendererProps, "onFilterClick" | "getIcon" | "getLabel" | "getSublabel" | "filterButtonsVisibility"> &
TreeRendererOwnProps &
Omit<TreeProps, "data" | "nodeRenderer" | "getNode" | "enableVirtualization"> &
ComponentPropsWithoutRef<typeof LocalizationContextProvider>;
Expand All @@ -54,6 +54,7 @@ export function TreeRenderer({
selectionMode,
localizedStrings,
size,
filterButtonsVisibility,
...treeProps
}: TreeRendererProps) {
const { onNodeClick, onNodeKeyDown } = useSelectionHandler({
Expand All @@ -66,6 +67,7 @@ export function TreeRenderer({
return (
<TreeNodeRenderer
{...nodeProps}
filterButtonsVisibility={filterButtonsVisibility}
expandNode={expandNode}
getHierarchyLevelDetails={getHierarchyLevelDetails}
onFilterClick={onFilterClick}
Expand All @@ -79,7 +81,19 @@ export function TreeRenderer({
/>
);
},
[expandNode, getHierarchyLevelDetails, onFilterClick, onNodeClick, onNodeKeyDown, getIcon, getLabel, getSublabel, reloadTree, size],
[
filterButtonsVisibility,
expandNode,
getHierarchyLevelDetails,
onFilterClick,
onNodeClick,
onNodeKeyDown,
getIcon,
getLabel,
getSublabel,
reloadTree,
size,
],
);

const getNode = useCallback<TreeProps["getNode"]>((node) => createRenderedTreeNodeData(node, isNodeSelected ?? noopIsNodeSelected), [isNodeSelected]);
Expand Down
19 changes: 19 additions & 0 deletions packages/hierarchies-react/src/test/itwinui/Tree.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,25 @@ describe("Tree", () => {
expect(onFilterClick).to.be.calledOnceWith(hierarchyLevelDetails);
});

it("renders filter button when filter buttons are hidden, but node is filtered", async () => {
const rootNodes = createNodes([
{
id: "root-1",
isFilterable: true,
isFiltered: true,
},
]);

const hierarchyLevelDetails = {} as unknown as HierarchyLevelDetails;
getHierarchyLevelDetails.returns(hierarchyLevelDetails);

const { user, queryByText, getByRole } = render(<TreeRenderer rootNodes={rootNodes} filterButtonsVisibility={"hide"} {...initialProps} />);

expect(queryByText("root-1")).to.not.be.null;
await user.click(getByRole("button", { name: "Apply filter" }));
expect(onFilterClick).to.be.calledOnceWith(hierarchyLevelDetails);
});

describe("`ResultSetTooLarge` node", () => {
it("renders `ResultSetTooLarge` node with filtering and override support", async () => {
const rootNodes = createNodes([
Expand Down

0 comments on commit f94dcdd

Please sign in to comment.