Skip to content

Commit

Permalink
chore(incident): small cosmetic improvements (#2020)
Browse files Browse the repository at this point in the history
  • Loading branch information
shahargl authored Sep 29, 2024
1 parent 02f219d commit 6c7ae5e
Show file tree
Hide file tree
Showing 3 changed files with 130 additions and 70 deletions.
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

0 comments on commit 6c7ae5e

Please sign in to comment.