mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
refactor(devtools): improve profiler recorder controls (#62010)
Reorganize the template and reduce the vertical space taken by the controls. PR Close #62010
This commit is contained in:
@@ -44,6 +44,7 @@ ng_project(
|
||||
"//:node_modules/@angular/material",
|
||||
"//:node_modules/rxjs",
|
||||
"//devtools/projects/ng-devtools/src/lib/devtools-tabs/profiler/timeline:timeline_rjs",
|
||||
"//devtools/projects/ng-devtools/src/lib/shared/button:button_rjs",
|
||||
"//devtools/projects/protocol:protocol_rjs",
|
||||
],
|
||||
)
|
||||
|
||||
+51
-50
@@ -1,65 +1,66 @@
|
||||
<div class="profiler-wrapper">
|
||||
<mat-card>
|
||||
@if (state() === 'idle') {
|
||||
<div class="recorder-controls">
|
||||
@switch (state()) {
|
||||
@case ('idle') {
|
||||
<button
|
||||
mat-icon-button
|
||||
color="primary"
|
||||
ng-button
|
||||
btnType="icon"
|
||||
(click)="startRecording()"
|
||||
class="profiler-control start-recording-button"
|
||||
matTooltip="Start recording"
|
||||
aria-label="Start recording"
|
||||
>
|
||||
<mat-icon> circle </mat-icon>
|
||||
</button>
|
||||
} @else if (state() === 'recording') {
|
||||
<button
|
||||
mat-icon-button
|
||||
(click)="stopRecording()"
|
||||
class="profiler-control recording-button"
|
||||
matTooltip="Stop recording"
|
||||
aria-label="Stop recording"
|
||||
>
|
||||
<mat-icon> circle </mat-icon>
|
||||
</button>
|
||||
} @else if (state() === 'visualizing') {
|
||||
<button
|
||||
mat-icon-button
|
||||
color="primary"
|
||||
(click)="discardRecording()"
|
||||
class="profiler-control discard-button"
|
||||
matTooltip="Clear recording"
|
||||
aria-label="Clear recording"
|
||||
>
|
||||
<mat-icon> not_interested </mat-icon>
|
||||
</button>
|
||||
}
|
||||
<p class="instructions" [class.hidden]="state() !== 'idle'">
|
||||
<span>
|
||||
Click the record button to start a new recording, or upload a JSON file containing profiler
|
||||
data.
|
||||
</span>
|
||||
<br />
|
||||
<span>
|
||||
|
||||
<p class="instructions">
|
||||
<span>
|
||||
Click the record button to start a new recording, or upload a JSON file containing
|
||||
profiler data.
|
||||
</span>
|
||||
<br />
|
||||
<input
|
||||
type="file"
|
||||
(change)="importProfilerResults($event)"
|
||||
placeholder="Upload file"
|
||||
accept=".json"
|
||||
/>
|
||||
</span>
|
||||
</p>
|
||||
<p class="instructions" [class.hidden]="state() !== 'recording'">
|
||||
Interact to preview change detection. Clicking stop ends this Profiler recording.
|
||||
</p>
|
||||
<p class="instructions" [class.hidden]="state() !== 'visualizing'">
|
||||
Click Save Profile to save your recording or click refresh to clear the current recording.
|
||||
</p>
|
||||
</mat-card>
|
||||
<div id="profiler-content-wrapper">
|
||||
@if (state() !== 'idle') {
|
||||
<div class="visualization">
|
||||
<ng-recording-timeline [stream]="stream" (exportProfile)="exportProfilerResults()" />
|
||||
</div>
|
||||
</p>
|
||||
}
|
||||
</div>
|
||||
@case ('recording') {
|
||||
<button
|
||||
ng-button
|
||||
btnType="icon"
|
||||
(click)="stopRecording()"
|
||||
class="recording-button"
|
||||
matTooltip="Stop recording"
|
||||
aria-label="Stop recording"
|
||||
>
|
||||
<mat-icon> circle </mat-icon>
|
||||
</button>
|
||||
|
||||
<p class="instructions">
|
||||
Interact to preview change detection. Clicking stop ends this Profiler recording.
|
||||
</p>
|
||||
}
|
||||
@case ('visualizing') {
|
||||
<button
|
||||
ng-button
|
||||
btnType="icon"
|
||||
(click)="discardRecording()"
|
||||
matTooltip="Clear recording"
|
||||
aria-label="Clear recording"
|
||||
>
|
||||
<mat-icon> not_interested </mat-icon>
|
||||
</button>
|
||||
|
||||
<p class="instructions">
|
||||
Click Save Profile to save your recording or click refresh to clear the current recording.
|
||||
</p>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
|
||||
@if (state() !== 'idle') {
|
||||
<div class="recording">
|
||||
<ng-recording-timeline [stream]="stream" (exportProfile)="exportProfilerResults()" />
|
||||
</div>
|
||||
}
|
||||
|
||||
+42
-50
@@ -1,55 +1,47 @@
|
||||
@use '../../../styles/typography';
|
||||
|
||||
:host,
|
||||
.profiler-wrapper {
|
||||
width: 100%;
|
||||
height: calc(100% - 30px);
|
||||
|
||||
p {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.mat-icon {
|
||||
font-size: 18px;
|
||||
top: 4px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.profiler-control {
|
||||
cursor: pointer;
|
||||
|
||||
&.recording-button {
|
||||
color: var(--dynamic-red-01);
|
||||
}
|
||||
}
|
||||
|
||||
.instructions {
|
||||
@extend %body-01;
|
||||
|
||||
&.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
input,
|
||||
span {
|
||||
margin-top: 5px;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
#profiler-content-wrapper {
|
||||
margin: 0;
|
||||
height: calc(100% - 30px);
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.visualization {
|
||||
margin: 0;
|
||||
:host {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.mdc-card {
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
.recorder-controls {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 0.25rem;
|
||||
border-bottom: 1px solid var(--color-separator);
|
||||
|
||||
button {
|
||||
$icon-size: 18px;
|
||||
margin: 0.625rem;
|
||||
color: var(--secondary-contrast);
|
||||
height: $icon-size;
|
||||
|
||||
&.recording-button {
|
||||
color: var(--dynamic-red-01);
|
||||
}
|
||||
|
||||
mat-icon {
|
||||
width: $icon-size;
|
||||
height: $icon-size;
|
||||
font-size: $icon-size;
|
||||
}
|
||||
}
|
||||
|
||||
.instructions {
|
||||
@extend %body-01;
|
||||
padding-block: 0.7rem;
|
||||
margin: 0;
|
||||
|
||||
input {
|
||||
margin-top: 0.5rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.recording {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,16 +8,15 @@
|
||||
|
||||
import {Component, inject, signal} from '@angular/core';
|
||||
import {MatDialog} from '@angular/material/dialog';
|
||||
import {MatIcon} from '@angular/material/icon';
|
||||
import {MatTooltip} from '@angular/material/tooltip';
|
||||
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';
|
||||
import {ButtonComponent} from '../../shared/button/button.component';
|
||||
|
||||
type State = 'idle' | 'recording' | 'visualizing';
|
||||
|
||||
@@ -28,7 +27,7 @@ const PROFILER_VERSION = 1;
|
||||
selector: 'ng-profiler',
|
||||
templateUrl: './profiler.component.html',
|
||||
styleUrls: ['./profiler.component.scss'],
|
||||
imports: [MatCard, MatIconButton, MatTooltip, MatIcon, TimelineComponent],
|
||||
imports: [MatTooltip, MatIcon, TimelineComponent, ButtonComponent],
|
||||
})
|
||||
export class ProfilerComponent {
|
||||
readonly state = signal<State>('idle');
|
||||
|
||||
+2
@@ -4,6 +4,8 @@
|
||||
display: block;
|
||||
overflow: auto;
|
||||
height: 100%;
|
||||
padding-bottom: 1rem;
|
||||
|
||||
::ng-deep {
|
||||
.as-split-gutter-icon {
|
||||
display: none;
|
||||
|
||||
@@ -15,4 +15,14 @@
|
||||
background: var(--dynamic-blue-02);
|
||||
color: var(--septenary-contrast);
|
||||
}
|
||||
|
||||
&.type-icon {
|
||||
background: transparent;
|
||||
border: none;
|
||||
padding: 0;
|
||||
|
||||
&.size-compact {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
import {ChangeDetectionStrategy, Component, input} from '@angular/core';
|
||||
|
||||
type ButtonType = 'primary'; // To be extended in future
|
||||
type ButtonType = 'primary' | 'icon';
|
||||
type ButtonSize = 'standard' | 'compact';
|
||||
|
||||
@Component({
|
||||
@@ -19,6 +19,7 @@ type ButtonSize = 'standard' | 'compact';
|
||||
host: {
|
||||
class: 'ng-button',
|
||||
'[class.type-primary]': `btnType() === 'primary'`,
|
||||
'[class.type-icon]': `btnType() === 'icon'`,
|
||||
'[class.size-compact]': `size() === 'compact'`,
|
||||
},
|
||||
})
|
||||
|
||||
@@ -148,3 +148,7 @@ mat-form-field {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
[hidden] {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user