Skip to content

Commit d07c2c0

Browse files
authored
Column Customization: New affordances (#6252)
* Motivation for features / changes This PR adds a new affordance for opening the column editor directly from the card menu. It also adds a close button inside the editor. * Screenshots of UI <img width="239" alt="Screenshot 2023-03-24 at 3 28 25 PM" src="https://user-images.githubusercontent.com/8672809/227654782-22bcbe4e-402d-4ed1-96a1-41ad105138ec.png"> <img width="259" alt="Screenshot 2023-03-24 at 3 28 18 PM" src="https://user-images.githubusercontent.com/8672809/227654785-d9b9be95-295f-44a7-b32f-744ad03282a6.png"> <img width="683" alt="Screenshot 2023-03-21 at 11 52 01 AM" src="https://user-images.githubusercontent.com/8672809/226712053-e0b78c56-0d57-4945-a17c-4bd7a6f8447b.png"> I changes
1 parent f9ece07 commit d07c2c0

14 files changed

+193
-10
lines changed

tensorboard/webapp/metrics/actions/index.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,14 @@ export const metricsSlideoutMenuToggled = createAction(
5151
'[Metrics] Slide out settings menu toggled'
5252
);
5353

54+
export const metricsSlideoutMenuOpened = createAction(
55+
'[Metrics] User requested to open the slide out menu'
56+
);
57+
58+
export const metricsSlideoutMenuClosed = createAction(
59+
'[Metrics] Slide out settings menu closed'
60+
);
61+
5462
export const metricsTagMetadataRequested = createAction(
5563
'[Metrics] Metrics Tag Metadata Requested'
5664
);

tensorboard/webapp/metrics/store/metrics_reducers.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1358,6 +1358,16 @@ const reducer = createReducer(
13581358
}),
13591359
on(actions.metricsSlideoutMenuToggled, (state) => {
13601360
return {...state, isSlideoutMenuOpen: !state.isSlideoutMenuOpen};
1361+
}),
1362+
on(actions.metricsSlideoutMenuOpened, (state) => {
1363+
// The reason the toggle action does not open the settings pane is because
1364+
// the settings pane is the only place the menu can be toggled. The open
1365+
// request can be made from the card when the settings menu is closed,
1366+
// therefore we need to make sure the settings menu is opened, too.
1367+
return {...state, isSlideoutMenuOpen: true, isSettingsPaneOpen: true};
1368+
}),
1369+
on(actions.metricsSlideoutMenuClosed, (state) => {
1370+
return {...state, isSlideoutMenuOpen: false};
13611371
})
13621372
);
13631373

tensorboard/webapp/metrics/store/metrics_reducers_test.ts

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3912,4 +3912,62 @@ describe('metrics reducers', () => {
39123912
expect(state3.isSettingsPaneOpen).toBe(false);
39133913
});
39143914
});
3915+
3916+
describe('Metrics Slideout Menu', () => {
3917+
describe('#metricsSlideoutMenuToggled', () => {
3918+
it('toggles the isSlideoutMenuOpen state', () => {
3919+
const state1 = buildMetricsState({
3920+
isSlideoutMenuOpen: false,
3921+
});
3922+
3923+
const state2 = reducers(state1, actions.metricsSlideoutMenuToggled());
3924+
expect(state2.isSlideoutMenuOpen).toBe(true);
3925+
3926+
const state3 = reducers(state2, actions.metricsSlideoutMenuToggled());
3927+
expect(state3.isSlideoutMenuOpen).toBe(false);
3928+
});
3929+
});
3930+
3931+
describe('#metricsSlideoutMenuOpened', () => {
3932+
it('sets the isSlideoutMenuOpen and isSettingsPaneOpen to true', () => {
3933+
const state1 = buildMetricsState({
3934+
isSlideoutMenuOpen: false,
3935+
isSettingsPaneOpen: false,
3936+
});
3937+
3938+
const state2 = reducers(state1, actions.metricsSlideoutMenuOpened());
3939+
expect(state2.isSlideoutMenuOpen).toBe(true);
3940+
expect(state2.isSettingsPaneOpen).toBe(true);
3941+
3942+
const state3 = reducers(state1, actions.metricsSlideoutMenuOpened());
3943+
expect(state3.isSlideoutMenuOpen).toBe(true);
3944+
expect(state3.isSettingsPaneOpen).toBe(true);
3945+
});
3946+
3947+
it('leaves isSettingsPaneOpen as true when it is already set', () => {
3948+
const state1 = buildMetricsState({
3949+
isSlideoutMenuOpen: false,
3950+
isSettingsPaneOpen: true,
3951+
});
3952+
3953+
const state2 = reducers(state1, actions.metricsSlideoutMenuOpened());
3954+
expect(state2.isSlideoutMenuOpen).toBe(true);
3955+
expect(state2.isSettingsPaneOpen).toBe(true);
3956+
});
3957+
});
3958+
3959+
describe('#metricsSlideoutMenuClosed', () => {
3960+
it('sets the isSlideoutMenuOpen to false', () => {
3961+
const state1 = buildMetricsState({
3962+
isSlideoutMenuOpen: true,
3963+
});
3964+
3965+
const state2 = reducers(state1, actions.metricsSlideoutMenuClosed());
3966+
expect(state2.isSlideoutMenuOpen).toBe(false);
3967+
3968+
const state3 = reducers(state1, actions.metricsSlideoutMenuClosed());
3969+
expect(state3.isSlideoutMenuOpen).toBe(false);
3970+
});
3971+
});
3972+
});
39153973
});

tensorboard/webapp/metrics/views/card_renderer/scalar_card_component.ng.html

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,15 @@
9393
<mat-icon svgIcon="get_app_24px"></mat-icon>
9494
<span>Download data</span>
9595
</button>
96+
<button
97+
*ngIf="columnCustomizationEnabled"
98+
mat-menu-item
99+
(click)="openSlideoutColumnEditMenu.emit()"
100+
aria-label="Open menu to edit data table columns"
101+
>
102+
<mat-icon svgIcon="edit_24px"></mat-icon>
103+
<span>Edit Table Columns</span>
104+
</button>
96105
</mat-menu>
97106
</span>
98107
</div>

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ export class ScalarCardComponent<Downloader> {
109109
new EventEmitter<TimeSelectionToggleAffordance>();
110110
@Output() onDataTableSorting = new EventEmitter<SortingInfo>();
111111
@Output() reorderColumnHeaders = new EventEmitter<ColumnHeader[]>();
112+
@Output() openSlideoutColumnEditMenu = new EventEmitter<void>();
112113

113114
@Output() onLineChartZoom = new EventEmitter<Extent>();
114115

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ import {
7474
sortingDataTable,
7575
stepSelectorToggled,
7676
timeSelectionChanged,
77+
metricsSlideoutMenuOpened,
7778
} from '../../actions';
7879
import {PluginType, ScalarStepDatum} from '../../data_source';
7980
import {
@@ -183,6 +184,7 @@ function isMinMaxStepValid(minMax: MinMaxStep | undefined): boolean {
183184
(onLineChartZoom)="onLineChartZoom($event)"
184185
(reorderColumnHeaders)="reorderColumnHeaders($event)"
185186
(onCardStateChanged)="onCardStateChanged($event)"
187+
(openSlideoutColumnEditMenu)="openSlideoutColumnEditMenu()"
186188
></scalar-card-component>
187189
`,
188190
styles: [
@@ -664,4 +666,8 @@ export class ScalarCardContainer implements CardRenderer, OnInit, OnDestroy {
664666
reorderColumnHeaders(headers: ColumnHeader[]) {
665667
this.store.dispatch(dataTableColumnDrag({newOrder: headers}));
666668
}
669+
670+
openSlideoutColumnEditMenu() {
671+
this.store.dispatch(metricsSlideoutMenuOpened());
672+
}
667673
}

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

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ import {
8080
metricsCardStateUpdated,
8181
stepSelectorToggled,
8282
timeSelectionChanged,
83+
metricsSlideoutMenuOpened,
8384
} from '../../actions';
8485
import {PluginType} from '../../data_source';
8586
import {
@@ -841,6 +842,21 @@ describe('scalar card', () => {
841842
// Clicking on overflow menu and mat button enqueue asyncs. Flush them.
842843
flush();
843844
}));
845+
846+
it('dispatches metricsSlideoutMenuOpened when edit columns button is clicked', fakeAsync(() => {
847+
store.overrideSelector(
848+
selectors.getIsScalarColumnCustomizationEnabled,
849+
true
850+
);
851+
const fixture = createComponent('card1');
852+
853+
openOverflowMenu(fixture);
854+
getMenuButton('Open menu to edit data table columns').click();
855+
fixture.detectChanges();
856+
857+
expect(dispatchedActions[0]).toEqual(metricsSlideoutMenuOpened());
858+
flush();
859+
}));
844860
});
845861

846862
describe('full size', () => {

tensorboard/webapp/metrics/views/main_view/main_view_component.scss

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,8 @@ limitations under the License.
168168

169169
.slide-out-menu {
170170
background-color: mat.get-color-from-palette($tb-background, background);
171-
height: 100%;
171+
// Make the menu the full height minus the size of the toolbar.
172+
height: calc(100% - 49px);
172173
position: absolute;
173174
right: 50px;
174175
top: 49px;

tensorboard/webapp/metrics/views/right_pane/scalar_column_editor/scalar_column_editor_component.ng.html

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
See the License for the specific language governing permissions and
1515
limitations under the License.
1616
-->
17-
<div>
17+
<div class="editor-controls">
1818
<mat-tab-group class="tab-group">
1919
<mat-tab [label]="'Single'">
2020
<ngContext
@@ -30,6 +30,17 @@
3030
</mat-tab>
3131
</mat-tab-group>
3232
</div>
33+
<div class="footer">
34+
<button
35+
mat-button
36+
class="close-button"
37+
(click)="onScalarTableColumnEditorClosed.emit()"
38+
i18n-aria-label="Label on a button to close the column editor."
39+
aria-label="Close column editor"
40+
>
41+
Close
42+
</button>
43+
</div>
3344

3445
<ng-template
3546
#headerList

tensorboard/webapp/metrics/views/right_pane/scalar_column_editor/scalar_column_editor_component.scss

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,18 @@ $_accent: map-get(mat.get-color-config($tb-theme), accent);
1919

2020
:host ::ng-deep .mat-tab-label {
2121
min-width: 0;
22+
padding: 0 30px;
23+
}
24+
.editor-controls {
25+
// controls should fill the full height except for the height of the footer.
26+
height: calc(100% - 45px);
2227
}
2328
.tab-group {
2429
// Override static position so this object is not seen in front of the
2530
// settings panel.
2631
position: relative;
2732
z-index: 0;
33+
height: 100%;
2834
}
2935
.header-list {
3036
margin-top: 5%;
@@ -46,3 +52,29 @@ $_accent: map-get(mat.get-color-config($tb-theme), accent);
4652
.highlight-top {
4753
border-top: 2px solid mat.get-color-from-palette($_accent);
4854
}
55+
56+
.footer {
57+
display: flex;
58+
position: absolute;
59+
left: 0;
60+
bottom: 0;
61+
box-sizing: border-box;
62+
width: 100%;
63+
align-items: center;
64+
justify-content: flex-end;
65+
padding: 4px;
66+
border-top: 1px solid mat.get-color-from-palette($tb-foreground, border);
67+
68+
@include tb-dark-theme {
69+
border-color: mat.get-color-from-palette($tb-dark-foreground, border);
70+
}
71+
}
72+
73+
.close-button {
74+
color: mat.get-color-from-palette($tb-foreground, secondary-text);
75+
width: 84px;
76+
77+
@include tb-dark-theme {
78+
color: mat.get-color-from-palette($tb-dark-foreground, secondary-text);
79+
}
80+
}

0 commit comments

Comments
 (0)