Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add sorting options for incident table #1940

Merged
merged 3 commits into from
Sep 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/openapi.json

Large diffs are not rendered by default.

75 changes: 68 additions & 7 deletions keep-ui/app/incidents/incident-table-component.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,74 @@
import {Table, TableBody, TableCell, TableHead, TableHeaderCell, TableRow} from "@tremor/react";
import { flexRender, Table as ReactTable } from "@tanstack/react-table";
import React from "react";
import {Icon, Table, TableBody, TableCell, TableHead, TableHeaderCell, TableRow} from "@tremor/react";
import {flexRender, Header, Table as ReactTable} from "@tanstack/react-table";
import React, {ReactNode} from "react";
import { IncidentDto } from "./model";
import { useRouter } from "next/navigation";

import {FaArrowDown, FaArrowRight, FaArrowUp} from "react-icons/fa";
interface Props {
table: ReactTable<IncidentDto>;
}

interface SortableHeaderCellProps {
header: Header<IncidentDto, unknown>;
children: ReactNode;
}

const SortableHeaderCell = ({
header,
children,
}: SortableHeaderCellProps) => {

const { column } = header;

return (
<TableHeaderCell
// className="text-tremor-content-strong dark:text-dark-tremor-content-strong"
className={`relative ${
column.getIsPinned() === false ? "hover:bg-slate-100" : ""
} group`}
>
<div className="flex items-center">
{column.getCanSort() && (
<>
<Icon
className="cursor-pointer"
size="xs"
color="neutral"
onClick={(event) => {
console.log("clicked for sorting");
event.stopPropagation();
const toggleSorting = header.column.getToggleSortingHandler();
if (toggleSorting) toggleSorting(event);
}}
tooltip={
column.getNextSortingOrder() === "asc"
? "Sort ascending"
: column.getNextSortingOrder() === "desc"
? "Sort descending"
: "Clear sort"
}
icon= {column.getIsSorted() ? (
column.getIsSorted() === "asc" ? FaArrowDown : FaArrowUp
) : (
FaArrowRight
)}
>
{/* Icon logic */}

</Icon>
{/* Custom styled vertical line separator */}
<div className="w-px h-5 mx-2 bg-gray-400"></div>
</>
)}

{children} {/* Column name or text */}
</div>

</TableHeaderCell>

);
};

export const IncidentTableComponent = (props: Props) => {

const { table } = props;
Expand All @@ -24,15 +85,15 @@ export const IncidentTableComponent = (props: Props) => {
>
{headerGroup.headers.map((header) => {
return (
<TableHeaderCell
className="text-tremor-content-strong dark:text-dark-tremor-content-strong"
<SortableHeaderCell
header={header}
key={header.id}
>
{flexRender(
header.column.columnDef.header,
header.getContext()
)}
</TableHeaderCell>
</SortableHeaderCell>
);
})}
</TableRow>
Expand Down
11 changes: 10 additions & 1 deletion keep-ui/app/incidents/incident.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { IncidentPlaceholder } from "./IncidentPlaceholder";
import Modal from "@/components/ui/Modal";
import { PlusCircleIcon } from "@heroicons/react/24/outline";
import PredictedIncidentsTable from "./predicted-incidents-table";
import {SortingState} from "@tanstack/react-table";

interface Pagination {
limit: number;
Expand All @@ -22,11 +23,17 @@ export default function Incident() {
offset: 0,
});

const [incidentsSorting, setIncidentsSorting] = useState<SortingState>([
{ id: "creation_time", desc: true },
]);

console.log('incidentSorting', incidentsSorting)

const {
data: incidents,
isLoading,
mutate: mutateIncidents,
} = useIncidents(true, incidentsPagination.limit, incidentsPagination.offset);
} = useIncidents(true, incidentsPagination.limit, incidentsPagination.offset, incidentsSorting[0]);
const {
data: predictedIncidents,
isLoading: isPredictedLoading,
Expand Down Expand Up @@ -102,6 +109,8 @@ export default function Incident() {
incidents={incidents}
mutate={mutateIncidents}
setPagination={setIncidentsPagination}
sorting={incidentsSorting}
setSorting={setIncidentsSorting}
editCallback={handleStartEdit}
/>
</Card>
Expand Down
57 changes: 36 additions & 21 deletions keep-ui/app/incidents/incidents-table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ import {
Badge,
} from "@tremor/react";
import {
DisplayColumnDef,
ExpandedState,
createColumnHelper,
getCoreRowModel,
useReactTable,
SortingState,
getSortedRowModel,
ColumnDef,
} from "@tanstack/react-table";
import { MdRemoveCircle, MdModeEdit } from "react-icons/md";
import { useSession } from "next-auth/react";
Expand All @@ -23,6 +25,8 @@ const columnHelper = createColumnHelper<IncidentDto>();
interface Props {
incidents: PaginatedIncidentsDto;
mutate: () => void;
sorting: SortingState,
setSorting: Dispatch<SetStateAction<any>>;
setPagination: Dispatch<SetStateAction<any>>;
editCallback: (rule: IncidentDto) => void;
}
Expand All @@ -31,6 +35,8 @@ export default function IncidentsTable({
incidents: incidents,
mutate,
setPagination,
sorting,
setSorting,
editCallback,
}: Props) {
const { data: session } = useSession();
Expand Down Expand Up @@ -76,22 +82,21 @@ export default function IncidentsTable({
header: "Group by value",
cell: ({ row }) => <div className="text-wrap">{row.original.rule_fingerprint || "-"}</div>,
}),
// columnHelper.display({
// id: "severity",
// header: "Severity",
// cell: (context) => {
// const severity = context.row.original.severity;
// let color;
// if (severity === "critical") color = "red";
// else if (severity === "info") color = "blue";
// else if (severity === "warning") color = "yellow";
// return <Badge color={color}>{severity}</Badge>;
// },
// }),
columnHelper.display({
id: "alert_count",
columnHelper.accessor("severity", {
id: "severity",
header: "Severity",
cell: (context) => {
const severity = context.row.original.severity;
let color;
if (severity === "critical") color = "red";
else if (severity === "info") color = "blue";
else if (severity === "warning") color = "yellow";
return <Badge color={color}>{severity}</Badge>;
},
}),
columnHelper.accessor("alerts_count", {
id: "alerts_count",
header: "Number of Alerts",
cell: (context) => context.row.original.number_of_alerts,
}),
columnHelper.display({
id: "alert_sources",
Expand Down Expand Up @@ -121,10 +126,10 @@ export default function IncidentsTable({
columnHelper.display({
id: "assignee",
header: "Assignee",
cell: (context) => context.row.original.assignee,
cell: ({row}) => row.original.assignee
}),
columnHelper.display({
id: "created_at",
columnHelper.accessor("creation_time", {
id: "creation_time",
header: "Created At",
cell: ({ row }) =>
new Date(row.original.creation_time + "Z").toLocaleString(),
Expand Down Expand Up @@ -160,17 +165,27 @@ export default function IncidentsTable({
</div>
),
}),
] as DisplayColumnDef<IncidentDto>[];
] as ColumnDef<IncidentDto>[];

const table = useReactTable({
columns,
data: incidents.items,
state: { expanded, pagination },
state: { expanded, pagination, sorting },
getCoreRowModel: getCoreRowModel(),
manualPagination: true,
rowCount: incidents.count,
onPaginationChange: setTablePagination,
onExpandedChange: setExpanded,
onSortingChange: (value) => {
if (typeof value === "function") {
setSorting(value)
}
},
getSortedRowModel: getSortedRowModel(),
enableSorting: true,
enableMultiSort: false,
manualSorting: true,
debugTable: true,
});

return (
Expand Down
2 changes: 1 addition & 1 deletion keep-ui/app/incidents/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export interface IncidentDto {
generated_summary: string;
assignee: string;
severity: string;
number_of_alerts: number;
alerts_count: number;
alert_sources: string[];
services: string[];
start_time?: Date;
Expand Down
4 changes: 2 additions & 2 deletions keep-ui/app/incidents/predicted-incidents-table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,9 @@ export default function PredictedIncidentsTable({
cell: ({ row }) => <div className="text-wrap">{row.original.generated_summary}</div>,
}),
columnHelper.display({
id: "alert_count",
id: "alerts_count",
header: "Number of Alerts",
cell: (context) => context.row.original.number_of_alerts,
cell: (context) => context.row.original.alerts_count,
}),
columnHelper.display({
id: "alert_sources",
Expand Down
4 changes: 3 additions & 1 deletion keep-ui/utils/hooks/useIncidents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { getApiURL } from "utils/apiUrl";
import { fetcher } from "utils/fetcher";
import { useWebsocket } from "./usePusher";
import { useCallback, useEffect } from "react";
import {SortingState} from "@tanstack/react-table";

interface IncidentUpdatePayload {
incident_id: string | null;
Expand All @@ -14,6 +15,7 @@ export const useIncidents = (
confirmed: boolean = true,
limit: number = 25,
offset: number = 0,
sorting: {id: string, desc: boolean} = {id: "creation_time", desc: false},
options: SWRConfiguration = {
revalidateOnFocus: false,
}
Expand All @@ -23,7 +25,7 @@ export const useIncidents = (
return useSWR<PaginatedIncidentsDto>(
() =>
session
? `${apiUrl}/incidents?confirmed=${confirmed}&limit=${limit}&offset=${offset}`
? `${apiUrl}/incidents?confirmed=${confirmed}&limit=${limit}&offset=${offset}&sorting=${sorting.desc ? "-" : ""}${sorting.id}`
: null,
(url) => fetcher(url, session?.accessToken),
options
Expand Down
Loading
Loading