Skip to content

Commit 5b64b03

Browse files
committed
Use links with custom scheme
1 parent 7dd14b9 commit 5b64b03

File tree

5 files changed

+61
-167
lines changed

5 files changed

+61
-167
lines changed
Lines changed: 6 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,7 @@
1-
import axios, { isAxiosError } from "axios";
2-
import type { AddChatContextFileResult } from "../types";
3-
4-
export const addChatContextFile = async (
5-
port: number,
6-
file: {
7-
name: string;
8-
content: string;
9-
}
10-
): Promise<AddChatContextFileResult> => {
11-
try {
12-
await axios.post(
13-
`http://localhost:${port}/api/digma/chat/context/file`,
14-
file
15-
);
16-
return { result: "success" };
17-
} catch (error) {
18-
return {
19-
result: "failure",
20-
error: {
21-
message: isAxiosError(error)
22-
? error.message
23-
: "Failed to add file to the chat context"
24-
}
25-
};
26-
}
1+
export const addChatContextIncidentFile = (
2+
ideUriScheme: string,
3+
incidentId: string
4+
): void => {
5+
const url = `${ideUriScheme}://digma.digma/chat/context/add/file/incident/${incidentId}`;
6+
window.open(url, "_blank", "noopener noreferrer");
277
};

src/components/IdeLauncher/IncidentDetails/index.tsx

Lines changed: 38 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
1-
import { formatISO } from "date-fns";
21
import { useCallback, useEffect, useState } from "react";
32
import { useParams } from "react-router";
4-
import { useGetIncidentQuery } from "../../../redux/services/digma";
5-
import type { GetIncidentResponse } from "../../../redux/services/types";
3+
import { usePrevious } from "../../../hooks/usePrevious";
64
import { isString } from "../../../typeGuards/isString";
7-
import { sendTrackingEvent } from "../../../utils/actions/sendTrackingEvent";
85
import { sendUserActionTrackingEvent } from "../../../utils/actions/sendUserActionTrackingEvent";
6+
import { uniqueBy } from "../../../utils/uniqueBy";
97
import {
108
Subtitle,
119
TextContainer,
@@ -14,55 +12,30 @@ import {
1412
import { NewButton } from "../../common/v3/NewButton";
1513
import type { SelectItem } from "../../common/v3/Select/types";
1614
import { IdeProjectSelect } from "../common/IdeProjectSelect";
17-
import { getSelectItemValue } from "../common/IdeProjectSelect/utils/getSelectedItemValue";
18-
import { parseSelectedItemValue } from "../common/IdeProjectSelect/utils/parseSelectedItemValue";
1915
import { scanRunningVSCodeIdeProjects } from "../scanRunningVSCodeIdeProjects";
2016
import { ButtonsContainer, EmphasizedText } from "../styles";
2117
import { trackingEvents } from "../tracking";
22-
import type { AddChatContextFileResult } from "../types";
23-
import { addChatContextFile } from "./addChatContextFile";
18+
import { addChatContextIncidentFile } from "./addChatContextFile";
2419

2520
export const IncidentDetails = () => {
2621
const params = useParams();
2722
const incidentId = params.id;
2823
const [selectItems, setSelectItems] = useState<SelectItem[]>();
2924
const [isIdeProjectScanningInProgress, setIsIdeProjectScanningInProgress] =
3025
useState(false);
26+
const previousIsProjectScanningInProgress = usePrevious(
27+
isIdeProjectScanningInProgress
28+
);
3129
const [
3230
isAddingChatContextFileInProgress,
3331
setAddingChatContextFileInProgress
3432
] = useState(false);
35-
const [addChatContextFileResult, setAddChatContextFileResult] =
36-
useState<AddChatContextFileResult>();
37-
38-
const {
39-
data: incidentData,
40-
isLoading,
41-
error
42-
} = useGetIncidentQuery(
43-
{ id: incidentId ?? "" },
44-
{
45-
skip: !incidentId
46-
}
47-
);
4833

4934
const tryToAddChatContextFile = useCallback(
50-
async (
51-
port: number,
52-
incidentId: string,
53-
incidentData: GetIncidentResponse
54-
) => {
55-
setAddChatContextFileResult(undefined);
35+
(ideUriScheme: string, incidentId: string) => {
5636
setAddingChatContextFileInProgress(true);
57-
const result = await addChatContextFile(port, {
58-
name: `incident-${incidentId}-${formatISO(new Date(), { format: "basic" })}.json`,
59-
content: JSON.stringify(incidentData, null, 2)
60-
});
61-
sendTrackingEvent(trackingEvents.IDE_CHAT_CONTEXT_FILE_RESULT_RECEIVED, {
62-
result
63-
});
64-
setAddChatContextFileResult(result);
65-
setAddingChatContextFileInProgress(false);
37+
38+
addChatContextIncidentFile(ideUriScheme, incidentId);
6639
},
6740
[]
6841
);
@@ -73,31 +46,43 @@ export const IncidentDetails = () => {
7346
const result = await scanRunningVSCodeIdeProjects();
7447
setIsIdeProjectScanningInProgress(false);
7548

49+
const ides = uniqueBy(
50+
result.map((x) => x.response),
51+
"ideUriScheme"
52+
);
53+
7654
setSelectItems(
77-
result.map((x, i) => ({
78-
label: `${x.response.ideName} (${x.response.workspace})`,
79-
description: `${x.response.ideName} (${x.response.workspace})`,
80-
value: getSelectItemValue(x.port, x.response.workspace),
55+
ides.map((x, i) => ({
56+
label: x.ideName,
57+
description: x.ideName,
58+
value: x.ideUriScheme,
8159
enabled: true,
8260
selected: result.length === 1 && i === 0
8361
}))
8462
);
8563
}, []);
8664

65+
// Automatically select the first IDE if there is only one available
8766
useEffect(() => {
88-
if (selectItems && selectItems.length === 1 && incidentId && incidentData) {
89-
void tryToAddChatContextFile(
90-
parseSelectedItemValue(selectItems[0].value).port,
91-
incidentId,
92-
incidentData
93-
);
94-
}
95-
}, [incidentId, incidentData, tryToAddChatContextFile, selectItems]);
96-
97-
const handleSelectChange = async (value: string | string[]) => {
67+
if (
68+
previousIsProjectScanningInProgress &&
69+
!isIdeProjectScanningInProgress &&
70+
selectItems?.length === 1 &&
71+
incidentId
72+
) {
73+
tryToAddChatContextFile(selectItems[0].value, incidentId);
74+
}
75+
}, [
76+
incidentId,
77+
isIdeProjectScanningInProgress,
78+
previousIsProjectScanningInProgress,
79+
tryToAddChatContextFile,
80+
selectItems
81+
]);
82+
83+
const handleSelectChange = (value: string | string[]) => {
9884
sendUserActionTrackingEvent(trackingEvents.IDE_PROJECT_SELECTED);
9985
const selectedValue = isString(value) ? value : value[0];
100-
const { port } = parseSelectedItemValue(selectedValue);
10186

10287
if (!selectItems) {
10388
return;
@@ -110,11 +95,11 @@ export const IncidentDetails = () => {
11095
}))
11196
);
11297

113-
if (!incidentId || !incidentData) {
98+
if (!incidentId) {
11499
return;
115100
}
116101

117-
await tryToAddChatContextFile(port, incidentId, incidentData);
102+
tryToAddChatContextFile(selectedValue, incidentId);
118103
};
119104

120105
const handleTryScanningAgainButtonClick = () => {
@@ -124,21 +109,6 @@ export const IncidentDetails = () => {
124109
window.location.reload();
125110
};
126111

127-
const handleTryShowIdeProjectAgainButtonClick = async () => {
128-
sendUserActionTrackingEvent(trackingEvents.TRY_AGAIN_BUTTON_CLICKED);
129-
const selectedItemValue = selectItems?.find((item) => item.selected)?.value;
130-
if (!selectedItemValue) {
131-
return;
132-
}
133-
134-
if (!incidentId || !incidentData) {
135-
return;
136-
}
137-
138-
const { port } = parseSelectedItemValue(selectedItemValue);
139-
await tryToAddChatContextFile(port, incidentId, incidentData);
140-
};
141-
142112
// const handleGetDigmaButtonClick = () => {
143113
// sendUserActionTrackingEvent(trackingEvents.GET_DIGMA_BUTTON_CLICKED);
144114
// window.open(
@@ -165,22 +135,6 @@ export const IncidentDetails = () => {
165135
);
166136
}
167137

168-
if (!incidentData && isLoading) {
169-
return (
170-
<TextContainer>
171-
<Title>Getting incident details</Title>
172-
</TextContainer>
173-
);
174-
}
175-
176-
if (!incidentData && error) {
177-
return (
178-
<TextContainer>
179-
<Title>Failed to get incident details</Title>
180-
</TextContainer>
181-
);
182-
}
183-
184138
if (isIdeProjectScanningInProgress) {
185139
return (
186140
<TextContainer>
@@ -201,40 +155,6 @@ export const IncidentDetails = () => {
201155
);
202156
}
203157

204-
if (addChatContextFileResult?.result === "failure") {
205-
return (
206-
<>
207-
<TextContainer>
208-
<Title>
209-
There was an issue adding the incident details to the IDE chat
210-
context
211-
</Title>
212-
<Subtitle>
213-
Please check that IDE is running and click the{" "}
214-
<EmphasizedText>Try again</EmphasizedText> button below.
215-
</Subtitle>
216-
</TextContainer>
217-
<NewButton
218-
label={"Try again"}
219-
onClick={() => {
220-
void handleTryShowIdeProjectAgainButtonClick();
221-
}}
222-
/>
223-
</>
224-
);
225-
}
226-
227-
if (addChatContextFileResult?.result === "success") {
228-
return (
229-
<TextContainer>
230-
<Title>
231-
Incident details have been added to the IDE chat context
232-
</Title>
233-
<Subtitle>You can close this tab.</Subtitle>
234-
</TextContainer>
235-
);
236-
}
237-
238158
if (!selectItems) {
239159
return null;
240160
}

src/components/IdeLauncher/scanRunningVSCodeIdeProjects.ts

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,16 @@ import type {
66
VSCodeIdeScanningResult
77
} from "./types";
88

9-
const PORT_RANGES_TO_SCAN = [
10-
[33100, 33119], // VS Code
11-
[33200, 33219], // Cursor
12-
[33300, 33319], // Windsurf
13-
[33400, 33419] // Unknown VS Code fork
14-
];
9+
const START_PORT_TO_SCAN = 33100;
10+
const END_PORT_TO_SCAN = 33119;
1511

1612
const ABOUT_PATH = "api/digma/about";
1713

1814
export const scanRunningVSCodeIdeProjects =
1915
async (): Promise<VSCodeIdeScanningResult> => {
20-
const instances = PORT_RANGES_TO_SCAN.flatMap(([start, end]) =>
21-
Array.from({ length: end - start + 1 }, (_, i) => start + i)
16+
const instances = Array.from(
17+
{ length: END_PORT_TO_SCAN - START_PORT_TO_SCAN + 1 },
18+
(_, i) => START_PORT_TO_SCAN + i
2219
).map((port) => ({
2320
port,
2421
url: `http://localhost:${port}/${ABOUT_PATH}`

src/components/IdeLauncher/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ export interface IntellijPluginInfo {
1313

1414
export interface VSCodeExtensionInfo {
1515
ideName: string;
16+
ideUriScheme: string;
1617
ideVersion: string;
1718
workspace: string;
1819
}

webpack.dev.ts

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -44,26 +44,22 @@ const apiProxyClient = axios.create({
4444
});
4545

4646
const login = async (credentials: Credentials) => {
47-
const response = await apiProxyClient.post<{
48-
accessToken: string;
49-
refreshToken: string;
50-
expiration: string;
51-
userId: string;
52-
}>("/authentication/login", credentials);
47+
const response = await apiProxyClient.post<Session>(
48+
"/authentication/login",
49+
credentials
50+
);
5351

5452
return response.data;
5553
};
5654

5755
const refreshToken = async (session: Session) => {
58-
const response = await apiProxyClient.post<{
59-
accessToken: string;
60-
refreshToken: string;
61-
expiration: string;
62-
userId: string;
63-
}>("/authentication/refresh-token", {
64-
accessToken: session.accessToken,
65-
refreshToken: session.refreshToken
66-
});
56+
const response = await apiProxyClient.post<Session>(
57+
"/authentication/refresh-token",
58+
{
59+
accessToken: session.accessToken,
60+
refreshToken: session.refreshToken
61+
}
62+
);
6763

6864
return response.data;
6965
};

0 commit comments

Comments
 (0)