mirror of
https://github.com/ansible/awx.git
synced 2026-01-13 19:10:07 -03:30
decouple App and Login components
This commit is contained in:
parent
6efd523db2
commit
9c6df68557
@ -1,12 +1,12 @@
|
||||
import React from 'react';
|
||||
import { HashRouter as Router } from 'react-router-dom';
|
||||
|
||||
import { shallow, mount } from 'enzyme';
|
||||
import App from '../src/App';
|
||||
import api from '../src/api';
|
||||
import { API_LOGOUT, API_CONFIG } from '../src/endpoints';
|
||||
|
||||
import Dashboard from '../src/pages/Dashboard';
|
||||
import Login from '../src/pages/Login';
|
||||
import { asyncFlush } from '../jest.setup';
|
||||
|
||||
const DEFAULT_ACTIVE_GROUP = 'views_group';
|
||||
@ -24,30 +24,6 @@ describe('<App />', () => {
|
||||
expect(appWrapper.length).toBe(1);
|
||||
});
|
||||
|
||||
test('renders login page when not authenticated', () => {
|
||||
api.isAuthenticated = jest.fn();
|
||||
api.isAuthenticated.mockReturnValue(false);
|
||||
|
||||
const appWrapper = mount(<Router><App /></Router>);
|
||||
|
||||
const login = appWrapper.find(Login);
|
||||
expect(login.length).toBe(1);
|
||||
const dashboard = appWrapper.find(Dashboard);
|
||||
expect(dashboard.length).toBe(0);
|
||||
});
|
||||
|
||||
test('renders dashboard when authenticated', () => {
|
||||
api.isAuthenticated = jest.fn();
|
||||
api.isAuthenticated.mockReturnValue(true);
|
||||
|
||||
const appWrapper = mount(<Router><App routeGroups={routeGroups} /></Router>);
|
||||
|
||||
const dashboard = appWrapper.find(Dashboard);
|
||||
expect(dashboard.length).toBe(1);
|
||||
const login = appWrapper.find(Login);
|
||||
expect(login.length).toBe(0);
|
||||
});
|
||||
|
||||
test('onNavToggle sets state.isNavOpen to opposite', () => {
|
||||
const appWrapper = shallow(<App />);
|
||||
expect(appWrapper.state().isNavOpen).toBe(true);
|
||||
|
||||
163
src/App.jsx
163
src/App.jsx
@ -1,6 +1,4 @@
|
||||
import React, { Fragment } from 'react';
|
||||
import { ConfigContext } from './context';
|
||||
|
||||
import React, { Component } from 'react';
|
||||
import {
|
||||
Redirect,
|
||||
Switch,
|
||||
@ -20,15 +18,15 @@ import { global_breakpoint_md as breakpointMd } from '@patternfly/react-tokens';
|
||||
|
||||
import api from './api';
|
||||
import { API_LOGOUT, API_CONFIG } from './endpoints';
|
||||
import { ConfigContext } from './context';
|
||||
|
||||
import Login from './pages/Login';
|
||||
import HelpDropdown from './components/HelpDropdown';
|
||||
import LogoutButton from './components/LogoutButton';
|
||||
import TowerLogo from './components/TowerLogo';
|
||||
import NavExpandableGroup from './components/NavExpandableGroup';
|
||||
|
||||
class App extends React.Component {
|
||||
constructor(props) {
|
||||
class App extends Component {
|
||||
constructor (props) {
|
||||
super(props);
|
||||
|
||||
// initialize with a closed navbar if window size is small
|
||||
@ -47,13 +45,21 @@ class App extends React.Component {
|
||||
};
|
||||
|
||||
onLogoClick = () => {
|
||||
this.setState({ activeGroup: 'views_group' });
|
||||
this.setState({
|
||||
activeGroup: 'views_group'
|
||||
});
|
||||
}
|
||||
|
||||
onDevLogout = async () => {
|
||||
await api.get(API_LOGOUT);
|
||||
this.setState({ activeGroup: 'views_group', activeItem: 'views_group_dashboard' });
|
||||
}
|
||||
|
||||
this.setState({
|
||||
activeGroup: 'views_group',
|
||||
activeItem: 'views_group_dashboard',
|
||||
});
|
||||
|
||||
window.location.replace('/#/login');
|
||||
};
|
||||
|
||||
async componentDidMount() {
|
||||
// Grab our config data from the API and store in state
|
||||
@ -67,80 +73,77 @@ class App extends React.Component {
|
||||
|
||||
render () {
|
||||
const { config, isNavOpen } = this.state;
|
||||
const { logo, loginInfo, navLabel, routeGroups = [] } = this.props;
|
||||
const { navLabel = '', routeGroups = [] } = this.props;
|
||||
|
||||
const header = (
|
||||
<PageHeader
|
||||
showNavToggle
|
||||
onNavToggle={() => this.onNavToggle()}
|
||||
logo={(
|
||||
<TowerLogo
|
||||
onClick={this.onLogoClick}
|
||||
/>
|
||||
)}
|
||||
toolbar={(
|
||||
<Toolbar>
|
||||
<ToolbarGroup>
|
||||
<ToolbarItem>
|
||||
<HelpDropdown />
|
||||
</ToolbarItem>
|
||||
<ToolbarItem>
|
||||
<LogoutButton
|
||||
onDevLogout={() => this.onDevLogout()}
|
||||
/>
|
||||
</ToolbarItem>
|
||||
</ToolbarGroup>
|
||||
</Toolbar>
|
||||
)}
|
||||
/>
|
||||
);
|
||||
|
||||
const sidebar = (
|
||||
<PageSidebar
|
||||
isNavOpen={isNavOpen}
|
||||
nav={(
|
||||
<Nav aria-label={navLabel}>
|
||||
<NavList>
|
||||
{routeGroups.map(params => (
|
||||
<NavExpandableGroup key={params.groupId} {...params} />
|
||||
))}
|
||||
</NavList>
|
||||
</Nav>
|
||||
)}
|
||||
/>
|
||||
);
|
||||
|
||||
return (
|
||||
api.isAuthenticated () ? (
|
||||
<Switch>
|
||||
<Route path="/login" render={() => <Redirect to='/home' />} />
|
||||
<Route exact path="/" render={() => <Redirect to='/home' />} />
|
||||
<Route render={() => (
|
||||
<ConfigContext.Provider value={config}>
|
||||
<Page
|
||||
usecondensed="True"
|
||||
header={(
|
||||
<PageHeader
|
||||
showNavToggle
|
||||
onNavToggle={() => this.onNavToggle()}
|
||||
logo={(
|
||||
<TowerLogo
|
||||
onClick={this.onLogoClick}
|
||||
/>
|
||||
)}
|
||||
toolbar={(
|
||||
<Toolbar>
|
||||
<ToolbarGroup>
|
||||
<ToolbarItem>
|
||||
<HelpDropdown />
|
||||
</ToolbarItem>
|
||||
<ToolbarItem>
|
||||
<LogoutButton
|
||||
onDevLogout={() => this.onDevLogout()}
|
||||
/>
|
||||
</ToolbarItem>
|
||||
</ToolbarGroup>
|
||||
</Toolbar>
|
||||
)}
|
||||
/>
|
||||
<ConfigContext.Provider value={config}>
|
||||
<Page
|
||||
usecondensed="True"
|
||||
header={header}
|
||||
sidebar={sidebar}
|
||||
>
|
||||
{
|
||||
//
|
||||
// Extract a flattened array of all route params from the provided route config
|
||||
// and use it to render route components.
|
||||
//
|
||||
// [{ routes }, { routes }] -> [route, route, route] -> (<Route/><Route/><Route/>)
|
||||
//
|
||||
routeGroups
|
||||
.reduce((allRoutes, { routes }) => allRoutes.concat(routes), [])
|
||||
.map(({ component: Component, path }) => (
|
||||
<Route
|
||||
key={path}
|
||||
path={path}
|
||||
render={params => (
|
||||
<Component {...params } />
|
||||
)}
|
||||
sidebar={(
|
||||
<PageSidebar
|
||||
isNavOpen={isNavOpen}
|
||||
nav={(
|
||||
<Nav aria-label={navLabel}>
|
||||
<NavList>
|
||||
{
|
||||
routeGroups.map(params => <NavExpandableGroup key={params.groupId} {...params} />)
|
||||
}
|
||||
</NavList>
|
||||
</Nav>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
>
|
||||
{
|
||||
//
|
||||
// Extract a flattened array of all route params from the provided route config
|
||||
// and use it to render route components.
|
||||
//
|
||||
// [{ routes }, { routes }] -> [route, route, route] -> (<Route/><Route/><Route/>)
|
||||
//
|
||||
routeGroups
|
||||
.reduce((allRoutes, { routes }) => allRoutes.concat(routes), [])
|
||||
.map(({ component: Component, path }) => (
|
||||
<Route key={path} path={path} render={params => <Component {...params } />} />
|
||||
))
|
||||
}
|
||||
</Page>
|
||||
</ConfigContext.Provider>
|
||||
)} />
|
||||
</Switch>
|
||||
) : (
|
||||
<Switch>
|
||||
<Route path="/login" render={() => <Login logo={logo} loginInfo={loginInfo} />} />
|
||||
<Redirect to="/login" />
|
||||
</Switch>
|
||||
)
|
||||
/>
|
||||
))
|
||||
}
|
||||
</Page>
|
||||
</ConfigContext.Provider>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
325
src/index.jsx
325
src/index.jsx
@ -1,7 +1,9 @@
|
||||
import React from 'react';
|
||||
import { render } from 'react-dom';
|
||||
import {
|
||||
HashRouter as Router,
|
||||
HashRouter,
|
||||
Redirect,
|
||||
Route,
|
||||
Switch,
|
||||
} from 'react-router-dom';
|
||||
import {
|
||||
@ -59,8 +61,23 @@ export async function main () {
|
||||
const { data } = await api.getRoot();
|
||||
const { custom_logo, custom_login_info } = data;
|
||||
|
||||
const loginRoutes = (
|
||||
<Switch>
|
||||
<Route
|
||||
path="/login"
|
||||
render={() => (
|
||||
<Login
|
||||
logo={custom_logo}
|
||||
loginInfo={custom_login_info}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
<Redirect to="/login" />
|
||||
</Switch>
|
||||
);
|
||||
|
||||
render(
|
||||
<Router>
|
||||
<HashRouter>
|
||||
<I18nProvider
|
||||
language={languageWithoutRegionCode}
|
||||
catalogs={catalogs}
|
||||
@ -68,158 +85,166 @@ export async function main () {
|
||||
<I18n>
|
||||
{({ i18n }) => (
|
||||
<Background>
|
||||
<App
|
||||
logo={custom_logo}
|
||||
loginInfo={custom_login_info}
|
||||
navLabel={i18n._(t`Primary Navigation`)}
|
||||
routeGroups={[
|
||||
{
|
||||
title: i18n._(t`Views`),
|
||||
groupId: 'views_group',
|
||||
routes: [
|
||||
{
|
||||
title: i18n._(t`Dashboard`),
|
||||
path: '/home',
|
||||
component: Dashboard
|
||||
},
|
||||
{
|
||||
title: i18n._(t`Jobs`),
|
||||
path: '/jobs',
|
||||
component: Jobs
|
||||
},
|
||||
{
|
||||
title: i18n._(t`Schedules`),
|
||||
path: '/schedules',
|
||||
component: Schedules
|
||||
},
|
||||
{
|
||||
title: i18n._(t`Portal Mode`),
|
||||
path: '/portal',
|
||||
component: Portal
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: i18n._(t`Resources`),
|
||||
groupId: 'resources_group',
|
||||
routes: [
|
||||
{
|
||||
title: i18n._(t`Templates`),
|
||||
path: '/templates',
|
||||
component: Templates
|
||||
},
|
||||
{
|
||||
title: i18n._(t`Credentials`),
|
||||
path: '/credentials',
|
||||
component: Credentials
|
||||
},
|
||||
{
|
||||
title: i18n._(t`Projects`),
|
||||
path: '/projects',
|
||||
component: Projects
|
||||
},
|
||||
{
|
||||
title: i18n._(t`Inventories`),
|
||||
path: '/inventories',
|
||||
component: Inventories
|
||||
},
|
||||
{
|
||||
title: i18n._(t`Inventory Scripts`),
|
||||
path: '/inventory_scripts',
|
||||
component: InventoryScripts
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: i18n._(t`Access`),
|
||||
groupId: 'access_group',
|
||||
routes: [
|
||||
{
|
||||
title: i18n._(t`Organizations`),
|
||||
path: '/organizations',
|
||||
component: Organizations
|
||||
},
|
||||
{
|
||||
title: i18n._(t`Users`),
|
||||
path: '/users',
|
||||
component: Users
|
||||
},
|
||||
{
|
||||
title: i18n._(t`Teams`),
|
||||
path: '/teams',
|
||||
component: Teams
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: i18n._(t`Administration`),
|
||||
groupId: 'administration_group',
|
||||
routes: [
|
||||
{
|
||||
title: i18n._(t`Credential Types`),
|
||||
path: '/credential_types',
|
||||
component: CredentialTypes
|
||||
},
|
||||
{
|
||||
title: i18n._(t`Notifications`),
|
||||
path: '/notification_templates',
|
||||
component: NotificationTemplates
|
||||
},
|
||||
{
|
||||
title: i18n._(t`Management Jobs`),
|
||||
path: '/management_jobs',
|
||||
component: ManagementJobs
|
||||
},
|
||||
{
|
||||
title: i18n._(t`Instance Groups`),
|
||||
path: '/instance_groups',
|
||||
component: InstanceGroups
|
||||
},
|
||||
{
|
||||
title: i18n._(t`Integrations`),
|
||||
path: '/applications',
|
||||
component: Applications
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: i18n._(t`Settings`),
|
||||
groupId: 'settings_group',
|
||||
routes: [
|
||||
{
|
||||
title: i18n._(t`Authentication`),
|
||||
path: '/auth_settings',
|
||||
component: AuthSettings
|
||||
},
|
||||
{
|
||||
title: i18n._(t`Jobs`),
|
||||
path: '/jobs_settings',
|
||||
component: JobsSettings
|
||||
},
|
||||
{
|
||||
title: i18n._(t`System`),
|
||||
path: '/system_settings',
|
||||
component: SystemSettings
|
||||
},
|
||||
{
|
||||
title: i18n._(t`User Interface`),
|
||||
path: '/ui_settings',
|
||||
component: UISettings
|
||||
},
|
||||
{
|
||||
title: i18n._(t`License`),
|
||||
path: '/license',
|
||||
component: License
|
||||
},
|
||||
],
|
||||
},
|
||||
]}
|
||||
/>
|
||||
{!api.isAuthenticated() ? loginRoutes : (
|
||||
<Switch>
|
||||
<Route path="/login" render={() => <Redirect to="/home" />} />
|
||||
<Route exact path="/" render={() => <Redirect to="/home" />} />
|
||||
<Route
|
||||
render={() => (
|
||||
<App
|
||||
navLabel={i18n._(t`Primary Navigation`)}
|
||||
routeGroups={[
|
||||
{
|
||||
title: i18n._(t`Views`),
|
||||
groupId: 'views_group',
|
||||
routes: [
|
||||
{
|
||||
title: i18n._(t`Dashboard`),
|
||||
path: '/home',
|
||||
component: Dashboard
|
||||
},
|
||||
{
|
||||
title: i18n._(t`Jobs`),
|
||||
path: '/jobs',
|
||||
component: Jobs
|
||||
},
|
||||
{
|
||||
title: i18n._(t`Schedules`),
|
||||
path: '/schedules',
|
||||
component: Schedules
|
||||
},
|
||||
{
|
||||
title: i18n._(t`Portal Mode`),
|
||||
path: '/portal',
|
||||
component: Portal
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: i18n._(t`Resources`),
|
||||
groupId: 'resources_group',
|
||||
routes: [
|
||||
{
|
||||
title: i18n._(t`Templates`),
|
||||
path: '/templates',
|
||||
component: Templates
|
||||
},
|
||||
{
|
||||
title: i18n._(t`Credentials`),
|
||||
path: '/credentials',
|
||||
component: Credentials
|
||||
},
|
||||
{
|
||||
title: i18n._(t`Projects`),
|
||||
path: '/projects',
|
||||
component: Projects
|
||||
},
|
||||
{
|
||||
title: i18n._(t`Inventories`),
|
||||
path: '/inventories',
|
||||
component: Inventories
|
||||
},
|
||||
{
|
||||
title: i18n._(t`Inventory Scripts`),
|
||||
path: '/inventory_scripts',
|
||||
component: InventoryScripts
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: i18n._(t`Access`),
|
||||
groupId: 'access_group',
|
||||
routes: [
|
||||
{
|
||||
title: i18n._(t`Organizations`),
|
||||
path: '/organizations',
|
||||
component: Organizations
|
||||
},
|
||||
{
|
||||
title: i18n._(t`Users`),
|
||||
path: '/users',
|
||||
component: Users
|
||||
},
|
||||
{
|
||||
title: i18n._(t`Teams`),
|
||||
path: '/teams',
|
||||
component: Teams
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: i18n._(t`Administration`),
|
||||
groupId: 'administration_group',
|
||||
routes: [
|
||||
{
|
||||
title: i18n._(t`Credential Types`),
|
||||
path: '/credential_types',
|
||||
component: CredentialTypes
|
||||
},
|
||||
{
|
||||
title: i18n._(t`Notifications`),
|
||||
path: '/notification_templates',
|
||||
component: NotificationTemplates
|
||||
},
|
||||
{
|
||||
title: i18n._(t`Management Jobs`),
|
||||
path: '/management_jobs',
|
||||
component: ManagementJobs
|
||||
},
|
||||
{
|
||||
title: i18n._(t`Instance Groups`),
|
||||
path: '/instance_groups',
|
||||
component: InstanceGroups
|
||||
},
|
||||
{
|
||||
title: i18n._(t`Integrations`),
|
||||
path: '/applications',
|
||||
component: Applications
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: i18n._(t`Settings`),
|
||||
groupId: 'settings_group',
|
||||
routes: [
|
||||
{
|
||||
title: i18n._(t`Authentication`),
|
||||
path: '/auth_settings',
|
||||
component: AuthSettings
|
||||
},
|
||||
{
|
||||
title: i18n._(t`Jobs`),
|
||||
path: '/jobs_settings',
|
||||
component: JobsSettings
|
||||
},
|
||||
{
|
||||
title: i18n._(t`System`),
|
||||
path: '/system_settings',
|
||||
component: SystemSettings
|
||||
},
|
||||
{
|
||||
title: i18n._(t`User Interface`),
|
||||
path: '/ui_settings',
|
||||
component: UISettings
|
||||
},
|
||||
{
|
||||
title: i18n._(t`License`),
|
||||
path: '/license',
|
||||
component: License
|
||||
},
|
||||
],
|
||||
},
|
||||
]}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</Switch>
|
||||
)}
|
||||
</Background>
|
||||
)}
|
||||
</I18n>
|
||||
</I18nProvider>
|
||||
</Router>, el);
|
||||
</HashRouter>, el);
|
||||
};
|
||||
|
||||
export default main();
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user