Skip to content

Commit

Permalink
refactor: move incident CRUD to useIncidentActions() hook, unify re…
Browse files Browse the repository at this point in the history
…validation (#2335)
  • Loading branch information
Kiryous authored Oct 29, 2024
1 parent fb0b81c commit 0570111
Show file tree
Hide file tree
Showing 10 changed files with 226 additions and 377 deletions.
43 changes: 14 additions & 29 deletions keep-ui/app/incidents/[id]/incident-chat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,32 +4,23 @@ import {
useCopilotChatSuggestions,
} from "@copilotkit/react-ui";
import { IncidentDto } from "../models";
import {
useIncident,
useIncidentAlerts,
useIncidents,
} from "utils/hooks/useIncidents";
import { useIncidentAlerts } from "utils/hooks/useIncidents";
import { EmptyStateCard } from "@/components/ui/EmptyStateCard";
import { useRouter } from "next/navigation";
import Loading from "app/loading";
import { useCopilotAction, useCopilotReadable } from "@copilotkit/react-core";
import { updateIncidentRequest } from "../create-or-update-incident";
import { useApiUrl } from "utils/hooks/useConfig";
import { useSession } from "next-auth/react";
import { toast } from "react-toastify";
import "@copilotkit/react-ui/styles.css";
import "./incident-chat.css";
import { Card } from "@tremor/react";
import { useIncidentActions } from "@/entities/incidents/model/useIncidentActions";

export default function IncidentChat({ incident }: { incident: IncidentDto }) {
const router = useRouter();
const apiUrl = useApiUrl();
const { mutate } = useIncidents(true, 20);
const { mutate: mutateIncident } = useIncident(incident.id);
const { data: alerts, isLoading: alertsLoading } = useIncidentAlerts(
incident.id
);
const { data: session } = useSession();

const { updateIncident } = useIncidentActions();

useCopilotReadable({
description: "incidentDetails",
Expand Down Expand Up @@ -79,22 +70,16 @@ export default function IncidentChat({ incident }: { incident: IncidentDto }) {
},
],
handler: async ({ name, summary }) => {
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,
apiUrl: apiUrl!,
});

if (response.ok) {
mutate();
mutateIncident();
toast.success("Incident updated successfully");
}
await updateIncident(
incident.id,
{
user_generated_name: name,
user_summary: summary,
assignee: incident.assignee,
same_incident_in_the_past_id: incident.same_incident_in_the_past_id,
},
true
);
},
});

Expand Down
127 changes: 28 additions & 99 deletions keep-ui/app/incidents/create-or-update-incident.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,83 +2,39 @@

import {
TextInput,
Textarea,
Divider,
Subtitle,
Text,
Button,
Select,
SelectItem,
} from "@tremor/react";
import { useSession } from "next-auth/react";
import { FormEvent, useEffect, useState } from "react";
import { toast } from "react-toastify";
import { useApiUrl } from "utils/hooks/useConfig";
import { IncidentDto } from "./models";
import { useIncidents } from "utils/hooks/useIncidents";
import { Session } from "next-auth";
import { useUsers } from "utils/hooks/useUsers";
const ReactQuill =
typeof window === "object" ? require("react-quill") : () => false;
import "react-quill/dist/quill.snow.css";
import "./react-quill-override.css";
import { useIncidentActions } from "@/entities/incidents/model/useIncidentActions";

interface Props {
incidentToEdit: IncidentDto | null;
createCallback?: (id: string) => void;
exitCallback?: () => void;
}

export const updateIncidentRequest = async ({
session,
incidentId,
incidentName,
incidentUserSummary,
incidentAssignee,
incidentSameIncidentInThePastId,
generatedByAi,
apiUrl,
}: {
session: Session | null;
incidentId: string;
incidentName: string;
incidentUserSummary: string;
incidentAssignee: string;
incidentSameIncidentInThePastId: string | null;
generatedByAi: boolean;
apiUrl: string;
}) => {
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;
};

export default function CreateOrUpdateIncident({
incidentToEdit,
createCallback,
exitCallback,
}: Props) {
const { data: session } = useSession();
const { mutate } = useIncidents(true, 20);
const [incidentName, setIncidentName] = useState<string>("");
const [incidentUserSummary, setIncidentUserSummary] = useState<string>("");
const [incidentAssignee, setIncidentAssignee] = useState<string>("");
const { data: users = [] } = useUsers();
const apiUrl = useApiUrl();
const { addIncident, updateIncident } = useIncidentActions();

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 All @@ -104,65 +60,38 @@ export default function CreateOrUpdateIncident({
setIncidentAssignee("");
};

const addIncident = async (e: FormEvent) => {
e.preventDefault();
const response = await fetch(`${apiUrl}/incidents`, {
method: "POST",
headers: {
Authorization: `Bearer ${session?.accessToken}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
user_generated_name: incidentName,
user_summary: incidentUserSummary,
assignee: incidentAssignee,
}),
});
if (response.ok) {
exitEditMode();
await mutate();
toast.success("Incident created successfully");

const created = await response.json();
createCallback?.(created.id); // close the modal and associate the alert incident
} else {
toast.error(
"Failed to create incident, please contact us if this issue persists."
);
}
// If the Incident is successfully updated or the user cancels the update we exit the editMode and set the editRule in the incident.tsx to null.
const exitEditMode = () => {
exitCallback?.();
clearForm();
};

// 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) => {
const handleSubmit = async (e: FormEvent) => {
e.preventDefault();
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,
apiUrl: apiUrl!,
});
if (response.ok) {
if (editMode) {
await updateIncident(
incidentToEdit!.id,
{
user_generated_name: incidentName,
user_summary: incidentUserSummary,
assignee: incidentAssignee,
same_incident_in_the_past_id:
incidentToEdit!.same_incident_in_the_past_id,
},
false
);
exitEditMode();
await mutate();
toast.success("Incident updated successfully");
} else {
toast.error(
"Failed to update incident, please contact us if this issue persists."
);
const newIncident = await addIncident({
user_generated_name: incidentName,
user_summary: incidentUserSummary,
assignee: incidentAssignee,
});
createCallback?.(newIncident.id);
exitEditMode();
}
};

// If the Incident is successfully updated or the user cancels the update we exit the editMode and set the editRule in the incident.tsx to null.
const exitEditMode = () => {
exitCallback?.();
clearForm();
};

const submitEnabled = (): boolean => {
return !!incidentName;
};
Expand Down Expand Up @@ -194,7 +123,7 @@ export default function CreateOrUpdateIncident({
};

return (
<form className="py-2" onSubmit={editMode ? updateIncident : addIncident}>
<form className="py-2" onSubmit={handleSubmit}>
<Subtitle>Incident Metadata</Subtitle>
<div className="mt-2.5">
<Text className="mb-2">
Expand Down
36 changes: 16 additions & 20 deletions keep-ui/app/incidents/incident-change-same-in-the-past.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
import { Button, Divider, Title } from "@tremor/react";
import Select from "@/components/ui/Select";
import { useSession } from "next-auth/react";
import { useRouter } from "next/navigation";
import { FormEvent, useState } from "react";
import { toast } from "react-toastify";
import { useIncidents, usePollIncidents } from "../../utils/hooks/useIncidents";
import Loading from "../loading";
import { updateIncidentRequest } from "./create-or-update-incident";
import { IncidentDto } from "./models";
import { useApiUrl } from "../../utils/hooks/useConfig";
import { useIncidentActions } from "@/entities/incidents/model/useIncidentActions";

interface ChangeSameIncidentInThePast {
incident: IncidentDto;
Expand All @@ -27,33 +24,32 @@ const ChangeSameIncidentInThePast = ({
const [selectedIncident, setSelectedIncident] = useState<
string | undefined
>();
const { data: session } = useSession();
const { updateIncident } = useIncidentActions();
const router = useRouter();
const apiUrl = useApiUrl();

const associateIncidentHandler = async (
selectedIncidentId: string | null
) => {
const response = await updateIncidentRequest({
session: session,
incidentId: incident.id,
incidentSameIncidentInThePastId: selectedIncidentId,
incidentName: incident.user_generated_name,
incidentUserSummary: incident.user_summary,
incidentAssignee: incident.assignee,
generatedByAi: false,
apiUrl: apiUrl!,
});
if (response.ok) {
mutate();
toast.success("Incident updated successfully!");
try {
await updateIncident(
incident.id,
{
same_incident_in_the_past_id: selectedIncidentId,
},
false
);
handleClose();
} catch (error) {
console.error(error);
}
};

const handleLinkIncident = (e: FormEvent) => {
e.preventDefault();
if (selectedIncident) associateIncidentHandler(selectedIncident);
if (!selectedIncident) {
return;
}
associateIncidentHandler(selectedIncident);
};

const handleUnlinkIncident = (e: FormEvent) => {
Expand Down
Loading

0 comments on commit 0570111

Please sign in to comment.