Skip to content

Commit c41e0f5

Browse files
committed
Support links to Span/Error in Web Admin
1 parent 6a8727a commit c41e0f5

File tree

18 files changed

+295
-20
lines changed

18 files changed

+295
-20
lines changed
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import { Navigate, useParams } from "react-router";
2+
import { useGetErrorEnvironmentQuery } from "../../../redux/services/digma";
3+
import { Spinner } from "../../common/v3/Spinner";
4+
import { TAB_IDS } from "../../Navigation/Tabs/types";
5+
import type { TabLocation } from "../common/RepositorySidebarOverlay/types";
6+
import * as s from "./styles";
7+
8+
const REFRESH_INTERVAL = 10 * 1000; // in milliseconds
9+
10+
export const ErrorLinkResolver = () => {
11+
const params = useParams();
12+
13+
const { data } = useGetErrorEnvironmentQuery(
14+
{
15+
id: params.id ?? ""
16+
},
17+
{
18+
skip: !params.id,
19+
pollingInterval: REFRESH_INTERVAL
20+
}
21+
);
22+
23+
if (!data) {
24+
return (
25+
<s.Container>
26+
<s.LoadingContainer>
27+
<Spinner size={50} />
28+
</s.LoadingContainer>
29+
</s.Container>
30+
);
31+
}
32+
33+
const sidebarLocation: TabLocation = {
34+
id: TAB_IDS.ERRORS,
35+
path: params.id
36+
};
37+
38+
if (data) {
39+
return (
40+
<Navigate
41+
replace={true}
42+
to={{
43+
pathname: "/home",
44+
search: new URLSearchParams({
45+
environment: data.environmentId,
46+
"sidebar-view": JSON.stringify(sidebarLocation)
47+
}).toString()
48+
}}
49+
/>
50+
);
51+
}
52+
};
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import styled from "styled-components";
2+
3+
export const Container = styled.div`
4+
display: flex;
5+
height: 100%;
6+
`;
7+
8+
export const LoadingContainer = styled.div`
9+
display: flex;
10+
align-items: center;
11+
justify-content: center;
12+
flex-grow: 1;
13+
`;

src/components/Admin/Header/index.tsx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,16 @@ export const Header = () => (
1616
</HeaderContent>
1717
}
1818
/>
19+
<Route path={"navigate"}>
20+
<Route
21+
path={"*"}
22+
element={
23+
<HeaderContent>
24+
<Greeting />
25+
</HeaderContent>
26+
}
27+
/>
28+
</Route>
1929
<Route path={"reports"}>
2030
<Route
2131
path={"*"}

src/components/Admin/Home/index.tsx

Lines changed: 81 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,37 @@ import {
55
} from "../../../containers/Admin/hooks";
66
import { useMount } from "../../../hooks/useMount";
77
import { useStableSearchParams } from "../../../hooks/useStableSearchParams";
8+
import { useGetSpanByIdQuery } from "../../../redux/services/digma";
89
import { InsightsSortingCriterion } from "../../../redux/services/types";
910
import {
1011
setSelectedEnvironmentId,
1112
setSelectedServices
1213
} from "../../../redux/slices/issuesReportSlice";
1314
import { RepositorySidebarOverlay } from "../common/RepositorySidebarOverlay";
14-
import type { RepositorySidebarQuery } from "../common/RepositorySidebarOverlay/types";
15+
import type {
16+
RepositorySidebarQuery,
17+
TabLocation
18+
} from "../common/RepositorySidebarOverlay/types";
1519
import { Environments } from "./Environments";
1620
import { Overview } from "./Overview";
1721
import { Reports } from "./Reports";
1822
import * as s from "./styles";
1923

24+
const getRepositorySidebarLocation = (
25+
locationParam: string | null
26+
): TabLocation | undefined => {
27+
if (!locationParam) {
28+
return undefined;
29+
}
30+
31+
try {
32+
const parsedLocation = JSON.parse(locationParam) as TabLocation;
33+
return parsedLocation;
34+
} catch {
35+
return undefined;
36+
}
37+
};
38+
2039
export const Home = () => {
2140
const environmentId = useAdminSelector(
2241
(state) => state.codeIssuesReport.selectedEnvironmentId
@@ -29,11 +48,26 @@ export const Home = () => {
2948
const [searchParams, setSearchParams] = useStableSearchParams();
3049
const environmentParam = searchParams.get("environment");
3150
const issuesParam = searchParams.get("issues");
51+
const [sidebarScope, setSidebarScope] = useState(
52+
searchParams.get("sidebar-scope") ?? undefined
53+
);
54+
const [sidebarLocation, setSidebarLocation] = useState(
55+
getRepositorySidebarLocation(searchParams.get("sidebar-view"))
56+
);
3257
const servicesParam = useMemo(
3358
() => searchParams.getAll("services"),
3459
[searchParams]
3560
);
3661

62+
const { data: spanInfo } = useGetSpanByIdQuery(
63+
{
64+
id: sidebarScope ?? ""
65+
},
66+
{
67+
skip: !sidebarScope
68+
}
69+
);
70+
3771
const queries: Record<string, RepositorySidebarQuery> = useMemo(
3872
() => ({
3973
"top-criticality": {
@@ -64,6 +98,8 @@ export const Home = () => {
6498

6599
const handleRepositorySidebarClose = () => {
66100
setIssuesQuery(undefined);
101+
setSidebarScope(undefined);
102+
setSidebarLocation(undefined);
67103
};
68104

69105
// TODO: replace with useEffect
@@ -112,7 +148,48 @@ export const Home = () => {
112148
});
113149
}, [setSearchParams, issuesQuery]);
114150

115-
const repositorySidebarQuery = issuesQuery ? queries[issuesQuery] : undefined;
151+
useEffect(() => {
152+
setSearchParams((params) => {
153+
if (sidebarScope) {
154+
params.set("sidebar-scope", sidebarScope);
155+
} else {
156+
params.delete("sidebar-scope");
157+
}
158+
return params;
159+
});
160+
}, [setSearchParams, sidebarScope]);
161+
162+
useEffect(() => {
163+
setSearchParams((params) => {
164+
if (sidebarLocation) {
165+
params.set("sidebar-view", JSON.stringify(sidebarLocation));
166+
} else {
167+
params.delete("sidebar-view");
168+
}
169+
return params;
170+
});
171+
}, [setSearchParams, sidebarLocation]);
172+
173+
const repositorySidebarQuery: RepositorySidebarQuery | undefined =
174+
sidebarScope && spanInfo
175+
? {
176+
query: {
177+
environment: environmentId ?? undefined,
178+
scopedSpanCodeObjectId: spanInfo?.spanCodeObjectId
179+
}
180+
}
181+
: sidebarLocation
182+
? {
183+
query: {
184+
environment: environmentId ?? undefined
185+
}
186+
}
187+
: issuesQuery
188+
? queries[issuesQuery]
189+
: undefined;
190+
const isRepositorySidebarOpen = Boolean(
191+
repositorySidebarQuery ?? sidebarLocation
192+
);
116193

117194
return (
118195
<s.Container>
@@ -124,7 +201,8 @@ export const Home = () => {
124201
<Environments />
125202
<RepositorySidebarOverlay
126203
sidebarQuery={repositorySidebarQuery}
127-
isSidebarOpen={Boolean(repositorySidebarQuery)}
204+
sidebarLocation={sidebarLocation}
205+
isSidebarOpen={isRepositorySidebarOpen}
128206
onSidebarClose={handleRepositorySidebarClose}
129207
/>
130208
</s.Container>
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import { Navigate, useParams } from "react-router";
2+
import { useGetSpanByIdQuery } from "../../../redux/services/digma";
3+
import { Spinner } from "../../common/v3/Spinner";
4+
import { TAB_IDS } from "../../Navigation/Tabs/types";
5+
import type { TabLocation } from "../common/RepositorySidebarOverlay/types";
6+
import * as s from "./styles";
7+
8+
const REFRESH_INTERVAL = 10 * 1000; // in milliseconds
9+
10+
export const SpanLinkResolver = () => {
11+
const params = useParams();
12+
13+
const { data } = useGetSpanByIdQuery(
14+
{
15+
id: params.id ?? ""
16+
},
17+
{
18+
skip: !params.id,
19+
pollingInterval: REFRESH_INTERVAL
20+
}
21+
);
22+
23+
if (!data) {
24+
return (
25+
<s.Container>
26+
<s.LoadingContainer>
27+
<Spinner size={50} />
28+
</s.LoadingContainer>
29+
</s.Container>
30+
);
31+
}
32+
33+
const sidebarLocation: TabLocation = {
34+
id: TAB_IDS.ISSUES
35+
};
36+
37+
if (data) {
38+
return (
39+
<Navigate
40+
replace={true}
41+
to={{
42+
pathname: "/home",
43+
search: new URLSearchParams({
44+
environment: data.environmentId,
45+
"sidebar-scope": params.id ?? "",
46+
"sidebar-view": JSON.stringify(sidebarLocation)
47+
}).toString()
48+
}}
49+
/>
50+
);
51+
}
52+
};
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import styled from "styled-components";
2+
3+
export const Container = styled.div`
4+
display: flex;
5+
height: 100%;
6+
`;
7+
8+
export const LoadingContainer = styled.div`
9+
display: flex;
10+
align-items: center;
11+
justify-content: center;
12+
flex-grow: 1;
13+
`;

src/components/Admin/common/RepositorySidebarOverlay/RepositorySidebar/Issues/index.tsx

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
setIssuesInsightInfoToOpenTicket,
1111
setScope
1212
} from "../../../../../../redux/slices/repositorySlice";
13+
import { initialState } from "../../../../../../store/insights/insightsSlice";
1314
import { useStore } from "../../../../../../store/useStore";
1415
import { useInsightsData } from "../../../../../Insights/hooks/useInsightsData";
1516
import { InsightsContent } from "../../../../../Insights/InsightsContent";
@@ -24,7 +25,7 @@ export const Issues = ({
2425
onScopeChange,
2526
onGoToTab
2627
}: IssuesProps) => {
27-
const { setInsightViewType } = useStore.getState();
28+
const { setInsightViewType, setInsightsSorting } = useStore.getState();
2829
const [isDrawerTransitioning, setIsDrawerTransitioning] = useState(false);
2930
const drawerRef = useRef<HTMLDivElement>(null);
3031
const dispatch = useAdminDispatch();
@@ -110,6 +111,14 @@ export const Issues = ({
110111
);
111112
}, [query, dispatch]);
112113

114+
// Set sorting on query change
115+
useEffect(() => {
116+
setInsightsSorting({
117+
criterion: query?.sortBy ?? initialState.sorting.criterion,
118+
order: query?.sortOrder ?? initialState.sorting.order
119+
});
120+
}, [query?.sortBy, query?.sortOrder, setInsightsSorting]);
121+
113122
return (
114123
<s.Container>
115124
<InsightsContent

src/components/Admin/common/RepositorySidebarOverlay/index.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,11 +55,13 @@ export const RepositorySidebarOverlay = ({
5555
isSidebarOpen,
5656
onSidebarClose,
5757
sidebarQuery,
58-
scopeDisplayName
58+
scopeDisplayName,
59+
sidebarLocation
5960
}: RepositorySidebarOverlayProps) => {
6061
const [isSidebarTransitioning, setIsSidebarTransitioning] = useState(false);
61-
const [currentTabLocation, setCurrentTabLocation] =
62-
useState<TabLocation>(initialTabLocation);
62+
const [currentTabLocation, setCurrentTabLocation] = useState<TabLocation>(
63+
sidebarLocation ?? initialTabLocation
64+
);
6365
const [currentSpanCodeObjectId, setCurrentSpanCodeObjectId] = useState(
6466
sidebarQuery?.query?.scopedSpanCodeObjectId
6567
);

src/components/Admin/common/RepositorySidebarOverlay/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ export interface RepositorySidebarOverlayProps {
88
isSidebarOpen: boolean;
99
onSidebarClose: () => void;
1010
sidebarQuery?: RepositorySidebarQuery;
11+
sidebarLocation?: TabLocation;
1112
scopeDisplayName?: string;
1213
}
1314

src/components/Agentic/IncidentDetails/AdditionalInfo/RelatedIssues/index.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ import { useStableSearchParams } from "../../../../../hooks/useStableSearchParam
55
import { useGetIncidentQuery } from "../../../../../redux/services/digma";
66
import type { GenericIncidentIssue } from "../../../../../redux/services/types";
77
import { sendUserActionTrackingEvent } from "../../../../../utils/actions/sendUserActionTrackingEvent";
8-
import { getIdeLauncherLinkForError } from "../../../../../utils/getIdeLauncherLinkForError";
9-
import { getIdeLauncherLinkForSpan } from "../../../../../utils/getIdeLauncherLinkForSpan";
108
import { getInsightTypeInfo } from "../../../../../utils/getInsightTypeInfo";
9+
import { getWebAdminLinkForSpan } from "../../../../../utils/getWebAdminLinkForSpan";
10+
import { getWebAdminLinkForError } from "../../../../../utils/getWebAdminLinkToError";
1111
import { roundTo } from "../../../../../utils/roundTo";
1212
import type { TagType } from "../../../../common/v3/Tag/types";
1313
import { Tooltip } from "../../../../common/v3/Tooltip";
@@ -97,7 +97,7 @@ export const RelatedIssues = () => {
9797
{issue.span_uid ? (
9898
<s.Link
9999
onClick={handleIssueLinkClick}
100-
href={getIdeLauncherLinkForSpan(issue.span_uid)}
100+
href={getWebAdminLinkForSpan(issue.span_uid)}
101101
target={"_blank"}
102102
rel={"noopener noreferrer"}
103103
>
@@ -118,7 +118,7 @@ export const RelatedIssues = () => {
118118
<Tooltip title={label}>
119119
<s.Link
120120
onClick={handleIssueLinkClick}
121-
href={getIdeLauncherLinkForError(issue.issue_id)}
121+
href={getWebAdminLinkForError(issue.issue_id)}
122122
target={"_blank"}
123123
rel={"noopener noreferrer"}
124124
>

0 commit comments

Comments
 (0)