Skip to content

Commit

Permalink
chore: alert timeline improvements (#2649)
Browse files Browse the repository at this point in the history
  • Loading branch information
talboren authored Nov 26, 2024
1 parent e2523a0 commit 5a57bc0
Show file tree
Hide file tree
Showing 10 changed files with 171 additions and 79 deletions.
7 changes: 5 additions & 2 deletions keep-ui/app/(keep)/alerts/alert-actions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ interface Props {
clearRowSelection: () => void;
setDismissModalAlert?: (alert: AlertDto[] | null) => void;
mutateAlerts?: () => void;
setIsIncidentSelectorOpen: (open: boolean) => void;
isIncidentSelectorOpen: boolean;
}

export default function AlertActions({
Expand All @@ -25,15 +27,16 @@ export default function AlertActions({
clearRowSelection,
setDismissModalAlert,
mutateAlerts,
setIsIncidentSelectorOpen,
isIncidentSelectorOpen,
}: Props) {
const router = useRouter();
const { useAllPresets } = usePresets();
const apiUrl = useApiUrl();
const { mutate: presetsMutator } = useAllPresets({
revalidateOnFocus: false,
});
const [isIncidentSelectorOpen, setIsIncidentSelectorOpen] =
useState<boolean>(false);

const [isCreateIncidentWithAIOpen, setIsCreateIncidentWithAIOpen] =
useState<boolean>(false);

Expand Down
88 changes: 57 additions & 31 deletions keep-ui/app/(keep)/alerts/alert-menu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,14 @@ import { useRouter } from "next/navigation";

interface Props {
alert: AlertDto;
isMenuOpen: boolean;
setIsMenuOpen: (key: string) => void;
isMenuOpen?: boolean;
setIsMenuOpen?: (key: string) => void;
setRunWorkflowModalAlert?: (alert: AlertDto) => void;
setDismissModalAlert?: (alert: AlertDto[]) => void;
setChangeStatusAlert?: (alert: AlertDto) => void;
presetName: string;
isInSidebar?: boolean;
setIsIncidentSelectorOpen?: (open: boolean) => void;
}

export default function AlertMenu({
Expand All @@ -43,6 +44,7 @@ export default function AlertMenu({
setChangeStatusAlert,
presetName,
isInSidebar,
setIsIncidentSelectorOpen,
}: Props) {
const router = useRouter();
const apiUrl = useApiUrl();
Expand Down Expand Up @@ -145,11 +147,11 @@ export default function AlertMenu({
const canAssign = true; // TODO: keep track of assignments for auditing

const handleMenuToggle = () => {
setIsMenuOpen(alert.fingerprint);
setIsMenuOpen!(alert.fingerprint);
};

const handleCloseMenu = () => {
setIsMenuOpen("");
setIsMenuOpen!("");
};

useEffect(() => {
Expand All @@ -168,8 +170,8 @@ export default function AlertMenu({
<Menu.Item>
{({ active }) => (
<button
className={`${
active ? "bg-slate-200" : "text-gray-900"
className={`${active ? "bg-slate-200" : "text-gray-900"} ${
isInSidebar ? "text-nowrap" : ""
} group flex w-full items-center rounded-md px-2 py-2 text-xs`}
onClick={() => {
setRunWorkflowModalAlert?.(alert);
Expand All @@ -181,21 +183,24 @@ export default function AlertMenu({
</button>
)}
</Menu.Item>
<Menu.Item>
{({ active }) => (
<Link
href={`/workflows/builder?alertName=${encodeURIComponent(
alertName
)}&alertSource=${alertSource}`}
className={`${
active ? "bg-slate-200" : "text-gray-900"
} group flex items-center rounded-md px-2 py-2 text-xs`}
>
<PlusIcon className="mr-2 h-4 w-4" aria-hidden="true" />
Create Workflow
</Link>
)}
</Menu.Item>
{!isInSidebar && (
<Menu.Item>
{({ active }) => (
<Link
href={`/workflows/builder?alertName=${encodeURIComponent(
alertName
)}&alertSource=${alertSource}`}
className={`${active ? "bg-slate-200" : "text-gray-900"} ${
isInSidebar ? "text-nowrap" : ""
} group flex items-center rounded-md px-2 py-2 text-xs`}
>
<PlusIcon className="mr-2 h-4 w-4" aria-hidden="true" />
Workflow
</Link>
)}
</Menu.Item>
)}

<Menu.Item>
{({ active }) => (
<button
Expand All @@ -208,8 +213,8 @@ export default function AlertMenu({
);
handleCloseMenu();
}}
className={`${
active ? "bg-slate-200" : "text-gray-900"
className={`${active ? "bg-slate-200" : "text-gray-900"} ${
isInSidebar ? "text-nowrap" : ""
} group flex w-full items-center rounded-md px-2 py-2 text-xs`}
>
<ArchiveBoxIcon className="mr-2 h-4 w-4" aria-hidden="true" />
Expand All @@ -222,15 +227,18 @@ export default function AlertMenu({
<button
onClick={() => {
router.replace(
`/alerts/${presetName}?alertPayloadFingerprint=${alert.fingerprint}&enrich=true`,
`/alerts/${presetName}?alertPayloadFingerprint=${alert.fingerprint}&enrich=true`
);
handleCloseMenu();
}}
className={`${
active ? "bg-slate-200" : "text-gray-900"
} group flex w-full items-center rounded-md px-2 py-2 text-xs`}
>
<AdjustmentsHorizontalIcon className="mr-2 h-4 w-4" aria-hidden="true" />
<AdjustmentsHorizontalIcon
className="mr-2 h-4 w-4"
aria-hidden="true"
/>
Enrich
</button>
)}
Expand All @@ -243,8 +251,8 @@ export default function AlertMenu({
callAssignEndpoint();
handleCloseMenu();
}}
className={`${
active ? "bg-slate-200" : "text-gray-900"
className={`${active ? "bg-slate-200" : "text-gray-900"} ${
isInSidebar ? "text-nowrap" : ""
} group flex w-full items-center rounded-md px-2 py-2 text-xs`}
>
<UserPlusIcon className="mr-2 h-4 w-4" aria-hidden="true" />
Expand All @@ -257,8 +265,8 @@ export default function AlertMenu({
{({ active }) => (
<button
onClick={openAlertPayloadModal}
className={`${
active ? "bg-slate-200" : "text-gray-900"
className={`${active ? "bg-slate-200" : "text-gray-900"} ${
isInSidebar ? "text-nowrap" : ""
} group flex w-full items-center rounded-md px-2 py-2 text-xs`}
>
<EyeIcon className="mr-2 h-4 w-4" aria-hidden="true" />
Expand Down Expand Up @@ -318,8 +326,8 @@ export default function AlertMenu({
setChangeStatusAlert?.(alert);
handleCloseMenu();
}}
className={`${
active ? "bg-slate-200" : "text-gray-900"
className={`${active ? "bg-slate-200" : "text-gray-900"} ${
isInSidebar ? "text-nowrap" : ""
} group flex w-full items-center rounded-md px-2 py-2 text-xs`}
>
<ChevronDoubleRightIcon
Expand All @@ -330,6 +338,24 @@ export default function AlertMenu({
</button>
)}
</Menu.Item>
{setIsIncidentSelectorOpen && (
<Menu.Item>
{({ active }) => (
<button
onClick={() => {
setIsIncidentSelectorOpen(true);
handleCloseMenu();
}}
className={`${active ? "bg-slate-200" : "text-gray-900"} ${
isInSidebar ? "text-nowrap" : ""
} group flex w-full items-center rounded-md px-2 py-2 text-xs`}
>
<PlusIcon className="mr-2 h-4 w-4" aria-hidden="true" />
Correlate Incident
</button>
)}
</Menu.Item>
)}
</>
);

Expand Down
2 changes: 1 addition & 1 deletion keep-ui/app/(keep)/alerts/alert-name.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ export default function AlertName({
}

return (
<div className="flex items-start justify-between">
<div className="flex items-center justify-between">
<div className="line-clamp-3 whitespace-pre-wrap" title={alert.name}>
{name}
</div>
Expand Down
62 changes: 43 additions & 19 deletions keep-ui/app/(keep)/alerts/alert-sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,51 @@ import { Fragment } from "react";
import Image from "next/image";
import { Dialog, Transition } from "@headlessui/react";
import { AlertDto } from "./models";
import { Button, Title, Badge } from "@tremor/react";
import { Button, Title, Badge, Divider } from "@tremor/react";
import { IoMdClose } from "react-icons/io";
import AlertTimeline from "./alert-timeline";
import { useAlerts } from "utils/hooks/useAlerts";
import { TopologyMap } from "../topology/ui/map";
import { TopologySearchProvider } from "@/app/(keep)/topology/TopologySearchContext";
import {
AlertSeverityBorderIcon,
AlertSeverityLabel,
} from "./alert-severity-border";
import { AlertSeverityLabel } from "./alert-severity-border";
import { FieldHeader } from "@/shared/ui/FieldHeader";
import { QuestionMarkCircleIcon } from "@heroicons/react/20/solid";
import { Tooltip } from "@/shared/ui/Tooltip";
import { Link } from "@/components/ui";
import { useProviders } from "@/utils/hooks/useProviders";
import AlertMenu from "./alert-menu";

type AlertSidebarProps = {
isOpen: boolean;
toggle: VoidFunction;
alert: AlertDto | null;
setRunWorkflowModalAlert?: (alert: AlertDto) => void;
setDismissModalAlert?: (alert: AlertDto[] | null) => void;
setChangeStatusAlert?: (alert: AlertDto) => void;
setIsIncidentSelectorOpen: (open: boolean) => void;
};

const AlertSidebar = ({ isOpen, toggle, alert }: AlertSidebarProps) => {
const AlertSidebar = ({
isOpen,
toggle,
alert,
setRunWorkflowModalAlert,
setDismissModalAlert,
setChangeStatusAlert,
setIsIncidentSelectorOpen,
}: AlertSidebarProps) => {
const { useAlertAudit } = useAlerts();
const {
data: auditData,
isLoading,
mutate,
} = useAlertAudit(alert?.fingerprint || "");

const { data: providers } = useProviders();
const providerName =
providers?.installed_providers.find((p) => p.id === alert?.providerId)
?.display_name || alert?.providerId;

const handleRefresh = async () => {
console.log("Refresh button clicked");
await mutate();
Expand Down Expand Up @@ -62,9 +78,18 @@ const AlertSidebar = ({ isOpen, toggle, alert }: AlertSidebarProps) => {
<Dialog.Panel className="fixed right-0 inset-y-0 w-2/4 bg-white z-30 p-6 overflow-auto flex flex-col">
<div className="flex justify-between mb-4">
<div>
{/*Will add soon*/}
{/*<AlertMenu alert={alert} presetName="feed" isInSidebar={true} />*/}
{/*<Divider></Divider>*/}
<AlertMenu
alert={alert!}
presetName="feed"
isInSidebar={true}
isMenuOpen={isOpen}
setIsMenuOpen={toggle}
setRunWorkflowModalAlert={setRunWorkflowModalAlert}
setDismissModalAlert={setDismissModalAlert}
setChangeStatusAlert={setChangeStatusAlert}
setIsIncidentSelectorOpen={setIsIncidentSelectorOpen}
/>
<Divider />
<Dialog.Title
className="text-xl font-bold flex flex-col gap-2 items-start"
as={Title}
Expand All @@ -84,16 +109,14 @@ const AlertSidebar = ({ isOpen, toggle, alert }: AlertSidebarProps) => {
{alert && (
<div className="space-y-4">
<div className="space-y-2">
<p>
<FieldHeader>Name</FieldHeader>
{alert.name}
</p>
<p>
<FieldHeader>Service</FieldHeader>
<Badge size="sm" color="gray">
{alert.service}
</Badge>
</p>
{alert.service && (
<p>
<FieldHeader>Service</FieldHeader>
<Badge size="sm" color="gray">
{alert.service}
</Badge>
</p>
)}
<p>
<FieldHeader>Source</FieldHeader>
<Image
Expand All @@ -103,6 +126,7 @@ const AlertSidebar = ({ isOpen, toggle, alert }: AlertSidebarProps) => {
height={24}
className="inline-block w-6 h-6"
/>
{providerName}
</p>
<p>
<FieldHeader>Description</FieldHeader>
Expand Down
3 changes: 3 additions & 0 deletions keep-ui/app/(keep)/alerts/alert-table-tab-panel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,9 @@ export default function AlertTableTabPanel({
presetId={preset.id}
presetTabs={presetTabs}
mutateAlerts={mutateAlerts}
setRunWorkflowModalAlert={setRunWorkflowModalAlert}
setDismissModalAlert={setDismissModalAlert}
setChangeStatusAlert={setChangeStatusAlert}
/>
);
}
24 changes: 24 additions & 0 deletions keep-ui/app/(keep)/alerts/alert-table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ interface Props {
isMenuColDisplayed?: boolean;
setDismissedModalAlert?: (alert: AlertDto[] | null) => void;
mutateAlerts?: () => void;
setRunWorkflowModalAlert?: (alert: AlertDto) => void;
setDismissModalAlert?: (alert: AlertDto[] | null) => void;
setChangeStatusAlert?: (alert: AlertDto) => void;
}

export function AlertTable({
Expand All @@ -69,6 +72,9 @@ export function AlertTable({
isRefreshAllowed = true,
setDismissedModalAlert,
mutateAlerts,
setRunWorkflowModalAlert,
setDismissModalAlert,
setChangeStatusAlert,
}: Props) {
const a11yContainerRef = useRef<HTMLDivElement>(null);

Expand Down Expand Up @@ -149,6 +155,8 @@ export function AlertTable({
const [selectedTab, setSelectedTab] = useState(0);
const [selectedAlert, setSelectedAlert] = useState<AlertDto | null>(null);
const [isSidebarOpen, setIsSidebarOpen] = useState(false);
const [isIncidentSelectorOpen, setIsIncidentSelectorOpen] =
useState<boolean>(false);

const filteredAlerts = alerts.filter((alert) => {
// First apply tab filter
Expand Down Expand Up @@ -285,6 +293,8 @@ export function AlertTable({
clearRowSelection={table.resetRowSelection}
setDismissModalAlert={setDismissedModalAlert}
mutateAlerts={mutateAlerts}
setIsIncidentSelectorOpen={setIsIncidentSelectorOpen}
isIncidentSelectorOpen={isIncidentSelectorOpen}
/>
) : (
<CopilotKit runtimeUrl="/api/copilotkit">
Expand Down Expand Up @@ -373,6 +383,20 @@ export function AlertTable({
isOpen={isSidebarOpen}
toggle={() => setIsSidebarOpen(false)}
alert={selectedAlert}
setRunWorkflowModalAlert={setRunWorkflowModalAlert}
setDismissModalAlert={setDismissModalAlert}
setChangeStatusAlert={setChangeStatusAlert}
setIsIncidentSelectorOpen={() => {
if (selectedAlert) {
table
.getRowModel()
.rows.find(
(row) => row.original.fingerprint === selectedAlert.fingerprint
)
?.toggleSelected();
setIsIncidentSelectorOpen(true);
}
}}
/>
</div>
);
Expand Down
Loading

0 comments on commit 5a57bc0

Please sign in to comment.