diff --git a/tensorboard/webapp/core/views/layout_container.ts b/tensorboard/webapp/core/views/layout_container.ts
index e714ed9b19..e90276da5b 100644
--- a/tensorboard/webapp/core/views/layout_container.ts
+++ b/tensorboard/webapp/core/views/layout_container.ts
@@ -20,11 +20,14 @@ import {
} from '@angular/core';
import {Store} from '@ngrx/store';
import {fromEvent, Observable, Subject} from 'rxjs';
-import {filter, takeUntil} from 'rxjs/operators';
+import {combineLatestWith, filter, map, takeUntil} from 'rxjs/operators';
import {MouseEventButtons} from '../../util/dom';
import {sideBarWidthChanged} from '../actions';
import {State} from '../state';
-import {getSideBarWidthInPercent} from '../store/core_selectors';
+import {
+ getRunsTableFullScreen,
+ getSideBarWidthInPercent,
+} from '../store/core_selectors';
@Component({
selector: 'tb-dashboard-layout',
@@ -41,6 +44,7 @@ import {getSideBarWidthInPercent} from '../store/core_selectors';
class="sidebar"
[style.width.%]="width$ | async"
[style.minWidth.px]="MINIMUM_SIDEBAR_WIDTH_IN_PX"
+ [style.maxWidth.%]="(runsTableFullScreen$ | async) ? 100 : ''"
>
@@ -55,9 +59,15 @@ import {getSideBarWidthInPercent} from '../store/core_selectors';
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class LayoutContainer implements OnDestroy {
- readonly width$: Observable = this.store.select(
- getSideBarWidthInPercent
- );
+ readonly runsTableFullScreen$ = this.store.select(getRunsTableFullScreen);
+ readonly width$: Observable = this.store
+ .select(getSideBarWidthInPercent)
+ .pipe(
+ combineLatestWith(this.runsTableFullScreen$),
+ map(([percentageWidth, fullScreen]) => {
+ return fullScreen ? 100 : percentageWidth;
+ })
+ );
private readonly ngUnsubscribe = new Subject();
private resizing: boolean = false;
diff --git a/tensorboard/webapp/core/views/layout_test.ts b/tensorboard/webapp/core/views/layout_test.ts
index 2a6b09454e..c4beca2435 100644
--- a/tensorboard/webapp/core/views/layout_test.ts
+++ b/tensorboard/webapp/core/views/layout_test.ts
@@ -23,7 +23,10 @@ import {provideMockTbStore} from '../../testing/utils';
import {MouseEventButtons} from '../../util/dom';
import {sideBarWidthChanged} from '../actions';
import {State} from '../state';
-import {getSideBarWidthInPercent} from '../store/core_selectors';
+import {
+ getRunsTableFullScreen,
+ getSideBarWidthInPercent,
+} from '../store/core_selectors';
import {LayoutContainer} from './layout_container';
@Component({
@@ -137,6 +140,15 @@ describe('layout test', () => {
expect(navEl.styles['width']).toBe('70%');
});
+ it('overrides max width when the runs table full screen is true', () => {
+ store.overrideSelector(getRunsTableFullScreen, true);
+ const fixture = TestBed.createComponent(TestableComponent);
+ fixture.detectChanges();
+
+ const navEl = fixture.debugElement.query(byCss.SIDEBAR_CONTAINER);
+ expect(navEl.styles['width']).toBe('100%');
+ });
+
describe('interactions', () => {
function triggerMouseMove(
fixture: ComponentFixture,
diff --git a/tensorboard/webapp/metrics/views/BUILD b/tensorboard/webapp/metrics/views/BUILD
index 77405137b5..66fbb2d274 100644
--- a/tensorboard/webapp/metrics/views/BUILD
+++ b/tensorboard/webapp/metrics/views/BUILD
@@ -33,6 +33,7 @@ tf_ng_module(
"//tensorboard/webapp:selectors",
"//tensorboard/webapp/angular:expect_angular_material_icon",
"//tensorboard/webapp/core",
+ "//tensorboard/webapp/core/store",
"//tensorboard/webapp/customization",
"//tensorboard/webapp/feature_flag/store",
"//tensorboard/webapp/feature_flag/store:types",
@@ -80,9 +81,11 @@ tf_ts_library(
"//tensorboard/webapp/angular:expect_angular_core_testing",
"//tensorboard/webapp/angular:expect_angular_platform_browser_animations",
"//tensorboard/webapp/angular:expect_ngrx_store_testing",
+ "//tensorboard/webapp/core/store",
"//tensorboard/webapp/feature_flag/store",
"//tensorboard/webapp/metrics/actions",
"//tensorboard/webapp/metrics/data_source",
+ "//tensorboard/webapp/metrics/views/main_view",
"//tensorboard/webapp/runs/views/runs_selector",
"//tensorboard/webapp/testing:utils",
"@npm//@angular/core",
diff --git a/tensorboard/webapp/metrics/views/metrics_container.ts b/tensorboard/webapp/metrics/views/metrics_container.ts
index 7328ab47c8..3059e52ff6 100644
--- a/tensorboard/webapp/metrics/views/metrics_container.ts
+++ b/tensorboard/webapp/metrics/views/metrics_container.ts
@@ -15,7 +15,8 @@ limitations under the License.
import {ChangeDetectionStrategy, Component} from '@angular/core';
import {Store} from '@ngrx/store';
import {getEnableHparamsInTimeSeries} from '../../feature_flag/store/feature_flag_selectors';
-import {State} from '../../feature_flag/store/feature_flag_types';
+import {State} from '../../app_state';
+import {getRunsTableFullScreen} from '../../core/store/core_selectors';
@Component({
selector: 'metrics-dashboard',
@@ -25,7 +26,10 @@ import {State} from '../../feature_flag/store/feature_flag_types';
[showHparamsAndMetrics]="showHparamsAndMetrics$ | async"
sidebar
>
-
+
`,
styleUrls: ['metrics_container.css'],
@@ -33,6 +37,7 @@ import {State} from '../../feature_flag/store/feature_flag_types';
})
export class MetricsDashboardContainer {
showHparamsAndMetrics$ = this.store.select(getEnableHparamsInTimeSeries);
+ runsTableFullScreen$ = this.store.select(getRunsTableFullScreen);
constructor(readonly store: Store) {}
}
diff --git a/tensorboard/webapp/metrics/views/metrics_container_test.ts b/tensorboard/webapp/metrics/views/metrics_container_test.ts
index 5814d45bfc..19748134b8 100644
--- a/tensorboard/webapp/metrics/views/metrics_container_test.ts
+++ b/tensorboard/webapp/metrics/views/metrics_container_test.ts
@@ -22,6 +22,8 @@ import {getEnableHparamsInTimeSeries} from '../../feature_flag/store/feature_fla
import {RunsSelectorContainer} from '../../runs/views/runs_selector/runs_selector_container';
import {provideMockTbStore} from '../../testing/utils';
import {MetricsDashboardContainer} from './metrics_container';
+import {getRunsTableFullScreen} from '../../core/store/core_selectors';
+import {MainViewContainer} from './main_view/main_view_container';
describe('metrics view', () => {
let store: MockStore;
@@ -64,4 +66,14 @@ describe('metrics view', () => {
.showHparamsAndMetrics
).toBeFalse();
});
+
+ it('hides main view when the runs table is full screen is true', () => {
+ store.overrideSelector(getRunsTableFullScreen, true);
+ const fixture = TestBed.createComponent(MetricsDashboardContainer);
+ fixture.detectChanges();
+
+ expect(
+ fixture.debugElement.query(By.directive(MainViewContainer))
+ ).toBeNull();
+ });
});
diff --git a/tensorboard/webapp/runs/views/runs_table/BUILD b/tensorboard/webapp/runs/views/runs_table/BUILD
index 79be955ddb..4d936d8af1 100644
--- a/tensorboard/webapp/runs/views/runs_table/BUILD
+++ b/tensorboard/webapp/runs/views/runs_table/BUILD
@@ -94,6 +94,7 @@ tf_ng_module(
"//tensorboard/webapp/angular:expect_angular_material_table",
"//tensorboard/webapp/app_routing",
"//tensorboard/webapp/app_routing:types",
+ "//tensorboard/webapp/core/actions",
"//tensorboard/webapp/experiments:types",
"//tensorboard/webapp/feature_flag/store",
"//tensorboard/webapp/hparams",
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 8763af9b5b..702428d747 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
@@ -91,3 +91,16 @@
+
+
+
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 6da2f0f472..31cb544a62 100644
--- a/tensorboard/webapp/runs/views/runs_table/runs_data_table.scss
+++ b/tensorboard/webapp/runs/views/runs_table/runs_data_table.scss
@@ -15,6 +15,11 @@ limitations under the License.
@use '@angular/material' as mat;
@import 'tensorboard/webapp/theme/tb_theme';
$_circle-size: 20px;
+$_arrow_size: 16px;
+
+:host {
+ width: 100%;
+}
.color-container {
display: flex;
@@ -30,10 +35,6 @@ $_circle-size: 20px;
outline: none;
}
-:host {
- width: 100%;
-}
-
tb-data-table-content-row,
tb-data-table-header-cell {
height: 44px;
@@ -52,3 +53,44 @@ tb-data-table-header-cell {
padding-right: 16px;
}
}
+
+.full-screen-toggle {
+ opacity: 0;
+ position: absolute;
+ height: 100%;
+ // Ensure the button is on the right side then add 2px for the drag target.
+ left: calc(100% + 2px);
+ top: 0;
+ z-index: 1;
+ display: flex;
+ align-items: center;
+
+ &:hover {
+ opacity: 0.8;
+ }
+
+ &.full-screen {
+ left: unset;
+ right: 0;
+ }
+
+ .full-screen-btn {
+ background-color: gray;
+ padding: 0;
+ min-width: $_arrow_size;
+ width: $_arrow_size;
+
+ &.expand {
+ border-radius: 0 $_arrow_size $_arrow_size 0;
+ }
+
+ &.collapse {
+ border-radius: $_arrow_size 0 0 $_arrow_size;
+ }
+
+ .expand-collapse-icon {
+ font-size: $_arrow_size;
+ width: $_arrow_size;
+ }
+ }
+}
diff --git a/tensorboard/webapp/runs/views/runs_table/runs_data_table.ts b/tensorboard/webapp/runs/views/runs_table/runs_data_table.ts
index fa6b3a2ff1..4a731900c9 100644
--- a/tensorboard/webapp/runs/views/runs_table/runs_data_table.ts
+++ b/tensorboard/webapp/runs/views/runs_table/runs_data_table.ts
@@ -38,6 +38,7 @@ export class RunsDataTable {
@Input() sortingInfo!: SortingInfo;
@Input() experimentIds!: string[];
@Input() regexFilter!: string;
+ @Input() isFullScreen!: boolean;
ColumnHeaderType = ColumnHeaderType;
@@ -46,6 +47,7 @@ export class RunsDataTable {
@Output() onSelectionToggle = new EventEmitter();
@Output() onAllSelectionToggle = new EventEmitter();
@Output() onRegexFilterChange = new EventEmitter();
+ @Output() toggleFullScreen = new EventEmitter();
@Output() onRunColorChange = new EventEmitter<{
runId: string;
newColor: string;
diff --git a/tensorboard/webapp/runs/views/runs_table/runs_table_container.ts b/tensorboard/webapp/runs/views/runs_table/runs_table_container.ts
index a68319a4f3..2ef43506d1 100644
--- a/tensorboard/webapp/runs/views/runs_table/runs_table_container.ts
+++ b/tensorboard/webapp/runs/views/runs_table/runs_table_container.ts
@@ -57,6 +57,7 @@ import {
getRunSelectorRegexFilter,
getRunSelectorSort,
getRunsLoadState,
+ getRunsTableFullScreen,
getRunsTableHeaders,
getRunsTableSortingInfo,
} from '../../../selectors';
@@ -90,6 +91,7 @@ import {
import {RunsTableColumn, RunTableItem} from './types';
import {getFilteredRenderableRunsFromRoute} from '../../../metrics/views/main_view/common_selectors';
import {RunToHParamValues} from '../../data_source/runs_data_source_types';
+import {runsTableFullScreenToggled} from '../../../core/actions';
const getRunsLoading = createSelector<
State,
@@ -239,12 +241,14 @@ function matchFilter(
[sortingInfo]="sortingInfo$ | async"
[experimentIds]="experimentIds"
[regexFilter]="regexFilter$ | async"
+ [isFullScreen]="runsTableFullScreen$ | async"
(sortDataBy)="sortDataBy($event)"
(orderColumns)="orderColumns($event)"
(onSelectionToggle)="onRunSelectionToggle($event)"
(onAllSelectionToggle)="onAllSelectionToggle($event)"
(onRunColorChange)="onRunColorChange($event)"
(onRegexFilterChange)="onRegexFilterChange($event)"
+ (toggleFullScreen)="toggleFullScreen()"
>
`,
host: {
@@ -252,6 +256,10 @@ function matchFilter(
},
styles: [
`
+ :host {
+ position: relative;
+ }
+
:host.flex-layout {
display: flex;
}
@@ -310,6 +318,7 @@ export class RunsTableContainer implements OnInit, OnDestroy {
regexFilter$ = this.store.select(getRunSelectorRegexFilter);
HParamsEnabled = new BehaviorSubject(false);
runsColumns$ = this.store.select(getRunsTableHeaders);
+ runsTableFullScreen$ = this.store.select(getRunsTableFullScreen);
runToHParamValues$ = this.store
.select(getFilteredRenderableRunsFromRoute)
@@ -777,6 +786,10 @@ export class RunsTableContainer implements OnInit, OnDestroy {
})
);
}
+
+ toggleFullScreen() {
+ this.store.dispatch(runsTableFullScreenToggled());
+ }
}
export const TEST_ONLY = {