Skip to content

Commit a5c4e61

Browse files
committed
Update the views for color by regex feature.
1 parent d4c5c82 commit a5c4e61

9 files changed

+189
-64
lines changed

tensorboard/webapp/runs/views/runs_table/BUILD

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,19 +79,22 @@ tf_ng_module(
7979
"//tensorboard/webapp/angular:expect_angular_material_button",
8080
"//tensorboard/webapp/angular:expect_angular_material_checkbox",
8181
"//tensorboard/webapp/angular:expect_angular_material_chips",
82+
"//tensorboard/webapp/angular:expect_angular_material_core",
8283
"//tensorboard/webapp/angular:expect_angular_material_dialog",
8384
"//tensorboard/webapp/angular:expect_angular_material_form_field",
8485
"//tensorboard/webapp/angular:expect_angular_material_icon",
8586
"//tensorboard/webapp/angular:expect_angular_material_input",
8687
"//tensorboard/webapp/angular:expect_angular_material_menu",
8788
"//tensorboard/webapp/angular:expect_angular_material_paginator",
8889
"//tensorboard/webapp/angular:expect_angular_material_progress_spinner",
90+
"//tensorboard/webapp/angular:expect_angular_material_select",
8991
"//tensorboard/webapp/angular:expect_angular_material_sort",
9092
"//tensorboard/webapp/angular:expect_angular_material_table",
9193
"//tensorboard/webapp/app_routing",
9294
"//tensorboard/webapp/app_routing:types",
9395
"//tensorboard/webapp/core/actions",
9496
"//tensorboard/webapp/experiments:types",
97+
"//tensorboard/webapp/experiments/store:selectors",
9598
"//tensorboard/webapp/feature_flag/store",
9699
"//tensorboard/webapp/hparams",
97100
"//tensorboard/webapp/hparams:types",
@@ -118,6 +121,7 @@ tf_ng_module(
118121
"//tensorboard/webapp/widgets/range_input:types",
119122
"@npm//@angular/common",
120123
"@npm//@angular/core",
124+
"@npm//@angular/forms",
121125
"@npm//@ngrx/store",
122126
"@npm//ngx-color-picker",
123127
"@npm//rxjs",
@@ -146,6 +150,7 @@ tf_ts_library(
146150
"//tensorboard/webapp/angular:expect_angular_material_checkbox",
147151
"//tensorboard/webapp/angular:expect_angular_material_chips",
148152
"//tensorboard/webapp/angular:expect_angular_material_chips_testing",
153+
"//tensorboard/webapp/angular:expect_angular_material_core",
149154
"//tensorboard/webapp/angular:expect_angular_material_dialog",
150155
"//tensorboard/webapp/angular:expect_angular_material_input",
151156
"//tensorboard/webapp/angular:expect_angular_material_menu",

tensorboard/webapp/runs/views/runs_table/regex_edit_dialog.ng.html

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,22 @@ <h1 mat-dialog-title>Color runs by regex</h1>
1919

2020
<mat-dialog-content>
2121
<p>Enter a regex with capturing groups to match against run names:</p>
22+
<mat-form-field>
23+
<mat-label>Regex type</mat-label>
24+
<mat-select
25+
[(value)]="regexMatchType"
26+
(selectionChange)="regexTypeChange($event)"
27+
>
28+
<mat-option value="regex_by_run">Run Name</mat-option>
29+
<mat-option value="regex_by_exp">Experiment Name</mat-option>
30+
</mat-select>
31+
</mat-form-field>
2232
<mat-form-field>
2333
<input
2434
matInput
2535
#regexStringInput
2636
value="{{ regexString }}"
27-
(keydown.enter)="onEnter($event.target.value)"
37+
(keydown.enter)="onEnter()"
2838
(input)="regexInputChange($event.target.value)"
2939
i18n-aria-label="Color Runs by Regex Query"
3040
aria-label="Color Runs by Regex Query"
@@ -95,7 +105,7 @@ <h4>Color group preview</h4>
95105
mat-raised-button
96106
color="primary"
97107
mat-dialog-close
98-
(click)="onSaveClick(regexStringInput.value)"
108+
(click)="onSaveClick()"
99109
>
100110
Save
101111
</button>

tensorboard/webapp/runs/views/runs_table/regex_edit_dialog_component.ts

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@ import {
2222
ViewChild,
2323
} from '@angular/core';
2424
import {MatDialogRef} from '@angular/material/dialog';
25-
import {Run} from '../../types';
25+
import {GroupByKey, Run} from '../../types';
26+
import {MatSelectChange} from '@angular/material/select';
27+
import {ChangeDetectorRef} from '@angular/core';
2628

2729
export interface ColorGroup {
2830
groupId: string;
@@ -39,33 +41,44 @@ export interface ColorGroup {
3941
export class RegexEditDialogComponent {
4042
@Input() regexString!: string;
4143
@Input() colorRunPairList!: ColorGroup[];
44+
@Input() selectedGroupBy!: GroupByKey;
4245

43-
@Output() onSave = new EventEmitter<string>();
46+
@Output() onSave = new EventEmitter();
4447
@Output() regexInputOnChange = new EventEmitter<string>();
48+
@Output() regexTypeOnChange = new EventEmitter<GroupByKey>();
4549

4650
timeOutId = 0;
4751
@ViewChild('regexStringInput', {static: true})
4852
regexStringInput!: ElementRef<HTMLInputElement>;
53+
regexMatchType = '';
4954

5055
constructor(
5156
public readonly dialogRef: MatDialogRef<RegexEditDialogComponent>,
52-
private readonly hostElRef: ElementRef
57+
private readonly hostElRef: ElementRef,
58+
private cdRef: ChangeDetectorRef
5359
) {}
5460

61+
ngOnInit() {
62+
this.regexMatchType =
63+
this.selectedGroupBy === GroupByKey.REGEX_BY_EXP
64+
? 'regex_by_exp'
65+
: 'regex_by_run';
66+
}
67+
5568
private resetFocus() {
5669
if (!this.hostElRef.nativeElement.contains(document.activeElement)) {
5770
const input = this.regexStringInput.nativeElement;
5871
input.focus();
5972
}
6073
}
6174

62-
onEnter(regexString: string) {
63-
this.onSaveClick(regexString);
75+
onEnter() {
76+
this.onSaveClick();
6477
this.dialogRef.close();
6578
}
6679

67-
onSaveClick(regexString: string) {
68-
this.onSave.emit(regexString);
80+
onSaveClick() {
81+
this.onSave.emit();
6982
}
7083

7184
fillExample(regexExample: string): void {
@@ -81,4 +94,15 @@ export class RegexEditDialogComponent {
8194
clearTimeout(this.timeOutId);
8295
this.timeOutId = setTimeout(this.resetFocus.bind(this), 0);
8396
}
97+
98+
regexTypeChange(event: MatSelectChange) {
99+
this.regexMatchType = event.value;
100+
// This line is needed to update the value on the HTML element.
101+
this.cdRef.detectChanges();
102+
this.regexTypeOnChange.emit(
103+
event.value === 'regex_by_run'
104+
? GroupByKey.REGEX
105+
: GroupByKey.REGEX_BY_EXP
106+
);
107+
}
84108
}

tensorboard/webapp/runs/views/runs_table/regex_edit_dialog_container.ts

Lines changed: 65 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import {
2121
debounceTime,
2222
filter,
2323
map,
24+
shareReplay,
2425
startWith,
2526
take,
2627
} from 'rxjs/operators';
@@ -31,6 +32,7 @@ import {runGroupByChanged} from '../../actions';
3132
import {
3233
getColorGroupRegexString,
3334
getRunIdsForExperiment,
35+
getRunGroupBy,
3436
getRuns,
3537
} from '../../store/runs_selectors';
3638
import {groupRuns} from '../../store/utils';
@@ -44,8 +46,10 @@ const INPUT_CHANGE_DEBOUNCE_INTERVAL_MS = 500;
4446
template: `<regex-edit-dialog-component
4547
[regexString]="groupByRegexString$ | async"
4648
[colorRunPairList]="colorRunPairList$ | async"
47-
(onSave)="onSave($event)"
49+
[selectedGroupBy]="groupByRegexType$ | async"
50+
(onSave)="onSave()"
4851
(regexInputOnChange)="onRegexInputOnChange($event)"
52+
(regexTypeOnChange)="onRegexTypeOnChange($event)"
4953
></regex-edit-dialog-component>`,
5054
styles: [
5155
`
@@ -60,17 +64,34 @@ const INPUT_CHANGE_DEBOUNCE_INTERVAL_MS = 500;
6064
})
6165
export class RegexEditDialogContainer {
6266
private readonly experimentIds: string[];
67+
private readonly expNameByExpId: Record<string, string>;
6368
private readonly runIdToEid$: Observable<Record<string, string>>;
6469
private readonly allRuns$: Observable<Run[]>;
6570
private readonly tentativeRegexString$: Subject<string> =
6671
new Subject<string>();
72+
private readonly tentativeRegexType$: Subject<GroupByKey> =
73+
new Subject<GroupByKey>();
6774

6875
readonly groupByRegexString$: Observable<string> = defer(() => {
6976
return merge(
7077
this.store.select(getColorGroupRegexString).pipe(take(1)),
7178
this.tentativeRegexString$
7279
);
73-
}).pipe(startWith(''));
80+
}).pipe(startWith(''), shareReplay(1));
81+
82+
readonly groupByRegexType$: Observable<GroupByKey> = merge(
83+
this.store.select(getRunGroupBy).pipe(
84+
take(1),
85+
map((group) => group.key)
86+
),
87+
this.tentativeRegexType$
88+
).pipe(
89+
filter(
90+
(key) => key === GroupByKey.REGEX || key === GroupByKey.REGEX_BY_EXP
91+
),
92+
startWith(GroupByKey.REGEX),
93+
shareReplay(1)
94+
);
7495

7596
readonly colorRunPairList$: Observable<ColorGroup[]> = defer(() => {
7697
return this.groupByRegexString$.pipe(
@@ -84,18 +105,31 @@ export class RegexEditDialogContainer {
84105
}
85106
}),
86107
combineLatestWith(
108+
this.groupByRegexType$,
87109
this.allRuns$,
88110
this.runIdToEid$,
89111
this.store.select(settingsSelectors.getColorPalette),
90112
this.store.select(getDarkModeEnabled)
91113
),
92114
map(
93-
([regexString, allRuns, runIdToEid, colorPalette, darkModeEnabled]) => {
115+
([
116+
regexString,
117+
regexType,
118+
allRuns,
119+
runIdToEid,
120+
colorPalette,
121+
darkModeEnabled,
122+
]) => {
94123
const groupBy = {
95-
key: GroupByKey.REGEX,
124+
key: regexType,
96125
regexString,
97126
};
98-
const groups = groupRuns(groupBy, allRuns, runIdToEid);
127+
const groups = groupRuns(
128+
groupBy,
129+
allRuns,
130+
runIdToEid,
131+
this.expNameByExpId
132+
);
99133
const groupKeyToColorString = new Map<string, string>();
100134
const colorRunPairList: ColorGroup[] = [];
101135

@@ -121,9 +155,14 @@ export class RegexEditDialogContainer {
121155
constructor(
122156
private readonly store: Store<State>,
123157
public dialogRef: MatDialogRef<RegexEditDialogContainer>,
124-
@Inject(MAT_DIALOG_DATA) data: {experimentIds: string[]}
158+
@Inject(MAT_DIALOG_DATA)
159+
data: {
160+
experimentIds: string[];
161+
expNameByExpId: Record<string, string>;
162+
}
125163
) {
126164
this.experimentIds = data.experimentIds;
165+
this.expNameByExpId = data.expNameByExpId;
127166

128167
this.runIdToEid$ = combineLatest(
129168
this.experimentIds.map((experimentId) => {
@@ -155,16 +194,29 @@ export class RegexEditDialogContainer {
155194
}
156195

157196
onRegexInputOnChange(regexString: string) {
197+
// Whenever regex input changes the subject emits new object.
158198
this.tentativeRegexString$.next(regexString);
159199
}
160200

161-
onSave(regexString: string): void {
162-
this.store.dispatch(
163-
runGroupByChanged({
164-
experimentIds: this.experimentIds,
165-
groupBy: {key: GroupByKey.REGEX, regexString: regexString},
166-
})
167-
);
201+
onRegexTypeOnChange(regexType: GroupByKey) {
202+
// Whenever regex type changes the subject emits new object.
203+
this.tentativeRegexType$.next(regexType);
204+
}
205+
206+
onSave(): void {
207+
this.groupByRegexString$
208+
.pipe(combineLatestWith(this.groupByRegexType$))
209+
.subscribe(([regexString, key]) => {
210+
if (regexString) {
211+
this.store.dispatch(
212+
runGroupByChanged({
213+
experimentIds: this.experimentIds,
214+
groupBy: {key, regexString},
215+
expNameByExpId: this.expNameByExpId,
216+
})
217+
);
218+
}
219+
});
168220
}
169221
}
170222

0 commit comments

Comments
 (0)