diff --git a/__tests__/tests/App.test.jsx b/__tests__/tests/App.test.jsx
new file mode 100644
index 0000000000..eff4a85736
--- /dev/null
+++ b/__tests__/tests/App.test.jsx
@@ -0,0 +1,37 @@
+import React from 'react';
+import { shallow, mount } from 'enzyme';
+import App from '../../src/App';
+import api from '../../src/api';
+import Dashboard from '../../src/pages/Dashboard';
+import Login from '../../src/pages/Login';
+
+describe('', () => {
+ test('renders without crashing', () => {
+ const appWrapper = shallow();
+ expect(appWrapper.length).toBe(1);
+ });
+
+ test('renders login page when not authenticated', () => {
+ api.isAuthenticated = jest.fn();
+ api.isAuthenticated.mockReturnValue(false);
+
+ const appWrapper = mount();
+
+ const redirectChild = appWrapper.find(Login);
+ expect(redirectChild.length).toBe(1);
+ const routeChild = appWrapper.find(Dashboard);
+ expect(routeChild.length).toBe(0);
+ });
+
+ test('renders dashboard when authenticated', () => {
+ api.isAuthenticated = jest.fn();
+ api.isAuthenticated.mockReturnValue(true);
+
+ const appWrapper = mount();
+
+ const redirectChild = appWrapper.find(Dashboard);
+ expect(redirectChild.length).toBe(1);
+ const routeChild = appWrapper.find(Login);
+ expect(routeChild.length).toBe(0);
+ });
+});
\ No newline at end of file
diff --git a/__tests__/tests/ConditionalRedirect.test.jsx b/__tests__/tests/ConditionalRedirect.test.jsx
new file mode 100644
index 0000000000..af241810eb
--- /dev/null
+++ b/__tests__/tests/ConditionalRedirect.test.jsx
@@ -0,0 +1,27 @@
+import React, { Component } from 'react';
+import {
+ Route,
+ Redirect
+} from 'react-router-dom';
+import { shallow } from 'enzyme';
+import ConditionalRedirect from '../../src/components/ConditionalRedirect';
+
+describe('', () => {
+ test('renders Redirect when shouldRedirect is passed truthy func', () => {
+ const truthyFunc = () => true;
+ const shouldHaveRedirectChild = shallow( truthyFunc()} />);
+ const redirectChild = shouldHaveRedirectChild.find(Redirect);
+ expect(redirectChild.length).toBe(1);
+ const routeChild = shouldHaveRedirectChild.find(Route);
+ expect(routeChild.length).toBe(0);
+ });
+
+ test('renders Route when shouldRedirect is passed falsy func', () => {
+ const falsyFunc = () => false;
+ const shouldHaveRouteChild = shallow( falsyFunc()} />);
+ const routeChild = shouldHaveRouteChild.find(Route);
+ expect(routeChild.length).toBe(1);
+ const redirectChild = shouldHaveRouteChild.find(Redirect);
+ expect(redirectChild.length).toBe(0);
+ });
+});
\ No newline at end of file
diff --git a/src/App.jsx b/src/App.jsx
index 7e6f5925c2..94a0bbfdd6 100644
--- a/src/App.jsx
+++ b/src/App.jsx
@@ -14,6 +14,7 @@ import {
Button,
ButtonVariant,
Nav,
+ NavExpandable,
NavGroup,
NavItem,
Page,
@@ -34,6 +35,9 @@ import api from './api';
import About from './components/About';
import TowerLogo from './components/TowerLogo';
+// import AuthenticatedRoute from './components/AuthenticatedRoute';
+// import UnauthenticatedRoute from './components/UnauthenticatedRoute';
+import ConditionalRedirect from './components/ConditionalRedirect';
import Applications from './pages/Applications';
import Credentials from './pages/Credentials';
@@ -55,32 +59,6 @@ import Teams from './pages/Teams';
import Templates from './pages/Templates';
import Users from './pages/Users';
-const AuthenticatedRoute = ({ component: Component, ...rest }) => (
- (
- api.isAuthenticated() ? (
-
- ) : (
-
- )
- )}/>
-);
-
-const UnauthenticatedRoute = ({ component: Component, ...rest }) => (
- (
- !api.isAuthenticated() ? (
-
- ) : (
-
- )
- )}/>
-);
-
class App extends React.Component {
constructor(props) {
super(props);
@@ -90,6 +68,8 @@ class App extends React.Component {
isNavOpen: (typeof window !== 'undefined' &&
window.innerWidth >= parseInt(breakpointMd.value, 10)),
};
+
+ this.state.activeGroup = this.state.activeItem.startsWith("settings_group_") ? "settings": "";
}
onNavToggle = () => {
@@ -98,8 +78,8 @@ class App extends React.Component {
this.setState({ isNavOpen: !isNavOpen });
}
- onNavSelect = ({ itemId }) => {
- this.setState({ activeItem: itemId });
+ onNavSelect = ({ groupId, itemId }) => {
+ this.setState({ activeGroup: groupId || "", activeItem: itemId });
};
onLogoClick = () => {
@@ -114,7 +94,7 @@ class App extends React.Component {
}
render() {
- const { activeItem, isNavOpen } = this.state;
+ const { activeItem, activeGroup, isNavOpen } = this.state;
const { logo, loginInfo } = this.props;
return (
@@ -132,8 +112,8 @@ class App extends React.Component {
[BackgroundImageSrc.filter]: '/assets/images/background-filter.svg'
}} />
- } />
- (
+ api.isAuthenticated()} redirectPath="/" path="/login" component={() => } />
+
Management Jobs
Instance Groups
Applications
- Settings
+
+
+ Authentication
+
+
+ Jobs
+
+
+ System
+
+
+ User Interface
+
+
)}
/>
)}>
- ()} />
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ !api.isAuthenticated()} redirectPath="/login" exact path="/" component={() => ()} />
+ !api.isAuthenticated()} redirectPath="/login" path="/home" component={Dashboard} />
+ !api.isAuthenticated()} redirectPath="/login" path="/jobs" component={Jobs} />
+ !api.isAuthenticated()} redirectPath="/login" path="/schedules" component={Schedules} />
+ !api.isAuthenticated()} redirectPath="/login" path="/portal" component={Portal} />
+ !api.isAuthenticated()} redirectPath="/login" path="/templates" component={Templates} />
+ !api.isAuthenticated()} redirectPath="/login" path="/credentials" component={Credentials} />
+ !api.isAuthenticated()} redirectPath="/login" path="/projects" component={Projects} />
+ !api.isAuthenticated()} redirectPath="/login" path="/inventories" component={Inventories} />
+ !api.isAuthenticated()} redirectPath="/login" path="/inventory_scripts" component={InventoryScripts} />
+ !api.isAuthenticated()} redirectPath="/login" path="/organizations" component={Organizations} />
+ !api.isAuthenticated()} redirectPath="/login" path="/users" component={Users} />
+ !api.isAuthenticated()} redirectPath="/login" path="/teams" component={Teams} />
+ !api.isAuthenticated()} redirectPath="/login" path="/credential_types" component={CredentialTypes} />
+ !api.isAuthenticated()} redirectPath="/login" path="/notification_templates" component={NotificationTemplates} />
+ !api.isAuthenticated()} redirectPath="/login" path="/management_jobs" component={ManagementJobs} />
+ !api.isAuthenticated()} redirectPath="/login" path="/instance_groups" component={InstanceGroups} />
+ !api.isAuthenticated()} redirectPath="/login" path="/applications" component={Applications} />
+ !api.isAuthenticated()} redirectPath="/login" path="/settings" component={Settings} />
- )} />
+
diff --git a/src/components/ConditionalRedirect.jsx b/src/components/ConditionalRedirect.jsx
new file mode 100644
index 0000000000..f71e6054a3
--- /dev/null
+++ b/src/components/ConditionalRedirect.jsx
@@ -0,0 +1,22 @@
+import React from 'react';
+import {
+ Route,
+ Redirect
+} from 'react-router-dom';
+
+const ConditionalRedirect = ({ component: Component, shouldRedirect, redirectPath, ...props }) => {
+ if (shouldRedirect()) {
+ return (
+
+ );
+ } else {
+ return (
+ ()} />
+ );
+ }
+};
+
+export default ConditionalRedirect;
\ No newline at end of file