Skip to content
This repository was archived by the owner on May 27, 2021. It is now read-only.

Commit 8104fae

Browse files
authored
Merge pull request #37 from andymikulski/normandy-remove-lilrouter
#31: Use react-router in Normandy
2 parents 826ed8d + fc895b0 commit 8104fae

38 files changed

+623
-513
lines changed

package.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@
55
"dependencies": {
66
"antd": "^3.2.1",
77
"autobind-decorator": "^2.1.0",
8+
"enzyme-adapter-react-16": "^1.1.1",
9+
"es6-promise": "^4.2.4",
810
"immutable": "^3.8.2",
11+
"isomorphic-fetch": "^2.2.1",
912
"js-cookie": "^2.2.0",
10-
"localforage": "^1.5.6",
1113
"lodash.get": "^4.4.2",
1214
"photon-ant": "^0.1.4",
1315
"react": "^16.2.0",
@@ -18,7 +20,6 @@
1820
"react-router-dom": "^4.2.2",
1921
"react-scripts": "1.1.1",
2022
"redux": "^3.7.2",
21-
"redux-little-router": "14.0.0-0",
2223
"redux-logger": "^3.0.6",
2324
"redux-thunk": "^2.2.0",
2425
"underscore": "^1.8.3"
@@ -38,6 +39,7 @@
3839
"devDependencies": {
3940
"babel-plugin-import": "^1.6.5",
4041
"babel-plugin-transform-decorators-legacy": "^1.3.4",
42+
"enzyme": "^3.3.0",
4143
"flow-bin": "^0.66.0",
4244
"prettier": "^1.11.1",
4345
"react-app-rewire-less": "^2.1.0",

src/console/App.js

Lines changed: 50 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import 'console/App.less';
77
import LoginPage from './LoginPage';
88
import Normandy from 'normandy/App';
99
import { BrowserRouter, NavLink, Link } from 'react-router-dom';
10-
import { Route, Redirect } from 'react-router';
10+
import { Route, Redirect, Switch } from 'react-router';
1111

1212
import { Alert, Layout } from 'antd';
1313
const { Header, Content } = Layout;
@@ -17,7 +17,7 @@ const Homepage = props => (
1717
<h3>Welcome {props.authToken ? 'back' : 'home'}!</h3>
1818
{props.authToken ? (
1919
<p>
20-
Go to the <Link to="/normandy">Normandy page</Link>.
20+
Go to the <Link to="/shield">SHIELD control panel</Link>.
2121
</p>
2222
) : (
2323
<p>
@@ -57,9 +57,7 @@ class App extends Component<AppProps, AppState> {
5757
Home
5858
</NavLink>
5959
<NavLink to="/login">Login</NavLink>
60-
<NavLink exact to="/normandy">
61-
Normandy
62-
</NavLink>
60+
<NavLink to="/shield">SHIELD</NavLink>
6361

6462
{this.state.username && (
6563
<Alert
@@ -71,38 +69,55 @@ class App extends Component<AppProps, AppState> {
7169
)}
7270
</Header>
7371
<Content className="app-content">
74-
{/* Homepage */}
75-
<Route
76-
exact
77-
path="/"
78-
component={() => <Homepage authToken={this.state.authToken} />}
79-
/>
72+
<Switch>
73+
{/* Homepage */}
74+
<Route
75+
exact
76+
path="/"
77+
component={() => <Homepage authToken={this.state.authToken} />}
78+
/>
79+
80+
{/* Login */}
81+
<Route
82+
exact
83+
path="/login/"
84+
component={() =>
85+
this.state.username ? (
86+
<Redirect to="/" />
87+
) : (
88+
<LoginPage onAuth={this.onUserLogin} />
89+
)
90+
}
91+
/>
8092

81-
{/* Login */}
82-
<Route
83-
exact
84-
path="/login/"
85-
component={() =>
86-
this.state.username ? (
87-
<Redirect to="/" />
88-
) : (
89-
<LoginPage onAuth={this.onUserLogin} />
90-
)
91-
}
92-
/>
93+
{/* Normandy App */}
94+
<Route
95+
path="/shield"
96+
component={props =>
97+
this.state.username ? (
98+
<Normandy
99+
authToken={this.state.authToken}
100+
urlPrefix="/shield"
101+
{...props}
102+
/>
103+
) : (
104+
<Redirect to="/login/?next=/shield" />
105+
)
106+
}
107+
/>
93108

94-
{/* Normandy App */}
95-
<Route
96-
exact
97-
path="/normandy/"
98-
component={() =>
99-
this.state.username ? (
100-
<Normandy authToken={this.state.authToken} />
101-
) : (
102-
<Redirect to="/login/?next=/normandy/" />
103-
)
104-
}
105-
/>
109+
<Route
110+
component={({ location }) => (
111+
<div>
112+
<h2>404 - Page Not Found</h2>
113+
<p>
114+
No delivery-console match for{' '}
115+
<code>{location.pathname}</code>
116+
</p>
117+
</div>
118+
)}
119+
/>
120+
</Switch>
106121
</Content>
107122
</Layout>
108123
</BrowserRouter>

src/console/App.test.js

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import React from 'react';
22
import ReactDOM from 'react-dom';
33
import App from './App';
4+
import { shallow } from 'enzyme';
45

5-
it('renders without crashing', () => {
6-
const div = document.createElement('div');
7-
ReactDOM.render(<App />, div);
8-
ReactDOM.unmountComponentAtNode(div);
6+
describe('delivery-console', () => {
7+
it('renders without crashing', () => {
8+
const wrapper = () => shallow(<App />);
9+
expect(wrapper).not.toThrow();
10+
});
911
});

src/normandy/App.js

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,40 @@
11
import React from 'react';
22
import { Provider } from 'react-redux';
33
import { applyMiddleware, compose, createStore } from 'redux';
4-
import { initializeCurrentLocation } from 'redux-little-router';
54
import thunk from 'redux-thunk';
65

6+
import App from 'normandy/components/App';
7+
import NormandyRouter, { NormandyLink } from './Router';
8+
79
import './less/main.less';
810

9-
import Router, {
10-
enhancer as routerEnhancer,
11-
middleware as routerMiddleware,
12-
} from 'normandy/routes';
1311
import reducers from 'normandy/state';
1412

15-
const middleware = [routerMiddleware, thunk];
13+
const middleware = [thunk];
1614

1715
const store = createStore(
1816
reducers,
1917
reducers(undefined, { type: 'initial' }),
20-
compose(applyMiddleware(...middleware), routerEnhancer),
18+
compose(applyMiddleware(...middleware)),
2119
);
2220

23-
const initialLocation = store.getState().router;
24-
if (initialLocation) {
25-
store.dispatch(initializeCurrentLocation(initialLocation));
26-
}
21+
export default class Root extends React.Component {
22+
componentWillMount() {
23+
// `NormandyLinks` are wrapped Links which append a prefix for nested apps.
24+
// At this point we know the prefix, so we can update all instances of the
25+
// Link here via the static PREFIX property.
26+
NormandyLink.PREFIX = this.props.urlPrefix || '';
27+
}
2728

28-
export default class Root extends React.PureComponent {
2929
render() {
30+
const urlPrefix = this.props.urlPrefix;
31+
3032
return (
31-
<div id="normandy-app">
32-
<Provider store={store}>
33-
<Router />
34-
</Provider>
35-
</div>
33+
<Provider store={store}>
34+
<App>
35+
<NormandyRouter urlPrefix={urlPrefix} />
36+
</App>
37+
</Provider>
3638
);
3739
}
3840
}

src/normandy/App.test.js

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,22 @@
11
import React from 'react';
22
import ReactDOM from 'react-dom';
33
import App from './App';
4+
import { shallow } from 'enzyme';
45

5-
it('renders without crashing', () => {
6-
const div = document.createElement('div');
7-
ReactDOM.render(<App />, div);
8-
ReactDOM.unmountComponentAtNode(div);
6+
describe('normandy', () => {
7+
beforeAll(() => {
8+
const fakeStorage = {
9+
store: {},
10+
getItem: key => fakeStorage.store[key] || null,
11+
setItem: (key, value) => (fakeStorage.store[key] = value),
12+
};
13+
Object.defineProperty(window, 'localStorage', {
14+
value: fakeStorage,
15+
});
16+
});
17+
18+
it('renders without crashing', () => {
19+
const wrapper = () => shallow(<App />);
20+
expect(wrapper).not.toThrow();
21+
});
922
});

src/normandy/Router.js

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
import React from 'react';
2+
import { Switch } from 'react-router-dom';
3+
import { Route } from 'react-router';
4+
5+
import CreateExtensionPage from 'normandy/components/extensions/CreateExtensionPage';
6+
import EditExtensionPage from 'normandy/components/extensions/EditExtensionPage';
7+
import ApprovalHistoryPage from 'normandy/components/recipes/ApprovalHistoryPage';
8+
import CreateRecipePage from 'normandy/components/recipes/CreateRecipePage';
9+
import CloneRecipePage from 'normandy/components/recipes/CloneRecipePage';
10+
import EditRecipePage from 'normandy/components/recipes/EditRecipePage';
11+
import ExtensionListing from 'normandy/components/extensions/ExtensionListing';
12+
import Gateway from 'normandy/components/pages/Gateway';
13+
import RecipeListing from 'normandy/components/recipes/RecipeListing';
14+
import RecipeDetailPage from 'normandy/components/recipes/RecipeDetailPage';
15+
16+
import { NavLink } from 'react-router-dom';
17+
18+
export default class NormandyRouter extends React.Component {
19+
static ROUTES = {
20+
'/': {
21+
component: Gateway,
22+
},
23+
// Recipes ---
24+
'/recipe': {
25+
component: RecipeListing,
26+
},
27+
'/recipe/new': {
28+
component: CreateRecipePage,
29+
},
30+
'/recipe/:recipeId': {
31+
component: RecipeDetailPage,
32+
},
33+
'/recipe/:recipeId/edit': {
34+
component: EditRecipePage,
35+
},
36+
'/recipe/:recipeId/approval_history': {
37+
component: ApprovalHistoryPage,
38+
},
39+
'/recipe/:recipeId/clone': {
40+
component: CloneRecipePage,
41+
},
42+
// Recipe Revisions ---
43+
'/recipe/:recipeId/rev/:revisionId': {
44+
component: RecipeDetailPage,
45+
},
46+
'/recipe/:recipeId/rev/:revisionId/clone': {
47+
component: CloneRecipePage,
48+
},
49+
// Extensions ---
50+
'/extension': {
51+
component: ExtensionListing,
52+
},
53+
'/extension/new': {
54+
component: CreateExtensionPage,
55+
},
56+
'/extension/:extensionId': {
57+
component: EditExtensionPage,
58+
},
59+
};
60+
61+
render() {
62+
const urlPrefix = this.props.urlPrefix || '';
63+
64+
return (
65+
<Switch>
66+
{Object.keys(NormandyRouter.ROUTES).map(route => {
67+
return (
68+
<Route
69+
key={route}
70+
exact
71+
path={`${urlPrefix}${route}`}
72+
{...NormandyRouter.ROUTES[route]}
73+
/>
74+
);
75+
})}
76+
77+
<Route
78+
component={({ location }) => (
79+
<div>
80+
<h2>404 - Page Not Found</h2>
81+
<p>
82+
No normandy match for <code>{location.pathname}</code>
83+
</p>
84+
</div>
85+
)}
86+
/>
87+
</Switch>
88+
);
89+
}
90+
}
91+
92+
export class NormandyLink extends React.Component {
93+
static PREFIX = '';
94+
render() {
95+
const { to, ...rest } = this.props;
96+
97+
return <NavLink to={`${NormandyLink.PREFIX}${to}`} {...rest} />;
98+
}
99+
}

src/normandy/components/App.js

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,8 @@ import { Layout, LocaleProvider } from 'antd';
22
import enUS from 'antd/lib/locale-provider/en_US';
33
import PropTypes from 'prop-types';
44
import React from 'react';
5-
import { Link } from 'redux-little-router';
5+
import { NormandyLink as Link } from 'normandy/Router';
66

7-
import CurrentUserDetails from 'normandy/components/common/CurrentUserDetails';
87
import NavigationCrumbs from 'normandy/components/common/NavigationCrumbs';
98
import NavigationMenu from 'normandy/components/common/NavigationMenu';
109
import EnvAlert from 'normandy/components/common/EnvAlert';
@@ -27,7 +26,7 @@ export default class App extends React.PureComponent {
2726

2827
return (
2928
<LocaleProvider locale={enUS}>
30-
<Layout>
29+
<Layout id="normandy-app">
3130
<EnvAlert />
3231

3332
{/*
@@ -38,9 +37,8 @@ export default class App extends React.PureComponent {
3837
<QueryServiceInfo />
3938

4039
<Header>
41-
<CurrentUserDetails />
4240
<div className="logo">
43-
<Link href="/">SHIELD Control Panel</Link>
41+
<Link to="/">SHIELD Control Panel</Link>
4442
</div>
4543
</Header>
4644

0 commit comments

Comments
 (0)