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

chore(incident): small cosmetic improvements #2020

Merged
merged 1 commit into from
Sep 29, 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
49 changes: 33 additions & 16 deletions keep-ui/app/alerts/alert-associate-incident-modal.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import Modal from "@/components/ui/Modal";
import { Button, Divider, Select, SelectItem, Title } from "@tremor/react";
import { Button, Divider, SelectItem, Title } from "@tremor/react";
import Select from "@/components/ui/Select";
import CreateOrUpdateIncident from "app/incidents/create-or-update-incident";
import { useSession } from "next-auth/react";
import { useRouter } from "next/navigation";
Expand Down Expand Up @@ -28,7 +29,9 @@ const AlertAssociateIncidentModal = ({
const { data: incidents, isLoading, mutate } = useIncidents(true, 100);
usePollIncidents(mutate);

const [selectedIncident, setSelectedIncident] = useState<string | undefined>();
const [selectedIncident, setSelectedIncident] = useState<
string | undefined
>();
// get the token
const { data: session } = useSession();
const router = useRouter();
Expand Down Expand Up @@ -106,20 +109,33 @@ const AlertAssociateIncidentModal = ({
<div className="h-full justify-center">
<Select
className="my-2.5"
placeholder={`Select incident`}
value={selectedIncident}
onValueChange={(value) => setSelectedIncident(value)}
>
{
incidents.items?.map((incident) => {
return (
<SelectItem key={incident.id} value={incident.id}>
{incident.user_generated_name || incident.ai_generated_name}
</SelectItem>
);
})!
placeholder="Select incident"
value={
selectedIncident
? {
value: selectedIncident,
label:
incidents.items.find(
(incident) => incident.id === selectedIncident
)?.user_generated_name ||
incidents.items.find(
(incident) => incident.id === selectedIncident
)?.ai_generated_name ||
"",
}
: null
}
</Select>
onChange={(selectedOption) =>
setSelectedIncident(selectedOption?.value)
}
options={incidents.items?.map((incident) => ({
value: incident.id,
label:
incident.user_generated_name ||
incident.ai_generated_name ||
"",
}))}
/>
<Divider />
<div className="flex items-center justify-between gap-6">
<Button
Expand All @@ -133,7 +149,8 @@ const AlertAssociateIncidentModal = ({

<Button
className="flex-1"
color="green"
color="orange"
variant="secondary"
onClick={showCreateIncidentForm}
>
Create a new incident
Expand Down
36 changes: 27 additions & 9 deletions keep-ui/app/incidents/create-or-update-incident.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import {
Subtitle,
Text,
Button,
Select,
SelectItem,
} from "@tremor/react";
import { useSession } from "next-auth/react";
import { FormEvent, useEffect, useState } from "react";
Expand All @@ -15,6 +17,7 @@ import { getApiURL } from "utils/apiUrl";
import { IncidentDto } from "./models";
import { useIncidents } from "utils/hooks/useIncidents";
import { Session } from "next-auth";
import { useUsers } from "utils/hooks/useUsers";

interface Props {
incidentToEdit: IncidentDto | null;
Expand Down Expand Up @@ -55,6 +58,7 @@ export default function CreateOrUpdateIncident({
const [incidentName, setIncidentName] = useState<string>("");
const [incidentUserSummary, setIncidentUserSummary] = useState<string>("");
const [incidentAssignee, setIncidentAssignee] = useState<string>("");
const { data: users = [] } = useUsers();
const editMode = incidentToEdit !== null;

// Display cancel btn if editing or we need to cancel for another reason (eg. going one step back in the modal etc.)
Expand Down Expand Up @@ -144,7 +148,7 @@ export default function CreateOrUpdateIncident({
<form className="py-2" onSubmit={editMode ? updateIncident : addIncident}>
<Subtitle>Incident Metadata</Subtitle>
<div className="mt-2.5">
<Text>
<Text className="mb-2">
Name<span className="text-red-500 text-xs">*</span>
</Text>
<TextInput
Expand All @@ -155,7 +159,7 @@ export default function CreateOrUpdateIncident({
/>
</div>
<div className="mt-2.5">
<Text>Summary</Text>
<Text className="mb-2">Summary</Text>
<Textarea
placeholder="What happened?"
required={false}
Expand All @@ -165,17 +169,31 @@ export default function CreateOrUpdateIncident({
</div>

<div className="mt-2.5">
<Text>Assignee</Text>
<TextInput
placeholder="Who is responsible"
value={incidentAssignee}
onValueChange={setIncidentAssignee}
/>
<Text className="mb-2">Assignee</Text>
{users.length > 0 ? (
<Select
placeholder="Who is responsible"
value={incidentAssignee}
onValueChange={setIncidentAssignee}
>
{users.map((user) => (
<SelectItem key={user.email} value={user.email}>
{user.name || user.email}
</SelectItem>
))}
</Select>
) : (
<TextInput
placeholder="Who is responsible"
value={incidentAssignee}
onValueChange={setIncidentAssignee}
/>
)}
</div>

<Divider />

<div className={"space-x-1 flex flex-row justify-end items-center"}>
<div className="mt-auto pt-6 space-x-1 flex flex-row justify-end items-center">
{cancellable && (
<Button
color="orange"
Expand Down
115 changes: 70 additions & 45 deletions keep-ui/app/incidents/incidents-table.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
import {
Button,
Badge,
Icon,
} from "@tremor/react";
import { Button, Badge, Icon } from "@tremor/react";
import {
ExpandedState,
createColumnHelper,
Expand All @@ -12,14 +8,18 @@ import {
getSortedRowModel,
ColumnDef,
} from "@tanstack/react-table";
import {MdRemoveCircle, MdModeEdit, MdKeyboardDoubleArrowRight} from "react-icons/md";
import {
MdRemoveCircle,
MdModeEdit,
MdKeyboardDoubleArrowRight,
} from "react-icons/md";
import { useSession } from "next-auth/react";
import {IncidentDto, PaginatedIncidentsDto, Status} from "./models";
import React, {Dispatch, SetStateAction, useEffect, useState} from "react";
import { IncidentDto, PaginatedIncidentsDto, Status } from "./models";
import React, { Dispatch, SetStateAction, useEffect, useState } from "react";
import Image from "next/image";
import IncidentPagination from "./incident-pagination";
import IncidentTableComponent from "./incident-table-component";
import {deleteIncident} from "./incident-candidate-actions";
import { deleteIncident } from "./incident-candidate-actions";
import {
CheckCircleIcon,
ExclamationCircleIcon,
Expand All @@ -32,31 +32,37 @@ const columnHelper = createColumnHelper<IncidentDto>();
interface Props {
incidents: PaginatedIncidentsDto;
mutate: () => void;
sorting: SortingState,
sorting: SortingState;
setSorting: Dispatch<SetStateAction<any>>;
setPagination: Dispatch<SetStateAction<any>>;
editCallback: (rule: IncidentDto) => void;
}

const STATUS_ICONS = {
[Status.Firing]: <Icon
icon={ExclamationCircleIcon}
tooltip={Status.Firing}
color="red"
className="w-4 h-4 mr-2"
/>,
[Status.Resolved]: <Icon
icon={CheckCircleIcon}
tooltip={Status.Resolved}
color="green"
className="w-4 h-4 mr-2"
/>,
[Status.Acknowledged]: <Icon
icon={PauseIcon}
tooltip={Status.Acknowledged}
color="gray"
className="w-4 h-4 mr-2"
/>,
[Status.Firing]: (
<Icon
icon={ExclamationCircleIcon}
tooltip={Status.Firing}
color="red"
className="w-4 h-4 mr-2"
/>
),
[Status.Resolved]: (
<Icon
icon={CheckCircleIcon}
tooltip={Status.Resolved}
color="green"
className="w-4 h-4 mr-2"
/>
),
[Status.Acknowledged]: (
<Icon
icon={PauseIcon}
tooltip={Status.Acknowledged}
color="gray"
className="w-4 h-4 mr-2"
/>
),
};

export default function IncidentsTable({
Expand All @@ -73,35 +79,40 @@ export default function IncidentsTable({
pageIndex: Math.ceil(incidents.offset / incidents.limit),
pageSize: incidents.limit,
});
const [changeStatusIncident, setChangeStatusIncident] = useState<IncidentDto | null>();
const [changeStatusIncident, setChangeStatusIncident] =
useState<IncidentDto | null>();

const handleChangeStatus = (e: React.MouseEvent, incident: IncidentDto) => {
e.preventDefault();
e.stopPropagation();
setChangeStatusIncident(incident);
}
};

useEffect(() => {
if (incidents.limit != pagination.pageSize) {
setPagination({
limit: pagination.pageSize,
offset: 0,
})
});
}
const currentOffset = pagination.pageSize * pagination.pageIndex;
if (incidents.offset != currentOffset) {
setPagination({
limit: pagination.pageSize,
offset: currentOffset,
})
});
}
}, [pagination])
}, [pagination]);

const columns = [
columnHelper.display({
id: "status",
header: "Status",
cell: ({ row }) => <span onClick={(e) => handleChangeStatus(e, row.original!)}>{STATUS_ICONS[row.original.status]}</span>,
cell: ({ row }) => (
<span onClick={(e) => handleChangeStatus(e, row.original!)}>
{STATUS_ICONS[row.original.status]}
</span>
),
}),
columnHelper.display({
id: "name",
Expand All @@ -115,12 +126,16 @@ export default function IncidentsTable({
columnHelper.display({
id: "user_summary",
header: "Summary",
cell: ({ row }) => <div className="text-wrap">{row.original.user_summary}</div>,
cell: ({ row }) => (
<div className="text-wrap">{row.original.user_summary}</div>
),
}),
columnHelper.display({
id: "rule_fingerprint",
header: "Group by value",
cell: ({ row }) => <div className="text-wrap">{row.original.rule_fingerprint || "-"}</div>,
cell: ({ row }) => (
<div className="text-wrap">{row.original.rule_fingerprint || "-"}</div>
),
}),
columnHelper.accessor("severity", {
id: "severity",
Expand Down Expand Up @@ -157,16 +172,22 @@ export default function IncidentsTable({
columnHelper.display({
id: "services",
header: "Involved Services",
cell: ({row}) =>
<div className="text-wrap">{row.original.services.map((service) =>
<Badge key={service} className="mr-1">{service}</Badge>
)}
</div>,
cell: ({ row }) => (
<div className="text-wrap">
{row.original.services
.filter((service) => service !== "null")
.map((service) => (
<Badge key={service} className="mr-1">
{service}
</Badge>
))}
</div>
),
}),
columnHelper.display({
id: "assignee",
header: "Assignee",
cell: ({ row }) => row.original.assignee
cell: ({ row }) => row.original.assignee,
}),
columnHelper.accessor("creation_time", {
id: "creation_time",
Expand Down Expand Up @@ -209,7 +230,11 @@ export default function IncidentsTable({
onClick={async (e: React.MouseEvent) => {
e.preventDefault();
e.stopPropagation();
await deleteIncident({incidentId: row.original.id!, mutate, session});
await deleteIncident({
incidentId: row.original.id!,
mutate,
session,
});
}}
/>
</div>
Expand All @@ -228,7 +253,7 @@ export default function IncidentsTable({
onExpandedChange: setExpanded,
onSortingChange: (value) => {
if (typeof value === "function") {
setSorting(value)
setSorting(value);
}
},
getSortedRowModel: getSortedRowModel(),
Expand All @@ -247,7 +272,7 @@ export default function IncidentsTable({
handleClose={() => setChangeStatusIncident(null)}
/>
<div className="mt-4 mb-8">
<IncidentPagination table={table} isRefreshAllowed={true}/>
<IncidentPagination table={table} isRefreshAllowed={true} />
</div>
</div>
);
Expand Down
Loading