Skip to content

Commit 5368d98

Browse files
authored
Linked Time: Make Prospective Fob Interactive (#6017)
Blocked by #6006 and #6016 ## Motivation for features / changes We believe the many check boxes in the settings panel to not be very discoverable and a generally poor user experience. ![image](https://user-images.githubusercontent.com/78179109/199616005-4fbe6df0-ebe8-462e-b684-cf883e6675cb.png) To remedy this we would like to shown a "Prospective Fob" when the user hovers over the scalar card chart. When the user clicks on this "prospective fob", a fob will be placed at the corresponding location and step selection / range selection will be enabled as appropriate. ## Technical description of changes ## Screenshots of UI changes Step Selection Disabled ![f469e422-ad1e-4c33-a329-4d60c3ba437f](https://user-images.githubusercontent.com/78179109/199615269-39b9305d-3922-4608-ad57-f122ebdff542.gif) Step Selection Enabled ![761fb76e-b4ff-43be-bfe8-cf9410752c81](https://user-images.githubusercontent.com/78179109/199615324-5f48779f-b880-4121-a71c-50ad2cf34920.gif) ## Detailed steps to verify changes work correctly (as executed by you) ### Enabling Step Selection 1) Start tensorboard 2) Navigate to http://localhost:6006?enableDataTable=true&allowRangeSelection=true&enableProspectiveFob=true 3) Hover over the X Axis of a scalar card chart 4) Assert a prospective fob is shown and has no deselect button 5) Click on the prospective fob 6) Assert step selection is enabled and the data table is shown ### Enabling Range Selection With Step Selection Enabled 1) Hovering the X Axis of the scalar card 2) Assert a prospective fob is shown 3) Click the prospective fob 4) Assert range selection is now enabled 5) Continue hovering the X Axis of the scalar card 6) Assert no prospective fob is shown 7) Remove a fob 8) Hover the X Axis of the scalar card 9) Assert a prospective fob is shown * Alternate designs / implementations considered
1 parent d712309 commit 5368d98

File tree

5 files changed

+113
-18
lines changed

5 files changed

+113
-18
lines changed

tensorboard/webapp/metrics/store/metrics_reducers.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import {DataLoadState} from '../../types/data';
2323
import {ElementId} from '../../util/dom';
2424
import {mapObjectValues} from '../../util/lang';
2525
import {composeReducers} from '../../util/ngrx';
26+
import {TimeSelectionAffordance} from '../../widgets/card_fob/card_fob_types';
2627
import * as actions from '../actions';
2728
import {
2829
isFailedTimeSeriesResponse,
@@ -1018,6 +1019,9 @@ const reducer = createReducer(
10181019
const {timeSelection} = change;
10191020
const nextStartStep = timeSelection.start.step;
10201021
const nextEndStep = timeSelection.end?.step;
1022+
const nextStepSelectorEnabled =
1023+
change.affordance === TimeSelectionAffordance.FOB_ADDED ||
1024+
state.stepSelectorEnabled;
10211025
const end =
10221026
nextEndStep === undefined
10231027
? null
@@ -1046,6 +1050,7 @@ const reducer = createReducer(
10461050
linkedTimeSelection,
10471051
cardStepIndex: nextCardStepIndexMap,
10481052
rangeSelectionEnabled,
1053+
stepSelectorEnabled: nextStepSelectorEnabled,
10491054
};
10501055
}),
10511056
on(actions.stepSelectorToggled, (state) => {

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

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3420,6 +3420,66 @@ describe('scalar card', () => {
34203420
]);
34213421
}));
34223422

3423+
it('dispatches timeSelectionChanged actions when fob is added by clicking prospective fob', fakeAsync(() => {
3424+
store.overrideSelector(
3425+
selectors.getIsLinkedTimeProspectiveFobEnabled,
3426+
true
3427+
);
3428+
const fixture = createComponent('card1');
3429+
fixture.detectChanges();
3430+
3431+
const testController = fixture.debugElement.query(
3432+
By.directive(CardFobControllerComponent)
3433+
).componentInstance;
3434+
testController.timeSelection = null;
3435+
testController.prospectiveStep = 10;
3436+
fixture.detectChanges();
3437+
3438+
// One prospective fob
3439+
let fobs = fixture.debugElement.queryAll(
3440+
By.directive(CardFobComponent)
3441+
);
3442+
expect(fobs.length).toEqual(1);
3443+
3444+
// Click the prospective fob to set the start time
3445+
fixture.debugElement
3446+
.query(By.css('.prospective-fob-area'))
3447+
.nativeElement.click();
3448+
fixture.detectChanges();
3449+
3450+
// One start fob + 1 prospective fob
3451+
fobs = fixture.debugElement.queryAll(By.directive(CardFobComponent));
3452+
expect(fobs.length).toEqual(2);
3453+
3454+
// Click the prospective fob to set the end time
3455+
testController.prospectiveStep = 25;
3456+
fixture.debugElement
3457+
.query(By.css('.prospective-fob-area'))
3458+
.nativeElement.click();
3459+
fixture.detectChanges();
3460+
3461+
// One start fob, one end fob
3462+
fobs = fixture.debugElement.queryAll(By.directive(CardFobComponent));
3463+
expect(fobs.length).toEqual(2);
3464+
3465+
expect(dispatchedActions).toEqual([
3466+
timeSelectionChanged({
3467+
timeSelection: {
3468+
start: {step: 10},
3469+
end: null,
3470+
},
3471+
affordance: TimeSelectionAffordance.FOB_ADDED,
3472+
}),
3473+
timeSelectionChanged({
3474+
timeSelection: {
3475+
start: {step: 10},
3476+
end: {step: 25},
3477+
},
3478+
affordance: TimeSelectionAffordance.FOB_ADDED,
3479+
}),
3480+
]);
3481+
}));
3482+
34233483
it('toggles when single fob is deselected', fakeAsync(() => {
34243484
const fixture = createComponent('card1');
34253485
fixture.detectChanges();

tensorboard/webapp/widgets/card_fob/card_fob_controller_component.ng.html

Lines changed: 23 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -16,25 +16,30 @@
1616
-->
1717

1818
<div>
19-
<div
20-
#prospectiveFobWrapper
21-
class="time-fob-wrapper prospectiveFob"
22-
*ngIf="prospectiveStep !== null && isProspectiveFobFeatureEnabled"
23-
[style.transform]="getCssTranslatePxForProspectiveFob()"
19+
<ng-container
20+
*ngIf="isProspectiveFobFeatureEnabled && !rangeSelectionEnabled"
2421
>
25-
<div *ngIf="showExtendedLine" class="extended-line"></div>
26-
<card-fob
27-
[ngClass]="isVertical() ? 'vertical-fob' : 'horizontal-fob'"
28-
[allowRemoval]="false"
29-
[step]="prospectiveStep"
30-
></card-fob>
31-
</div>
32-
<div
33-
class="prospective-fob-area"
34-
[ngClass]="isVertical() ? 'vertical-prospective-area' : 'horizontal-prospective-area'"
35-
(mousemove)="mouseOver($event)"
36-
(mouseleave)="onProspectiveAreaMouseLeave()"
37-
></div>
22+
<div
23+
#prospectiveFobWrapper
24+
*ngIf="prospectiveStep !== null"
25+
class="time-fob-wrapper prospectiveFob"
26+
[style.transform]="getCssTranslatePxForProspectiveFob()"
27+
>
28+
<div *ngIf="showExtendedLine" class="extended-line"></div>
29+
<card-fob
30+
[ngClass]="isVertical() ? 'vertical-fob' : 'horizontal-fob'"
31+
[allowRemoval]="false"
32+
[step]="prospectiveStep"
33+
></card-fob>
34+
</div>
35+
<div
36+
class="prospective-fob-area"
37+
[ngClass]="isVertical() ? 'vertical-prospective-area' : 'horizontal-prospective-area'"
38+
(mousemove)="mouseOver($event)"
39+
(mouseleave)="onProspectiveAreaMouseLeave()"
40+
(click)="prospectiveFobClicked($event)"
41+
></div>
42+
</ng-container>
3843
<div
3944
#startFobWrapper
4045
class="time-fob-wrapper"

tensorboard/webapp/widgets/card_fob/card_fob_controller_component.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,29 @@ export class CardFobControllerComponent {
380380
});
381381
}
382382

383+
prospectiveFobClicked(event: Event) {
384+
event.stopPropagation();
385+
if (this.prospectiveStep === null) {
386+
return;
387+
}
388+
const newTimeSelection = this.timeSelection
389+
? {
390+
...this.timeSelection,
391+
end: {
392+
step: this.prospectiveStep,
393+
},
394+
}
395+
: {
396+
start: {step: this.prospectiveStep},
397+
end: null,
398+
};
399+
400+
this.onTimeSelectionChanged.emit({
401+
affordance: TimeSelectionAffordance.FOB_ADDED,
402+
timeSelection: newTimeSelection,
403+
});
404+
}
405+
383406
/**
384407
* When in range selection(which means we have a start and an end
385408
* fob) clicking "X" to remove a fob will leave the remaining fob in place.

tensorboard/webapp/widgets/card_fob/card_fob_types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ export enum TimeSelectionAffordance {
4242
CHANGE_TO_SINGLE = 'changeToSingle',
4343
// User clicks on Histogram Chart to change to range selection.
4444
HISTOGRAM_CLICK_TO_RANGE = 'histogramClickToRange',
45+
// Adding a new fob
46+
FOB_ADDED = 'fobAdded',
4547
}
4648

4749
/**

0 commit comments

Comments
 (0)