Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,8 @@ export const subscribeToClientEvents = (

messageBus.on('getSignalGraph', getSignalGraphCallback(messageBus));

messageBus.on('toggleLogging', toggleSignalLogging);

if (appIsAngularInDevMode() && appIsSupportedAngularVersion() && appIsAngularIvy()) {
inspector.ref = setupInspector(messageBus);

Expand Down Expand Up @@ -711,3 +713,24 @@ const getSignalGraphCallback = (messageBus: MessageBus<Events>) => (element: Ele
messageBus.emit('latestSignalGraph', [{nodes, edges: graph.edges}]);
}
};

const toggleSignalLogging = ({element, signalId}: SignalNodePosition) => {
const ng = ngDebugClient();

// get injector from position
const node = queryDirectiveForest(
element,
initializeOrGetDirectiveForestHooks().getIndexedDirectiveForest(),
);
if (!node) {
return;
}

const injector = getInjectorFromElementNode(node.nativeElement!);

if (!injector) {
return;
}

ng.ɵtoggleDebugSignal?.(injector, signalId);
};
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ ng_project(
"//devtools/projects/ng-devtools/src/lib/devtools-tabs/directive-explorer/property-resolver:property-resolver_rjs",
"//devtools/projects/ng-devtools/src/lib/devtools-tabs/directive-explorer/property-tab:property-tab_rjs",
"//devtools/projects/ng-devtools/src/lib/devtools-tabs/directive-explorer/signals-view:signals-tab_rjs",
"//devtools/projects/ng-devtools/src/lib/shared/responsive-split:responsive-split_rjs",
"//devtools/projects/ng-devtools/src/lib/vendor/angular-split:angular-split_rjs",
"//devtools/projects/protocol:protocol_rjs",
],
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
<as-split unit="percent" [direction]="splitDirection()" [gutterSize]="9">
<as-split-area #directiveForestSplitArea size="60">
<as-split direction="vertical" [gutterSize]="9" unit="percent">
<as-split-area class="forest-breadcrumbs" size="30">
<as-split
[ngResponsiveSplit]="responsiveSplitConfig"
(directionChange)="onResponsiveSplitDirChange($event)"
direction="vertical"
[gutterSize]="9"
unit="percent"
>
<as-split-area class="forest-breadcrumbs" [size]="forestSplitSize()">
<ng-directive-forest
(selectNode)="handleNodeSelection($event)"
(selectDomElement)="handleSelectDomElement($event)"
Expand All @@ -25,7 +31,7 @@
</div>
</as-split-area>
@if (signalsOpen() && currentSelectedElement(); as currentSelectedElement) {
<as-split-area size="70">
<as-split-area [size]="signalGraphSplitSize()">
<ng-signals-tab
[currentElement]="currentSelectedElement.position"
(close)="signalsOpen.set(false)"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,16 @@ import {FormsModule} from '@angular/forms';
import {Platform} from '@angular/cdk/platform';
import {MatSnackBarModule, MatSnackBar} from '@angular/material/snack-bar';
import {SignalsTabComponent} from './signals-view/signals-tab.component';
import {
Direction,
ResponsiveSplitConfig,
ResponsiveSplitDirective,
} from '../../shared/responsive-split/responsive-split.directive';

const FOREST_VER_SPLIT_SIZE = 30;
const SIGNAL_GRAPH_VER_SPLIT_SIZE = 70;

const HOR_SPLIT_SIZE = 50;

const sameDirectives = (a: IndexedNode, b: IndexedNode) => {
if ((a.component && !b.component) || (!a.component && b.component)) {
Expand Down Expand Up @@ -86,6 +96,7 @@ const sameDirectives = (a: IndexedNode, b: IndexedNode) => {
FormsModule,
MatSnackBarModule,
SignalsTabComponent,
ResponsiveSplitDirective,
],
})
export class DirectiveExplorerComponent {
Expand Down Expand Up @@ -120,6 +131,15 @@ export class DirectiveExplorerComponent {
private readonly platform = inject(Platform);
private readonly snackBar = inject(MatSnackBar);

protected readonly responsiveSplitConfig: ResponsiveSplitConfig = {
defaultDirection: 'vertical',
aspectRatioBreakpoint: 1.5,
breakpointDirection: 'horizontal',
};

protected readonly forestSplitSize = signal<number>(FOREST_VER_SPLIT_SIZE);
protected readonly signalGraphSplitSize = signal<number>(SIGNAL_GRAPH_VER_SPLIT_SIZE);

constructor() {
afterRenderEffect((cleanup) => {
const splitElement = this.splitElementRef().nativeElement;
Expand Down Expand Up @@ -349,4 +369,14 @@ export class DirectiveExplorerComponent {
// TBD: Use the node argument for graph node selection/highlighting.
this.signalsOpen.set(true);
}

onResponsiveSplitDirChange(direction: Direction) {
if (direction === 'vertical') {
this.forestSplitSize.set(FOREST_VER_SPLIT_SIZE);
this.signalGraphSplitSize.set(SIGNAL_GRAPH_VER_SPLIT_SIZE);
} else {
this.forestSplitSize.set(HOR_SPLIT_SIZE);
this.signalGraphSplitSize.set(HOR_SPLIT_SIZE);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
<ng-property-tab-body
(inspect)="inspect.emit($event)"
(viewSource)="viewSource.emit($event)"
(showSignalGraph)="showSignalGraph.emit($event)"
[currentSelectedElement]="currentSelectedElement"
/>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
<ng-property-view
(inspect)="inspect.emit($event)"
(viewSource)="viewSource.emit(directive.name)"
(showSignalGraph)="showSignalGraph.emit($event)"
[directive]="directive"
/>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export class PropertyTabBodyComponent {
readonly currentSelectedElement = input.required<IndexedNode>();
readonly inspect = output<{node: FlatNode; directivePosition: DirectivePosition}>();
readonly viewSource = output<string>();
readonly showSignalGraph = output<FlatNode>();

readonly currentDirectives = computed(() => {
const selected = this.currentSelectedElement();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
[treeControl]="panel.controls().treeControl"
(updateValue)="updateValue($event)"
(inspect)="handleInspect($event)"
(showSignalGraph)="showSignalGraph.emit($event)"
/>
</mat-expansion-panel>
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ export class PropertyViewBodyComponent {
readonly directiveStateControls = input.required<DirectiveTreeData>();

readonly inspect = output<{node: FlatNode; directivePosition: DirectivePosition}>();
readonly showSignalGraph = output<FlatNode>();

protected readonly dependencies = computed(() => {
const metadata = this.controller().directiveMetadata;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,16 @@
<span class="value">
{{ node.prop.descriptor.preview }}
</span>
@if (isSignal(node)) {
<button
class="show-signal-btn"
type="button"
matTooltip="Show signal graph snapshot"
(click)="showGraph($event, node)"
>
<mat-icon>schema</mat-icon>
</button>
}
</div>
</mat-tree-node>
</mat-tree>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
*/

import {ChangeDetectionStrategy, Component, input, output} from '@angular/core';
import {MatTooltip} from '@angular/material/tooltip';
import {MatIcon} from '@angular/material/icon';
import {FlatTreeControl} from '@angular/cdk/tree';

Expand All @@ -29,13 +30,15 @@ import {MatTree, MatTreeNode, MatTreeNodeDef, MatTreeNodePadding} from '@angular
PropertyPreviewComponent,
PropertyEditorComponent,
MatIcon,
MatTooltip,
],
})
export class PropertyViewTreeComponent {
readonly dataSource = input.required<PropertyDataSource>();
readonly treeControl = input.required<FlatTreeControl<FlatNode>>();
readonly updateValue = output<any>();
readonly inspect = output<any>();
readonly showSignalGraph = output<FlatNode>();

hasChild = (_: number, node: FlatNode): boolean => node.expandable;

Expand All @@ -61,4 +64,13 @@ export class PropertyViewTreeComponent {
newValue,
});
}

isSignal(node: FlatNode) {
return node.prop.descriptor.containerType?.includes('Signal');
}

showGraph(event: Event, node: FlatNode) {
event.stopPropagation();
this.showSignalGraph.emit(node);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@
[directiveOutputControls]="directiveOutputControls()!"
[directiveStateControls]="directiveStateControls()!"
(inspect)="inspect.emit($event)"
(showSignalGraph)="showSignalGraph.emit($event)"
></ng-property-view-body>
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export class PropertyViewComponent {
readonly directive = input.required<{name: string}>();
readonly inspect = output<{node: FlatNode; directivePosition: DirectivePosition}>();
readonly viewSource = output<void>();
readonly showSignalGraph = output<FlatNode>();

private _nestedProps = inject(ElementPropertyResolver);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@
<mat-icon> arrow_outward </mat-icon>
View Source
</button>
<button mat-flat-button (click)="toggleLogging()">
<mat-icon> terminal </mat-icon>
Log Signal
</button>
</div>

<div class="signal-metadata">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -173,4 +173,12 @@ export class SignalsTabComponent implements OnDestroy {
frame!,
);
}

toggleLogging() {
const selected = this.selected();
if (!selected) {
return;
}
this.messageBus.emit('toggleLogging', [{element: this.currentElement()!, signalId: selected}]);
}
}
2 changes: 2 additions & 0 deletions devtools/projects/protocol/src/lib/messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,8 @@ export interface Events {
getSignalNestedProperties: (position: SignalNodePosition, path: string[]) => void;
signalNestedProperties: (position: SignalNodePosition, data: Properties, path: string[]) => void;

toggleLogging: (position: SignalNodePosition) => void;

getNestedProperties: (position: DirectivePosition, path: string[]) => void;
nestedProperties: (position: DirectivePosition, data: Properties, path: string[]) => void;

Expand Down
1 change: 1 addition & 0 deletions devtools/src/app/demo-app/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ sass_binary(
ng_project(
name = "demo-app",
srcs = [
"cookies.component.ts",
"demo-app.component.ts",
"demo-app.routes.ts",
"heavy.component.ts",
Expand Down
38 changes: 38 additions & 0 deletions devtools/src/app/demo-app/cookies.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/**
* @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.dev/license
*/

import {Component, signal, computed} from '@angular/core';

@Component({
selector: 'app-cookies',
template: `
<h2>Cookie recipe</h2>

<label>
# of cookies:
<input type="range" min="10" max="100" step="10" [value]="count()" (input)="update($event)" />
{{ count() }}
</label>

<p>Butter: {{ butter() }} cup(s)</p>
<p>Sugar: {{ sugar() }} cup(s)</p>
<p>Flour: {{ flour() }} cup(s)</p>
`,
})
export class CookieRecipe {
count = signal(10, {debugName: 'count'});

butter = computed(() => this.count() * 0.1, {debugName: 'butter'});
sugar = computed(() => this.count() * 0.05, {debugName: 'sugar'});
flour = computed(() => this.count() * 0.2, {debugName: 'flour'});

update(event: Event) {
const input = event.target as HTMLInputElement;
this.count.set(parseInt(input.value));
}
}
1 change: 1 addition & 0 deletions devtools/src/app/demo-app/demo-app.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@
<app-heavy></app-heavy>
<div #elementReference>HTMLElement</div>
<app-sample-properties></app-sample-properties>
<app-cookies />
3 changes: 2 additions & 1 deletion devtools/src/app/demo-app/demo-app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,15 @@ import {ZippyComponent} from './zippy.component';
import {HeavyComponent} from './heavy.component';
import {SamplePropertiesComponent} from './sample-properties.component';
import {RouterOutlet} from '@angular/router';
import {CookieRecipe} from './cookies.component';

@Component({
selector: 'app-demo-component',
templateUrl: './demo-app.component.html',
styleUrls: ['./demo-app.component.scss'],
encapsulation: ViewEncapsulation.None,
schemas: [CUSTOM_ELEMENTS_SCHEMA],
imports: [HeavyComponent, SamplePropertiesComponent, RouterOutlet],
imports: [HeavyComponent, SamplePropertiesComponent, RouterOutlet, CookieRecipe],
})
export class DemoAppComponent {
readonly zippy = viewChild(ZippyComponent);
Expand Down
2 changes: 1 addition & 1 deletion devtools/src/app/demo-app/sample-properties.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {SampleService} from './sample.service';

@Component({
selector: 'app-sample-properties',
template: '',
template: '{{computedObject()}}',
styles: [''],
})
export class SamplePropertiesComponent {
Expand Down
3 changes: 2 additions & 1 deletion packages/core/src/render3/util/global_utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ import {
getInjectorProviders,
getInjectorResolutionPath,
} from './injector_discovery_utils';
import {getSignalGraph} from './signal_debug';
import {getSignalGraph, toggleDebugSignal} from './signal_debug';

import {enableProfiling} from '../debug/chrome_dev_tools_performance';

Expand Down Expand Up @@ -75,6 +75,7 @@ const globalUtilsFunctions = {
'ɵsetProfiler': setProfiler,
'ɵgetSignalGraph': getSignalGraph,
'ɵgetDeferBlocks': getDeferBlocks,
'ɵtoggleDebugSignal': toggleDebugSignal,

'getDirectiveMetadata': getDirectiveMetadata,
'getComponent': getComponent,
Expand Down
Loading