diff --git a/package-lock.json b/package-lock.json
index fb84727ef..7ac500487 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "digma-ui",
- "version": "16.2.1",
+ "version": "16.3.0-alpha.3",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "digma-ui",
- "version": "16.2.1",
+ "version": "16.3.0-alpha.3",
"license": "MIT",
"dependencies": {
"@codemirror/lang-json": "^6.0.2",
diff --git a/package.json b/package.json
index c0991824a..8007ee9f5 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "digma-ui",
- "version": "16.2.1",
+ "version": "16.3.0-alpha.3",
"description": "Digma UI",
"scripts": {
"lint:eslint": "eslint --cache .",
diff --git a/src/components/Admin/ErrorLinkResolver/index.tsx b/src/components/Admin/ErrorLinkResolver/index.tsx
new file mode 100644
index 000000000..cf53757f6
--- /dev/null
+++ b/src/components/Admin/ErrorLinkResolver/index.tsx
@@ -0,0 +1,52 @@
+import { Navigate, useParams } from "react-router";
+import { useGetErrorEnvironmentQuery } from "../../../redux/services/digma";
+import { Spinner } from "../../common/v3/Spinner";
+import { TAB_IDS } from "../../Navigation/Tabs/types";
+import type { TabLocation } from "../common/RepositorySidebarOverlay/types";
+import * as s from "./styles";
+
+const REFRESH_INTERVAL = 10 * 1000; // in milliseconds
+
+export const ErrorLinkResolver = () => {
+ const params = useParams();
+
+ const { data } = useGetErrorEnvironmentQuery(
+ {
+ id: params.id ?? ""
+ },
+ {
+ skip: !params.id,
+ pollingInterval: REFRESH_INTERVAL
+ }
+ );
+
+ if (!data) {
+ return (
+
+
+
+
+
+ );
+ }
+
+ const sidebarLocation: TabLocation = {
+ id: TAB_IDS.ERRORS,
+ path: params.id
+ };
+
+ if (data) {
+ return (
+
+ );
+ }
+};
diff --git a/src/components/Admin/ErrorLinkResolver/styles.ts b/src/components/Admin/ErrorLinkResolver/styles.ts
new file mode 100644
index 000000000..cda60c3ed
--- /dev/null
+++ b/src/components/Admin/ErrorLinkResolver/styles.ts
@@ -0,0 +1,13 @@
+import styled from "styled-components";
+
+export const Container = styled.div`
+ display: flex;
+ height: 100%;
+`;
+
+export const LoadingContainer = styled.div`
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ flex-grow: 1;
+`;
diff --git a/src/components/Admin/Header/index.tsx b/src/components/Admin/Header/index.tsx
index 2f7aa971b..d93104f3e 100644
--- a/src/components/Admin/Header/index.tsx
+++ b/src/components/Admin/Header/index.tsx
@@ -16,6 +16,16 @@ export const Header = () => (
}
/>
+
+
+
+
+ }
+ />
+
{
+ if (!locationParam) {
+ return undefined;
+ }
+
+ try {
+ const parsedLocation = JSON.parse(locationParam) as TabLocation;
+ return parsedLocation;
+ } catch {
+ return undefined;
+ }
+};
+
export const Home = () => {
const environmentId = useAdminSelector(
(state) => state.codeIssuesReport.selectedEnvironmentId
@@ -29,11 +48,26 @@ export const Home = () => {
const [searchParams, setSearchParams] = useStableSearchParams();
const environmentParam = searchParams.get("environment");
const issuesParam = searchParams.get("issues");
+ const [sidebarScope, setSidebarScope] = useState(
+ searchParams.get("sidebar-scope") ?? undefined
+ );
+ const [sidebarLocation, setSidebarLocation] = useState(
+ getRepositorySidebarLocation(searchParams.get("sidebar-view"))
+ );
const servicesParam = useMemo(
() => searchParams.getAll("services"),
[searchParams]
);
+ const { data: spanInfo } = useGetSpanByIdQuery(
+ {
+ id: sidebarScope ?? ""
+ },
+ {
+ skip: !sidebarScope
+ }
+ );
+
const queries: Record = useMemo(
() => ({
"top-criticality": {
@@ -64,6 +98,8 @@ export const Home = () => {
const handleRepositorySidebarClose = () => {
setIssuesQuery(undefined);
+ setSidebarScope(undefined);
+ setSidebarLocation(undefined);
};
// TODO: replace with useEffect
@@ -112,7 +148,48 @@ export const Home = () => {
});
}, [setSearchParams, issuesQuery]);
- const repositorySidebarQuery = issuesQuery ? queries[issuesQuery] : undefined;
+ useEffect(() => {
+ setSearchParams((params) => {
+ if (sidebarScope) {
+ params.set("sidebar-scope", sidebarScope);
+ } else {
+ params.delete("sidebar-scope");
+ }
+ return params;
+ });
+ }, [setSearchParams, sidebarScope]);
+
+ useEffect(() => {
+ setSearchParams((params) => {
+ if (sidebarLocation) {
+ params.set("sidebar-view", JSON.stringify(sidebarLocation));
+ } else {
+ params.delete("sidebar-view");
+ }
+ return params;
+ });
+ }, [setSearchParams, sidebarLocation]);
+
+ const repositorySidebarQuery: RepositorySidebarQuery | undefined =
+ sidebarScope && spanInfo
+ ? {
+ query: {
+ environment: environmentId ?? undefined,
+ scopedSpanCodeObjectId: spanInfo?.spanCodeObjectId
+ }
+ }
+ : sidebarLocation
+ ? {
+ query: {
+ environment: environmentId ?? undefined
+ }
+ }
+ : issuesQuery
+ ? queries[issuesQuery]
+ : undefined;
+ const isRepositorySidebarOpen = Boolean(
+ repositorySidebarQuery ?? sidebarLocation
+ );
return (
@@ -124,7 +201,8 @@ export const Home = () => {
diff --git a/src/components/Admin/SpanLinkResolver/index.tsx b/src/components/Admin/SpanLinkResolver/index.tsx
new file mode 100644
index 000000000..6570f8dd4
--- /dev/null
+++ b/src/components/Admin/SpanLinkResolver/index.tsx
@@ -0,0 +1,52 @@
+import { Navigate, useParams } from "react-router";
+import { useGetSpanByIdQuery } from "../../../redux/services/digma";
+import { Spinner } from "../../common/v3/Spinner";
+import { TAB_IDS } from "../../Navigation/Tabs/types";
+import type { TabLocation } from "../common/RepositorySidebarOverlay/types";
+import * as s from "./styles";
+
+const REFRESH_INTERVAL = 10 * 1000; // in milliseconds
+
+export const SpanLinkResolver = () => {
+ const params = useParams();
+
+ const { data } = useGetSpanByIdQuery(
+ {
+ id: params.id ?? ""
+ },
+ {
+ skip: !params.id,
+ pollingInterval: REFRESH_INTERVAL
+ }
+ );
+
+ if (!data) {
+ return (
+
+
+
+
+
+ );
+ }
+
+ const sidebarLocation: TabLocation = {
+ id: TAB_IDS.ISSUES
+ };
+
+ if (data) {
+ return (
+
+ );
+ }
+};
diff --git a/src/components/Admin/SpanLinkResolver/styles.ts b/src/components/Admin/SpanLinkResolver/styles.ts
new file mode 100644
index 000000000..cda60c3ed
--- /dev/null
+++ b/src/components/Admin/SpanLinkResolver/styles.ts
@@ -0,0 +1,13 @@
+import styled from "styled-components";
+
+export const Container = styled.div`
+ display: flex;
+ height: 100%;
+`;
+
+export const LoadingContainer = styled.div`
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ flex-grow: 1;
+`;
diff --git a/src/components/Admin/common/RepositorySidebarOverlay/RepositorySidebar/Issues/index.tsx b/src/components/Admin/common/RepositorySidebarOverlay/RepositorySidebar/Issues/index.tsx
index 30b1e36fa..bb0cc7e02 100644
--- a/src/components/Admin/common/RepositorySidebarOverlay/RepositorySidebar/Issues/index.tsx
+++ b/src/components/Admin/common/RepositorySidebarOverlay/RepositorySidebar/Issues/index.tsx
@@ -10,6 +10,7 @@ import {
setIssuesInsightInfoToOpenTicket,
setScope
} from "../../../../../../redux/slices/repositorySlice";
+import { initialState } from "../../../../../../store/insights/insightsSlice";
import { useStore } from "../../../../../../store/useStore";
import { useInsightsData } from "../../../../../Insights/hooks/useInsightsData";
import { InsightsContent } from "../../../../../Insights/InsightsContent";
@@ -24,7 +25,7 @@ export const Issues = ({
onScopeChange,
onGoToTab
}: IssuesProps) => {
- const { setInsightViewType } = useStore.getState();
+ const { setInsightViewType, setInsightsSorting } = useStore.getState();
const [isDrawerTransitioning, setIsDrawerTransitioning] = useState(false);
const drawerRef = useRef(null);
const dispatch = useAdminDispatch();
@@ -110,6 +111,14 @@ export const Issues = ({
);
}, [query, dispatch]);
+ // Set sorting on query change
+ useEffect(() => {
+ setInsightsSorting({
+ criterion: query?.sortBy ?? initialState.sorting.criterion,
+ order: query?.sortOrder ?? initialState.sorting.order
+ });
+ }, [query?.sortBy, query?.sortOrder, setInsightsSorting]);
+
return (
{
const [isSidebarTransitioning, setIsSidebarTransitioning] = useState(false);
- const [currentTabLocation, setCurrentTabLocation] =
- useState(initialTabLocation);
+ const [currentTabLocation, setCurrentTabLocation] = useState(
+ sidebarLocation ?? initialTabLocation
+ );
const [currentSpanCodeObjectId, setCurrentSpanCodeObjectId] = useState(
sidebarQuery?.query?.scopedSpanCodeObjectId
);
@@ -155,10 +157,10 @@ export const RepositorySidebarOverlay = ({
},
{
spanCodeObjectId: newSpanCodeObjectId,
- tabLocation: { id: TAB_IDS.ISSUES }
+ tabLocation: sidebarLocation ?? { id: TAB_IDS.ISSUES }
}
);
- }, [history, sidebarQuery?.query?.scopedSpanCodeObjectId]);
+ }, [history, sidebarQuery?.query?.scopedSpanCodeObjectId, sidebarLocation]);
const handleSidebarClose = useCallback(() => {
dispatch(clear());
diff --git a/src/components/Admin/common/RepositorySidebarOverlay/types.ts b/src/components/Admin/common/RepositorySidebarOverlay/types.ts
index 2c5124088..4dd81405c 100644
--- a/src/components/Admin/common/RepositorySidebarOverlay/types.ts
+++ b/src/components/Admin/common/RepositorySidebarOverlay/types.ts
@@ -8,6 +8,7 @@ export interface RepositorySidebarOverlayProps {
isSidebarOpen: boolean;
onSidebarClose: () => void;
sidebarQuery?: RepositorySidebarQuery;
+ sidebarLocation?: TabLocation;
scopeDisplayName?: string;
}
diff --git a/src/components/Agentic/IncidentDetails/AdditionalInfo/RelatedIssues/index.tsx b/src/components/Agentic/IncidentDetails/AdditionalInfo/RelatedIssues/index.tsx
index 449427078..df879cdc5 100644
--- a/src/components/Agentic/IncidentDetails/AdditionalInfo/RelatedIssues/index.tsx
+++ b/src/components/Agentic/IncidentDetails/AdditionalInfo/RelatedIssues/index.tsx
@@ -5,9 +5,9 @@ import { useStableSearchParams } from "../../../../../hooks/useStableSearchParam
import { useGetIncidentQuery } from "../../../../../redux/services/digma";
import type { GenericIncidentIssue } from "../../../../../redux/services/types";
import { sendUserActionTrackingEvent } from "../../../../../utils/actions/sendUserActionTrackingEvent";
-import { getIdeLauncherLinkForError } from "../../../../../utils/getIdeLauncherLinkForError";
-import { getIdeLauncherLinkForSpan } from "../../../../../utils/getIdeLauncherLinkForSpan";
import { getInsightTypeInfo } from "../../../../../utils/getInsightTypeInfo";
+import { getWebAdminLinkForSpan } from "../../../../../utils/getWebAdminLinkForSpan";
+import { getWebAdminLinkForError } from "../../../../../utils/getWebAdminLinkToError";
import { roundTo } from "../../../../../utils/roundTo";
import type { TagType } from "../../../../common/v3/Tag/types";
import { Tooltip } from "../../../../common/v3/Tooltip";
@@ -97,7 +97,7 @@ export const RelatedIssues = () => {
{issue.span_uid ? (
@@ -118,7 +118,7 @@ export const RelatedIssues = () => {
diff --git a/src/components/Agentic/IncidentTemplate/MCPServerDialog/index.tsx b/src/components/Agentic/IncidentTemplate/MCPServerDialog/index.tsx
index 136bca8ce..e4da05c75 100644
--- a/src/components/Agentic/IncidentTemplate/MCPServerDialog/index.tsx
+++ b/src/components/Agentic/IncidentTemplate/MCPServerDialog/index.tsx
@@ -154,8 +154,10 @@ export const MCPServerDialog = ({
onClose();
};
+ const title = serverData?.uid ? "Set MCP Server" : "Add MCP Server";
+
return (
-
)}
+ {platform === "Web" && isAgenticEnabled && (
+
+ : LightBulbWithScrewIcon
+ }
+ onClick={handleInvestigateButtonClick}
+ isDisabled={investigateResult.isLoading}
+ label={
+ investigateResult.isLoading ? "Investigating..." : "Investigate"
+ }
+ />
+ )}
diff --git a/src/components/Errors/NewErrorCard/index.tsx b/src/components/Errors/NewErrorCard/index.tsx
index 6461ca896..fb9142ee9 100644
--- a/src/components/Errors/NewErrorCard/index.tsx
+++ b/src/components/Errors/NewErrorCard/index.tsx
@@ -3,6 +3,8 @@ import { CSSTransition } from "react-transition-group";
import { getFeatureFlagValue } from "../../../featureFlags";
import { usePrevious } from "../../../hooks/usePrevious";
import { platform } from "../../../platform";
+import { useInvestigateMutation } from "../../../redux/services/digma";
+import { useConfigSelector } from "../../../store/config/useConfigSelector";
import { ViewMode } from "../../../store/errors/errorsSlice";
import { useErrorsSelector } from "../../../store/errors/useErrorsSelector";
import { useStore } from "../../../store/useStore";
@@ -17,10 +19,15 @@ import {
import type { Option } from "../../common/AffectedEndpointsSelector/types";
import { CodeIcon } from "../../common/icons/16px/CodeIcon";
import { HistogramIcon } from "../../common/icons/16px/HistogramIcon";
+import { LightBulbWithScrewIcon } from "../../common/icons/16px/LightBulbWithScrewIcon";
import { PinFillIcon } from "../../common/icons/16px/PinFillIcon";
import { PinIcon } from "../../common/icons/16px/PinIcon";
import { NewIconButton } from "../../common/v3/NewIconButton";
import { Tooltip } from "../../common/v3/Tooltip";
+import {
+ InvestigateButton,
+ InvestigateButtonSpinner
+} from "../../Insights/InsightsCatalog/InsightsPage/InsightCardRenderer/insightCards/common/InsightCard/styles";
import { TimestampKeyValue } from "../ErrorCard/TimestampKeyValue";
import { usePinning } from "../GlobalErrorsList/usePinning";
import { getTagType, HIGH_SEVERITY_SCORE_THRESHOLD } from "../Score";
@@ -46,8 +53,10 @@ export const NewErrorCard = ({
const [isHistogramVisible, setIsHistogramVisible] = useState(false);
const chartContainerRef = useRef(null);
const { globalErrorsList } = useErrorsSelector();
+ const { isAgenticEnabled } = useConfigSelector();
const { setGlobalErrorsViewMode } = useStore.getState();
const [isPinned, setIsPinned] = useState(Boolean(data.pinnedAt));
+ const [investigate, investigateResult] = useInvestigateMutation();
const isOccurrenceChartEnabled = getFeatureFlagValue(
backendInfo,
@@ -228,6 +237,28 @@ export const NewErrorCard = ({
show();
};
+ const handleInvestigateButtonClick = () => {
+ sendUserActionTrackingEvent(
+ trackingEvents.ERROR_CARD_INVESTIGATE_BUTTON_CLICKED
+ );
+
+ void investigate({
+ data: {
+ targetId: id,
+ targetType: "error"
+ }
+ })
+ .unwrap()
+ .then((data) => {
+ const incidentId = data.incidentId;
+ openURLInDefaultBrowser(`/agentic/incidents/${incidentId}`);
+ })
+ .catch(() => {
+ // eslint-disable-next-line no-console
+ console.error("Failed to create incident from error");
+ });
+ };
+
const isCritical = score.score > HIGH_SEVERITY_SCORE_THRESHOLD;
const selectedOption = useMemo(
@@ -241,34 +272,61 @@ export const NewErrorCard = ({
const toolbarActions = [
...(isPinEnabled
? [
-
+
+
+
]
: []),
...(isOccurrenceChartEnabled && selectedEndpointKey
? [
-
+ >
+
+
]
: []),
...(platform === "Web"
? [
-
+
+
+ ]
+ : []),
+ ...(platform === "Web" && isAgenticEnabled
+ ? [
+
+ : LightBulbWithScrewIcon
+ }
+ onClick={handleInvestigateButtonClick}
+ isDisabled={investigateResult.isLoading}
+ label={
+ investigateResult.isLoading ? "Investigating..." : "Investigate"
+ }
/>
]
: [])
diff --git a/src/components/Errors/tracking.ts b/src/components/Errors/tracking.ts
index 2614c3415..9b77a2b56 100644
--- a/src/components/Errors/tracking.ts
+++ b/src/components/Errors/tracking.ts
@@ -10,6 +10,7 @@ export const trackingEvents = addPrefix(
FLOW_PAGINATION_BUTTON_CLICKED: "flow pagination button clicked",
TRACE_BUTTON_CLICKED: "trace button clicked",
OPEN_IN_IDE_BUTTON_CLICKED: "open in ide button clicked",
+ INVESTIGATE_BUTTON_CLICKED: "investigate button clicked",
ERROR_STACK_TRACE_ITEM_CLICKED: "error stack trace item clicked",
RAW_ERROR_STACK_TRACE_BUTTON_CLICKED:
"raw error stack trace button clicked",
@@ -46,6 +47,8 @@ export const trackingEvents = addPrefix(
ERROR_CARD_PIN_UNPIN_BUTTON_CLICKED: "error card pin unpin button clicked",
ERROR_CARD_OPEN_IN_IDE_BUTTON_CLICKED:
"error card open in ide button clicked",
+ ERROR_CARD_INVESTIGATE_BUTTON_CLICKED:
+ "error card investigate button clicked",
ERROR_CARD_DISMISS_BUTTON_CLICKED: "error card dismiss button clicked",
ERROR_CARD_PIN_UNDISMISS_BUTTON_CLICKED:
"error card pin undismiss button clicked"
diff --git a/src/components/Insights/InsightsCatalog/InsightsPage/InsightCardRenderer/insightCards/common/InsightCard/index.tsx b/src/components/Insights/InsightsCatalog/InsightsPage/InsightCardRenderer/insightCards/common/InsightCard/index.tsx
index b2e0d5854..f0ddb1837 100644
--- a/src/components/Insights/InsightsCatalog/InsightsPage/InsightCardRenderer/insightCards/common/InsightCard/index.tsx
+++ b/src/components/Insights/InsightsCatalog/InsightsPage/InsightCardRenderer/insightCards/common/InsightCard/index.tsx
@@ -2,7 +2,7 @@ import { Fragment, useEffect, useRef, useState } from "react";
import { usePrevious } from "../../../../../../../../hooks/usePrevious";
import { platform } from "../../../../../../../../platform";
import {
- useCreateIncidentFromInsightMutation,
+ useInvestigateMutation,
useMarkInsightReadMutation,
useRecheckInsightMutation
} from "../../../../../../../../redux/services/digma";
@@ -77,8 +77,7 @@ export const InsightCard = ({
} = useConfigSelector();
const cardRef = useRef(null);
const [showInfo, setShowInfo] = useState(false);
- const [createIncidentFromInsight, createIncidentFromInsightResult] =
- useCreateIncidentFromInsightMutation();
+ const [investigate, investigateResult] = useInvestigateMutation();
const isCritical = insight.criticality > HIGH_CRITICALITY_THRESHOLD;
@@ -288,8 +287,11 @@ export const InsightCard = ({
}
);
- void createIncidentFromInsight({
- insightId: insight.id
+ void investigate({
+ data: {
+ targetId: insight.id,
+ targetType: "issue"
+ }
})
.unwrap()
.then((data) => {
@@ -465,16 +467,14 @@ export const InsightCard = ({
return (
: LightBulbWithScrewIcon
}
onClick={handleInvestigateButtonClick}
- isDisabled={createIncidentFromInsightResult.isLoading}
+ isDisabled={investigateResult.isLoading}
label={
- createIncidentFromInsightResult.isLoading
- ? "Investigating..."
- : "Investigate"
+ investigateResult.isLoading ? "Investigating..." : "Investigate"
}
/>
);
@@ -534,7 +534,7 @@ export const InsightCard = ({
actions.push("pin");
}
- if (areInsightSuggestionsEnabled && onOpenSuggestion) {
+ if (areInsightSuggestionsEnabled && !isAgenticEnabled && onOpenSuggestion) {
actions.push("openSuggestion");
}
diff --git a/src/components/Insights/InsightsCatalog/index.tsx b/src/components/Insights/InsightsCatalog/index.tsx
index 4e9d2fe4a..aede21d3c 100644
--- a/src/components/Insights/InsightsCatalog/index.tsx
+++ b/src/components/Insights/InsightsCatalog/index.tsx
@@ -62,6 +62,11 @@ const getSortingOptions = (
label: "Criticality",
defaultOrder: SortingOrder.Desc
},
+ {
+ value: InsightsSortingCriterion.Severity,
+ label: "Severity",
+ defaultOrder: SortingOrder.Desc
+ },
{
value: InsightsSortingCriterion.Latest,
label: "Latest",
diff --git a/src/components/Navigation/SpanInfo/styles.ts b/src/components/Navigation/SpanInfo/styles.ts
index 3e6fabacb..62e516e5d 100644
--- a/src/components/Navigation/SpanInfo/styles.ts
+++ b/src/components/Navigation/SpanInfo/styles.ts
@@ -10,6 +10,7 @@ export const Container = styled.div`
overflow: hidden;
gap: 8px;
padding: 8px 8px 12px;
+ width: 100%;
`;
export const StyledCodeSnippet = styled(CodeSnippet)`
diff --git a/src/containers/Admin/router.tsx b/src/containers/Admin/router.tsx
index 7bc4773e5..fe13c0377 100644
--- a/src/containers/Admin/router.tsx
+++ b/src/containers/Admin/router.tsx
@@ -2,8 +2,10 @@ import type { RouteObject } from "react-router";
import { Navigate, createBrowserRouter, useRouteError } from "react-router";
import { Admin } from "../../components/Admin";
import { Environments } from "../../components/Admin/Environments";
+import { ErrorLinkResolver } from "../../components/Admin/ErrorLinkResolver";
import { Home } from "../../components/Admin/Home";
import { CodeIssues } from "../../components/Admin/Reports/CodeIssues";
+import { SpanLinkResolver } from "../../components/Admin/SpanLinkResolver";
import { RejectedTraces } from "../../components/Admin/Troubleshooting/RejectedTraces";
export const routes: RouteObject[] = [
@@ -53,6 +55,8 @@ export const routes: RouteObject[] = [
}
]
},
+ { path: "navigate/errors/:id", element: },
+ { path: "navigate/:id", element: },
{
path: "*",
element:
diff --git a/src/redux/services/digma.ts b/src/redux/services/digma.ts
index b027465bd..ef4d3455a 100644
--- a/src/redux/services/digma.ts
+++ b/src/redux/services/digma.ts
@@ -2,11 +2,11 @@ import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react";
import { isString } from "../../typeGuards/isString";
import type {
AddMCPServerPayload,
+ AgenticInvestigatePayload,
+ AgenticInvestigateResponse,
CloseIncidentPayload,
CreateEnvironmentPayload,
CreateEnvironmentResponse,
- CreateIncidentFromInsightPayload,
- CreateIncidentFromInsightResponse,
DeleteEnvironmentPayload,
DeleteEnvironmentResponse,
DeleteIncidentAgentDirectivePayload,
@@ -35,6 +35,8 @@ import type {
GetEnvironmentServicesPayload,
GetEnvironmentServicesResponse,
GetEnvironmentsResponse,
+ GetErrorEnvironmentPayload,
+ GetErrorEnvironmentResponse,
GetErrorPayload,
GetErrorResponse,
GetErrorsPayload,
@@ -194,6 +196,15 @@ export const digmaApi = createApi({
}),
providesTags: ["Error"]
}),
+ getErrorEnvironment: builder.query<
+ GetErrorEnvironmentResponse,
+ GetErrorEnvironmentPayload
+ >({
+ query: ({ id }) => ({
+ url: "CodeAnalytics/codeObjects/error_environment",
+ params: { errorId: id }
+ })
+ }),
getSpanInsight: builder.query<
GetSpanInsightResponse,
GetSpanInsightPayload
@@ -742,13 +753,14 @@ export const digmaApi = createApi({
}),
invalidatesTags: ["IncidentAgentMCPServer"]
}),
- createIncidentFromInsight: builder.mutation<
- CreateIncidentFromInsightResponse,
- CreateIncidentFromInsightPayload
+ investigate: builder.mutation<
+ AgenticInvestigateResponse,
+ AgenticInvestigatePayload
>({
- query: ({ insightId }) => ({
- url: `Agentic/issue-entry/${window.encodeURIComponent(insightId)}`,
- method: "POST"
+ query: ({ data }) => ({
+ url: `Agentic/investigate`,
+ method: "POST",
+ body: data
})
})
})
@@ -764,6 +776,7 @@ export const {
useGetBlockedTracesQuery,
useGetErrorsQuery,
useGetErrorQuery,
+ useGetErrorEnvironmentQuery,
useGetGlobalErrorsQuery,
useGetGlobalErrorFiltersQuery,
useGetErrorTimeseriesQuery,
@@ -821,5 +834,5 @@ export const {
useAddIncidentAgentMCPServerMutation,
useUpdateIncidentAgentMCPServerMutation,
useDeleteIncidentAgentMCPServerMutation,
- useCreateIncidentFromInsightMutation
+ useInvestigateMutation
} = digmaApi;
diff --git a/src/redux/services/types.ts b/src/redux/services/types.ts
index 6e5a55c84..43b0d0d8a 100644
--- a/src/redux/services/types.ts
+++ b/src/redux/services/types.ts
@@ -850,6 +850,14 @@ export interface GetErrorResponse {
originServices: ErrorOriginService[] | null;
}
+export interface GetErrorEnvironmentPayload {
+ id: string;
+}
+
+export interface GetErrorEnvironmentResponse {
+ environmentId: string;
+}
+
export enum GlobalErrorsSortingCriterion {
Criticality = "Criticality",
Latest = "Latest"
@@ -1288,10 +1296,13 @@ export interface DeleteMCPServerPayload {
id: string;
}
-export interface CreateIncidentFromInsightPayload {
- insightId: string;
+export interface AgenticInvestigatePayload {
+ data: {
+ targetId: string;
+ targetType: "issue" | "error";
+ };
}
-export interface CreateIncidentFromInsightResponse {
+export interface AgenticInvestigateResponse {
incidentId: string;
}
diff --git a/src/utils/getWebAdminLinkForSpan.ts b/src/utils/getWebAdminLinkForSpan.ts
new file mode 100644
index 000000000..fe727dbe7
--- /dev/null
+++ b/src/utils/getWebAdminLinkForSpan.ts
@@ -0,0 +1,12 @@
+export const getWebAdminLinkForSpan = (
+ spanUid?: string
+): string | undefined => {
+ if (!spanUid) {
+ return;
+ }
+
+ const baseURL = `${window.location.origin}/admin/navigate/${spanUid}`;
+ const url = new URL(baseURL);
+
+ return url.toString();
+};
diff --git a/src/utils/getWebAdminLinkToError.ts b/src/utils/getWebAdminLinkToError.ts
new file mode 100644
index 000000000..87b34b33f
--- /dev/null
+++ b/src/utils/getWebAdminLinkToError.ts
@@ -0,0 +1,12 @@
+export const getWebAdminLinkForError = (
+ errorId?: string
+): string | undefined => {
+ if (!errorId) {
+ return;
+ }
+
+ const baseURL = `${window.location.origin}/admin/navigate/errors/${errorId}`;
+ const url = new URL(baseURL);
+
+ return url.toString();
+};