Skip to content

Commit

Permalink
feat: add group by type class for config summary
Browse files Browse the repository at this point in the history
Fixes #2048

chore: update config class label
  • Loading branch information
mainawycliffe authored and moshloop committed Jul 3, 2024
1 parent d68661c commit def72c6
Show file tree
Hide file tree
Showing 9 changed files with 187 additions and 74 deletions.
12 changes: 9 additions & 3 deletions src/api/query-hooks/useConfigSummaryQuery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export function useConfigSummaryQuery({
const [searchParams] = useSearchParams({
sortBy: "type",
sortOrder: "asc",
groupBy: "type"
groupBy: "config_class,type"
});
const hideDeletedConfigs = useHideDeletedConfigs();
const labels = searchParams.get("labels") ?? undefined;
Expand All @@ -33,7 +33,8 @@ export function useConfigSummaryQuery({
}, [labels]);

const req: ConfigSummaryRequest = {
groupBy,
// group by config_class is always done on the frontend
groupBy: groupBy?.filter((g) => g !== "config_class") || undefined,
deleted: !hideDeletedConfigs,
filter: filterSummaryByLabel,
health: health ? tristateOutputToQueryParamValue(health) : undefined,
Expand All @@ -50,6 +51,11 @@ export function useConfigSummaryQuery({
return useQuery({
queryKey: ["configs", "configSummary", req],
queryFn: () => getConfigsSummary(req),
enabled
enabled,
select: (data) =>
data.map((summary) => ({
...summary,
config_class: summary.type.split("::")[0]
}))
});
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { ConfigSummary } from "@flanksource-ui/api/types/configs";
import { Badge } from "@flanksource-ui/ui/Badge/Badge";
import { CellContext } from "@tanstack/react-table";
import { IoChevronDown, IoChevronForward } from "react-icons/io5";
import ConfigsTypeIcon from "../../ConfigsTypeIcon";

export function ConfigSummaryTableVirtualAggregateColumn({
row
}: CellContext<ConfigSummary, any>) {
if (row.getCanExpand()) {
const groupingValue = row.getGroupingValue(row.groupingColumnId!) as string;
const count = row.subRows.reduce((acc, row) => acc + row.original.count, 0);
return (
<div
className="flex flex-row items-center gap-1"
style={{
marginLeft: row.depth * 20
}}
>
{row.getIsExpanded() ? <IoChevronDown /> : <IoChevronForward />}
{row.groupingColumnId === "type" ||
row.groupingColumnId === "config_class" ? (
<ConfigsTypeIcon
config={row.original}
showLabel={row.groupingColumnId === "type"}
showSecondaryIcon={row.groupingColumnId === "type"}
>
<div className="flex flex-row items-center gap-1">
{row.groupingColumnId === "config_class" && (
<span>{groupingValue}</span>
)}
<Badge text={count} />
</div>
</ConfigsTypeIcon>
) : (
<div className="flex flex-row gap-1 items-center">
{groupingValue ? (
<span>{groupingValue}</span>
) : (
<span className="text-gray-400">(None)</span>
)}
<Badge text={count} />
</div>
)}
</div>
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { ConfigSummary } from "@flanksource-ui/api/types/configs";
import { Badge } from "@flanksource-ui/ui/Badge/Badge";
import { CellContext } from "@tanstack/react-table";
import { BiLabel } from "react-icons/bi";

export function ConfigSummaryVirtualColumnCell({
getValue,
row,
groupByTags,
columnId
}: CellContext<ConfigSummary, any> & {
groupByTags: string[];
columnId: string;
}) {
const isTag = groupByTags.includes(columnId);
const value = getValue();

return (
<div
className="flex flex-1 flex-row gap-1 items-center"
style={{
marginLeft: row.depth * 20
}}
>
{isTag && <BiLabel />}
{value ? (
<span>{value}</span>
) : (
<span className="text-gray-400">(None)</span>
)}
<Badge text={row.original.count} />
</div>
);
}
129 changes: 68 additions & 61 deletions src/components/Configs/ConfigSummary/ConfigSummaryList.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import { ConfigSummary } from "@flanksource-ui/api/types/configs";
import { Badge } from "@flanksource-ui/ui/Badge/Badge";
import { DataTable } from "@flanksource-ui/ui/DataTable";
import ChangeCount, { CountBar } from "@flanksource-ui/ui/Icons/ChangeCount";
import { CellContext, ColumnDef, Row } from "@tanstack/react-table";
import { useCallback, useMemo } from "react";
import { BiLabel } from "react-icons/bi";
import { IoChevronDown, IoChevronForward } from "react-icons/io5";
import { useSearchParams } from "react-router-dom";
import ConfigListCostCell from "../ConfigList/Cells/ConfigListCostCell";
import ConfigListDateCell from "../ConfigList/Cells/ConfigListDateCell";
Expand All @@ -14,7 +13,8 @@ import {
ConfigSummaryHealthAggregateCell,
ConfigSummaryHealthCell
} from "./Cells/ConfigSummaryHealthCells";
import ChangeCount, { CountBar } from "@flanksource-ui/ui/Icons/ChangeCount";
import { ConfigSummaryTableVirtualAggregateColumn } from "./Cells/ConfigSummaryTableVirtualAggregateColumn";
import { ConfigSummaryVirtualColumnCell } from "./Cells/ConfigSummaryVirtualColumnCell";

export function getConfigStatusColor(health?: ConfigSummary["health"]) {
if (!health) {
Expand Down Expand Up @@ -51,7 +51,12 @@ function ConfigSummaryTypeCell({
}, [configType]);

return (
<span className="flex flex-nowrap gap-1">
<span
className="flex flex-nowrap gap-1"
style={{
marginLeft: row.depth * 20
}}
>
<ConfigsTypeIcon config={{ type: configType }}>
<div className="flex flex-row items-center gap-1">
<span className="pl-1">{value}</span>
Expand Down Expand Up @@ -93,10 +98,55 @@ function ConfigSummaryAnalysisCell({
);
}

function ConfigSummaryAnalysisAggregateCell({
row
}: CellContext<ConfigSummary, unknown>) {
const subRows = row.subRows;

const value = subRows.reduce((acc, row) => {
const analysis = row.original.analysis;
if (analysis) {
Object.entries(analysis).forEach(([key, value]) => {
acc[key] = (acc[key] || 0) + value;
});
}
return acc;
}, {} as Record<string, number>);

return (
<div className="flex flex-row gap-1 overflow-hidden truncate">
<CountBar
iconClass="px-1 bg-zinc-100"
items={Object.entries(value).map(([key, value]) => {
return {
count: value,
icon: (
<ConfigInsightsIcon
size={20}
analysis={{
analysis_type: key,
severity: ""
}}
/>
)
};
})}
/>
</div>
);
}

const configSummaryColumns: ColumnDef<ConfigSummary, any>[] = [
{
header: "changes",
accessorKey: "changes",
aggregatedCell: ({ getValue }) => {
const value = getValue();
if (!value) {
return null;
}
return <ChangeCount count={value} />;
},
cell: ({ getValue }: CellContext<ConfigSummary, any>) => {
const value = getValue();
if (!value) {
Expand All @@ -118,6 +168,7 @@ const configSummaryColumns: ColumnDef<ConfigSummary, any>[] = [
header: "analysis",
accessorKey: "analysis",
cell: ConfigSummaryAnalysisCell,
aggregatedCell: ConfigSummaryAnalysisAggregateCell,
minSize: 30,
maxSize: 100
},
Expand Down Expand Up @@ -176,7 +227,10 @@ export default function ConfigSummaryList({
const tags = groupBy
.filter(
(column) =>
column !== "type" && column !== "health" && column !== "status"
column !== "type" &&
column !== "health" &&
column !== "status" &&
column !== "config_class"
)
.filter((column) => row.original[column as keyof ConfigSummary]);
if (tags.length > 0) {
Expand All @@ -202,65 +256,17 @@ export default function ConfigSummaryList({
accessorKey: column,
maxSize: 250,
minSize: 100,
aggregatedCell: ({ row }) => {
if (row.getCanExpand()) {
const groupingValue = row.getGroupingValue(
row.groupingColumnId!
) as string;
const count = row.subRows.reduce(
(acc, row) => acc + row.original.count,
0
);
return (
<div
className="flex flex-row items-center gap-1"
style={{
marginLeft: row.depth * 20
}}
>
{row.getIsExpanded() ? <IoChevronDown /> : <IoChevronForward />}
{row.groupingColumnId === "type" ? (
<ConfigsTypeIcon config={row.original} showLabel>
<Badge text={count} />
</ConfigsTypeIcon>
) : (
<div className="flex flex-row gap-1 items-center">
{groupingValue ? (
<span>{groupingValue}</span>
) : (
<span className="text-gray-400">(None)</span>
)}
<Badge text={count} />
</div>
)}
</div>
);
}
},
aggregatedCell: ConfigSummaryTableVirtualAggregateColumn,
cell:
column === "type"
? ConfigSummaryTypeCell
: ({ getValue, row }: CellContext<ConfigSummary, any>) => {
const isTag = groupByTags.includes(column);
const value = getValue();

return (
<div
className="flex flex-1 flex-row gap-1 items-center"
style={{
marginLeft: (row.depth + 1) * 20
}}
>
{isTag && <BiLabel />}
{value ? (
<span>{value}</span>
) : (
<span className="text-gray-400">(None)</span>
)}
<Badge text={row.original.count} />
</div>
);
}
: (props) => (
<ConfigSummaryVirtualColumnCell
{...props}
groupByTags={groupByTags}
columnId={column}
/>
)
} satisfies ColumnDef<ConfigSummary>;
});
return [...newColumns, ...configSummaryColumns];
Expand All @@ -283,6 +289,7 @@ export default function ConfigSummaryList({
isLoading={isLoading}
className="max-w-full overflow-x-auto table-fixed table-auto"
savePreferences={false}
expandAllRows={groupBy[0] === "config_class"}
/>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { useSearchParams } from "react-router-dom";
*/
export default function useGroupBySearchParam(): string[] | undefined {
const [searchParams] = useSearchParams({
groupBy: "type"
groupBy: "config_class,type"
});

const groupByProp = searchParams.get("groupBy") ?? undefined;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ const items: GroupByOptions[] = [
label: "type",
value: "type",
icon: <BiLabel />
},
{
label: "provider",
value: "config_class",
icon: <BiLabel />
}
];

Expand All @@ -55,7 +60,7 @@ export default function ConfigGroupByDropdown({
if (configType) {
return [];
}
return ["type"];
return ["config_class", "type"];
}
return groupBy.split(",").map((v) => v.replace("__tag", "")) ?? [];
}, [configType, params, searchParamKey]);
Expand All @@ -66,9 +71,18 @@ export default function ConfigGroupByDropdown({
enabled: true,
select: (tags) => {
return [
...Object.values(items).filter(
(item) => !configType || item.value !== "type"
),
...Object.values(items).filter((item) => {
if (!configType) {
return false;
}
if (item.value === "type") {
return false;
}
if (item.value === "config_class") {
return false;
}
return true;
}),
...(tags && tags.length > 0
? tags
// ensure that the tags are unique
Expand Down
3 changes: 2 additions & 1 deletion src/components/Configs/ConfigsTypeIcon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,8 @@ export default function ConfigsTypeIcon({
)}
</span>
{showLabel && <span> {value}</span>}
{children && <span>{children}</span>}
{/* eslint-disable-next-line react/jsx-no-useless-fragment */}
{children && <>{children}</>}
</div>
);
}
2 changes: 0 additions & 2 deletions src/components/Topology/TopologyBreadcrumbs/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@ function TopologyBreadcrumbItem({
}) {
const { data: component } = useComponentNameQuery(topologyId, {});

console.log(component);

if (!component) {
return null;
}
Expand Down
Loading

0 comments on commit def72c6

Please sign in to comment.