Skip to content

Commit 6881428

Browse files
committed
Add incident cancellation and deletion support
1 parent df6c2f4 commit 6881428

File tree

10 files changed

+190
-1
lines changed

10 files changed

+190
-1
lines changed

src/components/Agentic/IncidentDetails/IncidentMetaData/index.tsx

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,17 @@ import { useParams } from "react-router";
44
import { useAgenticDispatch } from "../../../../containers/Agentic/hooks";
55
import { useGetIncidentQuery } from "../../../../redux/services/digma";
66
import {
7+
setIncidentToCancel,
78
setIncidentToClose,
9+
setIncidentToDelete,
810
setStatusDetails
911
} from "../../../../redux/slices/incidentsSlice";
12+
import { sendUserActionTrackingEvent } from "../../../../utils/actions/sendUserActionTrackingEvent";
1013
import { intersperse } from "../../../../utils/intersperse";
1114
import { InfoCircleIcon } from "../../../common/icons/InfoCircleIcon";
1215
import { NewIconButton } from "../../../common/v3/NewIconButton";
1316
import { Tooltip } from "../../../common/v3/Tooltip";
17+
import { trackingEvents } from "../../tracking";
1418
import { Divider } from "./Divider";
1519
import * as s from "./styles";
1620

@@ -56,14 +60,33 @@ export const IncidentMetaData = () => {
5660
);
5761
};
5862

63+
const handleCancelButtonClick = () => {
64+
sendUserActionTrackingEvent(trackingEvents.INCIDENT_CANCEL_BUTTON_CLICKED);
65+
if (!incidentId) {
66+
return;
67+
}
68+
69+
dispatch(setIncidentToCancel(incidentId));
70+
};
71+
5972
const handleCloseButtonClick = () => {
73+
sendUserActionTrackingEvent(trackingEvents.INCIDENT_CLOSE_BUTTON_CLICKED);
6074
if (!incidentId) {
6175
return;
6276
}
6377

6478
dispatch(setIncidentToClose(incidentId));
6579
};
6680

81+
const handleDeleteButtonClick = () => {
82+
sendUserActionTrackingEvent(trackingEvents.INCIDENT_DELETE_BUTTON_CLICKED);
83+
if (!incidentId) {
84+
return;
85+
}
86+
87+
dispatch(setIncidentToDelete(incidentId));
88+
};
89+
6790
if (!data) {
6891
return <s.Container />;
6992
}
@@ -160,12 +183,24 @@ export const IncidentMetaData = () => {
160183
return (
161184
<s.Container>
162185
<s.AttributesList>{attributes}</s.AttributesList>
186+
{data.status === "active" && (
187+
<s.CloseIncidentButton
188+
label={"Cancel incident"}
189+
onClick={handleCancelButtonClick}
190+
/>
191+
)}
163192
{data.status === "pending" && (
164193
<s.CloseIncidentButton
165194
label={"Close incident"}
166195
onClick={handleCloseButtonClick}
167196
/>
168197
)}
198+
{["closed", "cancelled"].includes(data.status) && (
199+
<s.CloseIncidentButton
200+
label={"Delete incident"}
201+
onClick={handleDeleteButtonClick}
202+
/>
203+
)}
169204
</s.Container>
170205
);
171206
};
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import {
2+
useAgenticDispatch,
3+
useAgenticSelector
4+
} from "../../../../containers/Agentic/hooks";
5+
import { useCancelIncidentMutation } from "../../../../redux/services/digma";
6+
import { setIncidentToCancel } from "../../../../redux/slices/incidentsSlice";
7+
import { CancelConfirmation } from "../../../common/CancelConfirmation";
8+
import * as s from "./styles";
9+
10+
export const CancelIncidentDialogOverlay = () => {
11+
const incidentId = useAgenticSelector(
12+
(state) => state.incidents.incidentToCancel
13+
);
14+
const dispatch = useAgenticDispatch();
15+
16+
const [cancelIncident] = useCancelIncidentMutation();
17+
18+
const handleCancelConfirmationDialogClose = () => {
19+
dispatch(setIncidentToCancel(null));
20+
};
21+
22+
const handleCancelConfirmationDialogConfirm = () => {
23+
if (incidentId) {
24+
void cancelIncident({ id: incidentId });
25+
}
26+
27+
dispatch(setIncidentToCancel(null));
28+
};
29+
30+
return (
31+
<s.StyledOverlay>
32+
<CancelConfirmation
33+
header={"Cancel incident?"}
34+
description={"Are you sure that you want to cancel the incident?"}
35+
onClose={handleCancelConfirmationDialogClose}
36+
onConfirm={handleCancelConfirmationDialogConfirm}
37+
confirmBtnText={"Yes, cancel"}
38+
cancelBtnText={"No"}
39+
/>
40+
</s.StyledOverlay>
41+
);
42+
};
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import styled from "styled-components";
2+
import { Overlay } from "../../../common/Overlay";
3+
4+
export const StyledOverlay = styled(Overlay)`
5+
align-items: center;
6+
`;
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import {
2+
useAgenticDispatch,
3+
useAgenticSelector
4+
} from "../../../../containers/Agentic/hooks";
5+
import { useDeleteIncidentMutation } from "../../../../redux/services/digma";
6+
import { setIncidentToDelete } from "../../../../redux/slices/incidentsSlice";
7+
import { CancelConfirmation } from "../../../common/CancelConfirmation";
8+
import * as s from "./styles";
9+
10+
export const DeleteIncidentDialogOverlay = () => {
11+
const incidentId = useAgenticSelector(
12+
(state) => state.incidents.incidentToDelete
13+
);
14+
const dispatch = useAgenticDispatch();
15+
16+
const [deleteIncident] = useDeleteIncidentMutation();
17+
18+
const handleDeleteConfirmationDialogClose = () => {
19+
dispatch(setIncidentToDelete(null));
20+
};
21+
22+
const handleDeleteConfirmationDialogConfirm = () => {
23+
if (incidentId) {
24+
void deleteIncident({ id: incidentId });
25+
}
26+
27+
dispatch(setIncidentToDelete(null));
28+
};
29+
30+
return (
31+
<s.StyledOverlay>
32+
<CancelConfirmation
33+
header={"Delete incident?"}
34+
description={"Are you sure that you want to delete the incident?"}
35+
onClose={handleDeleteConfirmationDialogClose}
36+
onConfirm={handleDeleteConfirmationDialogConfirm}
37+
confirmBtnText={"Yes, delete"}
38+
cancelBtnText={"No"}
39+
/>
40+
</s.StyledOverlay>
41+
);
42+
};
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import styled from "styled-components";
2+
import { Overlay } from "../../../common/Overlay";
3+
4+
export const StyledOverlay = styled(Overlay)`
5+
align-items: center;
6+
`;

src/components/Agentic/IncidentsContainer/index.tsx

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import { Outlet } from "react-router";
22
import { useAgenticSelector } from "../../../containers/Agentic/hooks";
3+
import { CancelIncidentDialogOverlay } from "./CancelIncidentDialogOverlay";
34
import { CloseIncidentDialogOverlay } from "./CloseIncidentDialogOverlay";
45
import { CreateIncidentChatOverlay } from "./CreateIncidentChatOverlay";
6+
import { DeleteIncidentDialogOverlay } from "./DeleteIncidentDialogOverlay";
57
import { StatusDetailsOverlay } from "./StatusDetailsOverlay";
68
import * as s from "./styles";
79

@@ -10,10 +12,18 @@ export const IncidentsContainer = () => {
1012
(state) => state.incidents.isCreateIncidentChatOpen
1113
);
1214

15+
const incidentToCancel = useAgenticSelector(
16+
(state) => state.incidents.incidentToCancel
17+
);
18+
1319
const incidentToClose = useAgenticSelector(
1420
(state) => state.incidents.incidentToClose
1521
);
1622

23+
const incidentToDelete = useAgenticSelector(
24+
(state) => state.incidents.incidentToDelete
25+
);
26+
1727
const statusDetails = useAgenticSelector(
1828
(state) => state.incidents.statusDetails
1929
);
@@ -22,7 +32,9 @@ export const IncidentsContainer = () => {
2232
<s.Container>
2333
<Outlet />
2434
{isCreateIncidentChatOpen && <CreateIncidentChatOverlay />}
35+
{incidentToCancel && <CancelIncidentDialogOverlay />}
2536
{incidentToClose && <CloseIncidentDialogOverlay />}
37+
{incidentToDelete && <DeleteIncidentDialogOverlay />}
2638
{statusDetails && <StatusDetailsOverlay />}
2739
</s.Container>
2840
);

src/components/Agentic/tracking.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ export const trackingEvents = addPrefix(
1313
INCIDENT_CREATION_CHAT_DIALOG_CLOSED:
1414
"incident creation chat dialog closed",
1515
VIEW_NEW_INCIDENT_LINK_CLICKED: "view incident link clicked",
16+
INCIDENT_CANCEL_BUTTON_CLICKED: "incident cancel button clicked",
17+
INCIDENT_CLOSE_BUTTON_CLICKED: "incident close button clicked",
18+
INCIDENT_DELETE_BUTTON_CLICKED: "incident delete button clicked",
1619
FLOW_CHART_NODE_CLICKED: "flow chart node clicked",
1720
FLOW_CHART_NODE_KEBAB_MENU_CLICKED: "flow chart node kebab menu clicked",
1821
FLOW_CHART_NODE_KEBAB_MENU_ITEM_CLICKED:

src/redux/services/digma.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,14 @@ import type {
44
AddMCPServerPayload,
55
AgenticInvestigatePayload,
66
AgenticInvestigateResponse,
7+
CancelIncidentPayload,
78
CloseIncidentPayload,
89
CreateEnvironmentPayload,
910
CreateEnvironmentResponse,
1011
DeleteEnvironmentPayload,
1112
DeleteEnvironmentResponse,
1213
DeleteIncidentAgentDirectivePayload,
14+
DeleteIncidentPayload,
1315
DeleteMCPServerPayload,
1416
DismissErrorPayload,
1517
DismissUndismissInsightPayload,
@@ -602,6 +604,20 @@ export const digmaApi = createApi({
602604
}),
603605
invalidatesTags: ["Incident"]
604606
}),
607+
cancelIncident: builder.mutation<void, CancelIncidentPayload>({
608+
query: ({ id }) => ({
609+
url: `Agentic/incidents/${window.encodeURIComponent(id)}/cancel`,
610+
method: "PUT"
611+
}),
612+
invalidatesTags: ["Incident"]
613+
}),
614+
deleteIncident: builder.mutation<void, DeleteIncidentPayload>({
615+
query: ({ id }) => ({
616+
url: `Agentic/incidents/${window.encodeURIComponent(id)}`,
617+
method: "DELETE"
618+
}),
619+
invalidatesTags: ["Incident"]
620+
}),
605621
getIncidentAgents: builder.query<
606622
GetIncidentAgentsResponse,
607623
GetIncidentAgentsPayload
@@ -820,6 +836,8 @@ export const {
820836
useGetIncidentsQuery,
821837
useGetIncidentQuery,
822838
useCloseIncidentMutation,
839+
useCancelIncidentMutation,
840+
useDeleteIncidentMutation,
823841
useGetIncidentAgentsQuery,
824842
useGetIncidentAgentEventsQuery,
825843
useGetIncidentAgentChatEventsQuery,

src/redux/services/types.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1091,7 +1091,12 @@ export interface GetBlockedTracesResponse {
10911091
total: number;
10921092
}
10931093

1094-
export type IncidentStatus = "active" | "pending" | "closed" | "error";
1094+
export type IncidentStatus =
1095+
| "active"
1096+
| "pending"
1097+
| "closed"
1098+
| "error"
1099+
| "cancelled";
10951100

10961101
export interface IncidentResponseItem {
10971102
id: string;
@@ -1111,6 +1116,14 @@ export interface CloseIncidentPayload {
11111116
id: string;
11121117
}
11131118

1119+
export interface CancelIncidentPayload {
1120+
id: string;
1121+
}
1122+
1123+
export interface DeleteIncidentPayload {
1124+
id: string;
1125+
}
1126+
11141127
export interface IncidentIssue {
11151128
issue_id: string;
11161129
span_uid: string | null;

src/redux/slices/incidentsSlice.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,18 @@ export interface StatusDetails<T = unknown> {
1010

1111
export interface IncidentsState extends BaseState {
1212
isCreateIncidentChatOpen: boolean;
13+
incidentToCancel: string | null;
1314
incidentToClose: string | null;
15+
incidentToDelete: string | null;
1416
statusDetails: StatusDetails | null;
1517
}
1618

1719
const initialState: IncidentsState = {
1820
version: STATE_VERSION,
1921
isCreateIncidentChatOpen: false,
22+
incidentToCancel: null,
2023
incidentToClose: null,
24+
incidentToDelete: null,
2125
statusDetails: null
2226
};
2327

@@ -28,9 +32,15 @@ export const incidentsSlice = createSlice({
2832
setIsCreateIncidentChatOpen: (state, action: { payload: boolean }) => {
2933
state.isCreateIncidentChatOpen = action.payload;
3034
},
35+
setIncidentToCancel: (state, action: { payload: string | null }) => {
36+
state.incidentToCancel = action.payload;
37+
},
3138
setIncidentToClose: (state, action: { payload: string | null }) => {
3239
state.incidentToClose = action.payload;
3340
},
41+
setIncidentToDelete: (state, action: { payload: string | null }) => {
42+
state.incidentToDelete = action.payload;
43+
},
3444
setStatusDetails: (state, action: { payload: StatusDetails | null }) => {
3545
state.statusDetails = action.payload;
3646
},
@@ -43,7 +53,9 @@ export const incidentsSlice = createSlice({
4353

4454
export const {
4555
setIsCreateIncidentChatOpen,
56+
setIncidentToCancel,
4657
setIncidentToClose,
58+
setIncidentToDelete,
4759
setStatusDetails,
4860
clear
4961
} = incidentsSlice.actions;

0 commit comments

Comments
 (0)