mirror of
https://github.com/ansible/awx.git
synced 2026-03-24 12:25:01 -02:30
moves some files to hooks in preparation for lingUI upgrade
This commit is contained in:
committed by
Jake McDermott
parent
33c3a6d89b
commit
d82f68c88e
@@ -12,8 +12,8 @@ import {
|
|||||||
import { BrandName } from '../../variables';
|
import { BrandName } from '../../variables';
|
||||||
import brandLogoImg from './brand-logo.svg';
|
import brandLogoImg from './brand-logo.svg';
|
||||||
|
|
||||||
class About extends React.Component {
|
function About({ ansible_version, version, isOpen, onClose, i18n }) {
|
||||||
static createSpeechBubble(version) {
|
const createSpeechBubble = () => {
|
||||||
let text = `${BrandName} ${version}`;
|
let text = `${BrandName} ${version}`;
|
||||||
let top = '';
|
let top = '';
|
||||||
let bottom = '';
|
let bottom = '';
|
||||||
@@ -28,31 +28,22 @@ class About extends React.Component {
|
|||||||
bottom = ` --${bottom}-- `;
|
bottom = ` --${bottom}-- `;
|
||||||
|
|
||||||
return top + text + bottom;
|
return top + text + bottom;
|
||||||
}
|
};
|
||||||
|
|
||||||
constructor(props) {
|
const speechBubble = createSpeechBubble();
|
||||||
super(props);
|
|
||||||
|
|
||||||
this.createSpeechBubble = this.constructor.createSpeechBubble.bind(this);
|
return (
|
||||||
}
|
<AboutModal
|
||||||
|
isOpen={isOpen}
|
||||||
render() {
|
onClose={onClose}
|
||||||
const { ansible_version, version, isOpen, onClose, i18n } = this.props;
|
productName={`Ansible ${BrandName}`}
|
||||||
|
trademark={i18n._(t`Copyright 2019 Red Hat, Inc.`)}
|
||||||
const speechBubble = this.createSpeechBubble(version);
|
brandImageSrc={brandLogoImg}
|
||||||
|
brandImageAlt={i18n._(t`Brand Image`)}
|
||||||
return (
|
>
|
||||||
<AboutModal
|
<pre>
|
||||||
isOpen={isOpen}
|
{speechBubble}
|
||||||
onClose={onClose}
|
{`
|
||||||
productName={`Ansible ${BrandName}`}
|
|
||||||
trademark={i18n._(t`Copyright 2019 Red Hat, Inc.`)}
|
|
||||||
brandImageSrc={brandLogoImg}
|
|
||||||
brandImageAlt={i18n._(t`Brand Image`)}
|
|
||||||
>
|
|
||||||
<pre>
|
|
||||||
{speechBubble}
|
|
||||||
{`
|
|
||||||
\\
|
\\
|
||||||
\\ ^__^
|
\\ ^__^
|
||||||
(oo)\\_______
|
(oo)\\_______
|
||||||
@@ -60,18 +51,17 @@ class About extends React.Component {
|
|||||||
||----w |
|
||----w |
|
||||||
|| ||
|
|| ||
|
||||||
`}
|
`}
|
||||||
</pre>
|
</pre>
|
||||||
<TextContent>
|
<TextContent>
|
||||||
<TextList component="dl">
|
<TextList component="dl">
|
||||||
<TextListItem component="dt">
|
<TextListItem component="dt">
|
||||||
{i18n._(t`Ansible Version`)}
|
{i18n._(t`Ansible Version`)}
|
||||||
</TextListItem>
|
</TextListItem>
|
||||||
<TextListItem component="dd">{ansible_version}</TextListItem>
|
<TextListItem component="dd">{ansible_version}</TextListItem>
|
||||||
</TextList>
|
</TextList>
|
||||||
</TextContent>
|
</TextContent>
|
||||||
</AboutModal>
|
</AboutModal>
|
||||||
);
|
);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
About.propTypes = {
|
About.propTypes = {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { Component } from 'react';
|
import React, { useState } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { withI18n } from '@lingui/react';
|
import { withI18n } from '@lingui/react';
|
||||||
import { t } from '@lingui/macro';
|
import { t } from '@lingui/macro';
|
||||||
@@ -17,129 +17,100 @@ import { QuestionCircleIcon, UserIcon } from '@patternfly/react-icons';
|
|||||||
const DOCLINK =
|
const DOCLINK =
|
||||||
'https://docs.ansible.com/ansible-tower/latest/html/userguide/index.html';
|
'https://docs.ansible.com/ansible-tower/latest/html/userguide/index.html';
|
||||||
|
|
||||||
class PageHeaderToolbar extends Component {
|
function PageHeaderToolbar({
|
||||||
constructor(props) {
|
isAboutDisabled,
|
||||||
super(props);
|
onAboutClick,
|
||||||
this.state = {
|
onLogoutClick,
|
||||||
isHelpOpen: false,
|
loggedInUser,
|
||||||
isUserOpen: false,
|
i18n,
|
||||||
};
|
}) {
|
||||||
|
const [isHelpOpen, setIsHelpOpen] = useState(false);
|
||||||
|
const [isUserOpen, setIsUserOpen] = useState(false);
|
||||||
|
|
||||||
this.handleHelpSelect = this.handleHelpSelect.bind(this);
|
const handleHelpSelect = () => {
|
||||||
this.handleHelpToggle = this.handleHelpToggle.bind(this);
|
setIsHelpOpen(!isHelpOpen);
|
||||||
this.handleUserSelect = this.handleUserSelect.bind(this);
|
};
|
||||||
this.handleUserToggle = this.handleUserToggle.bind(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
handleHelpSelect() {
|
const handleUserSelect = () => {
|
||||||
const { isHelpOpen } = this.state;
|
setIsUserOpen(!isUserOpen);
|
||||||
|
};
|
||||||
|
|
||||||
this.setState({ isHelpOpen: !isHelpOpen });
|
return (
|
||||||
}
|
<PageHeaderTools>
|
||||||
|
<PageHeaderToolsGroup>
|
||||||
handleUserSelect() {
|
<Tooltip position="left" content={<div>{i18n._(t`Info`)}</div>}>
|
||||||
const { isUserOpen } = this.state;
|
<PageHeaderToolsItem>
|
||||||
|
<Dropdown
|
||||||
this.setState({ isUserOpen: !isUserOpen });
|
isPlain
|
||||||
}
|
isOpen={isHelpOpen}
|
||||||
|
position={DropdownPosition.right}
|
||||||
handleHelpToggle(isOpen) {
|
onSelect={handleHelpSelect}
|
||||||
this.setState({ isHelpOpen: isOpen });
|
toggle={
|
||||||
}
|
<DropdownToggle
|
||||||
|
onToggle={setIsHelpOpen}
|
||||||
handleUserToggle(isOpen) {
|
aria-label={i18n._(t`Info`)}
|
||||||
this.setState({ isUserOpen: isOpen });
|
>
|
||||||
}
|
<QuestionCircleIcon />
|
||||||
|
</DropdownToggle>
|
||||||
render() {
|
}
|
||||||
const { isHelpOpen, isUserOpen } = this.state;
|
dropdownItems={[
|
||||||
const {
|
<DropdownItem key="help" target="_blank" href={DOCLINK}>
|
||||||
isAboutDisabled,
|
{i18n._(t`Help`)}
|
||||||
onAboutClick,
|
</DropdownItem>,
|
||||||
onLogoutClick,
|
<DropdownItem
|
||||||
loggedInUser,
|
key="about"
|
||||||
i18n,
|
component="button"
|
||||||
} = this.props;
|
isDisabled={isAboutDisabled}
|
||||||
|
onClick={onAboutClick}
|
||||||
return (
|
>
|
||||||
<PageHeaderTools>
|
{i18n._(t`About`)}
|
||||||
<PageHeaderToolsGroup>
|
</DropdownItem>,
|
||||||
<Tooltip position="left" content={<div>{i18n._(t`Info`)}</div>}>
|
]}
|
||||||
<PageHeaderToolsItem>
|
/>
|
||||||
<Dropdown
|
</PageHeaderToolsItem>
|
||||||
isPlain
|
</Tooltip>
|
||||||
isOpen={isHelpOpen}
|
<Tooltip position="left" content={<div>{i18n._(t`User`)}</div>}>
|
||||||
position={DropdownPosition.right}
|
<PageHeaderToolsItem>
|
||||||
onSelect={this.handleHelpSelect}
|
<Dropdown
|
||||||
toggle={
|
id="toolbar-user-dropdown"
|
||||||
<DropdownToggle
|
isPlain
|
||||||
onToggle={this.handleHelpToggle}
|
isOpen={isUserOpen}
|
||||||
aria-label={i18n._(t`Info`)}
|
position={DropdownPosition.right}
|
||||||
>
|
onSelect={handleUserSelect}
|
||||||
<QuestionCircleIcon />
|
toggle={
|
||||||
</DropdownToggle>
|
<DropdownToggle onToggle={setIsUserOpen}>
|
||||||
}
|
<UserIcon />
|
||||||
dropdownItems={[
|
{loggedInUser && (
|
||||||
<DropdownItem key="help" target="_blank" href={DOCLINK}>
|
<span style={{ marginLeft: '10px' }}>
|
||||||
{i18n._(t`Help`)}
|
{loggedInUser.username}
|
||||||
</DropdownItem>,
|
</span>
|
||||||
<DropdownItem
|
)}
|
||||||
key="about"
|
</DropdownToggle>
|
||||||
component="button"
|
}
|
||||||
isDisabled={isAboutDisabled}
|
dropdownItems={[
|
||||||
onClick={onAboutClick}
|
<DropdownItem
|
||||||
>
|
key="user"
|
||||||
{i18n._(t`About`)}
|
href={
|
||||||
</DropdownItem>,
|
loggedInUser ? `/users/${loggedInUser.id}/details` : '/home'
|
||||||
]}
|
}
|
||||||
/>
|
>
|
||||||
</PageHeaderToolsItem>
|
{i18n._(t`User Details`)}
|
||||||
</Tooltip>
|
</DropdownItem>,
|
||||||
<Tooltip position="left" content={<div>{i18n._(t`User`)}</div>}>
|
<DropdownItem
|
||||||
<PageHeaderToolsItem>
|
key="logout"
|
||||||
<Dropdown
|
component="button"
|
||||||
id="toolbar-user-dropdown"
|
onClick={onLogoutClick}
|
||||||
isPlain
|
id="logout-button"
|
||||||
isOpen={isUserOpen}
|
>
|
||||||
position={DropdownPosition.right}
|
{i18n._(t`Logout`)}
|
||||||
onSelect={this.handleUserSelect}
|
</DropdownItem>,
|
||||||
toggle={
|
]}
|
||||||
<DropdownToggle onToggle={this.handleUserToggle}>
|
/>
|
||||||
<UserIcon />
|
</PageHeaderToolsItem>
|
||||||
{loggedInUser && (
|
</Tooltip>
|
||||||
<span style={{ marginLeft: '10px' }}>
|
</PageHeaderToolsGroup>
|
||||||
{loggedInUser.username}
|
</PageHeaderTools>
|
||||||
</span>
|
);
|
||||||
)}
|
|
||||||
</DropdownToggle>
|
|
||||||
}
|
|
||||||
dropdownItems={[
|
|
||||||
<DropdownItem
|
|
||||||
key="user"
|
|
||||||
href={
|
|
||||||
loggedInUser
|
|
||||||
? `/users/${loggedInUser.id}/details`
|
|
||||||
: '/home'
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{i18n._(t`User Details`)}
|
|
||||||
</DropdownItem>,
|
|
||||||
<DropdownItem
|
|
||||||
key="logout"
|
|
||||||
component="button"
|
|
||||||
onClick={onLogoutClick}
|
|
||||||
id="logout-button"
|
|
||||||
>
|
|
||||||
{i18n._(t`Logout`)}
|
|
||||||
</DropdownItem>,
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
</PageHeaderToolsItem>
|
|
||||||
</Tooltip>
|
|
||||||
</PageHeaderToolsGroup>
|
|
||||||
</PageHeaderTools>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PageHeaderToolbar.propTypes = {
|
PageHeaderToolbar.propTypes = {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { Component, Fragment } from 'react';
|
import React, { useState, Fragment } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
import { withI18n } from '@lingui/react';
|
import { withI18n } from '@lingui/react';
|
||||||
@@ -32,27 +32,15 @@ const Expandable = styled(PFExpandable)`
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
class ErrorDetail extends Component {
|
function ErrorDetail({ error, i18n }) {
|
||||||
constructor(props) {
|
const { response } = error;
|
||||||
super(props);
|
const [isExpanded, setIsExpanded] = useState(false);
|
||||||
|
|
||||||
this.state = {
|
const handleToggle = () => {
|
||||||
isExpanded: false,
|
setIsExpanded(!isExpanded);
|
||||||
};
|
};
|
||||||
|
|
||||||
this.handleToggle = this.handleToggle.bind(this);
|
const renderNetworkError = () => {
|
||||||
this.renderNetworkError = this.renderNetworkError.bind(this);
|
|
||||||
this.renderStack = this.renderStack.bind(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
handleToggle() {
|
|
||||||
const { isExpanded } = this.state;
|
|
||||||
this.setState({ isExpanded: !isExpanded });
|
|
||||||
}
|
|
||||||
|
|
||||||
renderNetworkError() {
|
|
||||||
const { error } = this.props;
|
|
||||||
const { response } = error;
|
|
||||||
const message = getErrorMessage(response);
|
const message = getErrorMessage(response);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -74,31 +62,25 @@ class ErrorDetail extends Component {
|
|||||||
</CardBody>
|
</CardBody>
|
||||||
</Fragment>
|
</Fragment>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
renderStack() {
|
const renderStack = () => {
|
||||||
const { error } = this.props;
|
|
||||||
return <CardBody>{error.stack}</CardBody>;
|
return <CardBody>{error.stack}</CardBody>;
|
||||||
}
|
};
|
||||||
|
|
||||||
render() {
|
return (
|
||||||
const { isExpanded } = this.state;
|
<Expandable
|
||||||
const { error, i18n } = this.props;
|
toggleText={i18n._(t`Details`)}
|
||||||
|
onToggle={handleToggle}
|
||||||
return (
|
isExpanded={isExpanded}
|
||||||
<Expandable
|
>
|
||||||
toggleText={i18n._(t`Details`)}
|
<Card>
|
||||||
onToggle={this.handleToggle}
|
{Object.prototype.hasOwnProperty.call(error, 'response')
|
||||||
isExpanded={isExpanded}
|
? renderNetworkError()
|
||||||
>
|
: renderStack()}
|
||||||
<Card>
|
</Card>
|
||||||
{Object.prototype.hasOwnProperty.call(error, 'response')
|
</Expandable>
|
||||||
? this.renderNetworkError()
|
);
|
||||||
: this.renderStack()}
|
|
||||||
</Card>
|
|
||||||
</Expandable>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorDetail.propTypes = {
|
ErrorDetail.propTypes = {
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { act } from 'react-dom/test-utils';
|
||||||
import { mountWithContexts } from '../../../testUtils/enzymeHelpers';
|
import { mountWithContexts } from '../../../testUtils/enzymeHelpers';
|
||||||
|
|
||||||
import ErrorDetail from './ErrorDetail';
|
import ErrorDetail from './ErrorDetail';
|
||||||
@@ -39,7 +40,7 @@ describe('ErrorDetail', () => {
|
|||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
wrapper.find('ExpandableSection').prop('onToggle')();
|
act(() => wrapper.find('ExpandableSection').prop('onToggle')());
|
||||||
wrapper.update();
|
wrapper.update();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,80 +1,56 @@
|
|||||||
import React, { Component } from 'react';
|
import React, { useCallback, useEffect } from 'react';
|
||||||
import { Redirect, Link } from 'react-router-dom';
|
import { Redirect, Link } from 'react-router-dom';
|
||||||
import { PageSection, Card } from '@patternfly/react-core';
|
import { PageSection, Card } from '@patternfly/react-core';
|
||||||
import { withI18n } from '@lingui/react';
|
import { withI18n } from '@lingui/react';
|
||||||
import { t } from '@lingui/macro';
|
import { t } from '@lingui/macro';
|
||||||
|
import useRequest from '../../util/useRequest';
|
||||||
import { UnifiedJobsAPI } from '../../api';
|
import { UnifiedJobsAPI } from '../../api';
|
||||||
import ContentError from '../../components/ContentError';
|
import ContentError from '../../components/ContentError';
|
||||||
import { JOB_TYPE_URL_SEGMENTS } from '../../constants';
|
import { JOB_TYPE_URL_SEGMENTS } from '../../constants';
|
||||||
|
|
||||||
const NOT_FOUND = 'not found';
|
const NOT_FOUND = 'not found';
|
||||||
|
|
||||||
class JobTypeRedirect extends Component {
|
function JobTypeRedirect({ id, path, view, i18n }) {
|
||||||
static defaultProps = {
|
const {
|
||||||
view: 'output',
|
isLoading,
|
||||||
};
|
error,
|
||||||
|
result: { job },
|
||||||
constructor(props) {
|
request: loadJob,
|
||||||
super(props);
|
} = useRequest(
|
||||||
|
useCallback(async () => {
|
||||||
this.state = {
|
|
||||||
error: null,
|
|
||||||
job: null,
|
|
||||||
isLoading: true,
|
|
||||||
};
|
|
||||||
this.loadJob = this.loadJob.bind(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
this.loadJob();
|
|
||||||
}
|
|
||||||
|
|
||||||
async loadJob() {
|
|
||||||
const { id } = this.props;
|
|
||||||
this.setState({ isLoading: true });
|
|
||||||
try {
|
|
||||||
const { data } = await UnifiedJobsAPI.read({ id });
|
const { data } = await UnifiedJobsAPI.read({ id });
|
||||||
const job = data.results[0];
|
return { job: data };
|
||||||
this.setState({
|
}, [id]),
|
||||||
job,
|
{ job: {} }
|
||||||
isLoading: false,
|
);
|
||||||
error: job ? null : NOT_FOUND,
|
useEffect(() => {
|
||||||
});
|
loadJob();
|
||||||
} catch (error) {
|
}, [loadJob]);
|
||||||
this.setState({
|
|
||||||
error,
|
|
||||||
isLoading: false,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
if (error) {
|
||||||
const { path, view, i18n } = this.props;
|
return (
|
||||||
const { error, job, isLoading } = this.state;
|
<PageSection>
|
||||||
|
<Card>
|
||||||
if (error) {
|
{error === NOT_FOUND ? (
|
||||||
return (
|
<ContentError isNotFound>
|
||||||
<PageSection>
|
<Link to="/jobs">{i18n._(t`View all Jobs`)}</Link>
|
||||||
<Card>
|
</ContentError>
|
||||||
{error === NOT_FOUND ? (
|
) : (
|
||||||
<ContentError isNotFound>
|
<ContentError error={error} />
|
||||||
<Link to="/jobs">{i18n._(t`View all Jobs`)}</Link>
|
)}
|
||||||
</ContentError>
|
</Card>
|
||||||
) : (
|
</PageSection>
|
||||||
<ContentError error={error} />
|
);
|
||||||
)}
|
|
||||||
</Card>
|
|
||||||
</PageSection>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (isLoading) {
|
|
||||||
// TODO show loading state
|
|
||||||
return <div>Loading...</div>;
|
|
||||||
}
|
|
||||||
const type = JOB_TYPE_URL_SEGMENTS[job.type];
|
|
||||||
return <Redirect from={path} to={`/jobs/${type}/${job.id}/${view}`} />;
|
|
||||||
}
|
}
|
||||||
|
if (isLoading) {
|
||||||
|
// TODO show loading state
|
||||||
|
return <div>Loading...</div>;
|
||||||
|
}
|
||||||
|
const type = JOB_TYPE_URL_SEGMENTS[job.type];
|
||||||
|
return <Redirect from={path} to={`/jobs/${type}/${job.id}/${view}`} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JobTypeRedirect.defaultProps = {
|
||||||
|
view: 'output',
|
||||||
|
};
|
||||||
export default withI18n()(JobTypeRedirect);
|
export default withI18n()(JobTypeRedirect);
|
||||||
|
|||||||
@@ -1,21 +1,17 @@
|
|||||||
import React, { Component, Fragment } from 'react';
|
import React, { Fragment } from 'react';
|
||||||
import { withI18n } from '@lingui/react';
|
import { withI18n } from '@lingui/react';
|
||||||
import { t } from '@lingui/macro';
|
import { t } from '@lingui/macro';
|
||||||
|
|
||||||
import Breadcrumbs from '../../components/Breadcrumbs';
|
import Breadcrumbs from '../../components/Breadcrumbs';
|
||||||
|
|
||||||
class ManagementJobs extends Component {
|
function ManagementJobs({ i18n }) {
|
||||||
render() {
|
return (
|
||||||
const { i18n } = this.props;
|
<Fragment>
|
||||||
|
<Breadcrumbs
|
||||||
return (
|
breadcrumbConfig={{ '/management_jobs': i18n._(t`Management Jobs`) }}
|
||||||
<Fragment>
|
/>
|
||||||
<Breadcrumbs
|
</Fragment>
|
||||||
breadcrumbConfig={{ '/management_jobs': i18n._(t`Management Jobs`) }}
|
);
|
||||||
/>
|
|
||||||
</Fragment>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default withI18n()(ManagementJobs);
|
export default withI18n()(ManagementJobs);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React, { Component, Fragment } from 'react';
|
import React, { useState, Fragment } from 'react';
|
||||||
import { Route, withRouter, Switch } from 'react-router-dom';
|
import { Route, withRouter, Switch, useRouteMatch } from 'react-router-dom';
|
||||||
import { withI18n } from '@lingui/react';
|
import { withI18n } from '@lingui/react';
|
||||||
import { t } from '@lingui/macro';
|
import { t } from '@lingui/macro';
|
||||||
|
|
||||||
@@ -10,28 +10,19 @@ import OrganizationsList from './OrganizationList/OrganizationList';
|
|||||||
import OrganizationAdd from './OrganizationAdd/OrganizationAdd';
|
import OrganizationAdd from './OrganizationAdd/OrganizationAdd';
|
||||||
import Organization from './Organization';
|
import Organization from './Organization';
|
||||||
|
|
||||||
class Organizations extends Component {
|
function Organizations({ i18n }) {
|
||||||
constructor(props) {
|
const match = useRouteMatch();
|
||||||
super(props);
|
const [breadcrumbConfig, setBreadcrumbConfig] = useState({
|
||||||
|
'/organizations': i18n._(t`Organizations`),
|
||||||
const { i18n } = props;
|
'/organizations/add': i18n._(t`Create New Organization`),
|
||||||
|
});
|
||||||
this.state = {
|
|
||||||
breadcrumbConfig: {
|
|
||||||
'/organizations': i18n._(t`Organizations`),
|
|
||||||
'/organizations/add': i18n._(t`Create New Organization`),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
setBreadcrumbConfig = organization => {
|
|
||||||
const { i18n } = this.props;
|
|
||||||
|
|
||||||
|
const setBreadcrumb = organization => {
|
||||||
if (!organization) {
|
if (!organization) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const breadcrumbConfig = {
|
const breadcrumb = {
|
||||||
'/organizations': i18n._(t`Organizations`),
|
'/organizations': i18n._(t`Organizations`),
|
||||||
'/organizations/add': i18n._(t`Create New Organization`),
|
'/organizations/add': i18n._(t`Create New Organization`),
|
||||||
[`/organizations/${organization.id}`]: `${organization.name}`,
|
[`/organizations/${organization.id}`]: `${organization.name}`,
|
||||||
@@ -43,38 +34,29 @@ class Organizations extends Component {
|
|||||||
t`Notifications`
|
t`Notifications`
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
setBreadcrumbConfig(breadcrumb);
|
||||||
this.setState({ breadcrumbConfig });
|
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
return (
|
||||||
const { match } = this.props;
|
<Fragment>
|
||||||
const { breadcrumbConfig } = this.state;
|
<Breadcrumbs breadcrumbConfig={breadcrumbConfig} />
|
||||||
|
<Switch>
|
||||||
return (
|
<Route path={`${match.path}/add`}>
|
||||||
<Fragment>
|
<OrganizationAdd />
|
||||||
<Breadcrumbs breadcrumbConfig={breadcrumbConfig} />
|
</Route>
|
||||||
<Switch>
|
<Route path={`${match.path}/:id`}>
|
||||||
<Route path={`${match.path}/add`}>
|
<Config>
|
||||||
<OrganizationAdd />
|
{({ me }) => (
|
||||||
</Route>
|
<Organization setBreadcrumb={setBreadcrumb} me={me || {}} />
|
||||||
<Route path={`${match.path}/:id`}>
|
)}
|
||||||
<Config>
|
</Config>
|
||||||
{({ me }) => (
|
</Route>
|
||||||
<Organization
|
<Route path={`${match.path}`}>
|
||||||
setBreadcrumb={this.setBreadcrumbConfig}
|
<OrganizationsList />
|
||||||
me={me || {}}
|
</Route>
|
||||||
/>
|
</Switch>
|
||||||
)}
|
</Fragment>
|
||||||
</Config>
|
);
|
||||||
</Route>
|
|
||||||
<Route path={`${match.path}`}>
|
|
||||||
<OrganizationsList />
|
|
||||||
</Route>
|
|
||||||
</Switch>
|
|
||||||
</Fragment>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export { Organizations as _Organizations };
|
export { Organizations as _Organizations };
|
||||||
|
|||||||
@@ -11,6 +11,14 @@ import mockDetails from './data.project.json';
|
|||||||
import Project from './Project';
|
import Project from './Project';
|
||||||
|
|
||||||
jest.mock('../../api');
|
jest.mock('../../api');
|
||||||
|
jest.mock('react-router-dom', () => ({
|
||||||
|
...jest.requireActual('react-router-dom'),
|
||||||
|
useRouteMatch: () => ({
|
||||||
|
pathname: '/projects/1/details',
|
||||||
|
url: '/projects/1',
|
||||||
|
}),
|
||||||
|
useParams: () => ({ id: 1 }),
|
||||||
|
}));
|
||||||
|
|
||||||
const mockMe = {
|
const mockMe = {
|
||||||
is_super_user: true,
|
is_super_user: true,
|
||||||
@@ -50,7 +58,7 @@ describe('<Project />', () => {
|
|||||||
});
|
});
|
||||||
const tabs = await waitForElement(
|
const tabs = await waitForElement(
|
||||||
wrapper,
|
wrapper,
|
||||||
'.pf-c-tabs__item',
|
'.pf-c-tabs__item-text',
|
||||||
el => el.length === 6
|
el => el.length === 6
|
||||||
);
|
);
|
||||||
expect(tabs.at(3).text()).toEqual('Notifications');
|
expect(tabs.at(3).text()).toEqual('Notifications');
|
||||||
@@ -71,7 +79,7 @@ describe('<Project />', () => {
|
|||||||
});
|
});
|
||||||
const tabs = await waitForElement(
|
const tabs = await waitForElement(
|
||||||
wrapper,
|
wrapper,
|
||||||
'.pf-c-tabs__item',
|
'.pf-c-tabs__item-text',
|
||||||
el => el.length === 5
|
el => el.length === 5
|
||||||
);
|
);
|
||||||
tabs.forEach(tab => expect(tab.text()).not.toEqual('Notifications'));
|
tabs.forEach(tab => expect(tab.text()).not.toEqual('Notifications'));
|
||||||
@@ -91,7 +99,6 @@ describe('<Project />', () => {
|
|||||||
<Project setBreadcrumb={() => {}} me={mockMe} />
|
<Project setBreadcrumb={() => {}} me={mockMe} />
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
const tabs = await waitForElement(
|
const tabs = await waitForElement(
|
||||||
wrapper,
|
wrapper,
|
||||||
'.pf-c-tabs__item',
|
'.pf-c-tabs__item',
|
||||||
@@ -115,7 +122,6 @@ describe('<Project />', () => {
|
|||||||
<Project setBreadcrumb={() => {}} me={mockMe} />
|
<Project setBreadcrumb={() => {}} me={mockMe} />
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
const tabs = await waitForElement(
|
const tabs = await waitForElement(
|
||||||
wrapper,
|
wrapper,
|
||||||
'.pf-c-tabs__item',
|
'.pf-c-tabs__item',
|
||||||
|
|||||||
@@ -1,89 +1,21 @@
|
|||||||
/* eslint react/no-unused-state: 0 */
|
/* eslint react/no-unused-state: 0 */
|
||||||
import React, { Component } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { withRouter, Redirect } from 'react-router-dom';
|
import { withRouter, Redirect, useHistory } from 'react-router-dom';
|
||||||
|
|
||||||
import { CardBody } from '../../../components/Card';
|
import { CardBody } from '../../../components/Card';
|
||||||
import ContentError from '../../../components/ContentError';
|
|
||||||
import ContentLoading from '../../../components/ContentLoading';
|
|
||||||
import { JobTemplatesAPI } from '../../../api';
|
import { JobTemplatesAPI } from '../../../api';
|
||||||
import { JobTemplate } from '../../../types';
|
import { JobTemplate } from '../../../types';
|
||||||
import { getAddedAndRemoved } from '../../../util/lists';
|
import { getAddedAndRemoved } from '../../../util/lists';
|
||||||
import JobTemplateForm from '../shared/JobTemplateForm';
|
import JobTemplateForm from '../shared/JobTemplateForm';
|
||||||
|
|
||||||
class JobTemplateEdit extends Component {
|
function JobTemplateEdit({ template }) {
|
||||||
static propTypes = {
|
const { id, type } = template;
|
||||||
template: JobTemplate.isRequired,
|
const history = useHistory();
|
||||||
};
|
const [formSubmitError, setFormSubmitError] = useState(null);
|
||||||
|
|
||||||
constructor(props) {
|
const detailsUrl = `/templates/${type}/${id}/details`;
|
||||||
super(props);
|
|
||||||
|
|
||||||
this.state = {
|
const handleSubmit = async values => {
|
||||||
hasContentLoading: true,
|
|
||||||
contentError: null,
|
|
||||||
formSubmitError: null,
|
|
||||||
relatedCredentials: [],
|
|
||||||
relatedProjectPlaybooks: [],
|
|
||||||
};
|
|
||||||
|
|
||||||
const {
|
|
||||||
template: { id, type },
|
|
||||||
} = props;
|
|
||||||
this.detailsUrl = `/templates/${type}/${id}/details`;
|
|
||||||
|
|
||||||
this.handleCancel = this.handleCancel.bind(this);
|
|
||||||
this.handleSubmit = this.handleSubmit.bind(this);
|
|
||||||
this.loadRelatedCredentials = this.loadRelatedCredentials.bind(this);
|
|
||||||
this.submitLabels = this.submitLabels.bind(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
this.loadRelated();
|
|
||||||
}
|
|
||||||
|
|
||||||
async loadRelated() {
|
|
||||||
this.setState({ contentError: null, hasContentLoading: true });
|
|
||||||
try {
|
|
||||||
const [relatedCredentials] = await this.loadRelatedCredentials();
|
|
||||||
this.setState({
|
|
||||||
relatedCredentials,
|
|
||||||
});
|
|
||||||
} catch (contentError) {
|
|
||||||
this.setState({ contentError });
|
|
||||||
} finally {
|
|
||||||
this.setState({ hasContentLoading: false });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async loadRelatedCredentials() {
|
|
||||||
const {
|
|
||||||
template: { id },
|
|
||||||
} = this.props;
|
|
||||||
const params = {
|
|
||||||
page: 1,
|
|
||||||
page_size: 200,
|
|
||||||
order_by: 'name',
|
|
||||||
};
|
|
||||||
try {
|
|
||||||
const {
|
|
||||||
data: { results: credentials = [] },
|
|
||||||
} = await JobTemplatesAPI.readCredentials(id, params);
|
|
||||||
return credentials;
|
|
||||||
} catch (err) {
|
|
||||||
if (err.status !== 403) throw err;
|
|
||||||
|
|
||||||
this.setState({ hasRelatedCredentialAccess: false });
|
|
||||||
const {
|
|
||||||
template: {
|
|
||||||
summary_fields: { credentials = [] },
|
|
||||||
},
|
|
||||||
} = this.props;
|
|
||||||
|
|
||||||
return credentials;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async handleSubmit(values) {
|
|
||||||
const { template, history } = this.props;
|
|
||||||
const {
|
const {
|
||||||
labels,
|
labels,
|
||||||
instanceGroups,
|
instanceGroups,
|
||||||
@@ -95,25 +27,23 @@ class JobTemplateEdit extends Component {
|
|||||||
...remainingValues
|
...remainingValues
|
||||||
} = values;
|
} = values;
|
||||||
|
|
||||||
this.setState({ formSubmitError: null });
|
setFormSubmitError(null);
|
||||||
remainingValues.project = values.project.id;
|
remainingValues.project = values.project.id;
|
||||||
remainingValues.webhook_credential = webhook_credential?.id || null;
|
remainingValues.webhook_credential = webhook_credential?.id || null;
|
||||||
try {
|
try {
|
||||||
await JobTemplatesAPI.update(template.id, remainingValues);
|
await JobTemplatesAPI.update(template.id, remainingValues);
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
this.submitLabels(labels, template?.organization),
|
submitLabels(labels, template?.organization),
|
||||||
this.submitInstanceGroups(instanceGroups, initialInstanceGroups),
|
submitInstanceGroups(instanceGroups, initialInstanceGroups),
|
||||||
this.submitCredentials(credentials),
|
submitCredentials(credentials),
|
||||||
]);
|
]);
|
||||||
history.push(this.detailsUrl);
|
history.push(detailsUrl);
|
||||||
} catch (error) {
|
} catch (err) {
|
||||||
this.setState({ formSubmitError: error });
|
setFormSubmitError(err);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
async submitLabels(labels = [], orgId) {
|
|
||||||
const { template } = this.props;
|
|
||||||
|
|
||||||
|
const submitLabels = async (labels = [], orgId) => {
|
||||||
const { added, removed } = getAddedAndRemoved(
|
const { added, removed } = getAddedAndRemoved(
|
||||||
template.summary_fields.labels.results,
|
template.summary_fields.labels.results,
|
||||||
labels
|
labels
|
||||||
@@ -131,10 +61,9 @@ class JobTemplateEdit extends Component {
|
|||||||
...associationPromises,
|
...associationPromises,
|
||||||
]);
|
]);
|
||||||
return results;
|
return results;
|
||||||
}
|
};
|
||||||
|
|
||||||
async submitInstanceGroups(groups, initialGroups) {
|
const submitInstanceGroups = async (groups, initialGroups) => {
|
||||||
const { template } = this.props;
|
|
||||||
const { added, removed } = getAddedAndRemoved(initialGroups, groups);
|
const { added, removed } = getAddedAndRemoved(initialGroups, groups);
|
||||||
const disassociatePromises = await removed.map(group =>
|
const disassociatePromises = await removed.map(group =>
|
||||||
JobTemplatesAPI.disassociateInstanceGroup(template.id, group.id)
|
JobTemplatesAPI.disassociateInstanceGroup(template.id, group.id)
|
||||||
@@ -143,10 +72,9 @@ class JobTemplateEdit extends Component {
|
|||||||
JobTemplatesAPI.associateInstanceGroup(template.id, group.id)
|
JobTemplatesAPI.associateInstanceGroup(template.id, group.id)
|
||||||
);
|
);
|
||||||
return Promise.all([...disassociatePromises, ...associatePromises]);
|
return Promise.all([...disassociatePromises, ...associatePromises]);
|
||||||
}
|
};
|
||||||
|
|
||||||
async submitCredentials(newCredentials) {
|
const submitCredentials = async newCredentials => {
|
||||||
const { template } = this.props;
|
|
||||||
const { added, removed } = getAddedAndRemoved(
|
const { added, removed } = getAddedAndRemoved(
|
||||||
template.summary_fields.credentials,
|
template.summary_fields.credentials,
|
||||||
newCredentials
|
newCredentials
|
||||||
@@ -160,55 +88,32 @@ class JobTemplateEdit extends Component {
|
|||||||
);
|
);
|
||||||
const associatePromise = Promise.all(associateCredentials);
|
const associatePromise = Promise.all(associateCredentials);
|
||||||
return Promise.all([disassociatePromise, associatePromise]);
|
return Promise.all([disassociatePromise, associatePromise]);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleCancel = () => {
|
||||||
|
history.push(detailsUrl);
|
||||||
|
};
|
||||||
|
|
||||||
|
const canEdit = template.summary_fields.user_capabilities.edit;
|
||||||
|
|
||||||
|
if (!canEdit) {
|
||||||
|
return <Redirect to={detailsUrl} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
handleCancel() {
|
return (
|
||||||
const { history } = this.props;
|
<CardBody>
|
||||||
history.push(this.detailsUrl);
|
<JobTemplateForm
|
||||||
}
|
template={template}
|
||||||
|
handleCancel={handleCancel}
|
||||||
render() {
|
handleSubmit={handleSubmit}
|
||||||
const { template } = this.props;
|
submitError={formSubmitError}
|
||||||
const {
|
/>
|
||||||
contentError,
|
</CardBody>
|
||||||
formSubmitError,
|
);
|
||||||
hasContentLoading,
|
|
||||||
relatedProjectPlaybooks,
|
|
||||||
} = this.state;
|
|
||||||
const canEdit = template.summary_fields.user_capabilities.edit;
|
|
||||||
|
|
||||||
if (hasContentLoading) {
|
|
||||||
return (
|
|
||||||
<CardBody>
|
|
||||||
<ContentLoading />
|
|
||||||
</CardBody>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (contentError) {
|
|
||||||
return (
|
|
||||||
<CardBody>
|
|
||||||
<ContentError error={contentError} />
|
|
||||||
</CardBody>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!canEdit) {
|
|
||||||
return <Redirect to={this.detailsUrl} />;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<CardBody>
|
|
||||||
<JobTemplateForm
|
|
||||||
template={template}
|
|
||||||
handleCancel={this.handleCancel}
|
|
||||||
handleSubmit={this.handleSubmit}
|
|
||||||
relatedProjectPlaybooks={relatedProjectPlaybooks}
|
|
||||||
submitError={formSubmitError}
|
|
||||||
/>
|
|
||||||
</CardBody>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JobTemplateForm.propTypes = {
|
||||||
|
template: JobTemplate.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
export default withRouter(JobTemplateEdit);
|
export default withRouter(JobTemplateEdit);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import React, { Component } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { withI18n } from '@lingui/react';
|
import { withI18n } from '@lingui/react';
|
||||||
import { t } from '@lingui/macro';
|
import { t } from '@lingui/macro';
|
||||||
import { Route, withRouter, Switch } from 'react-router-dom';
|
import { Route, withRouter, Switch, useRouteMatch } from 'react-router-dom';
|
||||||
import { PageSection } from '@patternfly/react-core';
|
import { PageSection } from '@patternfly/react-core';
|
||||||
|
|
||||||
import { Config } from '../../contexts/Config';
|
import { Config } from '../../contexts/Config';
|
||||||
@@ -12,28 +12,21 @@ import WorkflowJobTemplate from './WorkflowJobTemplate';
|
|||||||
import JobTemplateAdd from './JobTemplateAdd';
|
import JobTemplateAdd from './JobTemplateAdd';
|
||||||
import WorkflowJobTemplateAdd from './WorkflowJobTemplateAdd';
|
import WorkflowJobTemplateAdd from './WorkflowJobTemplateAdd';
|
||||||
|
|
||||||
class Templates extends Component {
|
function Templates({ i18n }) {
|
||||||
constructor(props) {
|
const match = useRouteMatch();
|
||||||
super(props);
|
const [breadcrumbConfig, setBreadcrumbs] = useState({
|
||||||
const { i18n } = this.props;
|
'/templates': i18n._(t`Templates`),
|
||||||
|
'/templates/job_template/add': i18n._(t`Create New Job Template`),
|
||||||
|
'/templates/workflow_job_template/add': i18n._(
|
||||||
|
t`Create New Workflow Template`
|
||||||
|
),
|
||||||
|
});
|
||||||
|
|
||||||
this.state = {
|
const setBreadCrumbConfig = (template, schedule) => {
|
||||||
breadcrumbConfig: {
|
|
||||||
'/templates': i18n._(t`Templates`),
|
|
||||||
'/templates/job_template/add': i18n._(t`Create New Job Template`),
|
|
||||||
'/templates/workflow_job_template/add': i18n._(
|
|
||||||
t`Create New Workflow Template`
|
|
||||||
),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
setBreadCrumbConfig = (template, schedule) => {
|
|
||||||
const { i18n } = this.props;
|
|
||||||
if (!template) {
|
if (!template) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const breadcrumbConfig = {
|
const breadcrumb = {
|
||||||
'/templates': i18n._(t`Templates`),
|
'/templates': i18n._(t`Templates`),
|
||||||
'/templates/job_template/add': i18n._(t`Create New Job Template`),
|
'/templates/job_template/add': i18n._(t`Create New Job Template`),
|
||||||
'/templates/workflow_job_template/add': i18n._(
|
'/templates/workflow_job_template/add': i18n._(
|
||||||
@@ -73,62 +66,55 @@ class Templates extends Component {
|
|||||||
[`/templates/${template.type}/${template.id}/schedules/${schedule &&
|
[`/templates/${template.type}/${template.id}/schedules/${schedule &&
|
||||||
schedule.id}/edit`]: i18n._(t`Edit Details`),
|
schedule.id}/edit`]: i18n._(t`Edit Details`),
|
||||||
};
|
};
|
||||||
this.setState({ breadcrumbConfig });
|
setBreadcrumbs(breadcrumb);
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
return (
|
||||||
const { match, history, location } = this.props;
|
<>
|
||||||
const { breadcrumbConfig } = this.state;
|
<Breadcrumbs breadcrumbConfig={breadcrumbConfig} />
|
||||||
return (
|
<Switch>
|
||||||
<>
|
<Route path={`${match.path}/job_template/add`}>
|
||||||
<Breadcrumbs breadcrumbConfig={breadcrumbConfig} />
|
<JobTemplateAdd />
|
||||||
<Switch>
|
</Route>
|
||||||
<Route path={`${match.path}/job_template/add`}>
|
<Route path={`${match.path}/workflow_job_template/add`}>
|
||||||
<JobTemplateAdd />
|
<WorkflowJobTemplateAdd />
|
||||||
</Route>
|
</Route>
|
||||||
<Route path={`${match.path}/workflow_job_template/add`}>
|
<Route
|
||||||
<WorkflowJobTemplateAdd />
|
path={`${match.path}/job_template/:id`}
|
||||||
</Route>
|
render={({ match: newRouteMatch }) => (
|
||||||
<Route
|
<Config>
|
||||||
path={`${match.path}/job_template/:id`}
|
{({ me }) => (
|
||||||
render={({ match: newRouteMatch }) => (
|
<Template
|
||||||
<Config>
|
setBreadcrumb={setBreadCrumbConfig}
|
||||||
{({ me }) => (
|
me={me || {}}
|
||||||
<Template
|
match={newRouteMatch}
|
||||||
history={history}
|
/>
|
||||||
location={location}
|
)}
|
||||||
setBreadcrumb={this.setBreadCrumbConfig}
|
</Config>
|
||||||
me={me || {}}
|
)}
|
||||||
match={newRouteMatch}
|
/>
|
||||||
/>
|
<Route
|
||||||
)}
|
path={`${match.path}/workflow_job_template/:id`}
|
||||||
</Config>
|
render={({ match: newRouteMatch }) => (
|
||||||
)}
|
<Config>
|
||||||
/>
|
{({ me }) => (
|
||||||
<Route
|
<WorkflowJobTemplate
|
||||||
path={`${match.path}/workflow_job_template/:id`}
|
setBreadcrumb={setBreadCrumbConfig}
|
||||||
render={({ match: newRouteMatch }) => (
|
me={me || {}}
|
||||||
<Config>
|
match={newRouteMatch}
|
||||||
{({ me }) => (
|
/>
|
||||||
<WorkflowJobTemplate
|
)}
|
||||||
location={location}
|
</Config>
|
||||||
setBreadcrumb={this.setBreadCrumbConfig}
|
)}
|
||||||
me={me || {}}
|
/>
|
||||||
match={newRouteMatch}
|
<Route path={`${match.path}`}>
|
||||||
/>
|
<PageSection>
|
||||||
)}
|
<TemplateList />
|
||||||
</Config>
|
</PageSection>
|
||||||
)}
|
</Route>
|
||||||
/>
|
</Switch>
|
||||||
<Route path={`${match.path}`}>
|
</>
|
||||||
<PageSection>
|
);
|
||||||
<TemplateList />
|
|
||||||
</PageSection>
|
|
||||||
</Route>
|
|
||||||
</Switch>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export { Templates as _Templates };
|
export { Templates as _Templates };
|
||||||
|
|||||||
@@ -1,27 +1,24 @@
|
|||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import { createMemoryHistory } from 'history';
|
import { createMemoryHistory } from 'history';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
import { withI18n } from '@lingui/react';
|
|
||||||
import { t } from '@lingui/macro';
|
|
||||||
import { mountWithContexts, waitForElement } from './enzymeHelpers';
|
import { mountWithContexts, waitForElement } from './enzymeHelpers';
|
||||||
import { Config } from '../src/contexts/Config';
|
import { Config } from '../src/contexts/Config';
|
||||||
|
|
||||||
describe('mountWithContexts', () => {
|
describe('mountWithContexts', () => {
|
||||||
describe('injected I18nProvider', () => {
|
describe('injected I18nProvider', () => {
|
||||||
test('should mount and render', () => {
|
test('should mount and render', () => {
|
||||||
const Child = withI18n()(({ i18n }) => (
|
const Child = () => (
|
||||||
<div>
|
<div>
|
||||||
<span>{i18n._(t`Text content`)}</span>
|
<span>Text content</span>
|
||||||
</div>
|
</div>
|
||||||
));
|
);
|
||||||
const wrapper = mountWithContexts(<Child />);
|
const wrapper = mountWithContexts(<Child />);
|
||||||
expect(wrapper.find('div')).toMatchSnapshot();
|
expect(wrapper.find('div')).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should mount and render deeply nested consumer', () => {
|
test('should mount and render deeply nested consumer', () => {
|
||||||
const Child = withI18n()(({ i18n }) => (
|
const Child = () => <div>Text content</div>;
|
||||||
<div>{i18n._(t`Text content`)}</div>
|
|
||||||
));
|
|
||||||
const Parent = () => <Child />;
|
const Parent = () => <Child />;
|
||||||
const wrapper = mountWithContexts(<Parent />);
|
const wrapper = mountWithContexts(<Parent />);
|
||||||
expect(wrapper.find('Parent')).toMatchSnapshot();
|
expect(wrapper.find('Parent')).toMatchSnapshot();
|
||||||
@@ -146,7 +143,9 @@ describe('waitForElement', () => {
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
error = err;
|
error = err;
|
||||||
} finally {
|
} finally {
|
||||||
expect(error.message).toContain('Expected condition for <#does-not-exist> not met');
|
expect(error.message).toContain(
|
||||||
|
'Expected condition for <#does-not-exist> not met'
|
||||||
|
);
|
||||||
expect(error.message).toContain('el.length === 1');
|
expect(error.message).toContain('el.length === 1');
|
||||||
done();
|
done();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user