Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions tensorboard/webapp/metrics/internal_types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ export interface URLDeserializedState {
metrics: {
pinnedCards: CardUniqueInfo[];
smoothing: number | null;
tagFilter: string | null;
};
}

Expand Down
1 change: 1 addition & 0 deletions tensorboard/webapp/metrics/store/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ tf_ts_library(
"//tensorboard/webapp/metrics/actions",
"//tensorboard/webapp/metrics/data_source",
"//tensorboard/webapp/persistent_settings",
"//tensorboard/webapp/routes:testing",
"//tensorboard/webapp/types",
"//tensorboard/webapp/util:dom",
"@npm//@types/jasmine",
Expand Down
7 changes: 6 additions & 1 deletion tensorboard/webapp/metrics/store/metrics_reducers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -347,11 +347,16 @@ const reducer = createReducer(
};
}

return {
const newState = {
...state,
...resolvedResult,
settingOverrides: newSettings,
};

if (hydratedState.metrics.tagFilter !== null) {
newState.tagFilter = hydratedState.metrics.tagFilter;
}
return newState;
}),
on(globalSettingsLoaded, (state, {partialSettings}) => {
const metricsSettings: Partial<MetricsSettings> = {};
Expand Down
42 changes: 42 additions & 0 deletions tensorboard/webapp/metrics/store/metrics_reducers_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {buildRoute} from '../../app_routing/testing';
import {RouteKind} from '../../app_routing/types';
import * as coreActions from '../../core/actions';
import {globalSettingsLoaded} from '../../persistent_settings';
import {buildDeserializedState} from '../../routes/testing';
import {DataLoadState} from '../../types/data';
import {nextElementId} from '../../util/dom';
import * as actions from '../actions';
Expand Down Expand Up @@ -1778,6 +1779,47 @@ describe('metrics reducers', () => {
});
});

describe('tag filter hydration', () => {
it('rehydrates the value', () => {
const beforeState = buildMetricsState({tagFilter: 'foo'});
const action = routingActions.stateRehydratedFromUrl({
routeKind: RouteKind.EXPERIMENT,
partialState: {
metrics: {...buildDeserializedState().metrics, tagFilter: 'bar'},
},
});
const nextState = reducers(beforeState, action);

expect(nextState.tagFilter).toBe('bar');
});

it('rehydrates an empty string value', () => {
const beforeState = buildMetricsState({tagFilter: 'foo'});
const action = routingActions.stateRehydratedFromUrl({
routeKind: RouteKind.EXPERIMENT,
partialState: {
metrics: {...buildDeserializedState().metrics, tagFilter: ''},
},
});
const nextState = reducers(beforeState, action);

expect(nextState.tagFilter).toBe('');
});

it('does not hydrate when the value is null', () => {
const beforeState = buildMetricsState({tagFilter: 'foo'});
const action = routingActions.stateRehydratedFromUrl({
routeKind: RouteKind.EXPERIMENT,
partialState: {
metrics: {...buildDeserializedState().metrics, tagFilter: null},
},
});
const nextState = reducers(beforeState, action);

expect(nextState.tagFilter).toBe('foo');
});
});

describe('#globalSettingsLoaded', () => {
it('adds partial state from loading the settings to the (default) settings', () => {
const beforeState = buildMetricsState({
Expand Down
12 changes: 12 additions & 0 deletions tensorboard/webapp/routes/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,17 @@ tf_ts_library(
],
)

tf_ts_library(
name = "testing",
testonly = True,
srcs = [
"testing.ts",
],
deps = [
":dashboard_deeplink_provider_types",
],
)

tf_ts_library(
name = "routes_test_lib",
testonly = True,
Expand All @@ -60,6 +71,7 @@ tf_ts_library(
],
deps = [
":dashboard_deeplink_provider",
":testing",
"//tensorboard/webapp:app_state",
"//tensorboard/webapp:selectors",
"//tensorboard/webapp/angular:expect_angular_core_testing",
Expand Down
14 changes: 14 additions & 0 deletions tensorboard/webapp/routes/dashboard_deeplink_provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import {
DeserializedState,
PINNED_CARDS_KEY,
SMOOTHING_KEY,
TAG_FILTER_KEY,
} from './dashboard_deeplink_provider_types';

const COLOR_GROUP_REGEX_VALUE_PREFIX = 'regex:';
Expand Down Expand Up @@ -117,6 +118,14 @@ export class DashboardDeepLinkProvider extends DeepLinkProvider {
): Observable<SerializableQueryParams> {
return combineLatest([
this.getMetricsPinnedCards(store),
store.select(selectors.getMetricsTagFilter).pipe(
map((filterText) => {
if (!filterText) {
return [];
}
return [{key: TAG_FILTER_KEY, value: filterText}];
})
),
this.getFeatureFlagStates(store),
store.select(selectors.getMetricsSettingOverrides).pipe(
map((settingOverrides) => {
Expand Down Expand Up @@ -165,6 +174,7 @@ export class DashboardDeepLinkProvider extends DeepLinkProvider {
): DeserializedState {
let pinnedCards = null;
let smoothing = null;
let tagFilter = null;
let groupBy: GroupBy | null = null;

for (const {key, value} of queryParams) {
Expand Down Expand Up @@ -193,13 +203,17 @@ export class DashboardDeepLinkProvider extends DeepLinkProvider {
}
break;
}
case TAG_FILTER_KEY:
tagFilter = value;
break;
}
}

return {
metrics: {
pinnedCards: pinnedCards || [],
smoothing,
tagFilter,
},
runs: {
groupBy,
Expand Down
64 changes: 53 additions & 11 deletions tensorboard/webapp/routes/dashboard_deeplink_provider_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import {appStateFromMetricsState, buildMetricsState} from '../metrics/testing';
import * as selectors from '../selectors';
import {DashboardDeepLinkProvider} from './dashboard_deeplink_provider';
import {GroupBy, GroupByKey} from '../runs/types';
import {buildDeserializedState} from './testing';

describe('core deeplink provider', () => {
let store: MockStore<State>;
Expand Down Expand Up @@ -206,17 +207,21 @@ describe('core deeplink provider', () => {
},
]);

expect(state.metrics).toEqual({
pinnedCards: [
{plugin: PluginType.SCALARS, tag: 'accuracy'},
{
plugin: PluginType.IMAGES,
tag: 'loss',
runId: 'exp1/123',
sample: 5,
},
],
smoothing: null,
const defaultState = buildDeserializedState();
expect(state).toEqual({
...defaultState,
metrics: {
...defaultState.metrics,
pinnedCards: [
{plugin: PluginType.SCALARS, tag: 'accuracy'},
{
plugin: PluginType.IMAGES,
tag: 'loss',
runId: 'exp1/123',
sample: 5,
},
],
},
});
});

Expand Down Expand Up @@ -303,6 +308,43 @@ describe('core deeplink provider', () => {
}
});
});

describe('tag filter', () => {
it('serializes the filter text to the URL', () => {
store.overrideSelector(selectors.getMetricsTagFilter, 'accuracy');
store.refreshState();

expect(queryParamsSerialized.slice(-1)[0]).toEqual([
{key: 'tagFilter', value: 'accuracy'},
]);
});

it('does not serialize an empty string', () => {
store.overrideSelector(selectors.getMetricsTagFilter, '');
store.refreshState();

expect(queryParamsSerialized).toEqual([]);
});

it('deserializes the string from the URL', () => {
const state1 = provider.deserializeQueryParams([
{key: 'tagFilter', value: 'accuracy'},
]);
expect(state1.metrics.tagFilter).toBe('accuracy');
});

it('deserializes the empty string from the URL', () => {
const state1 = provider.deserializeQueryParams([
{key: 'tagFilter', value: ''},
]);
expect(state1.metrics.tagFilter).toBe('');
});

it('deserializes to null when no value is provided', () => {
const state = provider.deserializeQueryParams([]);
expect(state.metrics.tagFilter).toBe(null);
});
});
});

describe('feature flag', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,5 @@ export const SMOOTHING_KEY = 'smoothing';
export const PINNED_CARDS_KEY = 'pinnedCards';

export const RUN_COLOR_GROUP_KEY = 'runColorGroup';

export const TAG_FILTER_KEY = 'tagFilter';
31 changes: 31 additions & 0 deletions tensorboard/webapp/routes/testing.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/* Copyright 2021 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
import {DeserializedState} from './dashboard_deeplink_provider_types';

export function buildDeserializedState(
override: Partial<DeserializedState> = {}
) {
return {
runs: {
groupBy: null,
},
metrics: {
pinnedCards: [],
smoothing: null,
tagFilter: null,
},
...override,
};
}