diff --git a/tensorboard/webapp/metrics/views/card_renderer/scalar_card_data_table.ng.html b/tensorboard/webapp/metrics/views/card_renderer/scalar_card_data_table.ng.html index f787fb2a85..a2a49f9530 100644 --- a/tensorboard/webapp/metrics/views/card_renderer/scalar_card_data_table.ng.html +++ b/tensorboard/webapp/metrics/views/card_renderer/scalar_card_data_table.ng.html @@ -22,6 +22,7 @@ [selectableColumns]="selectableColumns" [numColumnsLoaded]="numColumnsLoaded" [hasMoreColumnsToLoad]="numColumnsLoaded === numColumnsToLoad" + [addColumnSize]="AddColumnSize.SMALL" (sortDataBy)="sortDataBy.emit($event)" (orderColumns)="onOrderColumns($event)" (addColumn)="addColumn.emit($event)" diff --git a/tensorboard/webapp/metrics/views/card_renderer/scalar_card_data_table.ts b/tensorboard/webapp/metrics/views/card_renderer/scalar_card_data_table.ts index 6764b0a3b5..97602aaecf 100644 --- a/tensorboard/webapp/metrics/views/card_renderer/scalar_card_data_table.ts +++ b/tensorboard/webapp/metrics/views/card_renderer/scalar_card_data_table.ts @@ -41,6 +41,7 @@ import { FilterAddedEvent, ReorderColumnEvent, AddColumnEvent, + AddColumnSize, } from '../../../widgets/data_table/types'; import {isDatumVisible} from './utils'; import {memoize} from '../../../util/memoize'; @@ -73,7 +74,8 @@ export class ScalarCardDataTable { @Output() addFilter = new EventEmitter(); @Output() loadAllColumns = new EventEmitter(); - ColumnHeaderType = ColumnHeaderType; + readonly ColumnHeaderType = ColumnHeaderType; + readonly AddColumnSize = AddColumnSize; // Columns must be memoized to stop needless re-rendering of the content and headers in these // columns. This has been known to cause problems with the controls in these columns, diff --git a/tensorboard/webapp/runs/views/runs_table/runs_data_table.ng.html b/tensorboard/webapp/runs/views/runs_table/runs_data_table.ng.html index 1b3dc0416a..9845b75c60 100644 --- a/tensorboard/webapp/runs/views/runs_table/runs_data_table.ng.html +++ b/tensorboard/webapp/runs/views/runs_table/runs_data_table.ng.html @@ -33,6 +33,7 @@ [hasMoreColumnsToLoad]="numColumnsLoaded === numColumnsToLoad" [columnFilters]="columnFilters" [loading]="loading" + [shouldAddBorders]="true" (sortDataBy)="sortDataBy.emit($event)" (orderColumns)="orderColumns.emit($event)" (addColumn)="addColumn.emit($event)" diff --git a/tensorboard/webapp/runs/views/runs_table/runs_data_table.scss b/tensorboard/webapp/runs/views/runs_table/runs_data_table.scss index 2f1e9610c1..31534ca835 100644 --- a/tensorboard/webapp/runs/views/runs_table/runs_data_table.scss +++ b/tensorboard/webapp/runs/views/runs_table/runs_data_table.scss @@ -18,10 +18,6 @@ $_circle-size: 20px; :host { min-width: 100%; - - & ::ng-deep tb-data-table .data-table { - @include tb-theme-foreground-prop(border-top, border, 1px solid); - } } .color-container { @@ -55,14 +51,6 @@ tb-data-table-header-cell { padding: 0 4px; vertical-align: middle; @include tb-theme-foreground-prop(border-bottom, border, 1px solid); - - &:last-child { - @include tb-theme-foreground-prop(border-right, border, 1px solid); - } -} - -tb-data-table-header-cell:last-of-type { - @include tb-theme-foreground-prop(border-right, border, 1px solid); } .table-column-selected, diff --git a/tensorboard/webapp/theme/_tb_theme.template.scss b/tensorboard/webapp/theme/_tb_theme.template.scss index 6bef55d34f..46a748a128 100644 --- a/tensorboard/webapp/theme/_tb_theme.template.scss +++ b/tensorboard/webapp/theme/_tb_theme.template.scss @@ -312,14 +312,16 @@ $tb-dark-theme: map_merge( button.mat-mdc-button-base { --tb-icon-width: 24px; --tb-icon-height: 24px; + --tb-icon-button-width: 40px; + --tb-icon-button-height: 40px; --mdc-text-button-label-text-tracking: normal; --mdc-filled-button-label-text-tracking: normal; --mdc-outlined-button-label-text-tracking: normal; --mdc-protected-button-label-text-tracking: normal; &[mat-icon-button].mat-mdc-icon-button { - width: 40px; - height: 40px; + width: var(--tb-icon-button-width); + height: var(--tb-icon-button-height); display: inline-flex; justify-content: center; align-items: center; diff --git a/tensorboard/webapp/widgets/data_table/data_table_component.ng.html b/tensorboard/webapp/widgets/data_table/data_table_component.ng.html index 9fea50b51f..c641da6dd3 100644 --- a/tensorboard/webapp/widgets/data_table/data_table_component.ng.html +++ b/tensorboard/webapp/widgets/data_table/data_table_component.ng.html @@ -43,16 +43,26 @@ > -
-
- +
+
+
+
+ +
+ +
+
+
-
diff --git a/tensorboard/webapp/widgets/data_table/data_table_component.scss b/tensorboard/webapp/widgets/data_table/data_table_component.scss index db88c5d54f..4413c69100 100644 --- a/tensorboard/webapp/widgets/data_table/data_table_component.scss +++ b/tensorboard/webapp/widgets/data_table/data_table_component.scss @@ -17,23 +17,35 @@ limitations under the License. $_accent: map-get(mat.get-color-config($tb-theme), accent); +.data-table-wrapper { + display: flex; + + &.should-add-borders { + .left-section, + .right-section { + @include tb-theme-foreground-prop(border-top, border, 1px solid); + } + + .add-button-column { + @include tb-theme-foreground-prop(border-left, border, 1px solid); + } + } +} + .data-table { font-size: 13px; display: table; width: 100%; - .header { - display: table-row; - z-index: 1; - } - .header { background-color: mat.get-color-from-palette($tb-background, background); + display: table-row; + font-weight: bold; position: sticky; text-align: left; top: 0; - font-weight: bold; vertical-align: bottom; + z-index: 1; &:hover { cursor: pointer; @@ -55,7 +67,38 @@ $_accent: map-get(mat.get-color-config($tb-theme), accent); justify-content: center; } -.add-button-cell { - display: table-cell; - width: 40px; +.left-section { + flex-grow: 1; +} + +.right-section { + background-color: mat.get-color-from-palette($tb-background, background); + position: sticky; + right: -1px; // Prevent fractional width from creating a gap. + z-index: 1; + + @include tb-dark-theme { + background-color: map-get($tb-dark-background, background); + } + + .add-button-column { + width: 40px; + height: 100%; + + .add-button { + position: sticky; + top: 0; + } + } +} + +.right-section .add-button-column.small-add-button { + display: flex; + justify-content: center; + width: 24px; + + .add-button { + --tb-icon-button-width: 20px; + --tb-icon-button-height: 20px; + } } diff --git a/tensorboard/webapp/widgets/data_table/data_table_component.ts b/tensorboard/webapp/widgets/data_table/data_table_component.ts index afc9722202..f4e1f108e1 100644 --- a/tensorboard/webapp/widgets/data_table/data_table_component.ts +++ b/tensorboard/webapp/widgets/data_table/data_table_component.ts @@ -38,6 +38,7 @@ import { ReorderColumnEvent, Side, AddColumnEvent, + AddColumnSize, } from './types'; import {HeaderCellComponent} from './header_cell_component'; import {Subscription} from 'rxjs'; @@ -67,6 +68,8 @@ export class DataTableComponent implements OnDestroy, AfterContentInit { @Input() hasMoreColumnsToLoad!: boolean; @Input() columnFilters!: Map; @Input() loading: boolean = false; + @Input() shouldAddBorders: boolean = false; + @Input() addColumnSize: AddColumnSize = AddColumnSize.DEFAULT; @ContentChildren(HeaderCellComponent) headerCells!: QueryList; @@ -102,6 +105,7 @@ export class DataTableComponent implements OnDestroy, AfterContentInit { readonly SortingOrder = SortingOrder; readonly Side = Side; + readonly AddColumnSize = AddColumnSize; constructor( private readonly customModal: CustomModal, diff --git a/tensorboard/webapp/widgets/data_table/data_table_test.ts b/tensorboard/webapp/widgets/data_table/data_table_test.ts index eb918b4774..6ec0d1b542 100644 --- a/tensorboard/webapp/widgets/data_table/data_table_test.ts +++ b/tensorboard/webapp/widgets/data_table/data_table_test.ts @@ -45,6 +45,8 @@ import {ColumnSelectorModule} from './column_selector_module'; import {FilterDialog} from './filter_dialog_component'; import {CustomModal} from '../custom_modal/custom_modal'; +const ADD_BUTTON_PREDICATE = By.css('.add-button'); + @Component({ selector: 'testable-comp', template: ` @@ -595,7 +597,7 @@ describe('data table', () => { it('does not show add button when there are no selectable columns', () => { const fixture = createComponent({}); - expect(fixture.debugElement.query(By.css('.add-column-button'))).toBeNull(); + expect(fixture.debugElement.query(ADD_BUTTON_PREDICATE)).toBeNull(); }); it('renders column selector when + button is clicked', () => { @@ -612,7 +614,7 @@ describe('data table', () => { expect( fixture.debugElement.query(By.directive(ColumnSelectorComponent)) ).toBeNull(); - const addBtn = fixture.debugElement.query(By.css('.add-column-btn')); + const addBtn = fixture.debugElement.query(ADD_BUTTON_PREDICATE); addBtn.nativeElement.click(); expect( fixture.debugElement.query(By.directive(ColumnSelectorComponent)) diff --git a/tensorboard/webapp/widgets/data_table/types.ts b/tensorboard/webapp/widgets/data_table/types.ts index 70efa4bd02..b2d3e29cf0 100644 --- a/tensorboard/webapp/widgets/data_table/types.ts +++ b/tensorboard/webapp/widgets/data_table/types.ts @@ -136,3 +136,8 @@ export enum ColumnGroup { HPARAM = 'HPARAM', OTHER = 'OTHER', } + +export enum AddColumnSize { + DEFAULT = 'DEFAULT', + SMALL = 'SMALL', +}