Skip to content

Commit 94129a8

Browse files
authored
Adds redux code for displaying shared hparam columns in the Time Series page (#6727)
## Motivation for features / changes Required redux edits for displaying hparams in time series. ## Technical description of changes Adds a new property to HparamsState, `dashboardDisplayedHparamColumns` to represent the columns shown across the time series page (similar in concept to the existing `dashboardFilters`) Adds four actions for hparam column manipulation: - dashboardHparamColumnAdded - dashboardHparamColumnRemoved - dashboardHparamColumnToggled - dashboardHparamColumnOrderChanged and reducer logic to handle these events. Note that the add actions cannot simply pass the header index in this case as the table components will not have knowledge of the relative index of hparam columns. The actions instead specify the column to insert next to and the side, and the indices are computed from within the reducer (this can be seen as simply moving the index computation from the component to the reducer, which better conforms to https://redux.js.org/style-guide/#put-as-much-logic-as-possible-in-reducers ) Also exports required types from widgets/data_table - these will be also used by the runs and metrics tables the following PRs ## Detailed steps to verify changes work correctly (as executed by you) - Unit tests pass ## Alternate designs / implementations considered (or N/A) An alternative is to duplicate the hparams state across the runs and scalar card tables as RunsDataState.runsTableHeaders and MetricsState.singleSelectionHeaders/MetricsState.rangeSelectionHeaders, but this would either incur massive complications in syncing the various column operations (add/remove/hide/sort) or alternatively, would force the user to duplicate operations multiple times to get the hparams columns in sync. The chosen design also aligns with [keeping state minimal](https://redux.js.org/style-guide/#keep-state-minimal-and-derive-additional-values).
1 parent 28be621 commit 94129a8

File tree

18 files changed

+752
-139
lines changed

18 files changed

+752
-139
lines changed

tensorboard/webapp/hparams/BUILD

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,9 @@ tf_ng_module(
3737
"//tensorboard/webapp/hparams/_redux:hparams_actions",
3838
"//tensorboard/webapp/hparams/_redux:hparams_module",
3939
"//tensorboard/webapp/hparams/_redux:hparams_selectors",
40+
"//tensorboard/webapp/persistent_settings:config_module",
4041
"@npm//@angular/core",
42+
"@npm//@ngrx/store",
4143
],
4244
)
4345

tensorboard/webapp/hparams/_redux/BUILD

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ tf_ts_library(
5050
deps = [
5151
":types",
5252
"//tensorboard/webapp/hparams:types",
53+
"//tensorboard/webapp/widgets/data_table:types",
5354
"@npm//@ngrx/store",
5455
],
5556
)
@@ -65,6 +66,7 @@ tf_ts_library(
6566
":utils",
6667
"//tensorboard/webapp/hparams:_types",
6768
"//tensorboard/webapp/runs/actions",
69+
"//tensorboard/webapp/widgets/data_table:types",
6870
"@npm//@ngrx/store",
6971
],
7072
)
@@ -171,6 +173,7 @@ tf_ts_library(
171173
"//tensorboard/webapp/testing:utils",
172174
"//tensorboard/webapp/util:types",
173175
"//tensorboard/webapp/webapp_data_source:http_client_testing",
176+
"//tensorboard/webapp/widgets/data_table:types",
174177
"@npm//@ngrx/effects",
175178
"@npm//@ngrx/store",
176179
"@npm//@types/jasmine",

tensorboard/webapp/hparams/_redux/hparams_actions.ts

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,11 @@ limitations under the License.
1717
*/
1818

1919
import {createAction, props} from '@ngrx/store';
20-
import {HparamAndMetricSpec, SessionGroup} from '../types';
20+
import {
21+
AddColumnEvent,
22+
ReorderColumnEvent,
23+
} from '../../widgets/data_table/types';
24+
import {HparamAndMetricSpec, SessionGroup, ColumnHeader} from '../types';
2125
import {HparamFilter, MetricFilter} from './types';
2226

2327
export const hparamsFetchSessionGroupsSucceeded = createAction(
@@ -47,3 +51,23 @@ export const dashboardMetricFilterRemoved = createAction(
4751
'[Hparams] Dashboard Metric Filter Removed',
4852
props<{name: string}>()
4953
);
54+
55+
export const dashboardHparamColumnAdded = createAction(
56+
'[Hparams] Dashboard Hparam Column Added',
57+
props<AddColumnEvent>()
58+
);
59+
60+
export const dashboardHparamColumnRemoved = createAction(
61+
'[Hparams] Dashboard Hparam Column Removed',
62+
props<{column: ColumnHeader}>()
63+
);
64+
65+
export const dashboardHparamColumnToggled = createAction(
66+
'[Hparams] Dashboard Hparam Column Toggled',
67+
props<{column: ColumnHeader}>()
68+
);
69+
70+
export const dashboardHparamColumnOrderChanged = createAction(
71+
'[Hparams] Dashboard Hparam Column Order Changed',
72+
props<ReorderColumnEvent>()
73+
);

tensorboard/webapp/hparams/_redux/hparams_reducers.ts

Lines changed: 82 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ See the License for the specific language governing permissions and
1313
limitations under the License.
1414
==============================================================================*/
1515
import {Action, ActionReducer, createReducer, on} from '@ngrx/store';
16+
import {ColumnHeader, Side} from '../../widgets/data_table/types';
1617
import * as actions from './hparams_actions';
1718
import {HparamsState} from './types';
1819

@@ -26,6 +27,7 @@ const initialState: HparamsState = {
2627
hparams: new Map(),
2728
metrics: new Map(),
2829
},
30+
dashboardDisplayedHparamColumns: [],
2931
};
3032

3133
const reducer: ActionReducer<HparamsState, Action> = createReducer(
@@ -87,7 +89,86 @@ const reducer: ActionReducer<HparamsState, Action> = createReducer(
8789
metrics: nextMetricFilters,
8890
},
8991
};
90-
})
92+
}),
93+
on(actions.dashboardHparamColumnAdded, (state, {column, nextTo, side}) => {
94+
const {dashboardDisplayedHparamColumns: oldColumns} = state;
95+
96+
let destinationIndex = oldColumns.length; // Default to append at end.
97+
if (nextTo !== undefined && side !== undefined) {
98+
const nextToIndex = oldColumns.findIndex(
99+
(col) => col.name === nextTo.name
100+
);
101+
if (nextToIndex !== -1) {
102+
destinationIndex = side === Side.RIGHT ? nextToIndex + 1 : nextToIndex;
103+
}
104+
}
105+
const newColumn = {...column, enabled: true};
106+
const newColumns = [...oldColumns];
107+
newColumns.splice(destinationIndex, 0, newColumn);
108+
109+
return {
110+
...state,
111+
dashboardDisplayedHparamColumns: newColumns,
112+
};
113+
}),
114+
on(actions.dashboardHparamColumnRemoved, (state, {column}) => {
115+
const newColumns = state.dashboardDisplayedHparamColumns.filter(
116+
({name}) => name !== column.name
117+
);
118+
119+
return {
120+
...state,
121+
dashboardDisplayedHparamColumns: newColumns,
122+
};
123+
}),
124+
on(actions.dashboardHparamColumnToggled, (state, {column: toggledColumn}) => {
125+
const newColumns = state.dashboardDisplayedHparamColumns.map((column) => {
126+
if (column.name === toggledColumn.name) {
127+
return {
128+
...column,
129+
enabled: !toggledColumn.enabled,
130+
};
131+
}
132+
return column;
133+
});
134+
135+
return {
136+
...state,
137+
dashboardDisplayedHparamColumns: newColumns,
138+
};
139+
}),
140+
on(
141+
actions.dashboardHparamColumnOrderChanged,
142+
(state, {source, destination, side}) => {
143+
const {dashboardDisplayedHparamColumns: columns} = state;
144+
const sourceIndex = columns.findIndex(
145+
(column: ColumnHeader) => column.name === source.name
146+
);
147+
let destinationIndex = columns.findIndex(
148+
(column: ColumnHeader) => column.name === destination.name
149+
);
150+
if (sourceIndex === -1 || sourceIndex === destinationIndex) {
151+
return state;
152+
}
153+
if (destinationIndex === -1) {
154+
// Use side as a backup to determine source position if destination isn't found.
155+
if (side !== undefined) {
156+
destinationIndex = side === Side.LEFT ? 0 : columns.length - 1;
157+
} else {
158+
return state;
159+
}
160+
}
161+
162+
const newColumns = [...columns];
163+
newColumns.splice(sourceIndex, 1);
164+
newColumns.splice(destinationIndex, 0, source);
165+
166+
return {
167+
...state,
168+
dashboardDisplayedHparamColumns: newColumns,
169+
};
170+
}
171+
)
91172
);
92173

93174
export function reducers(state: HparamsState | undefined, action: Action) {

0 commit comments

Comments
 (0)