@@ -232,6 +232,18 @@ const UIStrings = {
232232 * @description Text in Timeline Panel of the Performance panel
233233 */
234234 initializingTracing : 'Initializing tracing…' ,
235+ /**
236+ * @description Text in Timeline Panel of the Performance panel. Shown to the user after they request to download the trace.
237+ */
238+ preparingTraceForDownload : 'Preparing…' ,
239+ /**
240+ * @description Text in Timeline Panel of the Performance panel. Shown to the user after they request to download the trace.
241+ */
242+ compressingTraceForDownload : 'Compressing…' ,
243+ /**
244+ * @description Text in Timeline Panel of the Performance panel. Shown to the user after they request to download the trace.
245+ */
246+ encodingTraceForDownload : 'Encoding…' ,
235247 /**
236248 * @description Tooltip description for a checkbox that toggles the visibility of data added by extensions of this panel (Performance).
237249 */
@@ -1455,6 +1467,9 @@ export class TimelinePanel extends Common.ObjectWrapper.eventMixin<EventTypes, t
14551467 }
14561468
14571469 this . #showExportTraceErrorDialog( error ) ;
1470+ } finally {
1471+ this . statusDialog ?. remove ( ) ;
1472+ this . statusDialog = null ;
14581473 }
14591474 }
14601475
@@ -1464,6 +1479,24 @@ export class TimelinePanel extends Common.ObjectWrapper.eventMixin<EventTypes, t
14641479 addModifications : boolean ,
14651480 shouldCompress : boolean ,
14661481 } ) : Promise < void > {
1482+ this . statusDialog = new StatusDialog (
1483+ {
1484+ hideStopButton : true ,
1485+ showProgress : true ,
1486+ } ,
1487+ async ( ) => {
1488+ this . statusDialog ?. remove ( ) ;
1489+ this . statusDialog = null ;
1490+ } ) ;
1491+ this . statusDialog . showPane ( this . statusPaneContainer , 'tinted' ) ;
1492+ this . statusDialog . updateStatus ( i18nString ( UIStrings . preparingTraceForDownload ) ) ;
1493+ this . statusDialog . updateProgressBar ( i18nString ( UIStrings . preparingTraceForDownload ) , 0 ) ;
1494+ this . statusDialog . requestUpdate ( ) ;
1495+ await this . statusDialog . updateComplete ;
1496+ // Not sure why the above isn't sufficient.
1497+ await new Promise ( resolve => requestAnimationFrame ( resolve ) ) ;
1498+ await new Promise ( resolve => requestAnimationFrame ( resolve ) ) ;
1499+
14671500 // Base the filename on the trace's time of recording
14681501 const isoDate =
14691502 Platform . DateUtilities . toISO8601Compact ( metadata . startTime ? new Date ( metadata . startTime ) : new Date ( ) ) ;
@@ -1499,8 +1532,16 @@ export class TimelinePanel extends Common.ObjectWrapper.eventMixin<EventTypes, t
14991532 let blob = new Blob ( blobParts , { type : 'application/json' } ) ;
15001533
15011534 if ( config . shouldCompress ) {
1535+ this . statusDialog . updateStatus ( i18nString ( UIStrings . compressingTraceForDownload ) ) ;
1536+ this . statusDialog . updateProgressBar ( i18nString ( UIStrings . compressingTraceForDownload ) , 0 ) ;
1537+
15021538 fileName = `${ fileName } .gz` as Platform . DevToolsPath . RawPathString ;
1503- const gzStream = Common . Gzip . compressStream ( blob . stream ( ) ) ;
1539+ const inputSize = blob . size ;
1540+ const monitoredStream = Common . Gzip . createMonitoredStream ( blob . stream ( ) , bytesRead => {
1541+ this . statusDialog ?. updateProgressBar (
1542+ i18nString ( UIStrings . compressingTraceForDownload ) , bytesRead / inputSize * 100 ) ;
1543+ } ) ;
1544+ const gzStream = Common . Gzip . compressStream ( monitoredStream ) ;
15041545 blob = await new Response ( gzStream , {
15051546 headers : { 'Content-Type' : 'application/gzip' } ,
15061547 } ) . blob ( ) ;
@@ -1515,9 +1556,12 @@ export class TimelinePanel extends Common.ObjectWrapper.eventMixin<EventTypes, t
15151556 try {
15161557 // The maximum string length in v8 is `2 ** 29 - 23`, aka 538 MB.
15171558 // If the gzipped&base64-encoded trace is larger than that, this'll throw a RangeError.
1559+ this . statusDialog . updateStatus ( i18nString ( UIStrings . encodingTraceForDownload ) ) ;
1560+ this . statusDialog . updateProgressBar ( i18nString ( UIStrings . encodingTraceForDownload ) , 100 ) ;
15181561 bytesAsB64 = await Common . Base64 . encode ( blob ) ;
15191562 } catch {
15201563 }
1564+
15211565 if ( bytesAsB64 ?. length ) {
15221566 const contentData = new TextUtils . ContentData . ContentData ( bytesAsB64 , /* isBase64=*/ true , blob . type ) ;
15231567 await Workspace . FileManager . FileManager . instance ( ) . save ( fileName , contentData , /* forceSaveAs=*/ true ) ;
@@ -1531,6 +1575,9 @@ export class TimelinePanel extends Common.ObjectWrapper.eventMixin<EventTypes, t
15311575 a . click ( ) ;
15321576 URL . revokeObjectURL ( url ) ;
15331577 }
1578+
1579+ this . statusDialog . remove ( ) ;
1580+ this . statusDialog = null ;
15341581 }
15351582
15361583 async handleSaveToFileAction ( ) : Promise < void > {
0 commit comments