Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] fix: Readonly - friendly errors #2613

Draft
wants to merge 5 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions keep-ui/app/(keep)/ai/ai.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@
import { Card, List, ListItem, Title, Subtitle } from "@tremor/react";
import { useAIStats, usePollAILogs } from "utils/hooks/useAI";
import { useHydratedSession as useSession } from "@/shared/lib/hooks/useHydratedSession";
import { useApiUrl } from "utils/hooks/useConfig";
import { useApiUrl, useConfig } from "utils/hooks/useConfig";
import { toast } from "react-toastify";
import { useEffect, useState, useRef, FormEvent } from "react";
import { AILogs } from "./model";
import { ReadOnlyAwareToaster } from "@/shared/lib/ReadOnlyAwareToaster";

export default function Ai() {
const { data: aistats, isLoading } = useAIStats();
Expand All @@ -16,6 +17,7 @@ export default function Ai() {
const [animate, setAnimate] = useState(false);
const onlyOnce = useRef(false);
const apiUrl = useApiUrl();
const { data: configData} = useConfig();

const mutateAILogs = (logs: AILogs) => {
setBasicAlgorithmLog(logs.log);
Expand Down Expand Up @@ -52,8 +54,8 @@ export default function Ai() {
body: JSON.stringify({}),
});
if (!response.ok) {
toast.error(
"Failed to mine incidents, please contact us if this issue persists."
ReadOnlyAwareToaster.error(
"Failed to mine incidents, please contact us if this issue persists.", configData
);
}

Expand Down
10 changes: 6 additions & 4 deletions keep-ui/app/(keep)/alerts/ViewAlertModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ import { AlertDto } from "./models"; // Adjust the import path as needed
import Modal from "@/components/ui/Modal"; // Ensure this path matches your project structure
import { Button, Icon, Switch, Text } from "@tremor/react";
import { toast } from "react-toastify";
import { useApiUrl } from "utils/hooks/useConfig";
import { useApiUrl, useConfig } from "utils/hooks/useConfig";
import { useHydratedSession as useSession } from "@/shared/lib/hooks/useHydratedSession";
import { XMarkIcon } from "@heroicons/react/24/outline";
import "./ViewAlertModal.css";
import React, { useState } from "react";
import { ReadOnlyAwareToaster } from "@/shared/lib/ReadOnlyAwareToaster";

interface ViewAlertModalProps {
alert: AlertDto | null | undefined;
Expand All @@ -27,6 +28,7 @@ export const ViewAlertModal: React.FC<ViewAlertModalProps> = ({
const [showHighlightedOnly, setShowHighlightedOnly] = useState(false);
const { data: session } = useSession();
const apiUrl = useApiUrl();
const { data: configData } = useConfig();

const unEnrichAlert = async (key: string) => {
if (confirm(`Are you sure you want to un-enrich ${key}?`)) {
Expand All @@ -49,12 +51,12 @@ export const ViewAlertModal: React.FC<ViewAlertModalProps> = ({
await mutate();
} else {
// Handle error
toast.error(`Failed to un-enriched ${key}`);
ReadOnlyAwareToaster.error(`Failed to un-enriched ${key}`, configData);
await mutate();
}
} catch (error) {
// Handle unexpected error
toast.error("An unexpected error occurred");
ReadOnlyAwareToaster.error("An unexpected error occurred", configData);
}
}
};
Expand Down Expand Up @@ -104,7 +106,7 @@ export const ViewAlertModal: React.FC<ViewAlertModalProps> = ({
await navigator.clipboard.writeText(JSON.stringify(alert, null, 2));
toast.success("Alert copied to clipboard!");
} catch (err) {
toast.error("Failed to copy alert.");
ReadOnlyAwareToaster.error("Failed to copy alert.", configData);
}
}
};
Expand Down
8 changes: 5 additions & 3 deletions keep-ui/app/(keep)/alerts/alert-associate-incident-modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,15 @@ import { CreateOrUpdateIncidentForm } from "@/features/create-or-update-incident
import { useHydratedSession as useSession } from "@/shared/lib/hooks/useHydratedSession";
import { FormEvent, useCallback, useEffect, useState } from "react";
import { toast } from "react-toastify";
import { useApiUrl } from "utils/hooks/useConfig";
import { useApiUrl, useConfig } from "utils/hooks/useConfig";
import {
useIncidents,
usePollIncidents,
} from "../../../utils/hooks/useIncidents";
import Loading from "@/app/(keep)/loading";
import { AlertDto } from "./models";
import { getIncidentName } from "@/entities/incidents/lib/utils";
import { ReadOnlyAwareToaster } from "@/shared/lib/ReadOnlyAwareToaster";

interface AlertAssociateIncidentModalProps {
isOpen: boolean;
Expand All @@ -28,6 +29,7 @@ const AlertAssociateIncidentModal = ({
alerts,
}: AlertAssociateIncidentModalProps) => {
const [createIncident, setCreateIncident] = useState(false);
const { data: configData} = useConfig();

const { data: incidents, isLoading, mutate } = useIncidents(true, 100);
usePollIncidents(mutate);
Expand All @@ -54,8 +56,8 @@ const AlertAssociateIncidentModal = ({
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."
ReadOnlyAwareToaster.error(
"Failed to associated alerts with incident, please contact us if this issue persists.", configData
);
}
},
Expand Down
10 changes: 6 additions & 4 deletions keep-ui/app/(keep)/alerts/alert-change-status-modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import Select, {
} from "react-select";
import { useState } from "react";
import { AlertDto, Status } from "./models";
import { useApiUrl } from "utils/hooks/useConfig";
import { useApiUrl, useConfig } from "utils/hooks/useConfig";
import { useHydratedSession as useSession } from "@/shared/lib/hooks/useHydratedSession";
import { toast } from "react-toastify";
import {
Expand All @@ -20,6 +20,7 @@ import {
} from "@heroicons/react/24/outline";
import { usePresets } from "utils/hooks/usePresets";
import { useAlerts } from "utils/hooks/useAlerts";
import { ReadOnlyAwareToaster } from "@/shared/lib/ReadOnlyAwareToaster";

const statusIcons = {
[Status.Firing]: <ExclamationCircleIcon className="w-4 h-4 mr-2" />,
Expand Down Expand Up @@ -75,6 +76,7 @@ export default function AlertChangeStatusModal({
presetName,
}: Props) {
const { data: session } = useSession();
const { data: configData } = useConfig();
const [selectedStatus, setSelectedStatus] = useState<Status | null>(null);
const { useAllPresets } = usePresets();
const { mutate: presetsMutator } = useAllPresets();
Expand Down Expand Up @@ -105,7 +107,7 @@ export default function AlertChangeStatusModal({

const handleChangeStatus = async () => {
if (!selectedStatus) {
toast.error("Please select a new status.");
ReadOnlyAwareToaster.error("Please select a new status.", configData);
return;
}

Expand Down Expand Up @@ -137,10 +139,10 @@ export default function AlertChangeStatusModal({
await alertsMutator();
await presetsMutator();
} else {
toast.error("Failed to change alert status.");
ReadOnlyAwareToaster.error("Failed to change alert status.", configData);
}
} catch (error) {
toast.error("An error occurred while changing alert status.");
ReadOnlyAwareToaster.error("An error occurred while changing alert status.", configData);
}
};

Expand Down
13 changes: 8 additions & 5 deletions keep-ui/app/(keep)/alerts/alert-method-modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
ProviderMethodParam,
} from "@/app/(keep)/providers/providers";
import { getSession } from "next-auth/react";
import { useApiUrl } from "utils/hooks/useConfig";
import { useApiUrl, useConfig } from "utils/hooks/useConfig";
import { toast } from "react-toastify";
import Loading from "@/app/(keep)/loading";
import {
Expand All @@ -22,6 +22,7 @@ import { useAlerts } from "utils/hooks/useAlerts";
import { useRouter, useSearchParams } from "next/navigation";
import { useProviders } from "utils/hooks/useProviders";
import Modal from "@/components/ui/Modal";
import { ReadOnlyAwareToaster } from "@/shared/lib/ReadOnlyAwareToaster";

const supportedParamTypes = ["datetime", "literal", "str"];

Expand All @@ -33,6 +34,7 @@ export function AlertMethodModal({ presetName }: AlertMethodModalProps) {
const searchParams = useSearchParams();
const router = useRouter();
const apiUrl = useApiUrl();
const { data: configData} = useConfig();

const alertFingerprint = searchParams?.get("alertFingerprint");
const providerId = searchParams?.get("providerId");
Expand Down Expand Up @@ -187,18 +189,19 @@ export function AlertMethodModal({ presetName }: AlertMethodModalProps) {
setIsLoading(false);
}
} else {
toast.error(
ReadOnlyAwareToaster.error(
`Failed to invoke "${method.name}" on ${
provider.details.name ?? provider.id
} due to ${responseObject.detail}`,
} due to ${responseObject.detail}`, configData,
{ position: toast.POSITION.TOP_LEFT }
);
}
} catch (e: any) {
toast.error(
ReadOnlyAwareToaster.error(
`Failed to invoke "${method.name}" on ${
provider.details.name ?? provider.id
} due to ${e.message}`,
} due to ${e.message}`,
configData,
{ position: toast.POSITION.TOP_LEFT }
);
handleClose();
Expand Down
6 changes: 4 additions & 2 deletions keep-ui/app/(keep)/alerts/alert-run-workflow-modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ import Modal from "@/components/ui/Modal";
import { useWorkflows } from "utils/hooks/useWorkflows";
import { useState } from "react";
import { useHydratedSession as useSession } from "@/shared/lib/hooks/useHydratedSession";
import { useApiUrl } from "utils/hooks/useConfig";
import { useApiUrl, useConfig } from "utils/hooks/useConfig";
import { toast } from "react-toastify";
import { useRouter } from "next/navigation";
import { ReadOnlyAwareToaster } from "@/shared/lib/ReadOnlyAwareToaster";

interface Props {
alert: AlertDto | null | undefined;
Expand All @@ -24,6 +25,7 @@ export default function AlertRunWorkflowModal({ alert, handleClose }: Props) {
const { data: session } = useSession();
const router = useRouter();
const apiUrl = useApiUrl();
const { data: configData } = useConfig();

const isOpen = !!alert;

Expand Down Expand Up @@ -54,7 +56,7 @@ export default function AlertRunWorkflowModal({ alert, handleClose }: Props) {
`/workflows/${selectedWorkflowId}/runs/${workflow_execution_id}`
);
} else {
toast.error("Failed to start workflow", { position: "top-left" });
ReadOnlyAwareToaster.error("Failed to start workflow", configData, { position: "top-left" });
}
clearAndClose();
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,12 @@ import {
import { useHydratedSession as useSession } from "@/shared/lib/hooks/useHydratedSession";
import { FormEvent, useEffect, useState } from "react";
import { toast } from "react-toastify";
import { useApiUrl } from "utils/hooks/useConfig";
import { useApiUrl, useConfig } from "utils/hooks/useConfig";
import { ExtractionRule } from "./model";
import { extractNamedGroups } from "./extractions-table";
import { useExtractions } from "utils/hooks/useExtractionRules";
import { AlertsRulesBuilder } from "@/app/(keep)/alerts/alerts-rules-builder";
import { ReadOnlyAwareToaster } from "@/shared/lib/ReadOnlyAwareToaster";

interface Props {
extractionToEdit: ExtractionRule | null;
Expand All @@ -32,6 +33,7 @@ export default function CreateOrUpdateExtractionRule({
editCallback,
}: Props) {
const { data: session } = useSession();
const { data: configData } = useConfig();
const { mutate } = useExtractions();
const [extractionName, setExtractionName] = useState<string>("");
const [isPreFormatting, setIsPreFormatting] = useState<boolean>(false);
Expand Down Expand Up @@ -97,8 +99,8 @@ export default function CreateOrUpdateExtractionRule({
mutate();
toast.success("Extraction rule created successfully");
} else {
toast.error(
"Failed to create extraction rule, please contact us if this issue persists."
ReadOnlyAwareToaster.error(
"Failed to create extraction rule, please contact us if this issue persists.", configData
);
}
};
Expand Down Expand Up @@ -130,8 +132,8 @@ export default function CreateOrUpdateExtractionRule({
mutate();
toast.success("Extraction updated successfully");
} else {
toast.error(
"Failed to update extraction, please contact us if this issue persists."
ReadOnlyAwareToaster.error(
"Failed to update extraction, please contact us if this issue persists.", configData
);
}
};
Expand Down
8 changes: 5 additions & 3 deletions keep-ui/app/(keep)/extraction/extractions-table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,15 @@ import {
} from "@tanstack/react-table";
import { MdRemoveCircle, MdModeEdit } from "react-icons/md";
import { useHydratedSession as useSession } from "@/shared/lib/hooks/useHydratedSession";
import { useApiUrl } from "utils/hooks/useConfig";
import { useApiUrl, useConfig } from "utils/hooks/useConfig";
import { useMappings } from "utils/hooks/useMappingRules";
import { toast } from "react-toastify";
import { ExtractionRule } from "./model";
import { QuestionMarkCircleIcon } from "@heroicons/react/24/outline";
import { IoCheckmark } from "react-icons/io5";
import { HiMiniXMark } from "react-icons/hi2";
import { useState } from "react";
import { ReadOnlyAwareToaster } from "@/shared/lib/ReadOnlyAwareToaster";

const columnHelper = createColumnHelper<ExtractionRule>();

Expand All @@ -53,6 +54,7 @@ export default function RulesTable({
}: Props) {
const { data: session } = useSession();
const { mutate } = useMappings();
const { data: configData } = useConfig();
const apiUrl = useApiUrl();
const [expanded, setExpanded] = useState<ExpandedState>({});

Expand Down Expand Up @@ -193,8 +195,8 @@ export default function RulesTable({
mutate();
toast.success("Extraction deleted successfully");
} else {
toast.error(
"Failed to delete extraction rule, contact us if this persists"
ReadOnlyAwareToaster.error(
"Failed to delete extraction rule, contact us if this persists", configData
);
}
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { IncidentDto } from "@/entities/incidents/model";
import { AuditEvent } from "@/utils/hooks/useAlerts";
import { useApiUrl } from "@/utils/hooks/useConfig";
import { useApiUrl, useConfig } from "@/utils/hooks/useConfig";
import { TextInput, Button } from "@tremor/react";
import { useHydratedSession as useSession } from "@/shared/lib/hooks/useHydratedSession";
import { useState, useCallback, useEffect } from "react";
import { toast } from "react-toastify";
import { KeyedMutator } from "swr";
import { ReadOnlyAwareToaster } from "@/shared/lib/ReadOnlyAwareToaster";

export function IncidentActivityComment({
incident,
Expand All @@ -17,6 +18,7 @@ export function IncidentActivityComment({
const [comment, setComment] = useState("");
const apiUrl = useApiUrl();
const { data: session } = useSession();
const { data: configData } = useConfig();

const onSubmit = useCallback(async () => {
const response = await fetch(`${apiUrl}/incidents/${incident.id}/comment`, {
Expand All @@ -35,7 +37,7 @@ export function IncidentActivityComment({
setComment("");
mutator();
} else {
toast.error("Failed to add comment", { position: "top-right" });
ReadOnlyAwareToaster.error("Failed to add comment", configData, { position: "top-right" });
}
}, [
apiUrl,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ import { Button, Icon } from "@tremor/react";
import { AlertDto } from "@/app/(keep)/alerts/models";
import { useHydratedSession as useSession } from "@/shared/lib/hooks/useHydratedSession";
import { toast } from "react-toastify";
import { useApiUrl } from "utils/hooks/useConfig";
import { useApiUrl, useConfig } from "utils/hooks/useConfig";
import { useIncidentAlerts } from "utils/hooks/useIncidents";
import { LinkSlashIcon } from "@heroicons/react/24/outline";
import { ReadOnlyAwareToaster } from "@/shared/lib/ReadOnlyAwareToaster";

interface Props {
incidentId: string;
Expand All @@ -14,6 +15,7 @@ export default function IncidentAlertMenu({ incidentId, alert }: Props) {
const apiUrl = useApiUrl();
const { data: session } = useSession();
const { mutate } = useIncidentAlerts(incidentId);
const { data: configData } = useConfig();

function onRemove() {
if (confirm("Are you sure you want to remove correlation?")) {
Expand All @@ -31,8 +33,9 @@ export default function IncidentAlertMenu({ incidentId, alert }: Props) {
});
mutate();
} else {
toast.error(
ReadOnlyAwareToaster.error(
"Failed to remove alert from incident, please contact us if this issue persists.",
configData,
{
position: "top-right",
}
Expand Down
Loading
Loading