diff --git a/awx/ui_next/src/screens/Team/Team.jsx b/awx/ui_next/src/screens/Team/Team.jsx
index aa726bef18..d0a385017e 100644
--- a/awx/ui_next/src/screens/Team/Team.jsx
+++ b/awx/ui_next/src/screens/Team/Team.jsx
@@ -1,7 +1,14 @@
-import React, { Component } from 'react';
+import React, { useState, useEffect } from 'react';
import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
-import { Switch, Route, withRouter, Redirect, Link } from 'react-router-dom';
+import {
+ Link,
+ Redirect,
+ Route,
+ Switch,
+ useLocation,
+ useParams,
+} from 'react-router-dom';
import { Card, PageSection } from '@patternfly/react-core';
import CardCloseButton from '@components/CardCloseButton';
import { TabbedCardHeader } from '@components/Card';
@@ -11,148 +18,110 @@ import TeamDetail from './TeamDetail';
import TeamEdit from './TeamEdit';
import { TeamsAPI } from '@api';
-class Team extends Component {
- constructor(props) {
- super(props);
+function Team({ i18n, setBreadcrumb }) {
+ const [team, setTeam] = useState(null);
+ const [contentError, setContentError] = useState(null);
+ const [hasContentLoading, setHasContentLoading] = useState(true);
+ const location = useLocation();
+ const { id } = useParams();
- this.state = {
- team: null,
- hasContentLoading: true,
- contentError: null,
- isInitialized: false,
- };
- this.loadTeam = this.loadTeam.bind(this);
+ useEffect(() => {
+ (async () => {
+ try {
+ const { data } = await TeamsAPI.readDetail(id);
+ setBreadcrumb(data);
+ setTeam(data);
+ } catch (error) {
+ setContentError(error);
+ } finally {
+ setHasContentLoading(false);
+ }
+ })();
+ }, [id, setBreadcrumb]);
+
+ const tabsArray = [
+ { name: i18n._(t`Details`), link: `/teams/${id}/details`, id: 0 },
+ { name: i18n._(t`Users`), link: `/teams/${id}/users`, id: 1 },
+ { name: i18n._(t`Access`), link: `/teams/${id}/access`, id: 2 },
+ ];
+
+ let cardHeader = (
+
+
+
+
+ );
+
+ if (location.pathname.endsWith('edit')) {
+ cardHeader = null;
}
- async componentDidMount() {
- await this.loadTeam();
- this.setState({ isInitialized: true });
- }
-
- async componentDidUpdate(prevProps) {
- const { location, match } = this.props;
- const url = `/teams/${match.params.id}/`;
-
- if (
- prevProps.location.pathname.startsWith(url) &&
- prevProps.location !== location &&
- location.pathname === `${url}details`
- ) {
- await this.loadTeam();
- }
- }
-
- async loadTeam() {
- const { match, setBreadcrumb } = this.props;
- const id = parseInt(match.params.id, 10);
-
- this.setState({ contentError: null, hasContentLoading: true });
- try {
- const { data } = await TeamsAPI.readDetail(id);
- setBreadcrumb(data);
- this.setState({ team: data });
- } catch (err) {
- this.setState({ contentError: err });
- } finally {
- this.setState({ hasContentLoading: false });
- }
- }
-
- render() {
- const { location, match, i18n } = this.props;
-
- const { team, contentError, hasContentLoading, isInitialized } = this.state;
-
- const tabsArray = [
- { name: i18n._(t`Details`), link: `${match.url}/details`, id: 0 },
- { name: i18n._(t`Users`), link: `${match.url}/users`, id: 1 },
- { name: i18n._(t`Access`), link: `${match.url}/access`, id: 2 },
- ];
-
- let cardHeader = (
-
-
-
-
- );
-
- if (!isInitialized) {
- cardHeader = null;
- }
-
- if (location.pathname.endsWith('edit')) {
- cardHeader = null;
- }
-
- if (!hasContentLoading && contentError) {
- return (
-
-
-
- {contentError.response.status === 404 && (
-
- {i18n._(`Team not found.`)}{' '}
- {i18n._(`View all Teams.`)}
-
- )}
-
-
-
- );
- }
-
+ if (!hasContentLoading && contentError) {
return (
- {cardHeader}
-
-
- {team && (
- }
- />
+
+ {contentError.response.status === 404 && (
+
+ {i18n._(`Team not found.`)}{' '}
+ {i18n._(`View all Teams.`)}
+
)}
- {team && (
- }
- />
- )}
- {team && (
- Coming soon :)}
- />
- )}
- {team && (
- Coming soon :)}
- />
- )}
-
- !hasContentLoading && (
-
- {match.params.id && (
-
- {i18n._(`View Team Details`)}
-
- )}
-
- )
- }
- />
- ,
-
+
);
}
+
+ return (
+
+
+ {cardHeader}
+
+
+ {team && (
+
+
+
+ )}
+ {team && (
+ }
+ />
+ )}
+ {team && (
+ Coming soon :)}
+ />
+ )}
+ {team && (
+ Coming soon :)}
+ />
+ )}
+
+ !hasContentLoading && (
+
+ {id && (
+
+ {i18n._(`View Team Details`)}
+
+ )}
+
+ )
+ }
+ />
+
+
+
+ );
}
-export default withI18n()(withRouter(Team));
+export default withI18n()(Team);
export { Team as _Team };
diff --git a/awx/ui_next/src/screens/Team/Team.test.jsx b/awx/ui_next/src/screens/Team/Team.test.jsx
index f6b8ac5b04..946b7e77f5 100644
--- a/awx/ui_next/src/screens/Team/Team.test.jsx
+++ b/awx/ui_next/src/screens/Team/Team.test.jsx
@@ -1,4 +1,5 @@
import React from 'react';
+import { act } from 'react-dom/test-utils';
import { createMemoryHistory } from 'history';
import { TeamsAPI } from '@api';
import { mountWithContexts, waitForElement } from '@testUtils/enzymeHelpers';
@@ -34,34 +35,46 @@ async function getTeams() {
}
describe('', () => {
- test('initially renders succesfully', () => {
+ let wrapper;
+
+ beforeEach(() => {
TeamsAPI.readDetail.mockResolvedValue({ data: mockTeam });
TeamsAPI.read.mockImplementation(getTeams);
- mountWithContexts( {}} me={mockMe} />);
+ });
+
+ test('initially renders succesfully', async () => {
+ await act(async () => {
+ wrapper = mountWithContexts(
+ {}} me={mockMe} />
+ );
+ });
+ expect(wrapper.find('Team').length).toBe(1);
});
test('should show content error when user attempts to navigate to erroneous route', async () => {
const history = createMemoryHistory({
initialEntries: ['/teams/1/foobar'],
});
- const wrapper = mountWithContexts(
- {}} me={mockMe} />,
- {
- context: {
- router: {
- history,
- route: {
- location: history.location,
- match: {
- params: { id: 1 },
- url: '/teams/1/foobar',
- path: '/teams/1/foobar',
+ await act(async () => {
+ wrapper = mountWithContexts(
+ {}} me={mockMe} />,
+ {
+ context: {
+ router: {
+ history,
+ route: {
+ location: history.location,
+ match: {
+ params: { id: 1 },
+ url: '/teams/1/foobar',
+ path: '/teams/1/foobar',
+ },
},
},
},
- },
- }
- );
+ }
+ );
+ });
await waitForElement(wrapper, 'ContentError', el => el.length === 1);
});
});
diff --git a/awx/ui_next/src/screens/Team/TeamList/index.js b/awx/ui_next/src/screens/Team/TeamList/index.js
index 7f52a34617..83c3d034bd 100644
--- a/awx/ui_next/src/screens/Team/TeamList/index.js
+++ b/awx/ui_next/src/screens/Team/TeamList/index.js
@@ -1,2 +1,2 @@
-export { default as TeamList } from './TeamList';
+export { default } from './TeamList';
export { default as TeamListItem } from './TeamListItem';
diff --git a/awx/ui_next/src/screens/Team/Teams.jsx b/awx/ui_next/src/screens/Team/Teams.jsx
index 8634a058ae..73368c85a2 100644
--- a/awx/ui_next/src/screens/Team/Teams.jsx
+++ b/awx/ui_next/src/screens/Team/Teams.jsx
@@ -1,79 +1,58 @@
-import React, { Component, Fragment } from 'react';
-import { Route, withRouter, Switch } from 'react-router-dom';
+import React, { useState, useCallback } from 'react';
+import { Route, Switch } from 'react-router-dom';
import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import { Config } from '@contexts/Config';
-import Breadcrumbs from '@components/Breadcrumbs/Breadcrumbs';
-
-import TeamsList from './TeamList/TeamList';
-import TeamAdd from './TeamAdd/TeamAdd';
+import Breadcrumbs from '@components/Breadcrumbs';
+import TeamList from './TeamList';
+import TeamAdd from './TeamAdd';
import Team from './Team';
-class Teams extends Component {
- constructor(props) {
- super(props);
+function Teams({ i18n }) {
+ const [breadcrumbConfig, setBreadcrumbConfig] = useState({
+ '/teams': i18n._(t`Teams`),
+ '/teams/add': i18n._(t`Create New Team`),
+ });
- const { i18n } = props;
+ const buildBreadcrumbConfig = useCallback(
+ team => {
+ if (!team) {
+ return;
+ }
- this.state = {
- breadcrumbConfig: {
+ setBreadcrumbConfig({
'/teams': i18n._(t`Teams`),
'/teams/add': i18n._(t`Create New Team`),
- },
- };
- }
+ [`/teams/${team.id}`]: `${team.name}`,
+ [`/teams/${team.id}/edit`]: i18n._(t`Edit Details`),
+ [`/teams/${team.id}/details`]: i18n._(t`Details`),
+ [`/teams/${team.id}/users`]: i18n._(t`Users`),
+ [`/teams/${team.id}/access`]: i18n._(t`Access`),
+ });
+ },
+ [i18n]
+ );
- setBreadcrumbConfig = team => {
- const { i18n } = this.props;
-
- if (!team) {
- return;
- }
-
- const breadcrumbConfig = {
- '/teams': i18n._(t`Teams`),
- '/teams/add': i18n._(t`Create New Team`),
- [`/teams/${team.id}`]: `${team.name}`,
- [`/teams/${team.id}/edit`]: i18n._(t`Edit Details`),
- [`/teams/${team.id}/details`]: i18n._(t`Details`),
- [`/teams/${team.id}/users`]: i18n._(t`Users`),
- [`/teams/${team.id}/access`]: i18n._(t`Access`),
- };
-
- this.setState({ breadcrumbConfig });
- };
-
- render() {
- const { match, history, location } = this.props;
- const { breadcrumbConfig } = this.state;
-
- return (
-
-
-
- } />
- (
-
- {({ me }) => (
-
- )}
-
- )}
- />
- } />
-
-
- );
- }
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+
+ {({ me }) => }
+
+
+
+ >
+ );
}
export { Teams as _Teams };
-export default withI18n()(withRouter(Teams));
+export default withI18n()(Teams);