Skip to content

Commit

Permalink
Fix table filtering
Browse files Browse the repository at this point in the history
  • Loading branch information
MichaelBurgess committed Dec 19, 2024
1 parent 831d6ac commit da3ba0b
Show file tree
Hide file tree
Showing 2 changed files with 122 additions and 86 deletions.
72 changes: 44 additions & 28 deletions ui/dashboard/src/components/dashboards/Table/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ import { usePanelControls } from "@powerpipe/hooks/usePanelControls";
import { usePopper } from "react-popper";
import { useSearchParams } from "react-router-dom";
import { useVirtualizer } from "@tanstack/react-virtual";
import useCopyToClipboard from "@powerpipe/hooks/useCopyToClipboard";
import { AsyncNoop } from "@powerpipe/types/func";

const ExternalLink = getComponent("external_link");

Expand Down Expand Up @@ -488,6 +490,7 @@ const CellControls = ({
const { styles, attributes } = usePopper(referenceElement, popperElement, {
placement: "bottom-start",
});
const { copy, copySuccess } = useCopyToClipboard();

return (
<>
Expand All @@ -502,11 +505,14 @@ const CellControls = ({
>
<div className="flex items-center space-x-1">
<CellControl
icon="content_copy"
title="Copy value"
onClick={() =>
addFilter("equal", column.name, value, context)
iconClassName={copySuccess ? "text-ok" : undefined}
icon={
copySuccess
? "materialsymbols-solid:content_copy"
: "content_copy"
}
title="Copy value"
onClick={!copySuccess ? async () => copy(value) : undefined}
/>
<CellControl
icon="filter_alt"
Expand Down Expand Up @@ -548,14 +554,27 @@ const CellControls = ({
);
};

const CellControl = ({ icon, title, onClick }) => {
const CellControl = ({
iconClassName,
icon,
title,
onClick,
}: {
iconClassName?: string;
icon: string;
title: string;
onClick: AsyncNoop | undefined;
}) => {
return (
<div
onClick={onClick}
className="cursor-pointer text-table-head hover:text-foreground"
className={classNames(
"text-table-head hover:text-foreground",
onClick ? "cursor-pointer" : null,
)}
title={title}
>
<Icon className="h-4 w-4" icon={icon} />
<Icon className={classNames(iconClassName, "h-4 w-4")} icon={icon} />
</div>
);
};
Expand Down Expand Up @@ -637,7 +656,9 @@ const useTableFilters = (panelName: string, context?: string) => {
value: any,
context?: string,
) => {
const index = urlFilters.expressions?.findIndex(
const newUrlFilters = { ...urlFilters };
const expressions = [...(newUrlFilters.expressions || [])];
const index = expressions.findIndex(
(e) =>
e.type === "dimension" &&
e.key === key &&
Expand All @@ -646,11 +667,8 @@ const useTableFilters = (panelName: string, context?: string) => {
);
let newFilters =
index !== undefined && index > -1
? [
...urlFilters.expressions?.slice(0, index),
...urlFilters.expressions?.slice(index + 1),
]
: urlFilters.expressions || [];
? [...expressions.slice(0, index), ...expressions.slice(index + 1)]
: expressions || [];
if (
newFilters.length === 1 &&
newFilters[0].operator === "equal" &&
Expand All @@ -676,10 +694,10 @@ const useTableFilters = (panelName: string, context?: string) => {
context,
});
}
urlFilters.expressions = newFilters;
newUrlFilters.expressions = newFilters;
const newPanelFilters = {
...allFilters,
[panelName]: urlFilters,
[panelName]: newUrlFilters,
};
searchParams.set("where", JSON.stringify(newPanelFilters));
setSearchParams(searchParams);
Expand All @@ -689,28 +707,26 @@ const useTableFilters = (panelName: string, context?: string) => {

const removeFilter = useCallback(
(key: string, value: any, context: string) => {
const index = urlFilters.expressions?.findIndex(
const newUrlFilters = { ...urlFilters };
let expressions = [...(newUrlFilters.expressions || [])];
const index = expressions.findIndex(
(e) =>
e.type === "dimension" &&
e.key === key &&
e.value === value &&
e.context === context,
);
const newFilters =
let newFilters =
index !== undefined
? [
...urlFilters.expressions?.slice(0, index),
...urlFilters.expressions?.slice(index + 1),
]
: urlFilters.expressions || [];
? [...expressions.slice(0, index), ...expressions.slice(index + 1)]
: expressions;
if (newFilters.length === 0) {
urlFilters.expressions = [{ operator: "equal" }];
} else {
urlFilters.expressions = newFilters;
newFilters = [{ operator: "equal" }];
}
newUrlFilters.expressions = newFilters;
const newPanelFilters = {
...allFilters,
[panelName]: urlFilters,
[panelName]: newUrlFilters,
};
searchParams.set("where", JSON.stringify(newPanelFilters));
setSearchParams(searchParams);
Expand Down Expand Up @@ -849,7 +865,7 @@ const TableViewVirtualizedRows = ({
<>
<div className="flex flex-col w-full overflow-hidden">
{filterEnabled && !!filters.length && (
<div className="flex flex-wrap gap-2 w-full p-4 justify-between">
<div className="flex flex-wrap gap-2 w-full p-4">
{filters.map((filter) => {
return (
<div
Expand All @@ -861,7 +877,7 @@ const TableViewVirtualizedRows = ({
icon={
filter.operator === "equal"
? "filter_alt"
: "do_not_disturb_on"
: "filter_alt_off"
}
/>
<span>{`${filter.key}: ${filter.value}`}</span>
Expand Down
136 changes: 78 additions & 58 deletions ui/dashboard/src/hooks/useDetectionGrouping.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import {
PanelDefinition,
PanelsMap,
} from "@powerpipe/types";
import { KeyValuePairs } from "@powerpipe/components/dashboards/common/types";
import { LeafNodeDataRow } from "@powerpipe/components/dashboards/common";
import { useDashboardState } from "./useDashboardState";
import { useDashboardControls } from "@powerpipe/components/dashboards/layout/Dashboard/DashboardControlsProvider";
Expand Down Expand Up @@ -573,74 +574,93 @@ function recordFilterValues(

const includeResult = (
result: DetectionResult,
filterConfig: Filter,
panel: PanelDefinition,
allFilters: KeyValuePairs<Filter>,
): boolean => {
if (
!filterConfig ||
!filterConfig.expressions ||
filterConfig.expressions.length === 0
) {
// If no filters, include this
if (Object.keys(allFilters).length === 0) {
return true;
}

const filterForRootPanel = allFilters[panel.name];
const filterForDetection = allFilters[result.detection.name];

// If no filters for the parent panel, or this panel, include
if (!filterForRootPanel && !filterForDetection) {
return true;
}

let matches: boolean[] = [];
for (const filter of filterConfig.expressions) {
if (!filter.type) {
continue;
}
for (const filter of [filterForRootPanel, filterForDetection].filter(
(f) => !!f && !!f.expressions?.length,
)) {
for (const expression of filter.expressions || []) {
if (!expression.type) {
continue;
}

switch (filter.type) {
case "benchmark": {
let matchesTrunk = false;
for (const benchmark of result.benchmark_trunk || []) {
const match = applyFilter(filter, benchmark.name);
if (match) {
matchesTrunk = true;
break;
switch (expression.type) {
case "benchmark": {
let matchesTrunk = false;
for (const benchmark of result.benchmark_trunk || []) {
const match = applyFilter(expression, benchmark.name);
if (match) {
matchesTrunk = true;
break;
}
}
matches.push(matchesTrunk);
break;
}
matches.push(matchesTrunk);
break;
}
case "detection": {
matches.push(applyFilter(filter, result.detection.name));
break;
}
case "dimension": {
let newRows: LeafNodeDataRow[] = [];
if (filter.context && result.detection.name !== filter.context) {
newRows = result.rows || [];
} else {
let includeRow = false;
for (const row of result.rows || []) {
includeRow =
filter.key in row && applyFilter(filter, row[filter.key]);
if (includeRow) {
newRows.push(row);
} else {
case "detection": {
matches.push(applyFilter(expression, result.detection.name));
break;
}
case "dimension": {
let newRows: LeafNodeDataRow[] = [];
if (
expression.context &&
result.detection.name !== expression.context
) {
newRows = result.rows || [];
} else {
let includeRow = false;
for (const row of result.rows || []) {
includeRow =
!!expression.key &&
expression.key in row &&
applyFilter(expression, row[expression.key]);
if (includeRow) {
newRows.push(row);
} else {
}
}
}
result.rows = newRows;
matches.push(true);
break;
}
result.rows = newRows;
matches.push(true);
break;
}
case "detection_tag": {
let matchesTags = false;
for (const [tagKey, tagValue] of Object.entries(result.tags || {})) {
if (filter.key === tagKey && applyFilter(filter, tagValue)) {
matchesTags = true;
break;
case "detection_tag": {
let matchesTags = false;
for (const [tagKey, tagValue] of Object.entries(result.tags || {})) {
if (
expression.key === tagKey &&
applyFilter(expression, tagValue)
) {
matchesTags = true;
break;
}
}
matches.push(matchesTags);
break;
}
matches.push(matchesTags);
break;
}
case "severity": {
matches.push(applyFilter(filter, result.severity || ""));
break;
case "severity": {
matches.push(applyFilter(expression, result.severity || ""));
break;
}
default:
matches.push(true);
}
default:
matches.push(true);
}
}
return matches.every((m) => m);
Expand All @@ -653,7 +673,7 @@ const useGroupingInternal = (
groupingConfig: DetectionDisplayGroup[],
skip = false,
) => {
const { filter: checkFilterConfig } = useFilterConfig(definition?.name);
const { allFilters } = useFilterConfig(definition?.name);

return useMemo(() => {
const filterValues = {
Expand Down Expand Up @@ -703,7 +723,7 @@ const useGroupingInternal = (
recordFilterValues(filterValues, detectionResult);

// See if the result needs to be filtered
if (!includeResult(detectionResult, checkFilterConfig)) {
if (!includeResult(detectionResult, definition, allFilters)) {
return;
}

Expand Down Expand Up @@ -747,7 +767,7 @@ const useGroupingInternal = (
detectionNodeStates,
filterValues,
] as const;
}, [checkFilterConfig, definition, groupingConfig, panelsMap, skip]);
}, [allFilters, definition, groupingConfig, panelsMap, skip]);
};

const GroupingProvider = ({
Expand Down

0 comments on commit da3ba0b

Please sign in to comment.