refactor(devtools): refactors property view drag-and-drop behavior (#60286)

The main goal of this change is to remove `categoryOrder` which effectively hard-codes the supported length of `panels`. Adding another item to `panels` is not rendered unless that is added to `categoryOrder`.

My solution to this is to make the set of categories a signal, with each category able to produce the data inside it. This allow `CdkDragDrop` to rearrange categories but then still produce the correct data in the template without needing a separate array to track order.

Also removed `hidden` and inlined it in the template, since the logic was the same for every panel.

`moveItemInArray` is unfortunately an in-place move, so I needed to manually clone the array to ensure `panels` observes an immutable update which works better with signals and change detection.

PR Close #60286
This commit is contained in:
Doug Parker 2025-03-07 15:58:26 -08:00 committed by Andrew Kushnir
parent b144dd946e
commit e59432cf07
2 changed files with 24 additions and 37 deletions

View file

@ -22,17 +22,16 @@
</mat-expansion-panel>
</div>
}
@for (index of categoryOrder; track $index) {
@for (panel of panels(); track $index) {
<div class="mat-accordion-content" cdkDrag>
@let panel = panels()[index];
@if (!panel.hidden) {
@if (panel.controls().dataSource.data.length > 0) {
<mat-expansion-panel [class]="panel.class" [expanded]="true">
<mat-expansion-panel-header collapsedHeight="25px" expandedHeight="25px">
<mat-panel-title>{{ panel.title }}</mat-panel-title>
</mat-expansion-panel-header>
<ng-property-view-tree
[dataSource]="panel.controls.dataSource"
[treeControl]="panel.controls.treeControl"
[dataSource]="panel.controls().dataSource"
[treeControl]="panel.controls().treeControl"
(updateValue)="updateValue($event)"
(inspect)="handleInspect($event)"
/>

View file

@ -7,7 +7,7 @@
*/
import {CdkDragDrop, moveItemInArray, CdkDropList, CdkDrag} from '@angular/cdk/drag-drop';
import {Component, computed, forwardRef, input, output} from '@angular/core';
import {Component, computed, forwardRef, input, output, signal} from '@angular/core';
import {DirectivePosition, SerializedInjectedService} from 'protocol';
import {
@ -44,37 +44,23 @@ export class PropertyViewBodyComponent {
readonly inspect = output<{node: FlatNode; directivePosition: DirectivePosition}>();
categoryOrder = [0, 1, 2];
readonly panels = computed<
protected readonly panels = signal([
{
title: string;
hidden: boolean;
controls: DirectiveTreeData;
class: string;
}[]
>(() => {
return [
{
title: 'Inputs',
hidden: this.directiveInputControls().dataSource.data.length === 0,
controls: this.directiveInputControls(),
class: 'cy-inputs',
},
{
title: 'Outputs',
hidden: this.directiveOutputControls().dataSource.data.length === 0,
controls: this.directiveOutputControls(),
class: 'cy-outputs',
},
{
title: 'Properties',
hidden: this.directiveStateControls().dataSource.data.length === 0,
controls: this.directiveStateControls(),
class: 'cy-properties',
},
];
});
title: 'Inputs',
controls: () => this.directiveInputControls(),
class: 'cy-inputs',
},
{
title: 'Outputs',
controls: () => this.directiveOutputControls(),
class: 'cy-outputs',
},
{
title: 'Properties',
controls: () => this.directiveStateControls(),
class: 'cy-properties',
},
]);
readonly controlsLoaded = computed(() => {
return (
@ -89,7 +75,9 @@ export class PropertyViewBodyComponent {
}
drop(event: CdkDragDrop<any, any>): void {
moveItemInArray(this.categoryOrder, event.previousIndex, event.currentIndex);
const panels = this.panels();
moveItemInArray(panels, event.previousIndex, event.currentIndex);
this.panels.set(Array.from(panels)); // Clone array for immutable update.
}
handleInspect(node: FlatNode): void {