Skip to content

Commit

Permalink
Merge branch 'main' into Feat/runbook
Browse files Browse the repository at this point in the history
  • Loading branch information
Mubashirshariq authored Oct 9, 2024
2 parents 76a9527 + 291c6cf commit 5fb1a26
Show file tree
Hide file tree
Showing 17 changed files with 554 additions and 95 deletions.
10 changes: 5 additions & 5 deletions keep-ui/app/alerts/alert-name.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ export default function AlertName({

return (
<div className="flex items-start justify-between">
<div className="truncate whitespace-pre-wrap" title={alert.name}>
<div className="line-clamp-3 whitespace-pre-wrap" title={alert.name}>
{name}
</div>
<div className="flex-shrink-0">
Expand Down Expand Up @@ -139,15 +139,15 @@ export default function AlertName({
relevantWorkflowExecution.workflow_status === "success"
? "green"
: relevantWorkflowExecution.workflow_status === "error"
? "red"
: "gray"
? "red"
: "gray"
}`}
tooltip={`${
relevantWorkflowExecution.workflow_status === "success"
? "Last workflow executed successfully"
: relevantWorkflowExecution.workflow_status === "error"
? "Last workflow execution failed"
: undefined
? "Last workflow execution failed"
: undefined
}`}
onClick={() => handleWorkflowClick(relevantWorkflowExecution)}
className="ml-1 cursor-pointer"
Expand Down
18 changes: 10 additions & 8 deletions keep-ui/app/incidents/[id]/incident-chat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -76,14 +76,16 @@ export default function IncidentChat({ incident }: { incident: IncidentDto }) {
},
],
handler: async ({ name, summary }) => {
const response = await updateIncidentRequest(
session,
incident.id,
name,
summary,
incident.assignee,
true
);
const response = await updateIncidentRequest({
session: session,
incidentId: incident.id,
incidentName: name,
incidentUserSummary: summary,
incidentAssignee: incident.assignee,
incidentSameIncidentInThePastId: incident.same_incident_in_the_past_id,
generatedByAi: true,
});

if (response.ok) {
mutate();
mutateIncident();
Expand Down
68 changes: 66 additions & 2 deletions keep-ui/app/incidents/[id]/incident-info.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import CreateOrUpdateIncident from "../create-or-update-incident";
import Modal from "@/components/ui/Modal";
import React, { useState } from "react";
import { MdBlock, MdDone, MdModeEdit } from "react-icons/md";
import { useIncident } from "@/utils/hooks/useIncidents";
import { useIncident, useIncidentFutureIncidents } from "@/utils/hooks/useIncidents";

import {
deleteIncident,
handleConfirmPredictedIncident,
Expand All @@ -17,12 +18,22 @@ import { Disclosure } from "@headlessui/react";
import classNames from "classnames";
import { IoChevronDown } from "react-icons/io5";
import IncidentChangeStatusModal from "@/app/incidents/incident-change-status-modal";
import ChangeSameIncidentInThePast from "@/app/incidents/incident-change-same-in-the-past";
import {STATUS_ICONS} from "@/app/incidents/statuses";

interface Props {
incident: IncidentDto;
}

function FollowingIncident({incidentId}: {incidentId: string}) {
const { data: incident } = useIncident(incidentId);
return (
<div>
<a className="text-orange-500" href={'/incidents/' + incidentId}>{incident?.user_generated_name || incident?.ai_generated_name}</a>
</div>
);
}

function Summary({
title,
summary,
Expand Down Expand Up @@ -86,14 +97,25 @@ export default function IncidentInformation({ incident }: Props) {
const [changeStatusIncident, setChangeStatusIncident] =
useState<IncidentDto | null>();

const [changeSameIncidentInThePast, setChangeSameIncidentInThePast] =
useState<IncidentDto | null>();

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

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

const formatString = "dd, MMM yyyy - HH:mm.ss 'UTC'";
const summary = incident.user_summary || incident.generated_summary;
const { data: same_incident_in_the_past } = useIncident(incident.same_incident_in_the_past_id);
const { data: same_incidents_in_the_future } = useIncidentFutureIncidents(incident.id);

const severity = incident.severity;
let severityColor;
Expand Down Expand Up @@ -195,10 +217,39 @@ export default function IncidentInformation({ incident }: Props) {
/>
) : null}
</div>
<div>
<h3 className="text-gray-500 text-sm">Assignee</h3>
{incident.assignee ? <p>{incident.assignee}</p> : <p>No assignee yet</p>}
</div>
<div>
<div className="flex flex-row gap-4">
<div>
<h3 className="text-gray-500 text-sm">Same incident in the past</h3>
{same_incident_in_the_past ?
<p><a className="text-orange-500" href={'/incidents/' + same_incident_in_the_past.id}>{same_incident_in_the_past.user_generated_name || same_incident_in_the_past.ai_generated_name}</a> (<a href="#" onClick={(e) => handleChangeSameIncidentInThePast(e, incident)} className="cursor-pointer text-orange-500">edit</a>)</p> :
<p>No linked incidents. Link same incident from the past to help the AI classifier. 🤔(<a onClick={(e) => handleChangeSameIncidentInThePast(e, incident)} className="cursor-pointer text-orange-500">link</a>)</p>}
</div>
<div>

</div>
</div>
{same_incidents_in_the_future && same_incidents_in_the_future.items.length > 0 && (
<div>
<h3 className="text-gray-500 text-sm">Following Incidents</h3>
<ul>
{same_incidents_in_the_future.items.map((item) => (
<li key={item.id}>
<FollowingIncident incidentId={item.id} />
</li>
))}
</ul>
</div>
)}
</div>
<div className="flex gap-4">
{!!incident.start_time && (
<div>
<h3 className="text-gray-500 text-sm">Started at</h3>
<h3 className="text-gray-500 text-sm">Started at</h3>
<p className="">
{format(new Date(incident.start_time), formatString)}
</p>
Expand Down Expand Up @@ -232,6 +283,19 @@ export default function IncidentInformation({ incident }: Props) {
/>
</Modal>

{changeSameIncidentInThePast ? <Modal
isOpen={changeSameIncidentInThePast !== null}
onClose={() => setChangeSameIncidentInThePast(null)}
title="Link to the same incident in the past"
className="w-[600px]"
>
<ChangeSameIncidentInThePast
incident={changeSameIncidentInThePast}
mutate={mutate}
handleClose={() => setChangeSameIncidentInThePast(null)}
/>
</Modal> : null}

<IncidentChangeStatusModal
incident={changeStatusIncident}
mutate={mutate}
Expand Down
69 changes: 39 additions & 30 deletions keep-ui/app/incidents/create-or-update-incident.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,30 +25,37 @@ interface Props {
exitCallback?: () => void;
}

export const updateIncidentRequest = async (
session: Session | null,
incidentId: string,
incidentName: string,
incidentUserSummary: string,
incidentAssignee: string,
generatedByAi: boolean = false
) => {
export const updateIncidentRequest = async ({
session,
incidentId,
incidentName,
incidentUserSummary,
incidentAssignee,
incidentSameIncidentInThePastId,
generatedByAi,
}: {
session: Session | null;
incidentId: string;
incidentName: string;
incidentUserSummary: string;
incidentAssignee: string;
incidentSameIncidentInThePastId: string | null;
generatedByAi: boolean;
}) => {
const apiUrl = getApiURL();
const response = await fetch(
`${apiUrl}/incidents/${incidentId}?generatedByAi=${generatedByAi}`,
{
method: "PUT",
headers: {
Authorization: `Bearer ${session?.accessToken}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
user_generated_name: incidentName,
user_summary: incidentUserSummary,
assignee: incidentAssignee,
}),
}
);
const response = await fetch(`${apiUrl}/incidents/${incidentId}?generatedByAi=${generatedByAi}`, {
method: "PUT",
headers: {
Authorization: `Bearer ${session?.accessToken}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
user_generated_name: incidentName,
user_summary: incidentUserSummary,
assignee: incidentAssignee,
same_incident_in_the_past_id: incidentSameIncidentInThePastId,
}),
});
return response;
};

Expand Down Expand Up @@ -120,13 +127,15 @@ export default function CreateOrUpdateIncident({
// This is the function that will be called on submitting the form in the editMode, it sends a PUT request to the backend.
const updateIncident = async (e: FormEvent) => {
e.preventDefault();
const response = await updateIncidentRequest(
session,
incidentToEdit?.id!,
incidentName,
incidentUserSummary,
incidentAssignee
);
const response = await updateIncidentRequest({
session: session,
incidentId: incidentToEdit?.id!,
incidentName: incidentName,
incidentUserSummary: incidentUserSummary,
incidentAssignee: incidentAssignee,
incidentSameIncidentInThePastId: incidentToEdit?.same_incident_in_the_past_id!,
generatedByAi: false,
})
if (response.ok) {
exitEditMode();
await mutate();
Expand Down
Loading

0 comments on commit 5fb1a26

Please sign in to comment.