Skip to content

Commit 0de506e

Browse files
authored
ng: introduce ngrx and create basic usage (#2561)
This change introduces ngrx, a state management, to our angular shell. The usage of ngrx is very limited. Soon, it will be expanded to make XHR to fetch list of plugins and properly render the header.
1 parent ae205a7 commit 0de506e

File tree

20 files changed

+505
-18
lines changed

20 files changed

+505
-18
lines changed

package.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,15 @@
4545
"typescript": "~3.4.5"
4646
},
4747
"dependencies": {
48-
"@angular/animations": "^8.1.2",
48+
"@angular/animations": "^8.2.2",
49+
"@angular/cdk": "^8.1.3",
4950
"@angular/common": "^8.1.2",
5051
"@angular/core": "^8.1.2",
52+
"@angular/forms": "^8.2.2",
53+
"@angular/material": "^8.1.3",
5154
"@angular/platform-browser": "^8.1.3",
5255
"@angular/router": "^8.1.2",
56+
"@ngrx/store": "^8.2.0",
5357
"rxjs": "^6.5.2",
5458
"zone.js": "^0.9.1"
5559
}

tensorboard/components/tf_ng_tensorboard/BUILD

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,31 @@ package(default_visibility = ["//tensorboard:internal"])
22

33
load("@npm_angular_bazel//:index.bzl", "ng_module")
44
load("//tensorboard/defs:defs.bzl", "tf_js_binary")
5+
load("//tensorboard/defs:web.bzl", "tf_web_library")
56

67
licenses(["notice"]) # Apache 2.0
78

9+
tf_web_library(
10+
name = "tf_ng_tensorboard",
11+
srcs = [
12+
":tf_ng_tensorboard_binary.js",
13+
"@npm//:node_modules/zone.js/dist/zone.js",
14+
],
15+
path = "/tf-ng-tensorboard",
16+
deps = [
17+
":tf_ng_tensorboard_binary",
18+
],
19+
)
20+
21+
# TODO(stephanwlee): move this to root level
22+
tf_web_library(
23+
name = "material_theme",
24+
srcs = [
25+
"@npm//:node_modules/@angular/material/prebuilt-themes/indigo-pink.css",
26+
],
27+
path = "/@angular",
28+
strip_prefix = "node_modules/@angular/material/prebuilt-themes",
29+
)
830

931
tf_js_binary(
1032
name = "tf_ng_tensorboard_binary",
@@ -14,8 +36,9 @@ tf_js_binary(
1436
":ng_main",
1537
"@npm//@angular/common",
1638
"@npm//@angular/core",
39+
"@npm//@angular/material",
1740
"@npm//@angular/platform-browser",
18-
"@npm//@angular/router",
41+
"@npm//@ngrx/store",
1942
"@npm//rxjs",
2043
"@npm//zone.js",
2144
],
@@ -40,15 +63,17 @@ ng_module(
4063
srcs = [
4164
"app.component.ts",
4265
"app.module.ts",
43-
"app-routing.module.ts",
66+
"reducers.ts",
4467
],
4568
assets = [
4669
"app.component.css",
4770
"app.component.html",
4871
],
4972
deps = [
73+
"//tensorboard/components/tf_ng_tensorboard/core",
74+
"//tensorboard/components/tf_ng_tensorboard/header",
5075
"@npm//@angular/core",
5176
"@npm//@angular/platform-browser",
52-
"@npm//@angular/router",
77+
"@npm//@ngrx/store",
5378
],
5479
)

tensorboard/components/tf_ng_tensorboard/app.component.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,5 @@
1515
limitations under the License.
1616
-->
1717
<div>
18-
Angular TensorBoard
18+
<app-header></app-header>
1919
</div>

tensorboard/components/tf_ng_tensorboard/app.component.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,23 @@ See the License for the specific language governing permissions and
1313
limitations under the License.
1414
==============================================================================*/
1515
import {Component} from '@angular/core';
16+
import {Store, select} from '@ngrx/store';
17+
import {State, getActivePlugin} from './core/core.reducers';
18+
import {changePlugin} from './core/core.actions';
19+
import {PluginId} from './types/api';
1620

1721
@Component({
1822
selector: 'tf-ng-tensorboard',
1923
templateUrl: './app.component.html',
2024
styleUrls: ['./app.component.css'],
2125
})
22-
export class AppComponent {}
26+
export class AppComponent {
27+
constructor(private store: Store<State>) {}
28+
29+
ngOnInit() {
30+
// TODO(stephanwlee): Instead of hardcoding it, consider reading it off of the
31+
// tf_dashboard.registry. It is current infeasible unless Angular source is also
32+
// compiled with JSCompiler.
33+
this.store.dispatch(changePlugin({plugin: 'Core'}));
34+
}
35+
}

tensorboard/components/tf_ng_tensorboard/app.module.ts

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,33 @@ See the License for the specific language governing permissions and
1313
limitations under the License.
1414
==============================================================================*/
1515
import {BrowserModule} from '@angular/platform-browser';
16+
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
1617
import {NgModule} from '@angular/core';
18+
import {StoreModule} from '@ngrx/store';
1719

18-
import {AppRoutingModule} from './app-routing.module';
1920
import {AppComponent} from './app.component';
21+
import {CoreModule} from './core/core.module';
22+
import {ROOT_REDUCERS, metaReducers} from './reducers';
23+
24+
import {HeaderModule} from './header/header.module';
2025

2126
@NgModule({
2227
declarations: [AppComponent],
23-
imports: [BrowserModule, AppRoutingModule],
28+
imports: [
29+
BrowserModule,
30+
BrowserAnimationsModule,
31+
CoreModule,
32+
HeaderModule,
33+
StoreModule.forRoot(ROOT_REDUCERS, {
34+
metaReducers,
35+
runtimeChecks: {
36+
strictStateImmutability: true,
37+
strictActionImmutability: true,
38+
strictStateSerializability: true,
39+
strictActionSerializability: true,
40+
},
41+
}),
42+
],
2443
providers: [],
2544
bootstrap: [AppComponent],
2645
})
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package(default_visibility = ["//tensorboard:internal"])
2+
3+
load("@npm_angular_bazel//:index.bzl", "ng_module")
4+
load("@npm_bazel_jasmine//:index.bzl", "jasmine_node_test")
5+
6+
ng_module(
7+
name = "core",
8+
srcs = [
9+
"core.actions.ts",
10+
"core.module.ts",
11+
"core.reducers.ts",
12+
],
13+
deps = [
14+
"//tensorboard/components/tf_ng_tensorboard/types",
15+
"@npm//@ngrx/store",
16+
],
17+
)
18+
19+
ng_module(
20+
name = "core_test_lib",
21+
testonly = True,
22+
srcs = [
23+
"core.reducers.test.ts",
24+
],
25+
deps = [
26+
":core",
27+
"@npm//@types/jasmine",
28+
"@npm//chai",
29+
],
30+
)
31+
32+
jasmine_node_test(
33+
name = "core_jasmine_test",
34+
deps = [
35+
":core_test_lib",
36+
],
37+
)
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/* Copyright 2019 The TensorFlow Authors. All Rights Reserved.
2+
3+
Licensed under the Apache License, Version 2.0 (the "License");
4+
you may not use this file except in compliance with the License.
5+
You may obtain a copy of the License at
6+
7+
http://www.apache.org/licenses/LICENSE-2.0
8+
9+
Unless required by applicable law or agreed to in writing, software
10+
distributed under the License is distributed on an "AS IS" BASIS,
11+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
See the License for the specific language governing permissions and
13+
limitations under the License.
14+
==============================================================================*/
15+
import {createAction, props} from '@ngrx/store';
16+
import {PluginId} from '../types/api';
17+
18+
// HACK: Below import is for type inference.
19+
// https://github.com/bazelbuild/rules_nodejs/issues/1013
20+
import * as _typeHackModels from '@ngrx/store/src/models';
21+
22+
export const changePlugin = createAction(
23+
'CHANGE_PLUGIN',
24+
props<{plugin: PluginId}>()
25+
);

tensorboard/components/tf_ng_tensorboard/app-routing.module.ts renamed to tensorboard/components/tf_ng_tensorboard/core/core.module.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,11 @@ See the License for the specific language governing permissions and
1313
limitations under the License.
1414
==============================================================================*/
1515
import {NgModule} from '@angular/core';
16-
import {Routes, RouterModule} from '@angular/router';
16+
import {StoreModule} from '@ngrx/store';
1717

18-
const routes: Routes = [];
18+
import {CORE_FEATURE_KEY, reducers} from './core.reducers';
1919

2020
@NgModule({
21-
imports: [RouterModule],
22-
exports: [RouterModule],
21+
imports: [StoreModule.forFeature(CORE_FEATURE_KEY, reducers)],
2322
})
24-
export class AppRoutingModule {}
23+
export class CoreModule {}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/* Copyright 2019 The TensorFlow Authors. All Rights Reserved.
2+
3+
Licensed under the Apache License, Version 2.0 (the "License");
4+
you may not use this file except in compliance with the License.
5+
You may obtain a copy of the License at
6+
7+
http://www.apache.org/licenses/LICENSE-2.0
8+
9+
Unless required by applicable law or agreed to in writing, software
10+
distributed under the License is distributed on an "AS IS" BASIS,
11+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
See the License for the specific language governing permissions and
13+
limitations under the License.
14+
==============================================================================*/
15+
import {expect} from 'chai';
16+
17+
import * as actions from './core.actions';
18+
import {reducers} from './core.reducers';
19+
20+
describe('core reducer', () => {
21+
describe('#changePlugin', () => {
22+
it('sets activePlugin to the one in action payload', () => {
23+
const state = {activePlugin: 'foo'};
24+
const nextState = reducers(state, actions.changePlugin({plugin: 'bar'}));
25+
26+
expect(nextState).to.have.property('activePlugin', 'bar');
27+
});
28+
});
29+
});
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/* Copyright 2019 The TensorFlow Authors. All Rights Reserved.
2+
3+
Licensed under the Apache License, Version 2.0 (the "License");
4+
you may not use this file except in compliance with the License.
5+
You may obtain a copy of the License at
6+
7+
http://www.apache.org/licenses/LICENSE-2.0
8+
9+
Unless required by applicable law or agreed to in writing, software
10+
distributed under the License is distributed on an "AS IS" BASIS,
11+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
See the License for the specific language governing permissions and
13+
limitations under the License.
14+
==============================================================================*/
15+
import {
16+
Action,
17+
createSelector,
18+
createReducer,
19+
on,
20+
createFeatureSelector,
21+
} from '@ngrx/store';
22+
import {PluginId} from '../types/api';
23+
import * as actions from './core.actions';
24+
25+
// HACK: These imports are for type inference.
26+
// https://github.com/bazelbuild/rules_nodejs/issues/1013
27+
import * as _typeHackSelector from '@ngrx/store/src/selector';
28+
import * as _typeHackStore from '@ngrx/store/store';
29+
30+
export const CORE_FEATURE_KEY = 'core';
31+
32+
export interface CoreState {
33+
activePlugin: PluginId;
34+
}
35+
36+
export interface State {
37+
[CORE_FEATURE_KEY]: CoreState;
38+
}
39+
40+
const initialState = {};
41+
42+
const reducer = createReducer(
43+
initialState,
44+
on(actions.changePlugin, (state: CoreState, {plugin}) => {
45+
return {
46+
activePlugin: plugin,
47+
};
48+
})
49+
);
50+
51+
export function reducers(state: CoreState, action: Action) {
52+
return reducer(state, action);
53+
}
54+
55+
const selectCoreState = createFeatureSelector<State, CoreState>(
56+
CORE_FEATURE_KEY
57+
);
58+
59+
export const getActivePlugin = createSelector(
60+
selectCoreState,
61+
(state: CoreState): PluginId => {
62+
return state.activePlugin;
63+
}
64+
);

0 commit comments

Comments
 (0)