angular/devtools/projects/ng-devtools/src/lib/devtools-tabs/profiler/profiler.component.ts
Matthieu Riegler 93845373a3 refactor(devtools): migrate to standalone (#53998)
Migrated with the schematics and cleanup by hand.

PR Close #53998
2024-01-23 09:53:24 +01:00

125 lines
3.7 KiB
TypeScript

/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {Component, OnInit} from '@angular/core';
import {MatDialog} from '@angular/material/dialog';
import {Events, MessageBus, ProfilerFrame} from 'protocol';
import {Subject} from 'rxjs';
import {FileApiService} from './file-api-service';
import {ProfilerImportDialogComponent} from './profiler-import-dialog.component';
import {TimelineComponent} from './timeline/timeline.component';
import {MatIcon} from '@angular/material/icon';
import {MatTooltip} from '@angular/material/tooltip';
import {MatIconButton} from '@angular/material/button';
import {MatCard} from '@angular/material/card';
type State = 'idle' | 'recording' | 'visualizing';
const SUPPORTED_VERSIONS = [1];
const PROFILER_VERSION = 1;
@Component({
selector: 'ng-profiler',
templateUrl: './profiler.component.html',
styleUrls: ['./profiler.component.scss'],
standalone: true,
imports: [MatCard, MatIconButton, MatTooltip, MatIcon, TimelineComponent],
})
export class ProfilerComponent implements OnInit {
state: State = 'idle';
stream = new Subject<ProfilerFrame[]>();
// We collect this buffer so we can have it available for export.
private _buffer: ProfilerFrame[] = [];
constructor(
private _fileApiService: FileApiService,
private _messageBus: MessageBus<Events>,
public dialog: MatDialog,
) {
this._fileApiService.uploadedData.subscribe((importedFile) => {
if (importedFile.error) {
console.error('Could not process uploaded file');
console.error(importedFile.error);
this.dialog.open(ProfilerImportDialogComponent, {
width: '600px',
data: {status: 'ERROR', errorMessage: importedFile.error},
});
return;
}
if (!SUPPORTED_VERSIONS.includes(importedFile.version)) {
const processDataDialog = this.dialog.open(ProfilerImportDialogComponent, {
width: '600px',
data: {
importedVersion: importedFile.version,
profilerVersion: PROFILER_VERSION,
status: 'INVALID_VERSION',
},
});
processDataDialog.afterClosed().subscribe((result) => {
if (result) {
this.state = 'visualizing';
this._buffer = importedFile.buffer;
setTimeout(() => this.stream.next(importedFile.buffer));
}
});
} else {
this.state = 'visualizing';
this._buffer = importedFile.buffer;
setTimeout(() => this.stream.next(importedFile.buffer));
}
});
}
startRecording(): void {
this.state = 'recording';
this._messageBus.emit('startProfiling');
}
stopRecording(): void {
this.state = 'visualizing';
this._messageBus.emit('stopProfiling');
this.stream.complete();
}
ngOnInit(): void {
this._messageBus.on('profilerResults', (remainingRecords) => {
if (remainingRecords.duration > 0 && remainingRecords.source) {
this.stream.next([remainingRecords]);
this._buffer.push(remainingRecords);
}
});
this._messageBus.on('sendProfilerChunk', (chunkOfRecords: ProfilerFrame) => {
this.stream.next([chunkOfRecords]);
this._buffer.push(chunkOfRecords);
});
}
exportProfilerResults(): void {
const fileToExport = {
version: PROFILER_VERSION,
buffer: this._buffer,
};
this._fileApiService.saveObjectAsJSON(fileToExport);
}
importProfilerResults(event: InputEvent): void {
this._fileApiService.publishFileUpload(event);
}
discardRecording(): void {
this.stream = new Subject<ProfilerFrame[]>();
this.state = 'idle';
this._buffer = [];
}
}