refactor(devtools): filtering providers by token within "injector tree" tab (#53313)

In some injectors, there are LOTS of providers, making it slightly inconvenient to search for a certain one. This commit introduces a search-by-token for providers of a specific injector.

PR Close #53313
This commit is contained in:
Tomasz Ducin
2023-12-01 18:38:14 +01:00
committed by Dylan Hunn
parent 26e40c7f89
commit 25cfccbadf
@@ -6,9 +6,11 @@
* found in the LICENSE file at https://angular.io/license
*/
import {NgForOf, NgIf} from '@angular/common';
import {Component, inject, Input} from '@angular/core';
import {Component, computed, inject, Input, signal} from '@angular/core';
import {MatFormFieldModule} from '@angular/material/form-field';
import {MatIconModule} from '@angular/material/icon';
import {MatInputModule} from '@angular/material/input';
import {MatSelectModule} from '@angular/material/select';
import {MatTableModule} from '@angular/material/table';
import {MatTooltipModule} from '@angular/material/tooltip';
import {Events, MessageBus, SerializedInjector, SerializedProviderRecord} from 'protocol';
@@ -19,8 +21,32 @@ import {Events, MessageBus, SerializedInjector, SerializedProviderRecord} from '
<h1>
Providers for {{ injector?.name }}
</h1>
<div *ngIf="injector" class="injector-providers">
<table *ngIf="providers.length > 0" mat-table [dataSource]="providers" class="mat-elevation-z4">
@if (injector){
<div class="injector-providers">
<mat-form-field appearance="fill" class="form-field-spacer">
<mat-label>Search by token</mat-label>
<input type="text" matInput
placeholder="Provider token"
(input)="searchToken.set($event.target.value)"
[value]="searchToken()"
/>
<mat-icon matSuffix (click)="searchToken.set('')">close</mat-icon>
</mat-form-field>
<mat-form-field class="form-field-spacer">
<mat-label>Search by type</mat-label>
<mat-select
[value]="searchType()"
(selectionChange)="searchType.set($event.value)"
>
<mat-option>None</mat-option>
@for (type of providerTypes; track type) {
<mat-option [value]="type">{{providerTypeToLabel[type]}}</mat-option>
}
</mat-select>
</mat-form-field>
@if(visibleProviders().length > 0){
<table mat-table [dataSource]="visibleProviders()" class="mat-elevation-z4">
<ng-container matColumnDef="token">
<th mat-header-cell *matHeaderCellDef> <h3 class="column-title">Token</h3> </th>
<td mat-cell *matCellDef="let provider"> {{provider.token}} </td>
@@ -32,7 +58,7 @@ import {Events, MessageBus, SerializedInjector, SerializedProviderRecord} from '
@if (provider.type === 'multi') {
multi (x{{ provider.index.length }})
} @else {
{{typeToLabel[provider.type]}}
{{providerTypeToLabel[provider.type]}}
}
</td>
</ng-container>
@@ -50,7 +76,10 @@ import {Events, MessageBus, SerializedInjector, SerializedProviderRecord} from '
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
}
</div>
}
`,
styles: [`
.select {
@@ -62,6 +91,10 @@ import {Events, MessageBus, SerializedInjector, SerializedProviderRecord} from '
padding: 16px;
}
.form-field-spacer {
margin: 0 4px 0 4px;
}
table {
width: 100%;
}
@@ -108,13 +141,31 @@ import {Events, MessageBus, SerializedInjector, SerializedProviderRecord} from '
}
`],
standalone: true,
imports: [NgIf, NgForOf, MatTableModule, MatIconModule, MatTooltipModule],
imports: [
MatTableModule, MatIconModule, MatTooltipModule, MatInputModule, MatSelectModule,
MatFormFieldModule
],
})
export class InjectorProvidersComponent {
@Input() injector: SerializedInjector;
@Input() providers: SerializedProviderRecord[] = [];
typeToLabel = {
searchToken = signal('');
searchType = signal('');
visibleProviders = computed(() => {
const searchToken = this.searchToken().toLowerCase();
const searchType = this.searchType();
const predicates: ((provider: SerializedProviderRecord) => boolean)[] = [];
searchToken &&
predicates.push((provider) => provider.token.toLowerCase().includes(searchToken));
searchType && predicates.push((provider) => provider.type === searchType);
return this.providers.filter(
(provider) => predicates.every((predicate) => predicate(provider)));
});
providerTypeToLabel = {
type: 'Type',
existing: 'useExisting',
factory: 'useFactory',
@@ -122,6 +173,8 @@ export class InjectorProvidersComponent {
value: 'useValue',
};
providerTypes = Object.keys(this.providerTypeToLabel);
messageBus = inject(MessageBus<Events>);
select(row: SerializedProviderRecord) {