Skip to content

Commit

Permalink
core: make sidebar resizable (tensorflow#5219)
Browse files Browse the repository at this point in the history
This change introduces new layout component that you can use to have
consistent layout in a plugin. This layout component is responsible for
interactions and remembering the last set width.
  • Loading branch information
stephanwlee authored and yatbear committed Mar 27, 2023
1 parent 9c10968 commit 9d0c18d
Show file tree
Hide file tree
Showing 28 changed files with 741 additions and 13 deletions.
1 change: 1 addition & 0 deletions tensorboard/webapp/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,7 @@ tf_svg_bundle(
"@com_google_material_design_icon//:content_copy_24px.svg",
"@com_google_material_design_icon//:dark_mode_24px.svg",
"@com_google_material_design_icon//:done_24px.svg",
"@com_google_material_design_icon//:drag_indicator_24px.svg",
"@com_google_material_design_icon//:edit_24px.svg",
"@com_google_material_design_icon//:error_24px.svg",
"@com_google_material_design_icon//:expand_less_24px.svg",
Expand Down
4 changes: 4 additions & 0 deletions tensorboard/webapp/core/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,16 @@ tf_ng_module(
name = "core",
srcs = [
"core_module.ts",
"index.ts",
],
deps = [
":state",
"//tensorboard/webapp/core/actions",
"//tensorboard/webapp/core/effects",
"//tensorboard/webapp/core/store",
"//tensorboard/webapp/core/views:layout",
"//tensorboard/webapp/deeplink",
"//tensorboard/webapp/persistent_settings",
"//tensorboard/webapp/webapp_data_source",
"@npm//@angular/core",
"@npm//@ngrx/effects",
Expand Down
5 changes: 5 additions & 0 deletions tensorboard/webapp/core/actions/core_actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,3 +93,8 @@ export const fetchRunSucceeded = createAction(
'[Core] Run Fetch Successful',
props<{runs: Run[]}>()
);

export const sideBarWidthChanged = createAction(
'[Core] Side Bar Width Changed',
props<{widthInPercent: number}>()
);
29 changes: 24 additions & 5 deletions tensorboard/webapp/core/core_module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,25 +13,44 @@ See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
import {NgModule} from '@angular/core';
import {StoreModule} from '@ngrx/store';
import {EffectsModule} from '@ngrx/effects';
import {createSelector, StoreModule} from '@ngrx/store';

import {DeepLinkerInterface} from '../deeplink';
import {
PersistableSettings,
PersistentSettingsConfigModule,
} from '../persistent_settings';
import {TBServerDataSourceModule} from '../webapp_data_source/tb_server_data_source_module';

import {reducers} from './store';
import {CoreEffects} from './effects';
import {CORE_FEATURE_KEY} from './store/core_types';
import {State} from './state';
import {getSideBarWidthInPercent, reducers} from './store';
import {
CORE_STORE_CONFIG_TOKEN,
getConfig,
} from './store/core_initial_state_provider';
import {DeepLinkerInterface} from '../deeplink';
import {CORE_FEATURE_KEY} from './store/core_types';

/** @typehack */ import * as _typeHackNgrxStore from '@ngrx/store';

export function getSideBarWidthSetting() {
return createSelector<State, number, PersistableSettings>(
getSideBarWidthInPercent,
(sideBarWidthInPercent) => {
return {sideBarWidthInPercent};
}
);
}

@NgModule({
imports: [
EffectsModule.forFeature([CoreEffects]),
StoreModule.forFeature(CORE_FEATURE_KEY, reducers, CORE_STORE_CONFIG_TOKEN),
TBServerDataSourceModule,
PersistentSettingsConfigModule.defineGlobalSetting<
State,
PersistableSettings
>(getSideBarWidthSetting),
],
providers: [
{
Expand Down
17 changes: 17 additions & 0 deletions tensorboard/webapp/core/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/* 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.
==============================================================================*/

export {sideBarWidthChanged} from './actions';
export {LayoutModule} from './views/layout_module';
2 changes: 2 additions & 0 deletions tensorboard/webapp/core/store/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ tf_ng_module(
"//tensorboard/webapp/core:types",
"//tensorboard/webapp/core/actions",
"//tensorboard/webapp/deeplink",
"//tensorboard/webapp/persistent_settings",
"//tensorboard/webapp/types",
"@npm//@angular/core",
"@npm//@ngrx/store",
Expand All @@ -36,6 +37,7 @@ tf_ts_library(
"//tensorboard/webapp/core/actions",
"//tensorboard/webapp/core/testing",
"//tensorboard/webapp/deeplink",
"//tensorboard/webapp/persistent_settings",
"//tensorboard/webapp/types",
"@npm//@types/jasmine",
],
Expand Down
22 changes: 22 additions & 0 deletions tensorboard/webapp/core/store/core_reducers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
import {Action, createReducer, on} from '@ngrx/store';

import {globalSettingsLoaded} from '../../persistent_settings';
import {DataLoadState} from '../../types/data';
import * as actions from '../actions';
import {CoreState, initialState} from './core_types';
Expand Down Expand Up @@ -159,6 +161,26 @@ const reducer = createReducer(
}),
on(actions.polymerInteropRunSelectionChanged, (state, {nextSelection}) => {
return {...state, polymerInteropRunSelection: new Set(nextSelection)};
}),
on(actions.sideBarWidthChanged, (state, {widthInPercent}) => {
return {
...state,
sideBarWidthInPercent: Math.min(Math.max(0, widthInPercent), 100),
};
}),
on(globalSettingsLoaded, (state, {partialSettings}) => {
const nextState = {...state};

const sideBarWidthInPercent = partialSettings.sideBarWidthInPercent;
if (
typeof sideBarWidthInPercent === 'number' &&
sideBarWidthInPercent >= 0 &&
sideBarWidthInPercent <= 100
) {
nextState.sideBarWidthInPercent = sideBarWidthInPercent;
}

return nextState;
})
);

Expand Down
81 changes: 81 additions & 0 deletions tensorboard/webapp/core/store/core_reducers_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
} from '../testing';
import {DataLoadState} from '../../types/data';
import {PluginsListFailureCode} from '../types';
import {globalSettingsLoaded} from '../../persistent_settings';

function createPluginsListing() {
return {
Expand Down Expand Up @@ -558,4 +559,84 @@ describe('core reducer', () => {
});
});
});

describe('#sideBarWidthChanged', () => {
it('sets sideBarWidthInPercent', () => {
const state = createCoreState({
sideBarWidthInPercent: 0,
});
const nextState = reducers(
state,
actions.sideBarWidthChanged({widthInPercent: 30})
);

expect(nextState.sideBarWidthInPercent).toBe(30);
});

it('clips the value so it is between 0 and 100, inclusive', () => {
const state1 = createCoreState({
sideBarWidthInPercent: 5,
});
const state2 = reducers(
state1,
actions.sideBarWidthChanged({widthInPercent: -10})
);
expect(state2.sideBarWidthInPercent).toBe(0);

const state3 = reducers(
state2,
actions.sideBarWidthChanged({widthInPercent: 100})
);
expect(state3.sideBarWidthInPercent).toBe(100);
});
});

describe('#globalSettingsLoaded', () => {
it('loads sideBarWidthInPercent from settings when present', () => {
const state = createCoreState({
sideBarWidthInPercent: 0,
});
const nextState = reducers(
state,
globalSettingsLoaded({partialSettings: {sideBarWidthInPercent: 40}})
);

expect(nextState.sideBarWidthInPercent).toBe(40);
});

it('ignores partial settings without the sidebar width', () => {
const state = createCoreState({
sideBarWidthInPercent: 0,
});
const nextState = reducers(
state,
globalSettingsLoaded({partialSettings: {}})
);

expect(nextState.sideBarWidthInPercent).toBe(0);
});

it('loads when value is in between 0-100, inclusive', () => {
const state1 = createCoreState({
sideBarWidthInPercent: 0,
});
const state2 = reducers(
state1,
globalSettingsLoaded({partialSettings: {sideBarWidthInPercent: 101}})
);
expect(state2.sideBarWidthInPercent).toBe(0);

const state3 = reducers(
state2,
globalSettingsLoaded({partialSettings: {sideBarWidthInPercent: -1}})
);
expect(state3.sideBarWidthInPercent).toBe(0);

const state4 = reducers(
state3,
globalSettingsLoaded({partialSettings: {sideBarWidthInPercent: NaN}})
);
expect(state4.sideBarWidthInPercent).toBe(0);
});
});
});
7 changes: 7 additions & 0 deletions tensorboard/webapp/core/store/core_selectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,3 +79,10 @@ export const getEnvironment = createSelector(
return state.environment;
}
);

export const getSideBarWidthInPercent = createSelector(
selectCoreState,
(state: CoreState): number => {
return state.sideBarWidthInPercent;
}
);
15 changes: 15 additions & 0 deletions tensorboard/webapp/core/store/core_selectors_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,19 @@ describe('core selectors', () => {
expect(selectors.getAppLastLoadedTimeInMs(state)).toBe(1);
});
});

describe('#getSideBarWidthInPercent', () => {
beforeEach(() => {
selectors.getSideBarWidthInPercent.release();
});

it('returns sidebar width information', () => {
const state = createState(
createCoreState({
sideBarWidthInPercent: 15,
})
);
expect(selectors.getSideBarWidthInPercent(state)).toBe(15);
});
});
});
3 changes: 3 additions & 0 deletions tensorboard/webapp/core/store/core_types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ export interface CoreState {
// For now, we want them here for Polymer interop states reasons, too.
polymerInteropRuns: Run[];
polymerInteropRunSelection: Set<RunId>;
// Number between 0 and 100.
sideBarWidthInPercent: number;
}

/*
Expand Down Expand Up @@ -97,4 +99,5 @@ export const initialState: CoreState = {
},
polymerInteropRuns: [],
polymerInteropRunSelection: new Set(),
sideBarWidthInPercent: 30,
};
1 change: 1 addition & 0 deletions tensorboard/webapp/core/testing/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ export function createCoreState(override?: Partial<CoreState>): CoreState {
},
polymerInteropRuns: [],
polymerInteropRunSelection: new Set(),
sideBarWidthInPercent: 0,
...override,
};
}
Expand Down
33 changes: 32 additions & 1 deletion tensorboard/webapp/core/views/BUILD
Original file line number Diff line number Diff line change
@@ -1,7 +1,34 @@
load("//tensorboard/defs:defs.bzl", "tf_ng_module", "tf_ts_library")
load("//tensorboard/defs:defs.bzl", "tf_ng_module", "tf_sass_binary", "tf_ts_library")

package(default_visibility = ["//tensorboard:internal"])

tf_sass_binary(
name = "layout_styles",
src = "layout_container.scss",
)

tf_ng_module(
name = "layout",
srcs = [
"layout_container.ts",
"layout_module.ts",
],
assets = [":layout_styles"],
deps = [
"//tensorboard/webapp/angular:expect_angular_material_button",
"//tensorboard/webapp/angular:expect_angular_material_icon",
"//tensorboard/webapp/core:state",
"//tensorboard/webapp/core:types",
"//tensorboard/webapp/core/actions",
"//tensorboard/webapp/core/store",
"//tensorboard/webapp/util:dom",
"@npm//@angular/common",
"@npm//@angular/core",
"@npm//@ngrx/store",
"@npm//rxjs",
],
)

tf_ng_module(
name = "hash_storage",
srcs = [
Expand Down Expand Up @@ -61,11 +88,13 @@ tf_ts_library(
srcs = [
"dark_mode_supporter_test.ts",
"hash_storage_test.ts",
"layout_test.ts",
"page_title_test.ts",
],
deps = [
":dark_mode_supporter",
":hash_storage",
":layout",
":page_title",
"//tensorboard/webapp:app_state",
"//tensorboard/webapp:selectors",
Expand All @@ -80,6 +109,8 @@ tf_ts_library(
"//tensorboard/webapp/core/testing",
"//tensorboard/webapp/deeplink",
"//tensorboard/webapp/experiments/store:testing",
"//tensorboard/webapp/testing:mat_icon",
"//tensorboard/webapp/util:dom",
"@npm//@angular/common",
"@npm//@angular/compiler",
"@npm//@angular/core",
Expand Down
Loading

0 comments on commit 9d0c18d

Please sign in to comment.