Skip to content

Commit

Permalink
Merge branch 'main' into feat-pd-app
Browse files Browse the repository at this point in the history
  • Loading branch information
talboren authored Nov 6, 2024
2 parents b17b146 + a6a2999 commit e2bff6d
Show file tree
Hide file tree
Showing 95 changed files with 2,883 additions and 1,464 deletions.
202 changes: 99 additions & 103 deletions keep-ui/app/alerts/alert-associate-incident-modal.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import Modal from "@/components/ui/Modal";
import { Button, Divider, SelectItem, Title } from "@tremor/react";
import { Button, Divider, Title } from "@tremor/react";
import Select from "@/components/ui/Select";
import CreateOrUpdateIncident from "app/incidents/create-or-update-incident";
import { CreateOrUpdateIncidentForm } from "@/features/create-or-update-incident";
import { useSession } from "next-auth/react";
import { useRouter } from "next/navigation";
import { FormEvent, useCallback, useEffect, useState } from "react";
import { toast } from "react-toastify";
import { useApiUrl } from "utils/hooks/useConfig";
import { useIncidents, usePollIncidents } from "../../utils/hooks/useIncidents";
import Loading from "../loading";
import { AlertDto } from "./models";
import { getIncidentName } from "@/entities/incidents/lib/utils";

interface AlertAssociateIncidentModalProps {
isOpen: boolean;
Expand All @@ -35,27 +35,29 @@ const AlertAssociateIncidentModal = ({
// get the token
const { data: session } = useSession();
const apiUrl = useApiUrl();
const router = useRouter();

const associateAlertsHandler = async (incidentId: string) => {
const response = await fetch(`${apiUrl}/incidents/${incidentId}/alerts`, {
method: "POST",
headers: {
Authorization: `Bearer ${session?.accessToken}`,
"Content-Type": "application/json",
},
body: JSON.stringify(alerts.map(({ event_id }) => event_id)),
});
if (response.ok) {
handleSuccess();
await mutate();
toast.success("Alerts associated with incident successfully");
} else {
toast.error(
"Failed to associated alerts with incident, please contact us if this issue persists."
);
}
};

const associateAlertsHandler = useCallback(
async (incidentId: string) => {
const response = await fetch(`${apiUrl}/incidents/${incidentId}/alerts`, {
method: "POST",
headers: {
Authorization: `Bearer ${session?.accessToken}`,
"Content-Type": "application/json",
},
body: JSON.stringify(alerts.map(({ event_id }) => event_id)),
});
if (response.ok) {
handleSuccess();
await mutate();
toast.success("Alerts associated with incident successfully");
} else {
toast.error(
"Failed to associated alerts with incident, please contact us if this issue persists."
);
}
},
[alerts, apiUrl, handleSuccess, mutate, session?.accessToken]
);

const handleAssociateAlerts = (e: FormEvent) => {
e.preventDefault();
Expand Down Expand Up @@ -87,100 +89,94 @@ const AlertAssociateIncidentModal = ({
}, [hideCreateIncidentForm, isOpen]);

// if this modal should not be open, do nothing
if (!alerts) return null;
if (!alerts) {
return null;
}

const renderSelectIncidentForm = () => {
if (!incidents || incidents.items.length === 0) {
return (
<div className="flex flex-col">
<Title className="text-md text-gray-500 my-4">No incidents yet</Title>

<Button
className="flex-1"
color="orange"
onClick={showCreateIncidentForm}
>
Create a new incident
</Button>
</div>
);
}

const selectedIncidentInstance = incidents.items.find(
(incident) => incident.id === selectedIncident
);

return (
<div className="h-full justify-center">
<Select
className="my-2.5"
placeholder="Select incident"
value={
selectedIncidentInstance
? {
value: selectedIncident,
label: getIncidentName(selectedIncidentInstance),
}
: null
}
onChange={(selectedOption) =>
setSelectedIncident(selectedOption?.value)
}
options={incidents.items?.map((incident) => ({
value: incident.id,
label: getIncidentName(incident),
}))}
/>
<Divider />
<div className="flex items-center justify-between gap-6">
<Button
className="flex-1"
color="orange"
onClick={handleAssociateAlerts}
disabled={!selectedIncidentInstance}
>
Associate {alerts.length} alert{alerts.length > 1 ? "s" : ""}
</Button>

<Button
className="flex-1"
color="orange"
variant="secondary"
onClick={showCreateIncidentForm}
>
Create a new incident
</Button>
</div>
</div>
);
};

return (
<Modal
isOpen={isOpen}
onClose={handleClose}
title="Choose Incident"
title="Associate alerts to incident"
className="w-[600px]"
>
<div className="relative bg-white p-6 rounded-lg">
<div className="relative">
{isLoading ? (
<Loading />
) : createIncident ? (
<CreateOrUpdateIncident
<CreateOrUpdateIncidentForm
incidentToEdit={null}
createCallback={onIncidentCreated}
exitCallback={hideCreateIncidentForm}
/>
) : incidents && incidents.items.length > 0 ? (
<div className="h-full justify-center">
<Select
className="my-2.5"
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
}
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
className="flex-1"
color="orange"
onClick={handleAssociateAlerts}
disabled={selectedIncident === null}
>
Associate {alerts.length} alert{alerts.length > 1 ? "s" : ""}
</Button>

<Button
className="flex-1"
color="orange"
variant="secondary"
onClick={showCreateIncidentForm}
>
Create a new incident
</Button>
</div>
</div>
) : (
<div className="flex flex-col items-center justify-center gap-y-8 h-full">
<div className="text-center space-y-3">
<Title className="text-2xl">No Incidents Yet</Title>
</div>

<div className="flex items-center justify-between w-full gap-6">
<Button
className="flex-1"
color="orange"
onClick={() => router.push("/incidents")}
>
Incidents page
</Button>

<Button
className="flex-1"
color="green"
onClick={showCreateIncidentForm}
>
Create a new incident
</Button>
</div>
</div>
renderSelectIncidentForm()
)}
</div>
</Modal>
Expand Down
2 changes: 1 addition & 1 deletion keep-ui/app/alerts/alert-create-incident-ai-card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {
} from "@tremor/react";
import { Droppable, Draggable } from "react-beautiful-dnd";
import { AlertDto } from "./models";
import { IncidentCandidateDto } from "../incidents/models";
import { IncidentCandidateDto } from "@/entities/incidents/model";

interface IncidentCardProps {
incident: IncidentCandidateDto;
Expand Down
9 changes: 4 additions & 5 deletions keep-ui/app/alerts/alert-create-incident-ai-modal.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import React, { useState, useEffect, use } from "react";
import React, { useState } from "react";
import Modal from "@/components/ui/Modal";
import { Callout, Button, Title, Card, Text } from "@tremor/react";
import { Callout, Button, Title, Card } from "@tremor/react";
import { useSession } from "next-auth/react";
import { toast } from "react-toastify";
import Loading from "../loading";
import { AlertDto } from "./models";
import { IncidentDto, IncidentCandidateDto } from "../incidents/models";
import { useApiUrl, useConfig } from "utils/hooks/useConfig";
import { IncidentDto, IncidentCandidateDto } from "@/entities/incidents/model";
import { useApiUrl } from "utils/hooks/useConfig";
import { DragDropContext } from "react-beautiful-dnd";
import IncidentCard from "./alert-create-incident-ai-card";
import { useIncidents } from "utils/hooks/useIncidents";
Expand Down Expand Up @@ -47,7 +47,6 @@ const CreateIncidentWithAIModal = ({
>([]);
const [suggestionId, setSuggestionId] = useState<string>("");
const { data: session } = useSession();
const { data: configData } = useConfig();
const apiUrl = useApiUrl();
const router = useRouter();
const { mutate: mutateIncidents } = useIncidents(
Expand Down
2 changes: 1 addition & 1 deletion keep-ui/app/alerts/alert-presets.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ export default function AlertPresets({
</div>
</div>
</Modal>
<div className="flex w-full items-start xl:mt-6">
<div className="flex w-full items-start relative z-10">
<AlertsRulesBuilder
table={table}
defaultQuery=""
Expand Down
34 changes: 34 additions & 0 deletions keep-ui/app/alerts/alert-severity-border.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import clsx from "clsx";
import { Severity } from "./models";

export function AlertSeverityBorder({
severity,
}: {
severity: Severity | undefined;
}) {
const getSeverityBgClassName = (severity?: Severity) => {
switch (severity) {
case "critical":
return "bg-red-500";
case "high":
case "error":
return "bg-orange-500";
case "warning":
return "bg-yellow-500";
case "info":
return "bg-blue-500";
default:
return "bg-emerald-500";
}
};

return (
<div
className={clsx(
"absolute w-1 h-full top-0 left-0",
getSeverityBgClassName(severity)
)}
aria-label={severity}
/>
);
}
Loading

0 comments on commit e2bff6d

Please sign in to comment.