From e7a6e31a70c896cb8a0633099e4a3314edcf1ed0 Mon Sep 17 00:00:00 2001 From: hawkgs Date: Wed, 12 Nov 2025 16:28:42 +0200 Subject: [PATCH] fix(devtools): refine when signal graph button is shown Show the signal graph button only when a signal-graph-eligible node from the directive explorer is selected; Fix client app error when a `defer` node is selected (related) --- .../integration/view-component-metadata.e2e.js | 2 +- .../src/lib/client-event-subscribers.ts | 2 ++ .../src/lib/component-tree/component-tree.ts | 6 +++++- .../property-tab-header.component.html | 17 +++-------------- .../property-tab-header.component.scss | 2 +- .../property-tab-header.component.ts | 2 -- .../property-view-body.component.scss | 4 ++-- .../property-view-header.component.scss | 1 - .../signal-graph/signal-graph-manager.ts | 5 +++-- devtools/projects/protocol/src/lib/messages.ts | 2 +- 10 files changed, 18 insertions(+), 25 deletions(-) diff --git a/devtools/cypress/integration/view-component-metadata.e2e.js b/devtools/cypress/integration/view-component-metadata.e2e.js index c25a45d1eb3..175314cce48 100644 --- a/devtools/cypress/integration/view-component-metadata.e2e.js +++ b/devtools/cypress/integration/view-component-metadata.e2e.js @@ -8,7 +8,7 @@ const prepareHeaderExpansionPanelForAssertions = (selector) => { cy.get('.tree-wrapper').find(selector).first().click({force: true}); - cy.get('.element-header .component-name').click(); + cy.get('.node-header .component-name').click(); }; describe('Viewing component metadata', () => { diff --git a/devtools/projects/ng-devtools-backend/src/lib/client-event-subscribers.ts b/devtools/projects/ng-devtools-backend/src/lib/client-event-subscribers.ts index 57c1e718b01..096aeb01c8b 100644 --- a/devtools/projects/ng-devtools-backend/src/lib/client-event-subscribers.ts +++ b/devtools/projects/ng-devtools-backend/src/lib/client-event-subscribers.ts @@ -654,12 +654,14 @@ const getSignalGraphCallback = (messageBus: MessageBus) => (element: Ele initializeOrGetDirectiveForestHooks().getIndexedDirectiveForest(), ); if (!node) { + messageBus.emit('latestSignalGraph', [null]); return; } const injector = getInjectorFromElementNode(node.nativeElement!); if (!injector) { + messageBus.emit('latestSignalGraph', [null]); return; } diff --git a/devtools/projects/ng-devtools-backend/src/lib/component-tree/component-tree.ts b/devtools/projects/ng-devtools-backend/src/lib/component-tree/component-tree.ts index d2c028b0681..cb3e615887d 100644 --- a/devtools/projects/ng-devtools-backend/src/lib/component-tree/component-tree.ts +++ b/devtools/projects/ng-devtools-backend/src/lib/component-tree/component-tree.ts @@ -76,7 +76,11 @@ export function getInjectorResolutionPath(injector: Injector): Injector[] { } export function getInjectorFromElementNode(element: Node): Injector | null { - return ngDebugClient().getInjector?.(element) ?? null; + try { + return ngDebugClient().getInjector?.(element) ?? null; + } catch { + return null; + } } function getDirectivesFromElement(element: HTMLElement): { diff --git a/devtools/projects/ng-devtools/src/lib/devtools-tabs/directive-explorer/property-tab/property-tab-header/property-tab-header.component.html b/devtools/projects/ng-devtools/src/lib/devtools-tabs/directive-explorer/property-tab/property-tab-header/property-tab-header.component.html index d98f3a5d640..b0521713e0a 100644 --- a/devtools/projects/ng-devtools/src/lib/devtools-tabs/directive-explorer/property-tab/property-tab-header/property-tab-header.component.html +++ b/devtools/projects/ng-devtools/src/lib/devtools-tabs/directive-explorer/property-tab/property-tab-header/property-tab-header.component.html @@ -4,7 +4,7 @@ -
+
- } +
+
{{ currentSelectedElement().element }}
} diff --git a/devtools/projects/ng-devtools/src/lib/devtools-tabs/directive-explorer/property-tab/property-tab-header/property-tab-header.component.scss b/devtools/projects/ng-devtools/src/lib/devtools-tabs/directive-explorer/property-tab/property-tab-header/property-tab-header.component.scss index 7864538acd2..9c154e4d909 100644 --- a/devtools/projects/ng-devtools/src/lib/devtools-tabs/directive-explorer/property-tab/property-tab-header/property-tab-header.component.scss +++ b/devtools/projects/ng-devtools/src/lib/devtools-tabs/directive-explorer/property-tab/property-tab-header/property-tab-header.component.scss @@ -8,7 +8,7 @@ width: 100%; } - .element-header { + .node-header { @extend %body-bold-01; display: flex; justify-content: space-between; diff --git a/devtools/projects/ng-devtools/src/lib/devtools-tabs/directive-explorer/property-tab/property-tab-header/property-tab-header.component.ts b/devtools/projects/ng-devtools/src/lib/devtools-tabs/directive-explorer/property-tab/property-tab-header/property-tab-header.component.ts index 421db999745..f536e1fc0c3 100644 --- a/devtools/projects/ng-devtools/src/lib/devtools-tabs/directive-explorer/property-tab/property-tab-header/property-tab-header.component.ts +++ b/devtools/projects/ng-devtools/src/lib/devtools-tabs/directive-explorer/property-tab/property-tab-header/property-tab-header.component.ts @@ -13,7 +13,6 @@ import {MatIcon} from '@angular/material/icon'; import {IndexedNode} from '../../directive-forest/index-forest'; import {ComponentMetadataComponent} from './component-metadata/component-metadata.component'; import {ButtonComponent} from '../../../../shared/button/button.component'; -import {Settings} from '../../../../application-services/settings'; import {SUPPORTED_APIS} from '../../../../application-providers/supported_apis'; @Component({ @@ -24,7 +23,6 @@ import {SUPPORTED_APIS} from '../../../../application-providers/supported_apis'; imports: [MatExpansionModule, MatIcon, ComponentMetadataComponent, ButtonComponent], }) export class PropertyTabHeaderComponent { - private readonly settings = inject(Settings); private readonly supportedApis = inject(SUPPORTED_APIS); protected readonly currentSelectedElement = input.required(); diff --git a/devtools/projects/ng-devtools/src/lib/devtools-tabs/directive-explorer/property-tab/property-view/property-view-body/property-view-body.component.scss b/devtools/projects/ng-devtools/src/lib/devtools-tabs/directive-explorer/property-tab/property-view/property-view-body/property-view-body.component.scss index 6f29fa93058..168e90667ca 100644 --- a/devtools/projects/ng-devtools/src/lib/devtools-tabs/directive-explorer/property-tab/property-view/property-view-body/property-view-body.component.scss +++ b/devtools/projects/ng-devtools/src/lib/devtools-tabs/directive-explorer/property-tab/property-view/property-view-body/property-view-body.component.scss @@ -59,7 +59,7 @@ } } - .mat-accordion-content:not(:empty):not(:last-child) { - border-bottom: 1px solid var(--color-separator); + .mat-accordion-content:not(:empty) { + border-top: 1px solid var(--color-separator); } } diff --git a/devtools/projects/ng-devtools/src/lib/devtools-tabs/directive-explorer/property-tab/property-view/property-view-header/property-view-header.component.scss b/devtools/projects/ng-devtools/src/lib/devtools-tabs/directive-explorer/property-tab/property-view/property-view-header/property-view-header.component.scss index a7e3d6bf660..3244fbd8913 100644 --- a/devtools/projects/ng-devtools/src/lib/devtools-tabs/directive-explorer/property-tab/property-view/property-view-header/property-view-header.component.scss +++ b/devtools/projects/ng-devtools/src/lib/devtools-tabs/directive-explorer/property-tab/property-view/property-view-header/property-view-header.component.scss @@ -8,7 +8,6 @@ mat-toolbar { overflow: hidden; line-height: 25px; height: auto; - border-bottom: 1px solid var(--color-separator); .button-wrapper { display: flex; diff --git a/devtools/projects/ng-devtools/src/lib/devtools-tabs/directive-explorer/signal-graph/signal-graph-manager.ts b/devtools/projects/ng-devtools/src/lib/devtools-tabs/directive-explorer/signal-graph/signal-graph-manager.ts index 411914682fe..41513ec63ae 100644 --- a/devtools/projects/ng-devtools/src/lib/devtools-tabs/directive-explorer/signal-graph/signal-graph-manager.ts +++ b/devtools/projects/ng-devtools/src/lib/devtools-tabs/directive-explorer/signal-graph/signal-graph-manager.ts @@ -29,8 +29,9 @@ export class SignalGraphManager { constructor() { this.lastesSignalGraphMessageUnlistenFn = this.messageBus.on( 'latestSignalGraph', - (graph: DebugSignalGraph) => { - this.signalGraph.set(graph); + (graph: DebugSignalGraph | null) => { + // TODO(hawkgs): Drop logical or after/in resource viz PR. + this.signalGraph.set(graph || {nodes: [], edges: []}); }, ); } diff --git a/devtools/projects/protocol/src/lib/messages.ts b/devtools/projects/protocol/src/lib/messages.ts index 6f78dddabb0..47a54db3a12 100644 --- a/devtools/projects/protocol/src/lib/messages.ts +++ b/devtools/projects/protocol/src/lib/messages.ts @@ -381,7 +381,7 @@ export interface Events { inspectorEnd: () => void; getSignalGraph: (query: ElementPosition) => void; - latestSignalGraph: (graph: DebugSignalGraph) => void; + latestSignalGraph: (graph: DebugSignalGraph | null) => void; getSignalNestedProperties: (position: SignalNodePosition, path: string[]) => void; signalNestedProperties: (position: SignalNodePosition, data: Properties, path: string[]) => void;