1- import axios from "axios" ;
2- import { useEffect , useState } from "react" ;
1+ import { useCallback , useEffect , useState } from "react" ;
32import { Helmet } from "react-helmet" ;
43import { useTheme } from "styled-components" ;
54import { isString } from "../../typeGuards/isString" ;
65import { getThemeKind } from "../common/App/styles" ;
6+ import { NewButton } from "../common/v3/NewButton" ;
77import { Select } from "../common/v3/Select" ;
88import { SelectItem } from "../common/v3/Select/types" ;
9- import { scanIDEs } from "./scanIDEs" ;
9+ import { scanRunningIdeProjects } from "./scanRunningIdeProjects" ;
10+ import { showIdeProject } from "./showIdeProject" ;
1011import * as s from "./styles" ;
12+ import { ShowIdeProjectResult } from "./types" ;
1113
1214const SELECT_VALUE_DELIMITER = ":" ;
1315
16+ const getSelectItemValue = ( port : number , project : string ) =>
17+ `${ port } ${ SELECT_VALUE_DELIMITER } ${ project } ` ;
18+
19+ const parseSelectedItemValue = ( value : string ) => {
20+ const [ port , project ] = value . split ( SELECT_VALUE_DELIMITER ) ;
21+ return { port : Number ( port ) , project } ;
22+ } ;
23+
1424const getURLQueryParams = ( url : string ) => {
1525 const searchParams = new URLSearchParams ( url ) ;
1626 const params : Record < string , string > = { } ;
@@ -23,126 +33,198 @@ const getURLQueryParams = (url: string) => {
2333export const IdeLauncher = ( ) => {
2434 const theme = useTheme ( ) ;
2535 const themeKind = getThemeKind ( theme ) ;
26- const [ isInitialLoading , setInitialLoading ] = useState ( true ) ;
27- // const [isOpening, setIsOpening] = useState(false);
28- const [ items , setItems ] = useState < SelectItem [ ] > ( [ ] ) ;
29- const params = getURLQueryParams ( window . location . search ) ;
36+ const [ selectItems , setSelectItems ] = useState < SelectItem [ ] > ( ) ;
3037 const isMobile = [ "Android" , "iPhone" , "iPad" ] . some ( ( x ) =>
3138 window . navigator . userAgent . includes ( x )
3239 ) ;
40+ const [ isIdeProjectScanningInProgress , setIsIdeProjectScanningInProgress ] =
41+ useState ( false ) ;
42+ const [ isShowIdeProjectInProgress , setIsShowIdeProjectInProgress ] =
43+ useState ( false ) ;
44+ const [ showIdeProjectResult , setShowIdeProjectResult ] =
45+ useState < ShowIdeProjectResult > ( ) ;
46+
47+ const tryToShowIdeProject = useCallback (
48+ async ( port : number , project : string ) => {
49+ setShowIdeProjectResult ( undefined ) ;
50+ setIsShowIdeProjectInProgress ( true ) ;
51+ const params = getURLQueryParams ( window . location . search ) ;
52+ const result = await showIdeProject ( port , project , params ) ;
53+ setShowIdeProjectResult ( result ) ;
54+ setIsShowIdeProjectInProgress ( false ) ;
55+ } ,
56+ [ ]
57+ ) ;
58+
59+ const tryToScanRunningIdeProjects = useCallback ( async ( ) => {
60+ setSelectItems ( undefined ) ;
61+ setIsIdeProjectScanningInProgress ( true ) ;
62+ const result = await scanRunningIdeProjects ( ) ;
63+ setIsIdeProjectScanningInProgress ( false ) ;
64+
65+ const projects = result
66+ . filter ( ( x ) => x . response . isCentralized )
67+ . flatMap ( ( info ) =>
68+ info . response . openProjects . map ( ( project ) => ( {
69+ ...info ,
70+ project : project ,
71+ port : info . port
72+ } ) )
73+ ) ;
74+
75+ setSelectItems (
76+ projects . map ( ( x , i ) => ( {
77+ label : `${ x . response . name } (${ x . project } )` ,
78+ description : `${ x . response . name } (${ x . project } )` ,
79+ value : getSelectItemValue ( x . port , x . project ) ,
80+ enabled : true ,
81+ selected : projects . length === 1 && i === 0
82+ } ) )
83+ ) ;
84+
85+ if ( projects . length === 1 ) {
86+ await tryToShowIdeProject ( projects [ 0 ] . port , projects [ 0 ] . project ) ;
87+ }
88+ } , [ tryToShowIdeProject ] ) ;
3389
3490 const handleSelectChange = ( value : string | string [ ] ) => {
3591 const selectedValue = isString ( value ) ? value : value [ 0 ] ;
36- const [ port , project ] = selectedValue . split ( SELECT_VALUE_DELIMITER ) ;
3792
38- const pluginParams = Object . entries ( params ) . reduce ( ( acc , [ key , value ] ) => {
39- const KEY_PREFIX = "plugin." ;
40- if ( key . startsWith ( KEY_PREFIX ) ) {
41- const newKey = key . replace ( KEY_PREFIX , "" ) ;
42- acc [ newKey ] = value ;
93+ setSelectItems ( ( prev ) => {
94+ if ( ! prev ) {
95+ return prev ;
4396 }
4497
45- return acc ;
46- } , { } as Record < string , string > ) ;
47-
48- axios
49- . get ( `http://localhost:${ port } /api/digma/show` , {
50- params : { ...pluginParams , projectName : project }
51- } )
52- . then ( ( ) => {
53- // TODO: handle response
54- } )
55- . catch ( ( ) => {
56- // TODO: handle error
57- } ) ;
58-
59- // setIsOpening(true);
60-
61- const itemToSelect = items . find ( ( item ) => item . value === selectedValue ) ;
62- setItems (
63- items . map ( ( item ) => ( { ...item , selected : item === itemToSelect } ) )
64- ) ;
98+ return prev . map ( ( item ) => ( {
99+ ...item ,
100+ selected : item . value === selectedValue
101+ } ) ) ;
102+ } ) ;
103+ } ;
104+
105+ const handleRefreshButtonClick = ( ) => {
106+ window . location . reload ( ) ;
107+ } ;
108+
109+ const handleTryAgainButtonClick = async ( ) => {
110+ const selectedItemValue = selectItems ?. find ( ( item ) => item . selected ) ?. value ;
111+ if ( ! selectedItemValue ) {
112+ return ;
113+ }
114+
115+ const { port, project } = parseSelectedItemValue ( selectedItemValue ) ;
116+ await tryToShowIdeProject ( port , project ) ;
65117 } ;
66118
67119 useEffect ( ( ) => {
68- async function getIDEsInfo ( ) {
69- const ideInfo = await scanIDEs ( ) ;
70- const projects = ideInfo
71- . filter ( ( x ) => x . response . isCentralized )
72- . flatMap ( ( info ) =>
73- info . response . openProjects . map ( ( project ) => ( {
74- ...info ,
75- project : project ,
76- port : info . port
77- } ) )
78- ) ;
79-
80- setItems (
81- projects . map ( ( x ) => ( {
82- label : `${ x . response . name } (${ x . project } )` ,
83- description : `${ x . response . name } (${ x . project } )` ,
84- value : [ x . port , x . project ] . join ( SELECT_VALUE_DELIMITER ) ,
85- enabled : true ,
86- selected : false
87- } ) )
88- ) ;
89- setInitialLoading ( false ) ;
120+ async function initialScan ( ) {
121+ await tryToScanRunningIdeProjects ( ) ;
90122 }
91123
92124 if ( ! isMobile ) {
93- void getIDEsInfo ( ) ;
125+ void initialScan ( ) ;
94126 }
95- } , [ isMobile ] ) ;
127+ } , [ isMobile , tryToScanRunningIdeProjects ] ) ;
96128
97- const selectedItem = items . find ( ( item ) => item . selected ) ;
129+ const selectedItem = selectItems ? .find ( ( item ) => item . selected ) ;
98130
99131 const renderContent = ( ) => {
100132 if ( isMobile ) {
101133 return (
102134 < s . TextContainer >
103- < s . Title > Failed to open </ s . Title >
135+ < s . Title > Unsupported platform </ s . Title >
104136 < s . Description >
105- This cannot be opened on your mobile device. Please switch to a
106- desktop with an IDE installed.
137+ The IDE cannot be opened on this device.
107138 </ s . Description >
108139 </ s . TextContainer >
109140 ) ;
110141 }
111142
112- return isInitialLoading ? (
113- < > Scanning running IDEs...</ >
114- ) : (
115- < >
143+ if ( isIdeProjectScanningInProgress ) {
144+ return (
116145 < s . TextContainer >
117- < s . Title > Select an IDE to view the Digma issue</ s . Title >
118- < s . Description >
119- { items . length > 0 ? (
120- < >
121- Please select the IDE project you'd like to open all
122- endpoints in the { params . environment ?? "selected" } environment.
123- </ >
124- ) : (
125- < > No IDEs with enabled Digma plugin found</ >
126- ) }
127- </ s . Description >
146+ < s . Title > Looking for running IDEs...</ s . Title >
128147 </ s . TextContainer >
129- { items . length > 0 && (
148+ ) ;
149+ }
150+
151+ if ( isShowIdeProjectInProgress ) {
152+ return (
153+ < s . TextContainer >
154+ < s . Title >
155+ Opening the { selectedItem ?. label ?? "IDE project" } ...
156+ </ s . Title >
157+ </ s . TextContainer >
158+ ) ;
159+ }
160+
161+ if ( showIdeProjectResult ?. error ) {
162+ return (
163+ < >
164+ < s . TextContainer >
165+ < s . Title >
166+ Failed to open the { selectedItem ?. label ?? "IDE project" }
167+ </ s . Title >
168+ < s . Description >
169+ Please check that IDE is running and click the{ " " }
170+ < s . ButtonName > Try again</ s . ButtonName > button below.
171+ </ s . Description >
172+ </ s . TextContainer >
173+ < NewButton
174+ label = { "Try again" }
175+ onClick = { ( ) => {
176+ void handleTryAgainButtonClick ( ) ;
177+ } }
178+ />
179+ </ >
180+ ) ;
181+ }
182+
183+ if ( ! selectItems ) {
184+ return null ;
185+ }
186+
187+ if ( selectItems . length === 0 ) {
188+ return (
189+ < >
190+ < s . TextContainer >
191+ < s . Title > Failed to find IDEs with Digma plugin running</ s . Title >
192+ < s . Description >
193+ Please open the IDE with Digma plugin installed, check its
194+ settings and click the < s . ButtonName > Refresh</ s . ButtonName > button
195+ below.
196+ </ s . Description >
197+ </ s . TextContainer >
198+ < NewButton label = { "Refresh" } onClick = { handleRefreshButtonClick } />
199+ </ >
200+ ) ;
201+ }
202+
203+ if ( selectItems . length > 0 ) {
204+ return (
205+ < >
206+ < s . TextContainer >
207+ < s . Title > Select the IDE project to view issues in Digma</ s . Title >
208+ < s . Description >
209+ Please select the IDE project you'd like to open.
210+ </ s . Description >
211+ </ s . TextContainer >
130212 < s . SelectContainer >
131213 < Select
132214 placeholder = { selectedItem ?. label ?? "Select IDE Project" }
133- items = { items }
215+ items = { selectItems }
134216 onChange = { handleSelectChange }
135217 />
136218 </ s . SelectContainer >
137- ) }
138- </ >
139- ) ;
219+ </ >
220+ ) ;
221+ }
140222 } ;
141223
142224 return (
143225 < s . Container >
144226 < Helmet >
145- < title > IDE Launcher</ title >
227+ < title > Digma IDE Plugin Launcher</ title >
146228 </ Helmet >
147229 < s . Header >
148230 < a
@@ -153,7 +235,6 @@ export const IdeLauncher = () => {
153235 < s . Logo src = { `/images/digmaLogo_${ themeKind } .svg` } />
154236 </ a >
155237 </ s . Header >
156-
157238 < s . Content > { renderContent ( ) } </ s . Content >
158239 < s . Footer >
159240 < span > © { new Date ( ) . getFullYear ( ) } </ span >
0 commit comments