@@ -18,6 +18,7 @@ import { initiateRemoteCommunicationChannelSocket } from "./lib/remote";
18
18
import { Emitter } from "@gitpod/gitpod-protocol/lib/util/event" ;
19
19
import { DisposableCollection } from "@gitpod/gitpod-protocol/lib/util/disposable" ;
20
20
import debounce from "lodash/debounce" ;
21
+ import { type UUID } from "node:crypto" ;
21
22
22
23
const onDidChangeState = new Emitter < void > ( ) ;
23
24
let state : IDEFrontendState = "initializing" as IDEFrontendState ;
@@ -104,6 +105,7 @@ async function initiateRemoteTerminal(terminal: Terminal): Promise<void | Reconn
104
105
if ( ! initialTerminalResizeRequest . ok ) {
105
106
output ( "Could not setup IDE. Retry?" , {
106
107
formActions : [ reloadButton ] ,
108
+ reason : "error" ,
107
109
} ) ;
108
110
return ;
109
111
}
@@ -118,7 +120,6 @@ async function initiateRemoteTerminal(terminal: Terminal): Promise<void | Reconn
118
120
119
121
const socket = new ReconnectingWebSocket ( socketURL , [ ] , webSocketSettings ) ;
120
122
socket . onopen = async ( ) => {
121
- outputDialog . close ( ) ;
122
123
( document . querySelector ( ".xterm-helper-textarea" ) as HTMLTextAreaElement ) . focus ( ) ;
123
124
124
125
await runRealTerminal ( term , socket as WebSocket ) ;
@@ -228,14 +229,18 @@ function handleDisconnected(e: CloseEvent | ErrorEvent, socket: ReconnectingWebS
228
229
case 1005 :
229
230
output ( "For some reason the WebSocket closed. Reload?" , {
230
231
formActions : [ reconnectButton , reloadButton ] ,
232
+ reason : "error" ,
231
233
} ) ;
232
234
case 1006 :
233
235
if ( navigator . onLine ) {
234
236
output ( "Cannot reach workspace, consider reloading" , {
235
237
formActions : [ reloadButton ] ,
238
+ reason : "error" ,
236
239
} ) ;
237
240
} else {
238
- output ( "You are offline, please connect to the internet and refresh this page" ) ;
241
+ output ( "You are offline, please connect to the internet and refresh this page" , {
242
+ reason : "error" ,
243
+ } ) ;
239
244
}
240
245
break ;
241
246
default :
@@ -246,19 +251,57 @@ function handleDisconnected(e: CloseEvent | ErrorEvent, socket: ReconnectingWebS
246
251
console . error ( e ) ;
247
252
}
248
253
249
- const outputDialog = document . getElementById ( "output" ) as HTMLDialogElement ;
250
- const outputContent = document . getElementById ( "outputContent" ) ! ;
251
- function output ( message : string , options ?: { formActions : HTMLInputElement [ ] | HTMLButtonElement [ ] } ) {
252
- if ( typeof outputDialog . showModal === "function" ) {
253
- outputContent . innerText = message ;
254
- if ( options ?. formActions ) {
255
- for ( const action of options . formActions ) {
256
- outputDialog . querySelector ( "form" ) ! . appendChild ( action ) ;
257
- }
258
- }
259
- outputDialog . showModal ( ) ;
254
+ type OutputReason = "info" | "error" ;
255
+
256
+ const outputStack = new Set < UUID > ( ) ;
257
+ export const output = (
258
+ message : string ,
259
+ options ?: { formActions ?: ( HTMLInputElement | HTMLButtonElement ) [ ] ; reason ?: OutputReason } ,
260
+ ) : UUID => {
261
+ const outputId = crypto . randomUUID ( ) ;
262
+ const dialogElement = document . createElement ( "dialog" ) ;
263
+ dialogElement . id = outputId ;
264
+
265
+ const outputContent = document . createElement ( "p" ) ;
266
+ outputContent . innerText = message ;
267
+ dialogElement . appendChild ( outputContent ) ;
268
+
269
+ const outputForm = document . createElement ( "form" ) ;
270
+ outputForm . method = "dialog" ;
271
+ const formActions = options ?. formActions ?? [ ] ;
272
+ const dismissButton = document . createElement ( "button" ) ;
273
+ dismissButton . innerText = "Dismiss" ;
274
+ formActions . push ( dismissButton ) ;
275
+ for ( const action of formActions ) {
276
+ outputForm . appendChild ( action ) ;
260
277
}
261
- }
278
+
279
+ const outputReasonInput = document . createElement ( "input" ) ;
280
+ outputReasonInput . type = "hidden" ;
281
+ outputReasonInput . value = options ?. reason ?? "info" ;
282
+ outputForm . appendChild ( outputReasonInput ) ;
283
+
284
+ dialogElement . appendChild ( outputForm ) ;
285
+
286
+ document . body . appendChild ( dialogElement ) ;
287
+ dialogElement . showModal ( ) ;
288
+
289
+ outputStack . add ( outputId ) ;
290
+
291
+ return outputId ;
292
+ } ;
293
+
294
+ export const closeModal = ( id : UUID ) => {
295
+ const dialogElement = document . getElementById ( id ) as HTMLDialogElement ;
296
+ if ( ! dialogElement ) {
297
+ console . warn ( `Could not find dialog with ID ${ id } ` ) ;
298
+ return ;
299
+ }
300
+
301
+ dialogElement . close ( ) ;
302
+ dialogElement . remove ( ) ;
303
+ outputStack . delete ( id ) ;
304
+ } ;
262
305
263
306
let attachAddon : AttachAddon ;
264
307
@@ -306,6 +349,9 @@ window.gitpod.ideService = {
306
349
toDispose . push ( {
307
350
dispose : ( ) => {
308
351
socket . close ( ) ;
352
+ for ( const id of outputStack ) {
353
+ closeModal ( id ) ;
354
+ }
309
355
} ,
310
356
} ) ;
311
357
} ) ;
0 commit comments