@@ -18,6 +18,7 @@ import { initiateRemoteCommunicationChannelSocket } from "./lib/remote";
1818import { Emitter } from "@gitpod/gitpod-protocol/lib/util/event" ;
1919import { DisposableCollection } from "@gitpod/gitpod-protocol/lib/util/disposable" ;
2020import debounce from "lodash/debounce" ;
21+ import { type UUID } from "node:crypto" ;
2122
2223const onDidChangeState = new Emitter < void > ( ) ;
2324let state : IDEFrontendState = "initializing" as IDEFrontendState ;
@@ -104,6 +105,7 @@ async function initiateRemoteTerminal(terminal: Terminal): Promise<void | Reconn
104105 if ( ! initialTerminalResizeRequest . ok ) {
105106 output ( "Could not setup IDE. Retry?" , {
106107 formActions : [ reloadButton ] ,
108+ reason : "error" ,
107109 } ) ;
108110 return ;
109111 }
@@ -118,7 +120,6 @@ async function initiateRemoteTerminal(terminal: Terminal): Promise<void | Reconn
118120
119121 const socket = new ReconnectingWebSocket ( socketURL , [ ] , webSocketSettings ) ;
120122 socket . onopen = async ( ) => {
121- outputDialog . close ( ) ;
122123 ( document . querySelector ( ".xterm-helper-textarea" ) as HTMLTextAreaElement ) . focus ( ) ;
123124
124125 await runRealTerminal ( term , socket as WebSocket ) ;
@@ -228,14 +229,18 @@ function handleDisconnected(e: CloseEvent | ErrorEvent, socket: ReconnectingWebS
228229 case 1005 :
229230 output ( "For some reason the WebSocket closed. Reload?" , {
230231 formActions : [ reconnectButton , reloadButton ] ,
232+ reason : "error" ,
231233 } ) ;
232234 case 1006 :
233235 if ( navigator . onLine ) {
234236 output ( "Cannot reach workspace, consider reloading" , {
235237 formActions : [ reloadButton ] ,
238+ reason : "error" ,
236239 } ) ;
237240 } 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+ } ) ;
239244 }
240245 break ;
241246 default :
@@ -246,19 +251,57 @@ function handleDisconnected(e: CloseEvent | ErrorEvent, socket: ReconnectingWebS
246251 console . error ( e ) ;
247252}
248253
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 ) ;
260277 }
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+ } ;
262305
263306let attachAddon : AttachAddon ;
264307
@@ -306,6 +349,9 @@ window.gitpod.ideService = {
306349 toDispose . push ( {
307350 dispose : ( ) => {
308351 socket . close ( ) ;
352+ for ( const id of outputStack ) {
353+ closeModal ( id ) ;
354+ }
309355 } ,
310356 } ) ;
311357 } ) ;
0 commit comments