From 569c0414f8dc0c93ea7e3cde7c9e7481958a33bd Mon Sep 17 00:00:00 2001 From: Matthieu Riegler Date: Sun, 17 Mar 2024 14:56:46 +0100 Subject: [PATCH 1/4] refactor(devtools): fix issue with virtual scroll viewport in the directive forest In some cases the height of the viewport wasn't calculated correctly because of extension tabs quirks. This commit fixes this issue. Fixes #53704 --- .../directive-forest/directive-forest.component.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/devtools/projects/ng-devtools/src/lib/devtools-tabs/directive-explorer/directive-forest/directive-forest.component.ts b/devtools/projects/ng-devtools/src/lib/devtools-tabs/directive-explorer/directive-forest/directive-forest.component.ts index 43ecc5b8b2f6..c4d00e6d9fc7 100644 --- a/devtools/projects/ng-devtools/src/lib/devtools-tabs/directive-explorer/directive-forest/directive-forest.component.ts +++ b/devtools/projects/ng-devtools/src/lib/devtools-tabs/directive-explorer/directive-forest/directive-forest.component.ts @@ -16,6 +16,7 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, + ElementRef, EventEmitter, HostListener, Input, @@ -99,11 +100,13 @@ export class DirectiveForestComponent { readonly itemHeight = 18; private _initialized = false; + private resizeObserver: ResizeObserver; constructor( private _tabUpdate: TabUpdate, private _messageBus: MessageBus, private _cdr: ChangeDetectorRef, + private elementRef: ElementRef, ) { this.subscribeToInspectorEvents(); this._tabUpdate.tabUpdate$.pipe(takeUntilDestroyed()).subscribe(() => { @@ -114,6 +117,17 @@ export class DirectiveForestComponent { }); } }); + + // In some cases there a height changes, we need to recalculate the viewport size. + this.resizeObserver = new ResizeObserver(() => { + this.viewport.scrollToIndex(0); + this.viewport.checkViewportSize(); + }); + this.resizeObserver.observe(this.elementRef.nativeElement); + } + + ngOnDestroy(): void { + this.resizeObserver.disconnect(); } subscribeToInspectorEvents(): void { From fe6af0a2c092996d760278ed61b9d066345d04b4 Mon Sep 17 00:00:00 2001 From: Matthieu Riegler Date: Sun, 17 Mar 2024 14:57:59 +0100 Subject: [PATCH 2/4] refactor(devtools): improve signal support. In some cases signals weren't unwraped thus not reading the value correctly. This commit fixes this issue. --- .../ng-devtools-backend/src/lib/client-event-subscribers.ts | 4 ++-- .../src/lib/state-serializer/serialized-descriptor-factory.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) 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 b89bde1aa960..32d0df8df252 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 @@ -51,7 +51,7 @@ import {ComponentTreeNode} from './interfaces'; import {ngDebugDependencyInjectionApiIsSupported} from './ng-debug-api/ng-debug-api'; import {setConsoleReference} from './set-console-reference'; import {serializeDirectiveState} from './state-serializer/state-serializer'; -import {runOutsideAngular} from './utils'; +import {runOutsideAngular, unwrapSignal} from './utils'; import {DirectiveForestHooks} from './hooks/hooks'; export const subscribeToClientEvents = ( @@ -194,7 +194,7 @@ const getNestedPropertiesCallback = } let data = current.instance; for (const prop of propPath) { - data = data[prop]; + data = unwrapSignal(data[prop]); if (!data) { console.error('Cannot access the properties', propPath, 'of', node); } diff --git a/devtools/projects/ng-devtools-backend/src/lib/state-serializer/serialized-descriptor-factory.ts b/devtools/projects/ng-devtools-backend/src/lib/state-serializer/serialized-descriptor-factory.ts index 67311d761a22..e25266d781ab 100644 --- a/devtools/projects/ng-devtools-backend/src/lib/state-serializer/serialized-descriptor-factory.ts +++ b/devtools/projects/ng-devtools-backend/src/lib/state-serializer/serialized-descriptor-factory.ts @@ -325,11 +325,11 @@ function getLevelDescriptorValue( const isReadonly = isSignal(prop); switch (type) { case PropType.Array: - return prop.map((_: any, idx: number) => + return value.map((_: any, idx: number) => continuation(value, idx, isReadonly, currentLevel + 1, level), ); case PropType.Object: - return getKeys(prop).reduce( + return getKeys(value).reduce( (accumulator, propName) => { if (!ignoreList.has(propName)) { accumulator[propName] = continuation( From 6c9a89807f712906f9313b99e310af9df2d80bdd Mon Sep 17 00:00:00 2001 From: Matthieu Riegler Date: Sun, 17 Mar 2024 15:18:13 +0100 Subject: [PATCH 3/4] refactor(devtools): prevent dblclick on the expand arrow to show the element panel This will improve the UX --- .../directive-forest.component.html | 28 ++++++++++--------- .../directive-forest.component.ts | 4 +++ 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/devtools/projects/ng-devtools/src/lib/devtools-tabs/directive-explorer/directive-forest/directive-forest.component.html b/devtools/projects/ng-devtools/src/lib/devtools-tabs/directive-explorer/directive-forest/directive-forest.component.html index 9c390af10847..39e3e162ae99 100644 --- a/devtools/projects/ng-devtools/src/lib/devtools-tabs/directive-explorer/directive-forest/directive-forest.component.html +++ b/devtools/projects/ng-devtools/src/lib/devtools-tabs/directive-explorer/directive-forest/directive-forest.component.html @@ -21,19 +21,21 @@ (mouseleave)="removeHighlight()" [style.padding-left]="15 + 15 * node.level + 'px'" > -
- @if (node.expandable) { - - } - {{ node.name }} +
+ @if (node.expandable) { + + + } + {{ node.name }} @if (node.directives) { [{{ node.directives }}] diff --git a/devtools/projects/ng-devtools/src/lib/devtools-tabs/directive-explorer/directive-forest/directive-forest.component.ts b/devtools/projects/ng-devtools/src/lib/devtools-tabs/directive-explorer/directive-forest/directive-forest.component.ts index c4d00e6d9fc7..81cd5a6c6976 100644 --- a/devtools/projects/ng-devtools/src/lib/devtools-tabs/directive-explorer/directive-forest/directive-forest.component.ts +++ b/devtools/projects/ng-devtools/src/lib/devtools-tabs/directive-explorer/directive-forest/directive-forest.component.ts @@ -344,6 +344,10 @@ export class DirectiveForestComponent { } } + stopPropagation(event: Event): void { + event.stopPropagation(); + } + private _findMatchedNodes(): number[] { const indexesOfMatchedNodes: number[] = []; for (let i = 0; i < this.dataSource.data.length; i++) { From 0b1c58e464d1b9e4b172d64576d0d7f431af6158 Mon Sep 17 00:00:00 2001 From: Matthieu Riegler Date: Sun, 17 Mar 2024 15:57:05 +0100 Subject: [PATCH 4/4] refactor(devtools): hide hydration error when the component tree is collapsed This commit improves the devtools UX. --- .../directive-forest.component.html | 60 ++++++++++--------- 1 file changed, 31 insertions(+), 29 deletions(-) diff --git a/devtools/projects/ng-devtools/src/lib/devtools-tabs/directive-explorer/directive-forest/directive-forest.component.html b/devtools/projects/ng-devtools/src/lib/devtools-tabs/directive-explorer/directive-forest/directive-forest.component.html index 39e3e162ae99..dee01c775974 100644 --- a/devtools/projects/ng-devtools/src/lib/devtools-tabs/directive-explorer/directive-forest/directive-forest.component.html +++ b/devtools/projects/ng-devtools/src/lib/devtools-tabs/directive-explorer/directive-forest/directive-forest.component.html @@ -37,39 +37,41 @@ } {{ node.name }} - @if (node.directives) { - [{{ node.directives }}] - } - @if (isSelected(node)) { - == $ng0 - } - - @switch(node.hydration?.status) { - @case('hydrated') { - water_drop + @if (node.directives) { + [{{ node.directives }}] } - @case('skipped') { - invert_colors_off + @if (isSelected(node)) { + == $ng0 } - @case('mismatched') { - error_outline - } - } -
- @if(node.hydration?.status === 'mismatched' && (node.hydration.expectedNodeDetails || node.hydration.actualNodeDetails)) { -
- @if(node.hydration.expectedNodeDetails) { -
Expected Dom:
-
{{node.hydration.expectedNodeDetails}}
- } - @if(node.hydration.actualNodeDetails) { -
Actual Dom:
-
{{node.hydration.actualNodeDetails}}
+ + @switch (node.hydration?.status) { + @case ('hydrated') { + water_drop + } + @case ('skipped') { + invert_colors_off + } + @case ('mismatched') { + error_outline + } }
- } + @if ( + treeControl.isExpanded(node) && + node.hydration?.status === 'mismatched' && + (node.hydration.expectedNodeDetails || node.hydration.actualNodeDetails) + ) { +
+ @if (node.hydration.expectedNodeDetails) { +
Expected Dom:
+
{{node.hydration.expectedNodeDetails}}
+ } + @if (node.hydration.actualNodeDetails) { +
Actual Dom:
+
{{node.hydration.actualNodeDetails}}
+ } +
+ }
- -