Skip to content

Commit bd2ba99

Browse files
authored
timeseries: run selection based on regex filter (#5252)
Previously, regex filter was mainly to influence the list you see on the runs table. This is where it differs from the traditional runs-selector (Polymer) which not only filtered runs but also changed the runs selection that you see on the chart. This change brings the Polymer behavior to Angular as users have preferred that.
1 parent d4b37e3 commit bd2ba99

File tree

9 files changed

+59
-288
lines changed

9 files changed

+59
-288
lines changed

tensorboard/webapp/runs/actions/runs_actions.ts

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -62,11 +62,6 @@ export const runPageSelectionToggled = createAction(
6262
props<{experimentIds: string[]; runIds: string[]}>()
6363
);
6464

65-
export const runsSelectAll = createAction(
66-
'[Runs] Runs Select All',
67-
props<{experimentIds: string[]}>()
68-
);
69-
7065
export const runSelectorPaginationOptionChanged = createAction(
7166
'[Runs] Run Selector Pagination Option Changed',
7267
props<{pageSize: number; pageIndex: number}>()

tensorboard/webapp/runs/store/runs_reducers.ts

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -218,24 +218,6 @@ const dataReducer: ActionReducer<RunsDataState, Action> = createReducer(
218218
selectionState: nextSelectionState,
219219
};
220220
}),
221-
on(runsActions.runsSelectAll, (state, {experimentIds}) => {
222-
const stateKey = serializeExperimentIds(experimentIds);
223-
const nextSelectionState = new Map(state.selectionState);
224-
const subSelectionState = new Map(nextSelectionState.get(stateKey) ?? []);
225-
226-
for (const experimentId of experimentIds) {
227-
for (const runId of state.runIds[experimentId]) {
228-
subSelectionState.set(runId, true);
229-
}
230-
}
231-
232-
nextSelectionState.set(stateKey, subSelectionState);
233-
234-
return {
235-
...state,
236-
selectionState: nextSelectionState,
237-
};
238-
}),
239221
on(runsActions.fetchRunsSucceeded, (state, {runsForAllExperiments}) => {
240222
const groupKeyToColorString = new Map(state.groupKeyToColorString);
241223
const defaultRunColorForGroupBy = new Map(state.defaultRunColorForGroupBy);

tensorboard/webapp/runs/store/runs_reducers_test.ts

Lines changed: 0 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -587,38 +587,6 @@ describe('runs_reducers', () => {
587587
});
588588
});
589589

590-
describe('runsSelectAll', () => {
591-
it('selects all runs', () => {
592-
const state = buildRunsState({
593-
runIds: {
594-
e1: ['r1', 'r2'],
595-
e2: ['r3'],
596-
},
597-
selectionState: new Map([['["e1","e2"]', new Map([['r1', false]])]]),
598-
});
599-
600-
const nextState = runsReducers.reducers(
601-
state,
602-
actions.runsSelectAll({
603-
experimentIds: ['e1', 'e2'],
604-
})
605-
);
606-
607-
expect(nextState.data.selectionState).toEqual(
608-
new Map([
609-
[
610-
'["e1","e2"]',
611-
new Map([
612-
['r1', true],
613-
['r2', true],
614-
['r3', true],
615-
]),
616-
],
617-
])
618-
);
619-
});
620-
});
621-
622590
describe('runSelectorPaginationOptionChanged', () => {
623591
it('updates the pagination option', () => {
624592
const state = buildRunsState(undefined, {

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

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
<div class="table-container">
2525
<div role="table">
2626
<ng-container *ngTemplateOutlet="header"></ng-container>
27-
<ng-container *ngTemplateOutlet="selectAll"></ng-container>
2827
<div role="rowgroup" class="rows">
2928
<ng-container *ngFor="let item of pageItems; trackBy: tableTrackBy">
3029
<ng-container
@@ -58,21 +57,6 @@
5857
(page)="onPaginationChange.emit($event)"
5958
></mat-paginator>
6059

61-
<ng-template #selectAll>
62-
<div
63-
*ngIf="allPageItemsSelected() && numSelectedItems !== allItemsLength"
64-
class="select-all"
65-
role="row"
66-
>
67-
<span role="columnheader"
68-
>All runs in this page are selected but not all runs ({{ numSelectedItems
69-
}} of {{ allItemsLength }}) are selected.</span
70-
><button mat-button (click)="onSelectAllPages.emit()">
71-
Select all runs
72-
</button>
73-
</div>
74-
</ng-template>
75-
7660
<ng-template #header>
7761
<div class="header" role="rowgroup">
7862
<div

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,6 @@ export class RunsTableComponent implements OnChanges {
109109
@Output() onRegexFilterChange = new EventEmitter<string>();
110110
@Output() onSelectionToggle = new EventEmitter<RunTableItem>();
111111
@Output() onPageSelectionToggle = new EventEmitter<{items: RunTableItem[]}>();
112-
@Output() onSelectAllPages = new EventEmitter<void>();
113112
@Output()
114113
onPaginationChange = new EventEmitter<{
115114
pageIndex: number;

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

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,6 @@ import {
6767
runSelectorPaginationOptionChanged,
6868
runSelectorRegexFilterChanged,
6969
runSelectorSortChanged,
70-
runsSelectAll,
7170
runTableShown,
7271
} from '../../actions';
7372
import {SortKey, SortType} from '../../types';
@@ -208,7 +207,6 @@ function matchFilter(
208207
[usePagination]="usePagination"
209208
(onSelectionToggle)="onRunSelectionToggle($event)"
210209
(onPageSelectionToggle)="onPageSelectionToggle($event)"
211-
(onSelectAllPages)="onSelectAllPages()"
212210
(onPaginationChange)="onPaginationChange($event)"
213211
(onRegexFilterChange)="onRegexFilterChange($event)"
214212
(onSortChange)="onSortChange($event)"
@@ -592,16 +590,6 @@ export class RunsTableContainer implements OnInit, OnDestroy {
592590
);
593591
}
594592

595-
onSelectAllPages() {
596-
if (!this.usePagination) {
597-
throw new Error(
598-
'Select all events cannot be dispatched when pagination is disabled'
599-
);
600-
}
601-
602-
this.store.dispatch(runsSelectAll({experimentIds: this.experimentIds}));
603-
}
604-
605593
onPaginationChange(event: {pageIndex: number; pageSize: number}) {
606594
if (!this.usePagination) {
607595
throw new Error(

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

Lines changed: 0 additions & 202 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,6 @@ import {
8484
runSelectorPaginationOptionChanged,
8585
runSelectorRegexFilterChanged,
8686
runSelectorSortChanged,
87-
runsSelectAll,
8887
runTableShown,
8988
} from '../../actions';
9089
import {DomainType} from '../../data_source/runs_data_source_types';
@@ -1823,207 +1822,6 @@ describe('runs_table', () => {
18231822
);
18241823
}
18251824
);
1826-
1827-
it('does not render select all button when pagination is disabled', () => {
1828-
store.overrideSelector(getRunSelectorPaginationOption, {
1829-
pageIndex: 0,
1830-
pageSize: 2,
1831-
});
1832-
store.overrideSelector(getRuns, [
1833-
buildRun({id: 'book1', name: "The Philosopher's Stone"}),
1834-
buildRun({id: 'book2', name: 'The Chamber Of Secrets'}),
1835-
buildRun({id: 'book3', name: 'The Prisoner of Azkaban'}),
1836-
]);
1837-
store.overrideSelector(
1838-
getCurrentRouteRunSelection,
1839-
new Map([
1840-
['book1', true],
1841-
['book2', true],
1842-
['book3', false],
1843-
])
1844-
);
1845-
1846-
const fixture = createComponent(
1847-
['tolkien'],
1848-
[RunsTableColumn.CHECKBOX, RunsTableColumn.RUN_NAME],
1849-
false /* usePagination */
1850-
);
1851-
fixture.detectChanges();
1852-
1853-
const showAll = fixture.nativeElement.querySelector(
1854-
Selector.SELECT_ALL_ROW
1855-
);
1856-
expect(showAll).not.toBeTruthy();
1857-
});
1858-
1859-
it('renders select all button when page is selected but not all items', () => {
1860-
store.overrideSelector(getRunSelectorPaginationOption, {
1861-
pageIndex: 0,
1862-
pageSize: 2,
1863-
});
1864-
store.overrideSelector(getRuns, [
1865-
buildRun({id: 'book1', name: "The Philosopher's Stone"}),
1866-
buildRun({id: 'book2', name: 'The Chamber Of Secrets'}),
1867-
buildRun({id: 'book3', name: 'The Prisoner of Azkaban'}),
1868-
]);
1869-
store.overrideSelector(
1870-
getCurrentRouteRunSelection,
1871-
new Map([
1872-
['book1', true],
1873-
['book2', true],
1874-
['book3', false],
1875-
])
1876-
);
1877-
1878-
const fixture = createComponent(
1879-
['tolkien'],
1880-
[RunsTableColumn.CHECKBOX, RunsTableColumn.RUN_NAME],
1881-
true /* usePagination */
1882-
);
1883-
fixture.detectChanges();
1884-
1885-
const showAll = fixture.nativeElement.querySelector(
1886-
Selector.SELECT_ALL_ROW
1887-
);
1888-
expect(showAll.textContent).toContain(
1889-
'All runs in this page are selected but not all runs (2 of 3)'
1890-
);
1891-
});
1892-
1893-
it('does not render select if everything is selected', () => {
1894-
store.overrideSelector(getRunSelectorPaginationOption, {
1895-
pageIndex: 0,
1896-
pageSize: 2,
1897-
});
1898-
store.overrideSelector(getRuns, [
1899-
buildRun({id: 'book1', name: "The Philosopher's Stone"}),
1900-
buildRun({id: 'book2', name: 'The Chamber Of Secrets'}),
1901-
buildRun({id: 'book3', name: 'The Prisoner of Azkaban'}),
1902-
]);
1903-
store.overrideSelector(
1904-
getCurrentRouteRunSelection,
1905-
new Map([
1906-
['book1', true],
1907-
['book2', true],
1908-
['book3', true],
1909-
])
1910-
);
1911-
1912-
const fixture = createComponent(
1913-
['rowling'],
1914-
[RunsTableColumn.CHECKBOX, RunsTableColumn.RUN_NAME],
1915-
true /* usePagination */
1916-
);
1917-
fixture.detectChanges();
1918-
1919-
const showAll = fixture.nativeElement.querySelector(
1920-
Selector.SELECT_ALL_ROW
1921-
);
1922-
expect(showAll).toBeNull();
1923-
});
1924-
1925-
it('does not render select all if page is not all selected', () => {
1926-
store.overrideSelector(getRunSelectorPaginationOption, {
1927-
pageIndex: 0,
1928-
pageSize: 2,
1929-
});
1930-
store.overrideSelector(getRuns, [
1931-
buildRun({id: 'book1', name: "The Philosopher's Stone"}),
1932-
buildRun({id: 'book2', name: 'The Chamber Of Secrets'}),
1933-
buildRun({id: 'book3', name: 'The Prisoner of Azkaban'}),
1934-
]);
1935-
store.overrideSelector(
1936-
getCurrentRouteRunSelection,
1937-
new Map([
1938-
['book1', true],
1939-
['book2', false],
1940-
['book3', true],
1941-
])
1942-
);
1943-
1944-
const fixture = createComponent(
1945-
['rowling'],
1946-
[RunsTableColumn.CHECKBOX, RunsTableColumn.RUN_NAME],
1947-
true /* usePagination */
1948-
);
1949-
fixture.detectChanges();
1950-
1951-
const showAll = fixture.nativeElement.querySelector(
1952-
Selector.SELECT_ALL_ROW
1953-
);
1954-
expect(showAll).toBeNull();
1955-
});
1956-
1957-
it('renders select all even when all filtered items are selected', () => {
1958-
store.overrideSelector(getRunSelectorRegexFilter, '[oO]f');
1959-
store.overrideSelector(getRunSelectorPaginationOption, {
1960-
pageIndex: 0,
1961-
pageSize: 2,
1962-
});
1963-
store.overrideSelector(getRuns, [
1964-
buildRun({id: 'book1', name: "The Philosopher's Stone"}),
1965-
buildRun({id: 'book2', name: 'The Chamber Of Secrets'}),
1966-
buildRun({id: 'book3', name: 'The Prisoner of Azkaban'}),
1967-
]);
1968-
store.overrideSelector(
1969-
getCurrentRouteRunSelection,
1970-
new Map([
1971-
['book1', false],
1972-
['book2', true],
1973-
['book3', true],
1974-
])
1975-
);
1976-
1977-
const fixture = createComponent(
1978-
['tolkien'],
1979-
[RunsTableColumn.CHECKBOX, RunsTableColumn.RUN_NAME],
1980-
true /* usePagination */
1981-
);
1982-
fixture.detectChanges();
1983-
1984-
const showAll = fixture.nativeElement.querySelector(
1985-
Selector.SELECT_ALL_ROW
1986-
);
1987-
expect(showAll.textContent).toContain(
1988-
'All runs in this page are selected but not all runs (2 of 3)'
1989-
);
1990-
});
1991-
1992-
it('dispatches runsSelectAll when click on select', () => {
1993-
store.overrideSelector(getRunSelectorPaginationOption, {
1994-
pageIndex: 0,
1995-
pageSize: 2,
1996-
});
1997-
store.overrideSelector(getRuns, [
1998-
buildRun({id: 'book1', name: "The Philosopher's Stone"}),
1999-
buildRun({id: 'book2', name: 'The Chamber Of Secrets'}),
2000-
buildRun({id: 'book3', name: 'The Prisoner of Azkaban'}),
2001-
]);
2002-
store.overrideSelector(
2003-
getCurrentRouteRunSelection,
2004-
new Map([
2005-
['book1', true],
2006-
['book2', true],
2007-
['book3', false],
2008-
])
2009-
);
2010-
2011-
const fixture = createComponent(
2012-
['rowling'],
2013-
[RunsTableColumn.CHECKBOX, RunsTableColumn.RUN_NAME],
2014-
true /* usePagination */
2015-
);
2016-
fixture.detectChanges();
2017-
2018-
const button = fixture.nativeElement.querySelector('.select-all button');
2019-
button.click();
2020-
2021-
expect(dispatchSpy).toHaveBeenCalledWith(
2022-
runsSelectAll({
2023-
experimentIds: ['rowling'],
2024-
})
2025-
);
2026-
});
20271825
});
20281826

20291827
describe('"too many runs" alert', () => {

tensorboard/webapp/util/ui_selectors.ts

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,10 @@ import {createSelector} from '@ngrx/store';
2929

3030
import {getExperimentIdsFromRoute} from '../app_routing/store/app_routing_selectors';
3131
import {State} from '../app_state';
32-
import {getRunSelectionMap} from '../runs/store/runs_selectors';
32+
import {
33+
getRunSelectionMap,
34+
getRunSelectorRegexFilter,
35+
} from '../runs/store/runs_selectors';
3336

3437
/** @typehack */ import * as _typeHackStore from '@ngrx/store';
3538

@@ -46,5 +49,22 @@ export const getCurrentRouteRunSelection = createSelector(
4649
}
4750
return getRunSelectionMap(state, {experimentIds});
4851
},
49-
(runSelection) => runSelection
52+
getRunSelectorRegexFilter,
53+
(runSelection, regexFilter) => {
54+
if (!runSelection) return null;
55+
56+
let regexExp: RegExp;
57+
58+
try {
59+
regexExp = new RegExp(regexFilter, 'i');
60+
} catch {
61+
regexExp = new RegExp('');
62+
}
63+
64+
const filteredSelection = new Map<string, boolean>();
65+
for (const [key, value] of runSelection.entries()) {
66+
filteredSelection.set(key, regexExp.test(key) && value);
67+
}
68+
return filteredSelection;
69+
}
5070
);

0 commit comments

Comments
 (0)