Skip to content

Commit 1cddf07

Browse files
authored
HParams: project header cell components (#6422)
## Motivation for features / changes This refactoring allows more customization of the data table which will be used by both the runs table and scalar card. This allows the parents(like the runs table) to add functionality to the header component such as the color pallet and select all checkbox. ## Technical description of changes This change pulls out the header cells from the DataTable and allows the parent component to project them back down. We add a HeaderCellComponent which is used keep consistency and allow the DataTable to still keep the logic which should be on all tables such as dragging and sorting. This is done by using event emitters in the HeaderCellComponent which the DataTable subscribes to. ## Screenshots of UI changes (or N/A) The Scalar table has no changes. <img width="358" alt="Screenshot 2023-06-07 at 9 38 21 PM" src="https://github.com/tensorflow/tensorboard/assets/8672809/7afd8a70-bfec-4707-a15c-f6abc28ec533"> This does break the runs data table which is still behind a flag. This will be fixed in a follow up. <img width="420" alt="Screenshot 2023-06-07 at 9 39 40 PM" src="https://github.com/tensorflow/tensorboard/assets/8672809/22f856aa-1921-442d-9342-f423f4db5b6e"> ## Detailed steps to verify changes work correctly (as executed by you) Ran it and clicked a round a lot to try and break it. ## Alternate designs / implementations considered (or N/A) We considered a more config based solution where we add lots of options for functionality in the header objects being passed down to the table.
1 parent 683184f commit 1cddf07

11 files changed

+404
-124
lines changed

tensorboard/webapp/metrics/views/card_renderer/scalar_card_data_table.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,16 @@ import {isDatumVisible} from './utils';
4848
[smoothingEnabled]="smoothingEnabled"
4949
(sortDataBy)="sortDataBy.emit($event)"
5050
(orderColumns)="orderColumns($event)"
51-
></tb-data-table>
51+
>
52+
<ng-container header>
53+
<ng-container *ngFor="let header of columnHeaders">
54+
<tb-data-table-header-cell
55+
*ngIf="header.enabled"
56+
[header]="header"
57+
[sortingInfo]="sortingInfo"
58+
></tb-data-table-header-cell> </ng-container
59+
></ng-container>
60+
</tb-data-table>
5261
`,
5362
changeDetection: ChangeDetectionStrategy.OnPush,
5463
})

tensorboard/webapp/widgets/data_table/BUILD

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,16 @@ tf_sass_binary(
1212
],
1313
)
1414

15+
tf_sass_binary(
16+
name = "header_cell_styles",
17+
src = "header_cell_component.scss",
18+
strict_deps = False,
19+
deps = [
20+
"//tensorboard/webapp:angular_material_sass_deps",
21+
"//tensorboard/webapp/theme",
22+
],
23+
)
24+
1525
tf_sass_binary(
1626
name = "data_table_header_styles",
1727
src = "data_table_header_component.scss",
@@ -37,10 +47,13 @@ tf_ng_module(
3747
srcs = [
3848
"data_table_component.ts",
3949
"data_table_module.ts",
50+
"header_cell_component.ts",
4051
],
4152
assets = [
4253
"data_table_component.ng.html",
54+
"header_cell_component.ng.html",
4355
":data_table_styles",
56+
":header_cell_styles",
4457
],
4558
deps = [
4659
":data_table_header",
@@ -50,6 +63,7 @@ tf_ng_module(
5063
"//tensorboard/webapp/widgets/line_chart_v2/lib:formatter",
5164
"@npm//@angular/common",
5265
"@npm//@angular/core",
66+
"@npm//rxjs",
5367
],
5468
)
5569

@@ -107,6 +121,7 @@ tf_ts_library(
107121
srcs = [
108122
"column_selector_test.ts",
109123
"data_table_test.ts",
124+
"header_cell_component_test.ts",
110125
],
111126
deps = [
112127
":column_selector",

tensorboard/webapp/widgets/data_table/data_table_component.ng.html

Lines changed: 1 addition & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -15,37 +15,7 @@
1515
<div class="data-table">
1616
<div class="header">
1717
<div class="col"></div>
18-
<ng-container *ngFor="let header of headers;">
19-
<div
20-
class="col"
21-
*ngIf="showColumn(header)"
22-
(click)="headerClicked(header.name)"
23-
>
24-
<div
25-
[draggable]="columnCustomizationEnabled"
26-
(dragstart)="dragStart(header)"
27-
(dragend)="dragEnd()"
28-
(dragenter)="dragEnter(header)"
29-
class="cell"
30-
[ngClass]="getHeaderHighlightStyle(header.name)"
31-
>
32-
<tb-data-table-header [header]="header"></tb-data-table-header>
33-
34-
<div class="sorting-icon-container">
35-
<mat-icon
36-
*ngIf="sortingInfo.order === SortingOrder.ASCENDING || header.name !== sortingInfo.name"
37-
[ngClass]="header.name === sortingInfo.name ? 'show' : 'show-on-hover'"
38-
svgIcon="arrow_upward_24px"
39-
></mat-icon>
40-
<mat-icon
41-
*ngIf="sortingInfo.order === SortingOrder.DESCENDING && header.name === sortingInfo.name"
42-
[ngClass]="header.name === sortingInfo.name ? 'show' : 'show-on-hover'"
43-
svgIcon="arrow_downward_24px"
44-
></mat-icon>
45-
</div>
46-
</div>
47-
</div>
48-
</ng-container>
18+
<ng-content select="[header]"></ng-content>
4919
</div>
5020
<ng-container *ngFor="let runData of data;">
5121
<div class="row">

tensorboard/webapp/widgets/data_table/data_table_component.scss

Lines changed: 0 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -47,13 +47,6 @@ $_accent: map-get(mat.get-color-config($tb-theme), accent);
4747
@include tb-dark-theme {
4848
background-color: map-get($tb-dark-background, background);
4949
}
50-
.col:hover .show-on-hover {
51-
opacity: 0.3;
52-
}
53-
54-
.col {
55-
vertical-align: bottom;
56-
}
5750
}
5851

5952
.col {
@@ -90,30 +83,4 @@ $_accent: map-get(mat.get-color-config($tb-theme), accent);
9083
fill: unset;
9184
}
9285
}
93-
94-
.sorting-icon-container {
95-
width: 12px;
96-
height: 12px;
97-
border-radius: 5px;
98-
}
99-
100-
.show {
101-
opacity: 1;
102-
}
103-
104-
.show-on-hover {
105-
opacity: 0;
106-
}
107-
108-
.highlight {
109-
background-color: mat.get-color-from-palette(mat.$gray-palette, 200);
110-
}
111-
112-
.highlight-border-right {
113-
border-right: 2px solid mat.get-color-from-palette($_accent);
114-
}
115-
116-
.highlight-border-left {
117-
border-left: 2px solid mat.get-color-from-palette($_accent);
118-
}
11986
}

tensorboard/webapp/widgets/data_table/data_table_component.ts

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,15 @@ limitations under the License.
1414
==============================================================================*/
1515

1616
import {
17+
AfterContentInit,
1718
ChangeDetectionStrategy,
1819
Component,
20+
ContentChildren,
1921
EventEmitter,
2022
Input,
2123
OnDestroy,
2224
Output,
25+
QueryList,
2326
} from '@angular/core';
2427
import {
2528
ColumnHeader,
@@ -33,6 +36,8 @@ import {
3336
numberFormatter,
3437
relativeTimeFormatter,
3538
} from '../line_chart_v2/lib/formatter';
39+
import {HeaderCellComponent} from './header_cell_component';
40+
import {Subscription} from 'rxjs';
3641

3742
enum Side {
3843
RIGHT,
@@ -49,7 +54,7 @@ const preventDefault = function (e: MouseEvent) {
4954
styleUrls: ['data_table_component.css'],
5055
changeDetection: ChangeDetectionStrategy.OnPush,
5156
})
52-
export class DataTableComponent implements OnDestroy {
57+
export class DataTableComponent implements OnDestroy, AfterContentInit {
5358
// The order of this array of headers determines the order which they are
5459
// displayed in the table.
5560
@Input() headers!: ColumnHeader[];
@@ -58,6 +63,10 @@ export class DataTableComponent implements OnDestroy {
5863
@Input() columnCustomizationEnabled!: boolean;
5964
@Input() smoothingEnabled!: boolean;
6065

66+
@ContentChildren(HeaderCellComponent)
67+
headerCells!: QueryList<HeaderCellComponent>;
68+
headerCellSubscriptions: Subscription[] = [];
69+
6170
@Output() sortDataBy = new EventEmitter<SortingInfo>();
6271
@Output() orderColumns = new EventEmitter<ColumnHeader[]>();
6372

@@ -71,6 +80,29 @@ export class DataTableComponent implements OnDestroy {
7180

7281
ngOnDestroy() {
7382
document.removeEventListener('dragover', preventDefault);
83+
this.headerCellSubscriptions.forEach((subscription) => {
84+
subscription.unsubscribe();
85+
});
86+
}
87+
88+
ngAfterContentInit() {
89+
this.syncHeaders();
90+
this.headerCells.changes.subscribe(this.syncHeaders.bind(this));
91+
}
92+
93+
syncHeaders() {
94+
this.headerCellSubscriptions.forEach((subscription) => {
95+
subscription.unsubscribe();
96+
});
97+
this.headerCellSubscriptions = [];
98+
this.headerCells.forEach((headerCell) => {
99+
this.headerCellSubscriptions.push(
100+
headerCell.dragStart.subscribe(this.dragStart.bind(this)),
101+
headerCell.dragEnter.subscribe(this.dragEnter.bind(this)),
102+
headerCell.dragEnd.subscribe(this.dragEnd.bind(this)),
103+
headerCell.headerClicked.subscribe(this.headerClicked.bind(this))
104+
);
105+
});
74106
}
75107

76108
getFormattedDataForColumn(
@@ -154,6 +186,9 @@ export class DataTableComponent implements OnDestroy {
154186
this.draggingHeaderName = undefined;
155187
this.highlightedColumnName = undefined;
156188
document.removeEventListener('dragover', preventDefault);
189+
this.headerCells.forEach((headerCell) => {
190+
headerCell.highlightStyle$.next({});
191+
});
157192
}
158193

159194
dragEnter(header: ColumnHeader) {
@@ -169,6 +204,12 @@ export class DataTableComponent implements OnDestroy {
169204
this.highlightSide = Side.RIGHT;
170205
}
171206
this.highlightedColumnName = header.name;
207+
208+
this.headerCells.forEach((headerCell) => {
209+
headerCell.highlightStyle$.next(
210+
this.getHeaderHighlightStyle(headerCell.header.name)
211+
);
212+
});
172213
}
173214

174215
// Move the item at sourceIndex to destinationIndex

tensorboard/webapp/widgets/data_table/data_table_module.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,12 @@ import {CommonModule} from '@angular/common';
1717
import {NgModule} from '@angular/core';
1818
import {MatIconModule} from '@angular/material/icon';
1919
import {DataTableComponent} from './data_table_component';
20+
import {HeaderCellComponent} from './header_cell_component';
2021
import {DataTableHeaderModule} from './data_table_header_module';
2122

2223
@NgModule({
23-
declarations: [DataTableComponent],
24-
exports: [DataTableComponent],
24+
declarations: [DataTableComponent, HeaderCellComponent],
25+
exports: [DataTableComponent, HeaderCellComponent],
2526
imports: [CommonModule, MatIconModule, DataTableHeaderModule],
2627
})
2728
export class DataTableModule {}

0 commit comments

Comments
 (0)