Skip to content

Commit aa170ac

Browse files
feat(ui): add recursive expand/collapse toggle to json tree viewer
- add single toggle button in top-right corner of json-tree component - delegates to @alenaksu/json-viewer native expandAll()/collapseAll() API - button uses Material icons, semi-transparent until hovered - overflow: hidden on :host prevents scrollbar regression - update state-visualization docs to mention the feature
1 parent eeaac9f commit aa170ac

File tree

4 files changed

+54
-5
lines changed

4 files changed

+54
-5
lines changed

docs/docs/features/state-visualization.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ Explore your application state with a tree-based JSON viewer.
1111

1212
The state viewer provides an interactive tree representation of your entire NgRx store state. You can:
1313

14-
- Expand and collapse nested objects
14+
- Expand and collapse nested objects individually
15+
- Expand or collapse all nodes at once with the toggle button
1516
- Search through the state tree
1617
- Copy values to clipboard
1718
- View raw JSON
Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,7 @@
1-
<json-viewer [data]="jsonData"></json-viewer>
1+
<button mat-icon-button
2+
class="tree-toggle-btn"
3+
[matTooltip]="expanded ? 'Collapse All' : 'Expand All'"
4+
(click)="toggle()">
5+
<mat-icon>{{ expanded ? 'unfold_less' : 'unfold_more' }}</mat-icon>
6+
</button>
7+
<json-viewer #jsonViewer [data]="jsonData"></json-viewer>

projects/ngrx-devtool-ui/src/components/json-tree/json-tree.component.scss

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,25 @@
11
@use '../../styles/theme' as *;
22

3+
:host {
4+
display: block;
5+
position: relative;
6+
overflow: hidden;
7+
}
8+
9+
.tree-toggle-btn {
10+
position: absolute;
11+
top: 0;
12+
right: 0;
13+
z-index: 1;
14+
color: #{$color-on-surface-variant};
15+
opacity: 0.6;
16+
17+
&:hover {
18+
opacity: 1;
19+
color: #{$color-primary};
20+
}
21+
}
22+
323
json-viewer {
424
--background-color: #{$color-background};
525
--property-color: #{$color-primary};
Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,38 @@
1-
import { Component, CUSTOM_ELEMENTS_SCHEMA, Input } from '@angular/core';
1+
import { Component, CUSTOM_ELEMENTS_SCHEMA, ElementRef, Input, ViewChild } from '@angular/core';
2+
import { MatButtonModule } from '@angular/material/button';
3+
import { MatIconModule } from '@angular/material/icon';
4+
import { MatTooltipModule } from '@angular/material/tooltip';
5+
26
export interface JsonTreeNode {
37
key: string;
48
value?: string | number | boolean | null;
59
children?: JsonTreeNode[];
610
}
11+
712
@Component({
813
selector: 'app-json-tree',
9-
imports: [],
14+
imports: [MatButtonModule, MatIconModule, MatTooltipModule],
1015
templateUrl: './json-tree.component.html',
1116
styleUrl: './json-tree.component.scss',
1217
schemas: [CUSTOM_ELEMENTS_SCHEMA]
1318
})
14-
export class JsonTreeComponent{
19+
export class JsonTreeComponent {
1520
@Input() jsonData: unknown;
21+
22+
@ViewChild('jsonViewer', { static: false })
23+
jsonViewerRef!: ElementRef;
24+
25+
expanded = false;
26+
27+
toggle(): void {
28+
const viewer = this.jsonViewerRef?.nativeElement;
29+
if (!viewer) return;
30+
31+
this.expanded = !this.expanded;
32+
if (this.expanded && typeof viewer.expandAll === 'function') {
33+
viewer.expandAll();
34+
} else if (!this.expanded && typeof viewer.collapseAll === 'function') {
35+
viewer.collapseAll();
36+
}
37+
}
1638
}

0 commit comments

Comments
 (0)