update awx-pf to use withI18n i18n._ and t exclusively

This commit is contained in:
John Mitchell
2019-05-15 11:20:00 -04:00
parent 4407aeac20
commit 07664a05fd
57 changed files with 1343 additions and 1355 deletions

View File

@@ -9,7 +9,7 @@ import {
Button Button
} from '@patternfly/react-core'; } from '@patternfly/react-core';
import { I18n } from '@lingui/react'; import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro'; import { t } from '@lingui/macro';
import { RootDialog } from './contexts/RootDialog'; import { RootDialog } from './contexts/RootDialog';
@@ -66,92 +66,88 @@ class App extends Component {
render () { render () {
const { isAboutModalOpen, isNavOpen } = this.state; const { isAboutModalOpen, isNavOpen } = this.state;
const { render, routeGroups = [], navLabel = '' } = this.props; const { render, routeGroups = [], navLabel = '', i18n } = this.props;
return ( return (
<Config> <Config>
{({ ansible_version, version, me }) => ( {({ ansible_version, version, me }) => (
<I18n> <RootDialog>
{({ i18n }) => ( {({
<RootDialog> title,
{({ bodyText,
title, variant = 'info',
bodyText, clearRootDialogMessage
variant = 'info', }) => (
clearRootDialogMessage <Fragment>
}) => ( {(title || bodyText) && (
<Fragment> <AlertModal
{(title || bodyText) && ( variant={variant}
<AlertModal isOpen={!!(title || bodyText)}
variant={variant} onClose={clearRootDialogMessage}
isOpen={!!(title || bodyText)} title={title}
onClose={clearRootDialogMessage} actions={[
title={title} <Button
actions={[ key="close"
<Button variant="secondary"
key="close" onClick={clearRootDialogMessage}
variant="secondary"
onClick={clearRootDialogMessage}
>
{i18n._(t`Close`)}
</Button>
]}
> >
{bodyText} {i18n._(t`Close`)}
</AlertModal> </Button>
)} ]}
<Page >
usecondensed="True" {bodyText}
header={( </AlertModal>
<PageHeader
showNavToggle
onNavToggle={this.onNavToggle}
logo={<TowerLogo linkTo="/" />}
toolbar={(
<PageHeaderToolbar
loggedInUser={me}
isAboutDisabled={!version}
onAboutClick={this.onAboutModalOpen}
onLogoutClick={this.onLogout}
/>
)}
/>
)}
sidebar={(
<PageSidebar
isNavOpen={isNavOpen}
nav={(
<Nav aria-label={navLabel}>
<NavList>
{routeGroups.map(
({ groupId, groupTitle, routes }) => (
<NavExpandableGroup
key={groupId}
groupId={groupId}
groupTitle={groupTitle}
routes={routes}
/>
)
)}
</NavList>
</Nav>
)}
/>
)}
>
{render && render({ routeGroups })}
</Page>
<About
ansible_version={ansible_version}
version={version}
isOpen={isAboutModalOpen}
onClose={this.onAboutModalClose}
/>
</Fragment>
)} )}
</RootDialog> <Page
usecondensed="True"
header={(
<PageHeader
showNavToggle
onNavToggle={this.onNavToggle}
logo={<TowerLogo linkTo="/" />}
toolbar={(
<PageHeaderToolbar
loggedInUser={me}
isAboutDisabled={!version}
onAboutClick={this.onAboutModalOpen}
onLogoutClick={this.onLogout}
/>
)}
/>
)}
sidebar={(
<PageSidebar
isNavOpen={isNavOpen}
nav={(
<Nav aria-label={navLabel}>
<NavList>
{routeGroups.map(
({ groupId, groupTitle, routes }) => (
<NavExpandableGroup
key={groupId}
groupId={groupId}
groupTitle={groupTitle}
routes={routes}
/>
)
)}
</NavList>
</Nav>
)}
/>
)}
>
{render && render({ routeGroups })}
</Page>
<About
ansible_version={ansible_version}
version={version}
isOpen={isAboutModalOpen}
onClose={this.onAboutModalClose}
/>
</Fragment>
)} )}
</I18n> </RootDialog>
)} )}
</Config> </Config>
); );
@@ -159,4 +155,4 @@ class App extends Component {
} }
export { App as _App }; export { App as _App };
export default withNetwork(App); export default withI18n()(withNetwork(App));

View File

@@ -1,7 +1,7 @@
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { I18n } from '@lingui/react'; import { withI18n } from '@lingui/react';
import { Trans, t } from '@lingui/macro'; import { t } from '@lingui/macro';
import { import {
AboutModal, AboutModal,
TextContent, TextContent,
@@ -41,46 +41,43 @@ class About extends React.Component {
ansible_version, ansible_version,
version, version,
isOpen, isOpen,
onClose onClose,
i18n
} = this.props; } = this.props;
const speechBubble = this.createSpeechBubble(version); const speechBubble = this.createSpeechBubble(version);
return ( return (
<I18n> <AboutModal
{({ i18n }) => ( isOpen={isOpen}
<AboutModal onClose={onClose}
isOpen={isOpen} productName="Ansible Tower"
onClose={onClose} trademark={i18n._(t`Copyright 2018 Red Hat, Inc.`)}
productName="Ansible Tower" brandImageSrc={brandImg}
trademark={i18n._(t`Copyright 2018 Red Hat, Inc.`)} brandImageAlt={i18n._(t`Brand Image`)}
brandImageSrc={brandImg} logoImageSrc={logoImg}
brandImageAlt={i18n._(t`Brand Image`)} logoImageAlt={i18n._(t`AboutModal Logo`)}
logoImageSrc={logoImg} >
logoImageAlt={i18n._(t`AboutModal Logo`)} <pre>
> { speechBubble }
<pre> {`
{ speechBubble } \\
{` \\ ^__^
\\ (oo)\\_______
\\ ^__^ (__) A )\\
(oo)\\_______ ||----w |
(__) A )\\ || ||
||----w | `}
|| || </pre>
`} <TextContent>
</pre> <TextList component="dl">
<TextContent> <TextListItem component="dt">
<TextList component="dl"> {i18n._(t`Ansible Version`)}
<TextListItem component="dt"> </TextListItem>
<Trans>Ansible Version</Trans> <TextListItem component="dd">{ ansible_version }</TextListItem>
</TextListItem> </TextList>
<TextListItem component="dd">{ ansible_version }</TextListItem> </TextContent>
</TextList> </AboutModal>
</TextContent>
</AboutModal>
)}
</I18n>
); );
} }
} }
@@ -98,4 +95,4 @@ About.defaultProps = {
version: null, version: null,
}; };
export default About; export default withI18n()(About);

View File

@@ -1,6 +1,6 @@
import React, { Fragment } from 'react'; import React, { Fragment } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { I18n, i18nMark } from '@lingui/react'; import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro'; import { t } from '@lingui/macro';
import { Wizard } from '@patternfly/react-core'; import { Wizard } from '@patternfly/react-core';
import SelectResourceStep from './SelectResourceStep'; import SelectResourceStep from './SelectResourceStep';
@@ -127,113 +127,103 @@ class AddResourceRole extends React.Component {
} = this.state; } = this.state;
const { const {
onClose, onClose,
roles roles,
i18n
} = this.props; } = this.props;
const userColumns = [ const userColumns = [
{ name: i18nMark('Username'), key: 'username', isSortable: true } { name: i18n._(t`Username`), key: 'username', isSortable: true }
]; ];
const teamColumns = [ const teamColumns = [
{ name: i18nMark('Name'), key: 'name', isSortable: true } { name: i18n._(t`Name`), key: 'name', isSortable: true }
]; ];
let wizardTitle = ''; let wizardTitle = '';
switch (selectedResource) { switch (selectedResource) {
case 'users': case 'users':
wizardTitle = i18nMark('Add User Roles'); wizardTitle = i18n._(t`Add User Roles`);
break; break;
case 'teams': case 'teams':
wizardTitle = i18nMark('Add Team Roles'); wizardTitle = i18n._(t`Add Team Roles`);
break; break;
default: default:
wizardTitle = i18nMark('Add Roles'); wizardTitle = i18n._(t`Add Roles`);
} }
const steps = [ const steps = [
{ {
id: 1, id: 1,
name: i18nMark('Select Users Or Teams'), name: i18n._(t`Select Users Or Teams`),
component: ( component: (
<I18n> <div style={{ display: 'flex' }}>
{({ i18n }) => ( <SelectableCard
<div style={{ display: 'flex' }}> isSelected={selectedResource === 'users'}
<SelectableCard label={i18n._(t`Users`)}
isSelected={selectedResource === 'users'} onClick={() => this.handleResourceSelect('users')}
label={i18n._(t`Users`)} />
onClick={() => this.handleResourceSelect('users')} <SelectableCard
/> isSelected={selectedResource === 'teams'}
<SelectableCard label={i18n._(t`Teams`)}
isSelected={selectedResource === 'teams'} onClick={() => this.handleResourceSelect('teams')}
label={i18n._(t`Teams`)} />
onClick={() => this.handleResourceSelect('teams')} </div>
/>
</div>
)}
</I18n>
), ),
enableNext: selectedResource !== null enableNext: selectedResource !== null
}, },
{ {
id: 2, id: 2,
name: i18nMark('Select items from list'), name: i18n._(t`Select items from list`),
component: ( component: (
<I18n> <Fragment>
{({ i18n }) => ( {selectedResource === 'users' && (
<Fragment> <SelectResourceStep
{selectedResource === 'users' && ( columns={userColumns}
<SelectResourceStep displayKey="username"
columns={userColumns} onRowClick={this.handleResourceCheckboxClick}
displayKey="username" onSearch={this.readUsers}
onRowClick={this.handleResourceCheckboxClick} selectedLabel={i18n._(t`Selected`)}
onSearch={this.readUsers} selectedResourceRows={selectedResourceRows}
selectedLabel={i18n._(t`Selected`)} sortedColumnKey="username"
selectedResourceRows={selectedResourceRows} itemName="user"
sortedColumnKey="username" />
itemName="user"
/>
)}
{selectedResource === 'teams' && (
<SelectResourceStep
columns={teamColumns}
onRowClick={this.handleResourceCheckboxClick}
onSearch={this.readTeams}
selectedLabel={i18n._(t`Selected`)}
selectedResourceRows={selectedResourceRows}
itemName="team"
/>
)}
</Fragment>
)} )}
</I18n> {selectedResource === 'teams' && (
<SelectResourceStep
columns={teamColumns}
onRowClick={this.handleResourceCheckboxClick}
onSearch={this.readTeams}
selectedLabel={i18n._(t`Selected`)}
selectedResourceRows={selectedResourceRows}
itemName="team"
/>
)}
</Fragment>
), ),
enableNext: selectedResourceRows.length > 0 enableNext: selectedResourceRows.length > 0
}, },
{ {
id: 3, id: 3,
name: i18nMark('Apply roles'), name: i18n._(t`Apply roles`),
component: ( component: (
<I18n> <SelectRoleStep
{({ i18n }) => ( onRolesClick={this.handleRoleCheckboxClick}
<SelectRoleStep roles={roles}
onRolesClick={this.handleRoleCheckboxClick} selectedListKey={selectedResource === 'users' ? 'username' : 'name'}
roles={roles} selectedListLabel={i18n._(t`Selected`)}
selectedListKey={selectedResource === 'users' ? 'username' : 'name'} selectedResourceRows={selectedResourceRows}
selectedListLabel={i18n._(t`Selected`)} selectedRoleRows={selectedRoleRows}
selectedResourceRows={selectedResourceRows} />
selectedRoleRows={selectedRoleRows}
/>
)}
</I18n>
), ),
nextButtonText: i18nMark('Save'), nextButtonText: i18n._(t`Save`),
enableNext: selectedRoleRows.length > 0 enableNext: selectedRoleRows.length > 0
} }
]; ];
const currentStep = steps.find(step => step.id === currentStepId); const currentStep = steps.find(step => step.id === currentStepId);
// TODO: somehow internationalize steps and currentStep.nextButtonText
return ( return (
<Wizard <Wizard
style={{ overflow: 'scroll' }} style={{ overflow: 'scroll' }}
@@ -259,4 +249,4 @@ AddResourceRole.defaultProps = {
roles: {} roles: {}
}; };
export default AddResourceRole; export default withI18n()(AddResourceRole);

View File

@@ -1,7 +1,8 @@
import React, { Fragment } from 'react'; import React, { Fragment } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { withRouter } from 'react-router-dom'; import { withRouter } from 'react-router-dom';
import { i18nMark } from '@lingui/react'; import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import PaginatedDataList from '../PaginatedDataList'; import PaginatedDataList from '../PaginatedDataList';
import CheckboxListItem from '../ListItem'; import CheckboxListItem from '../ListItem';
import SelectedList from '../SelectedList'; import SelectedList from '../SelectedList';
@@ -87,11 +88,12 @@ class SelectResourceStep extends React.Component {
selectedLabel, selectedLabel,
selectedResourceRows, selectedResourceRows,
itemName, itemName,
i18n
} = this.props; } = this.props;
return ( return (
<Fragment> <Fragment>
{isLoading && (<div>Loading...</div>)} {isLoading && (<div>{i18n._(t`Loading...`)}</div>)}
{isInitialized && ( {isInitialized && (
<Fragment> <Fragment>
{selectedResourceRows.length > 0 && ( {selectedResourceRows.length > 0 && (
@@ -146,11 +148,11 @@ SelectResourceStep.propTypes = {
SelectResourceStep.defaultProps = { SelectResourceStep.defaultProps = {
displayKey: 'name', displayKey: 'name',
onRowClick: () => {}, onRowClick: () => {},
selectedLabel: i18nMark('Selected Items'), selectedLabel: null,
selectedResourceRows: [], selectedResourceRows: [],
sortedColumnKey: 'name', sortedColumnKey: 'name',
itemName: 'item', itemName: 'item',
}; };
export { SelectResourceStep as _SelectResourceStep }; export { SelectResourceStep as _SelectResourceStep };
export default withRouter(SelectResourceStep); export default withI18n()(withRouter(SelectResourceStep));

View File

@@ -1,7 +1,8 @@
import React, { Fragment } from 'react'; import React, { Fragment } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { i18nMark } from '@lingui/react'; import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import CheckboxCard from './CheckboxCard'; import CheckboxCard from './CheckboxCard';
import SelectedList from '../SelectedList'; import SelectedList from '../SelectedList';
@@ -14,7 +15,8 @@ class RolesStep extends React.Component {
selectedListKey, selectedListKey,
selectedListLabel, selectedListLabel,
selectedResourceRows, selectedResourceRows,
selectedRoleRows selectedRoleRows,
i18n
} = this.props; } = this.props;
return ( return (
@@ -24,7 +26,7 @@ class RolesStep extends React.Component {
<SelectedList <SelectedList
displayKey={selectedListKey} displayKey={selectedListKey}
isReadOnly isReadOnly
label={selectedListLabel} label={selectedListLabel || i18n._(t`Selected`)}
selected={selectedResourceRows} selected={selectedResourceRows}
showOverflowAfter={5} showOverflowAfter={5}
/> />
@@ -61,9 +63,9 @@ RolesStep.propTypes = {
RolesStep.defaultProps = { RolesStep.defaultProps = {
onRolesClick: () => {}, onRolesClick: () => {},
selectedListKey: 'name', selectedListKey: 'name',
selectedListLabel: i18nMark('Selected'), selectedListLabel: null,
selectedResourceRows: [], selectedResourceRows: [],
selectedRoleRows: [] selectedRoleRows: []
}; };
export default RolesStep; export default withI18n()(RolesStep);

View File

@@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { I18n } from '@lingui/react'; import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro'; import { t } from '@lingui/macro';
import { import {
FormSelect, FormSelect,
@@ -20,29 +20,25 @@ class AnsibleSelect extends React.Component {
} }
render () { render () {
const { label, value, data, defaultSelected } = this.props; const { label, value, data, defaultSelected, i18n } = this.props;
return ( return (
<I18n> <FormSelect
{({ i18n }) => ( value={value}
<FormSelect onChange={this.onSelectChange}
value={value} aria-label={i18n._(t`Select Input`)}
onChange={this.onSelectChange} >
aria-label={i18n._(t`Select Input`)} {data.map((datum) => (
> datum === defaultSelected ? (
{data.map((datum) => ( <FormSelectOption
datum === defaultSelected ? ( key=""
<FormSelectOption value=""
key="" label={i18n._(t`Use Default ${label}`)}
value="" />
label={i18n._(t`Use Default ${label}`)} ) : (
/> <FormSelectOption key={datum} value={datum} label={datum} />
) : ( )
<FormSelectOption key={datum} value={datum} label={datum} /> ))}
) </FormSelect>
))}
</FormSelect>
)}
</I18n>
); );
} }
} }
@@ -62,4 +58,4 @@ AnsibleSelect.propTypes = {
value: PropTypes.string.isRequired, value: PropTypes.string.isRequired,
}; };
export default AnsibleSelect; export default withI18n()(AnsibleSelect);

View File

@@ -3,40 +3,32 @@ import { string } from 'prop-types';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import { Button } from '@patternfly/react-core'; import { Button } from '@patternfly/react-core';
import { TimesIcon } from '@patternfly/react-icons'; import { TimesIcon } from '@patternfly/react-icons';
import { I18n } from '@lingui/react'; import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro'; import { t } from '@lingui/macro';
function CardCloseButton ({ linkTo, ...props }) { function CardCloseButton ({ linkTo, i18n, i18nHash, ...props }) {
if (linkTo) { if (linkTo) {
return ( return (
<I18n> <Link
{({ i18n }) => ( className="pf-c-button pf-c-card__close"
<Link aria-label={i18n._(t`Close`)}
className="pf-c-button pf-c-card__close" title={i18n._(t`Close`)}
aria-label={i18n._(t`Close`)} to={linkTo}
title={i18n._(t`Close`)} {...props}
to={linkTo} >
{...props} <TimesIcon />
> </Link>
<TimesIcon />
</Link>
)}
</I18n>
); );
} }
return ( return (
<I18n> <Button
{({ i18n }) => ( variant="plain"
<Button className="pf-c-card__close"
variant="plain" aria-label={i18n._(t`Close`)}
className="pf-c-card__close" {...props}
aria-label={i18n._(t`Close`)} >
{...props} <TimesIcon />
> </Button>
<TimesIcon />
</Button>
)}
</I18n>
); );
} }
CardCloseButton.propTypes = { CardCloseButton.propTypes = {
@@ -46,4 +38,4 @@ CardCloseButton.defaultProps = {
linkTo: null, linkTo: null,
}; };
export default CardCloseButton; export default withI18n()(CardCloseButton);

View File

@@ -1,6 +1,6 @@
import React, { Fragment } from 'react'; import React, { Fragment } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { I18n } from '@lingui/react'; import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro'; import { t } from '@lingui/macro';
import { import {
Checkbox, Checkbox,
@@ -85,70 +85,66 @@ class DataListToolbar extends React.Component {
sortOrder, sortOrder,
sortedColumnKey, sortedColumnKey,
additionalControls, additionalControls,
i18n
} = this.props; } = this.props;
const showExpandCollapse = (onCompact && onExpand); const showExpandCollapse = (onCompact && onExpand);
return ( return (
<I18n> <AWXToolbar>
{({ i18n }) => ( <Toolbar marginleft={noLeftMargin ? 1 : 0}>
<AWXToolbar> <ColumnLeft>
<Toolbar marginleft={noLeftMargin ? 1 : 0}> { showSelectAll && (
<ColumnLeft> <Fragment>
{ showSelectAll && ( <ToolbarItem>
<Fragment> <Checkbox
<ToolbarItem> checked={isAllSelected}
<Checkbox onChange={onSelectAll}
checked={isAllSelected} aria-label={i18n._(t`Select all`)}
onChange={onSelectAll} id="select-all"
aria-label={i18n._(t`Select all`)}
id="select-all"
/>
</ToolbarItem>
<VerticalSeparator />
</Fragment>
)}
<ToolbarItem css="flex-grow: 1;">
<Search
columns={columns}
onSearch={onSearch}
sortedColumnKey={sortedColumnKey}
/> />
</ToolbarItem> </ToolbarItem>
<VerticalSeparator /> <VerticalSeparator />
</ColumnLeft> </Fragment>
<ColumnRight> )}
<ToolbarItem> <ToolbarItem css="flex-grow: 1;">
<Sort <Search
columns={columns} columns={columns}
onSort={onSort} onSearch={onSearch}
sortOrder={sortOrder} sortedColumnKey={sortedColumnKey}
sortedColumnKey={sortedColumnKey} />
</ToolbarItem>
<VerticalSeparator />
</ColumnLeft>
<ColumnRight>
<ToolbarItem>
<Sort
columns={columns}
onSort={onSort}
sortOrder={sortOrder}
sortedColumnKey={sortedColumnKey}
/>
</ToolbarItem>
{showExpandCollapse && (
<Fragment>
<VerticalSeparator />
<ToolbarGroup>
<ExpandCollapse
isCompact={isCompact}
onCompact={onCompact}
onExpand={onExpand}
/> />
</ToolbarItem> </ToolbarGroup>
{showExpandCollapse && ( { additionalControls && (
<Fragment> <VerticalSeparator />
<VerticalSeparator />
<ToolbarGroup>
<ExpandCollapse
isCompact={isCompact}
onCompact={onCompact}
onExpand={onExpand}
/>
</ToolbarGroup>
{ additionalControls && (
<VerticalSeparator />
)}
</Fragment>
)} )}
<AdditionalControlsWrapper> </Fragment>
{additionalControls} )}
</AdditionalControlsWrapper> <AdditionalControlsWrapper>
</ColumnRight> {additionalControls}
</Toolbar> </AdditionalControlsWrapper>
</AWXToolbar> </ColumnRight>
</Toolbar>
)} </AWXToolbar>
</I18n>
); );
} }
} }
@@ -184,4 +180,4 @@ DataListToolbar.defaultProps = {
additionalControls: [], additionalControls: [],
}; };
export default DataListToolbar; export default withI18n()(DataListToolbar);

View File

@@ -1,6 +1,6 @@
import React, { Fragment } from 'react'; import React, { Fragment } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { I18n } from '@lingui/react'; import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro'; import { t } from '@lingui/macro';
import { import {
Button, Button,
@@ -22,36 +22,33 @@ class ExpandCollapse extends React.Component {
const { const {
onCompact, onCompact,
onExpand, onExpand,
isCompact isCompact,
i18n
} = this.props; } = this.props;
return ( return (
<I18n> <Fragment>
{({ i18n }) => ( <ToolbarItem>
<Fragment> <Button
<ToolbarItem> variant="plain"
<Button aria-label={i18n._(t`Collapse`)}
variant="plain" onClick={onCompact}
aria-label={i18n._(t`Collapse`)} style={isCompact ? ToolbarActiveStyle : null}
onClick={onCompact} >
style={isCompact ? ToolbarActiveStyle : null} <BarsIcon />
> </Button>
<BarsIcon /> </ToolbarItem>
</Button> <ToolbarItem>
</ToolbarItem> <Button
<ToolbarItem> variant="plain"
<Button aria-label={i18n._(t`Expand`)}
variant="plain" onClick={onExpand}
aria-label={i18n._(t`Expand`)} style={!isCompact ? ToolbarActiveStyle : null}
onClick={onExpand} >
style={!isCompact ? ToolbarActiveStyle : null} <EqualsIcon />
> </Button>
<EqualsIcon /> </ToolbarItem>
</Button> </Fragment>
</ToolbarItem>
</Fragment>
)}
</I18n>
); );
} }
} }
@@ -64,4 +61,4 @@ ExpandCollapse.propTypes = {
ExpandCollapse.defaultProps = {}; ExpandCollapse.defaultProps = {};
export default ExpandCollapse; export default withI18n()(ExpandCollapse);

View File

@@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { I18n } from '@lingui/react'; import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro'; import { t } from '@lingui/macro';
import { import {
ActionGroup, ActionGroup,
@@ -20,21 +20,17 @@ const buttonGroupStyle = {
marginRight: '20px' marginRight: '20px'
}; };
const FormActionGroup = ({ onSubmit, submitDisabled, onCancel }) => ( const FormActionGroup = ({ onSubmit, submitDisabled, onCancel, i18n }) => (
<I18n> <ActionGroup style={formActionGroupStyle}>
{({ i18n }) => ( <Toolbar>
<ActionGroup style={formActionGroupStyle}> <ToolbarGroup style={buttonGroupStyle}>
<Toolbar> <Button aria-label={i18n._(t`Save`)} variant="primary" type="submit" onClick={onSubmit} isDisabled={submitDisabled}>{i18n._(t`Save`)}</Button>
<ToolbarGroup style={buttonGroupStyle}> </ToolbarGroup>
<Button aria-label={i18n._(t`Save`)} variant="primary" type="submit" onClick={onSubmit} isDisabled={submitDisabled}>{i18n._(t`Save`)}</Button> <ToolbarGroup>
</ToolbarGroup> <Button aria-label={i18n._(t`Cancel`)} variant="secondary" type="button" onClick={onCancel}>{i18n._(t`Cancel`)}</Button>
<ToolbarGroup> </ToolbarGroup>
<Button aria-label={i18n._(t`Cancel`)} variant="secondary" type="button" onClick={onCancel}>{i18n._(t`Cancel`)}</Button> </Toolbar>
</ToolbarGroup> </ActionGroup>
</Toolbar>
</ActionGroup>
)}
</I18n>
); );
FormActionGroup.propTypes = { FormActionGroup.propTypes = {
@@ -47,4 +43,4 @@ FormActionGroup.defaultProps = {
submitDisabled: false, submitDisabled: false,
}; };
export default FormActionGroup; export default withI18n()(FormActionGroup);

View File

@@ -9,7 +9,7 @@ import {
InputGroup, InputGroup,
Modal, Modal,
} from '@patternfly/react-core'; } from '@patternfly/react-core';
import { I18n } from '@lingui/react'; import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro'; import { t } from '@lingui/macro';
import { withNetwork } from '../../contexts/Network'; import { withNetwork } from '../../contexts/Network';
@@ -130,7 +130,9 @@ class Lookup extends React.Component {
results, results,
count, count,
} = this.state; } = this.state;
const { id, lookupHeader = 'items', value, columns } = this.props; const { id, lookupHeader, value, columns, i18n } = this.props;
const header = lookupHeader || i18n._(t`items`);
const chips = value ? ( const chips = value ? (
<div className="pf-c-chip-group"> <div className="pf-c-chip-group">
@@ -143,64 +145,60 @@ class Lookup extends React.Component {
) : null; ) : null;
return ( return (
<I18n> <Fragment>
{({ i18n }) => ( <InputGroup className="awx-lookup">
<Fragment> <Button
<InputGroup className="awx-lookup"> aria-label="Search"
<Button id={id}
aria-label="Search" onClick={this.handleModalToggle}
id={id} variant={ButtonVariant.tertiary}
onClick={this.handleModalToggle} >
variant={ButtonVariant.tertiary} <SearchIcon />
> </Button>
<SearchIcon /> <div className="pf-c-form-control">
</Button> {chips}
<div className="pf-c-form-control"> </div>
{chips} </InputGroup>
</div> <Modal
</InputGroup> className="awx-c-modal"
<Modal title={i18n._(t`Select ${header}`)}
className="awx-c-modal" isOpen={isModalOpen}
title={`Select ${lookupHeader}`} onClose={this.handleModalToggle}
isOpen={isModalOpen} actions={[
onClose={this.handleModalToggle} <Button key="save" variant="primary" onClick={this.saveModal} style={(results.length === 0) ? { display: 'none' } : {}}>{i18n._(t`Save`)}</Button>,
actions={[ <Button key="cancel" variant="secondary" onClick={this.handleModalToggle}>{(results.length === 0) ? i18n._(t`Close`) : i18n._(t`Cancel`)}</Button>
<Button key="save" variant="primary" onClick={this.saveModal} style={(results.length === 0) ? { display: 'none' } : {}}>{i18n._(t`Save`)}</Button>, ]}
<Button key="cancel" variant="secondary" onClick={this.handleModalToggle}>{(results.length === 0) ? i18n._(t`Close`) : i18n._(t`Cancel`)}</Button> >
]} <PaginatedDataList
> items={results}
<PaginatedDataList itemCount={count}
items={results} itemName={lookupHeader}
itemCount={count} qsConfig={this.qsConfig}
itemName={lookupHeader} toolbarColumns={columns}
qsConfig={this.qsConfig} renderItem={item => (
toolbarColumns={columns} <CheckboxListItem
renderItem={item => ( key={item.id}
<CheckboxListItem itemId={item.id}
key={item.id} name={item.name}
itemId={item.id} isSelected={lookupSelectedItems.some(i => i.id === item.id)}
name={item.name} onSelect={() => this.toggleSelected(item)}
isSelected={lookupSelectedItems.some(i => i.id === item.id)}
onSelect={() => this.toggleSelected(item)}
/>
)}
alignToolbarLeft
showPageSizeOptions={false}
paginationStyling={paginationStyling}
/> />
{lookupSelectedItems.length > 0 && ( )}
<SelectedList alignToolbarLeft
label={i18n._(t`Selected`)} showPageSizeOptions={false}
selected={lookupSelectedItems} paginationStyling={paginationStyling}
showOverflowAfter={5} />
onRemove={this.toggleSelected} {lookupSelectedItems.length > 0 && (
/> <SelectedList
)} label={i18n._(t`Selected`)}
{ error ? <div>error</div> : '' } selected={lookupSelectedItems}
</Modal> showOverflowAfter={5}
</Fragment> onRemove={this.toggleSelected}
)} />
</I18n> )}
{ error ? <div>error</div> : '' }
</Modal>
</Fragment>
); );
} }
} }
@@ -217,9 +215,9 @@ Lookup.propTypes = {
Lookup.defaultProps = { Lookup.defaultProps = {
id: 'lookup-search', id: 'lookup-search',
lookupHeader: 'items', lookupHeader: null,
name: null, name: null,
}; };
export { Lookup as _Lookup }; export { Lookup as _Lookup };
export default withNetwork(withRouter(Lookup)); export default withI18n()(withNetwork(withRouter(Lookup)));

View File

@@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import { shape, number, string, bool, func } from 'prop-types'; import { shape, number, string, bool, func } from 'prop-types';
import { I18n } from '@lingui/react'; import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro'; import { t } from '@lingui/macro';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import { import {
@@ -37,66 +37,75 @@ function NotificationListItem (props) {
detailUrl, detailUrl,
successTurnedOn, successTurnedOn,
errorTurnedOn, errorTurnedOn,
toggleNotification toggleNotification,
i18n
} = props; } = props;
return ( return (
<I18n> <DataListItem
{({ i18n }) => ( aria-labelledby={`items-list-item-${notification.id}`}
<DataListItem key={notification.id}
aria-labelledby={`items-list-item-${notification.id}`} >
key={notification.id} <DataListItemRow>
> <DataListItemCells dataListCells={[
<DataListItemRow> <DataListCell key="name">
<DataListItemCells dataListCells={[ <Link
<DataListCell key="name"> to={{
<Link pathname: detailUrl
to={{ }}
pathname: detailUrl css="margin-right: 1.5em;"
}} >
css="margin-right: 1.5em;" <b id={`items-list-item-${notification.id}`}>{notification.name}</b>
> </Link>
<b id={`items-list-item-${notification.id}`}>{notification.name}</b> <Badge
</Link> css="text-transform: capitalize;"
<Badge isRead
css="text-transform: capitalize;" >
isRead {notification.notification_type}
> </Badge>
{notification.notification_type} </DataListCell>,
</Badge> <DataListCell righthalf="true" key="toggles">
</DataListCell>, <Switch
<DataListCell righthalf="true" key="toggles"> id={`notification-${notification.id}-success-toggle`}
<Switch label={i18n._(t`Successful`)}
id={`notification-${notification.id}-success-toggle`} isChecked={successTurnedOn}
label={i18n._(t`Successful`)} isDisabled={!canToggleNotifications}
isChecked={successTurnedOn} onChange={() => toggleNotification(
isDisabled={!canToggleNotifications} notification.id,
onChange={() => toggleNotification( successTurnedOn,
notification.id, 'success'
successTurnedOn, )}
'success' aria-label={i18n._(t`Toggle notification success`)}
)}
aria-label={i18n._(t`Toggle notification success`)}
/>
<Switch
id={`notification-${notification.id}-error-toggle`}
label={i18n._(t`Failure`)}
isChecked={errorTurnedOn}
isDisabled={!canToggleNotifications}
onChange={() => toggleNotification(
notification.id,
errorTurnedOn,
'error'
)}
aria-label={i18n._(t`Toggle notification failure`)}
/>
</DataListCell>
]}
/> />
</DataListItemRow> <Switch
</DataListItem> id={`notification-${notification.id}-error-toggle`}
)} label={i18n._(t`Failure`)}
</I18n> isChecked={errorTurnedOn}
isDisabled={!canToggleNotifications}
onChange={() => toggleNotification(
notification.id,
errorTurnedOn,
'error'
)}
aria-label={i18n._(t`Toggle notification failure`)}
/>
</DataListCell>
]}
/>
<Switch
id={`notification-${notification.id}-error-toggle`}
label={i18n._(t`Failure`)}
isChecked={errorTurnedOn}
isDisabled={!canToggleNotifications}
onChange={() => toggleNotification(
notification.id,
errorTurnedOn,
'error'
)}
aria-label={i18n._(t`Toggle notification failure`)}
/>
</DataListItemRow>
</DataListItem>
); );
} }
@@ -118,4 +127,4 @@ NotificationListItem.defaultProps = {
successTurnedOn: false, successTurnedOn: false,
}; };
export default NotificationListItem; export default withI18n()(NotificationListItem);

View File

@@ -1,8 +1,8 @@
import React from 'react'; import React, { Fragment } from 'react';
import { Redirect, withRouter } from 'react-router-dom'; import { Redirect, withRouter } from 'react-router-dom';
import { withI18n } from '@lingui/react';
import { Trans } from '@lingui/macro'; import { t } from '@lingui/macro';
import { withRootDialog } from '../contexts/RootDialog'; import { withRootDialog } from '../contexts/RootDialog';
@@ -14,16 +14,13 @@ const NotifyAndRedirect = ({
strict, strict,
sensitive, sensitive,
setRootDialogMessage, setRootDialogMessage,
location location,
i18n
}) => { }) => {
setRootDialogMessage({ setRootDialogMessage({
title: '404', title: '404',
bodyText: ( bodyText: (
<Trans> <Fragment>{i18n._(t`Cannot find route ${(<strong>{location.pathname}</strong>)}.`)}</Fragment>
Cannot find route
<strong>{` ${location.pathname}`}</strong>
.
</Trans>
), ),
variant: 'warning' variant: 'warning'
}); });
@@ -41,4 +38,4 @@ const NotifyAndRedirect = ({
}; };
export { NotifyAndRedirect as _NotifyAndRedirect }; export { NotifyAndRedirect as _NotifyAndRedirect };
export default withRootDialog(withRouter(NotifyAndRedirect)); export default withI18n()(withRootDialog(withRouter(NotifyAndRedirect)));

View File

@@ -1,8 +1,7 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro'; import { t } from '@lingui/macro';
import { I18n } from '@lingui/react';
import { import {
Dropdown, Dropdown,
DropdownItem, DropdownItem,
@@ -57,78 +56,75 @@ class PageHeaderToolbar extends Component {
isAboutDisabled, isAboutDisabled,
onAboutClick, onAboutClick,
onLogoutClick, onLogoutClick,
loggedInUser loggedInUser,
i18n
} = this.props; } = this.props;
return ( return (
<I18n> <Toolbar>
{({ i18n }) => ( <ToolbarGroup>
<Toolbar> <Tooltip position="left" content={<div>{i18n._(t`Info`)}</div>}>
<ToolbarGroup> <ToolbarItem>
<Tooltip position="left" content={<div>{i18n._(t`Info`)}</div>}> <Dropdown
<ToolbarItem> isPlain
<Dropdown isOpen={isHelpOpen}
isPlain position={DropdownPosition.right}
isOpen={isHelpOpen} onSelect={this.handleHelpSelect}
position={DropdownPosition.right} toggle={(
onSelect={this.handleHelpSelect} <DropdownToggle onToggle={this.handleHelpToggle}>
toggle={( <QuestionCircleIcon />
<DropdownToggle onToggle={this.handleHelpToggle}> </DropdownToggle>
<QuestionCircleIcon /> )}
</DropdownToggle> dropdownItems={[
<DropdownItem key="help" target="_blank" href={DOCLINK}>
{i18n._(t`Help`)}
</DropdownItem>,
<DropdownItem
key="about"
component="button"
isDisabled={isAboutDisabled}
onClick={onAboutClick}
>
{i18n._(t`About`)}
</DropdownItem>
]}
/>
</ToolbarItem>
</Tooltip>
<Tooltip position="left" content={<div>User</div>}>
<ToolbarItem>
<Dropdown
isPlain
isOpen={isUserOpen}
position={DropdownPosition.right}
onSelect={this.handleUserSelect}
toggle={(
<DropdownToggle onToggle={this.handleUserToggle}>
<UserIcon />
{loggedInUser && (
<span style={{ marginLeft: '10px' }}>
{loggedInUser.username}
</span>
)} )}
dropdownItems={[ </DropdownToggle>
<DropdownItem key="help" target="_blank" href={DOCLINK}> )}
{i18n._(t`Help`)} dropdownItems={[
</DropdownItem>, <DropdownItem key="user" href="#/home">
<DropdownItem {i18n._(t`User Details`)}
key="about" </DropdownItem>,
component="button" <DropdownItem
isDisabled={isAboutDisabled} key="logout"
onClick={onAboutClick} component="button"
> onClick={onLogoutClick}
{i18n._(t`About`)} >
</DropdownItem> {i18n._(t`Logout`)}
]} </DropdownItem>
/> ]}
</ToolbarItem> />
</Tooltip> </ToolbarItem>
<Tooltip position="left" content={<div>User</div>}> </Tooltip>
<ToolbarItem> </ToolbarGroup>
<Dropdown </Toolbar>
isPlain
isOpen={isUserOpen}
position={DropdownPosition.right}
onSelect={this.handleUserSelect}
toggle={(
<DropdownToggle onToggle={this.handleUserToggle}>
<UserIcon />
{loggedInUser && (
<span style={{ marginLeft: '10px' }}>
{loggedInUser.username}
</span>
)}
</DropdownToggle>
)}
dropdownItems={[
<DropdownItem key="user" href="#/home">
{i18n._(t`User Details`)}
</DropdownItem>,
<DropdownItem
key="logout"
component="button"
onClick={onLogoutClick}
>
{i18n._(t`Logout`)}
</DropdownItem>
]}
/>
</ToolbarItem>
</Tooltip>
</ToolbarGroup>
</Toolbar>
)}
</I18n>
); );
} }
} }
@@ -143,4 +139,4 @@ PageHeaderToolbar.defaultProps = {
isAboutDisabled: false isAboutDisabled: false
}; };
export default PageHeaderToolbar; export default withI18n()(PageHeaderToolbar);

View File

@@ -14,8 +14,8 @@ import {
EmptyStateBody, EmptyStateBody,
} from '@patternfly/react-core'; } from '@patternfly/react-core';
import { CubesIcon } from '@patternfly/react-icons'; import { CubesIcon } from '@patternfly/react-icons';
import { I18n, i18nMark } from '@lingui/react'; import { withI18n } from '@lingui/react';
import { Trans, t } from '@lingui/macro'; import { t } from '@lingui/macro';
import { withRouter, Link } from 'react-router-dom'; import { withRouter, Link } from 'react-router-dom';
import Pagination from '../Pagination'; import Pagination from '../Pagination';
@@ -108,13 +108,15 @@ class PaginatedDataList extends React.Component {
showPageSizeOptions, showPageSizeOptions,
paginationStyling, paginationStyling,
location, location,
i18n
} = this.props; } = this.props;
const { error } = this.state; const { error } = this.state;
const [orderBy, sortOrder] = this.getSortOrder(); const [orderBy, sortOrder] = this.getSortOrder();
const queryParams = parseNamespacedQueryString(qsConfig, location.search); const queryParams = parseNamespacedQueryString(qsConfig, location.search);
const columns = toolbarColumns || [{ name: i18n._(t`Name`), key: 'name', isSortable: true }];
return ( return (
<I18n> <Fragment>
{({ i18n }) => ( {error && (
<Fragment> <Fragment>
{error && ( {error && (
<Fragment> <Fragment>
@@ -128,24 +130,10 @@ class PaginatedDataList extends React.Component {
<EmptyState> <EmptyState>
<EmptyStateIcon icon={CubesIcon} /> <EmptyStateIcon icon={CubesIcon} />
<Title size="lg"> <Title size="lg">
<Trans> {i18n._(t`No ${ucFirst(itemNamePlural || pluralize(itemName))} Found`)}
No
{' '}
{ucFirst(itemNamePlural || pluralize(itemName))}
{' '}
Found
</Trans>
</Title> </Title>
<EmptyStateBody> <EmptyStateBody>
<Trans> {i18n._(t`Please add ${getArticle(itemName)} ${itemName} to populate this list`)}
Please add
{' '}
{getArticle(itemName)}
{' '}
{itemName}
{' '}
to populate this list
</Trans>
</EmptyStateBody> </EmptyStateBody>
</EmptyState> </EmptyState>
) : ( ) : (
@@ -199,9 +187,67 @@ class PaginatedDataList extends React.Component {
/> />
</Fragment> </Fragment>
)} )}
</Fragment> // TODO: replace with proper error handling
)}
{items.length === 0 ? (
<EmptyState>
<EmptyStateIcon icon={CubesIcon} />
<Title size="lg">
{i18n._(t`No ${ucFirst(itemNamePlural || pluralize(itemName))} Found`)}
</Title>
<EmptyStateBody>
{i18n._(t`Please add ${getArticle(itemName)} ${itemName} to populate this list`)}
</EmptyStateBody>
</EmptyState>
) : (
<Fragment>
<DataListToolbar
sortedColumnKey={orderBy}
sortOrder={sortOrder}
columns={columns}
onSearch={() => { }}
onSort={this.handleSort}
showSelectAll={showSelectAll}
isAllSelected={isAllSelected}
onSelectAll={onSelectAll}
additionalControls={additionalControls}
/>
<DataList aria-label={i18n._(t`${ucFirst(pluralize(itemName))} List`)}>
{items.map(item => (renderItem ? renderItem(item) : (
<DataListItem
aria-labelledby={`items-list-item-${item.id}`}
key={item.id}
>
<DataListItemRow>
<DataListItemCells dataListCells={[
<DataListCell key="team-name">
<TextContent style={detailWrapperStyle}>
<Link to={{ pathname: item.url }}>
<Text
id={`items-list-item-${item.id}`}
style={detailLabelStyle}
>
{item.name}
</Text>
</Link>
</TextContent>
</DataListCell>
]}
/>
</DataListItemRow>
</DataListItem>
)))}
</DataList>
<Pagination
count={itemCount}
page={queryParams.page}
pageCount={this.getPageCount()}
page_size={queryParams.page_size}
onSetPage={this.handleSetPage}
/>
</Fragment> </Fragment>
)} )}
</I18n> </Fragment>
); );
} }
} }
@@ -235,9 +281,7 @@ PaginatedDataList.propTypes = {
PaginatedDataList.defaultProps = { PaginatedDataList.defaultProps = {
renderItem: null, renderItem: null,
toolbarColumns: [ toolbarColumns: [],
{ name: i18nMark('Name'), key: 'name', isSortable: true },
],
additionalControls: [], additionalControls: [],
itemName: 'item', itemName: 'item',
itemNamePlural: '', itemNamePlural: '',
@@ -250,4 +294,4 @@ PaginatedDataList.defaultProps = {
}; };
export { PaginatedDataList as _PaginatedDataList }; export { PaginatedDataList as _PaginatedDataList };
export default withRouter(PaginatedDataList); export default withI18n()(withRouter(PaginatedDataList));

View File

@@ -3,7 +3,7 @@ import { string, func } from 'prop-types';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import { Button as PFButton } from '@patternfly/react-core'; import { Button as PFButton } from '@patternfly/react-core';
import { PlusIcon } from '@patternfly/react-icons'; import { PlusIcon } from '@patternfly/react-icons';
import { I18n } from '@lingui/react'; import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro'; import { t } from '@lingui/macro';
import styled from 'styled-components'; import styled from 'styled-components';
@@ -20,39 +20,32 @@ const Button = styled(PFButton)`
} }
`; `;
function ToolbarAddButton ({ linkTo, onClick }) { function ToolbarAddButton ({ linkTo, onClick, i18n }) {
if (!linkTo && !onClick) { if (!linkTo && !onClick) {
throw new Error('ToolbarAddButton requires either `linkTo` or `onClick` prop'); throw new Error('ToolbarAddButton requires either `linkTo` or `onClick` prop');
} }
if (linkTo) { if (linkTo) {
// TODO: This should only be a <Link> (no <Button>) but CSS is off // TODO: This should only be a <Link> (no <Button>) but CSS is off
return ( return (
<I18n> <Link to={linkTo}>
{({ i18n }) => (
<Link to={linkTo}>
<Button
variant="primary"
aria-label={i18n._(t`Add`)}
>
<PlusIcon />
</Button>
</Link>
)}
</I18n>
);
}
return (
<I18n>
{({ i18n }) => (
<Button <Button
variant="primary" variant="primary"
aria-label={i18n._(t`Add`)} aria-label={i18n._(t`Add`)}
onClick={onClick}
> >
<PlusIcon /> <PlusIcon />
</Button> </Button>
)} </Link>
</I18n> );
}
return (
<Button
variant="primary"
aria-label={i18n._(t`Add`)}
onClick={onClick}
>
<PlusIcon />
</Button>
); );
} }
ToolbarAddButton.propTypes = { ToolbarAddButton.propTypes = {
@@ -64,4 +57,4 @@ ToolbarAddButton.defaultProps = {
onClick: null onClick: null
}; };
export default ToolbarAddButton; export default withI18n()(ToolbarAddButton);

View File

@@ -2,9 +2,9 @@ import React, { Fragment } from 'react';
import { func, bool, number, string, arrayOf, shape } from 'prop-types'; import { func, bool, number, string, arrayOf, shape } from 'prop-types';
import { Button as PFButton, Tooltip } from '@patternfly/react-core'; import { Button as PFButton, Tooltip } from '@patternfly/react-core';
import { TrashAltIcon } from '@patternfly/react-icons'; import { TrashAltIcon } from '@patternfly/react-icons';
import { I18n, i18nMark } from '@lingui/react';
import { Trans, t } from '@lingui/macro';
import styled from 'styled-components'; import styled from 'styled-components';
import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import AlertModal from '../AlertModal'; import AlertModal from '../AlertModal';
import { pluralize } from '../../util/strings'; import { pluralize } from '../../util/strings';
@@ -89,103 +89,95 @@ class ToolbarDeleteButton extends React.Component {
} }
renderTooltip () { renderTooltip () {
const { itemsToDelete, itemName } = this.props; const { itemsToDelete, itemName, i18n } = this.props;
const itemsUnableToDelete = itemsToDelete
.filter(cannotDelete)
.map(item => (
<div key={item.id}>
{item.name}
</div>
));
if (itemsToDelete.some(cannotDelete)) { if (itemsToDelete.some(cannotDelete)) {
return ( return (
<div> <div>
<Trans> {i18n._(t`You do not have permission to delete the following ${pluralize(itemName)}: ${itemsUnableToDelete}`)}
You dont have permission to delete the following
{' '}
{pluralize(itemName)}
:
</Trans>
{itemsToDelete
.filter(cannotDelete)
.map(item => (
<div key={item.id}>
{item.name}
</div>
))
}
</div> </div>
); );
} }
if (itemsToDelete.length) { if (itemsToDelete.length) {
return i18nMark('Delete'); return i18n._(t`Delete`);
} }
return i18nMark('Select a row to delete'); return i18n._(t`Select a row to delete`);
} }
render () { render () {
const { itemsToDelete, itemName } = this.props; const { itemsToDelete, itemName, i18n } = this.props;
const { isModalOpen } = this.state; const { isModalOpen } = this.state;
const isDisabled = itemsToDelete.length === 0 const isDisabled = itemsToDelete.length === 0
|| itemsToDelete.some(cannotDelete); || itemsToDelete.some(cannotDelete);
return ( return (
<I18n> <Fragment>
{({ i18n }) => ( <Tooltip
<Fragment> content={this.renderTooltip()}
<Tooltip position="left"
content={this.renderTooltip()} >
position="left" <Button
> className="awx-ToolBarBtn"
variant="plain"
aria-label={i18n._(t`Delete`)}
onClick={this.handleConfirmDelete}
isDisabled={isDisabled}
>
<TrashAltIcon className="awx-ToolBarTrashCanIcon" />
</Button>
</Tooltip>
{ isModalOpen && (
<AlertModal
variant="danger"
title={itemsToDelete === 1
? i18n._(t`Delete ${itemName}`)
: i18n._(t`Delete ${pluralize(itemName)}`)
}
isOpen={isModalOpen}
onClose={this.handleCancelDelete}
actions={[
<Button <Button
variant="plain" key="delete"
aria-label={i18n._(t`Delete`)}
onClick={this.handleConfirmDelete}
isDisabled={isDisabled}
>
<TrashAltIcon />
</Button>
</Tooltip>
{ isModalOpen && (
<AlertModal
variant="danger" variant="danger"
title={itemsToDelete === 1 aria-label={i18n._(t`confirm delete`)}
? i18n._(t`Delete ${itemName}`) onClick={this.handleDelete}
: i18n._(t`Delete ${pluralize(itemName)}`)
}
isOpen={isModalOpen}
onClose={this.handleCancelDelete}
actions={[
<Button
key="delete"
variant="danger"
aria-label={i18n._(t`confirm delete`)}
onClick={this.handleDelete}
>
{i18n._(t`Delete`)}
</Button>,
<Button
key="cancel"
variant="secondary"
aria-label={i18n._(t`cancel delete`)}
onClick={this.handleCancelDelete}
>
{i18n._(t`Cancel`)}
</Button>
]}
> >
{i18n._(t`Are you sure you want to delete:`)} {i18n._(t`Delete`)}
</Button>,
<Button
key="cancel"
variant="secondary"
aria-label={i18n._(t`cancel delete`)}
onClick={this.handleCancelDelete}
>
{i18n._(t`Cancel`)}
</Button>
]}
>
{i18n._(t`Are you sure you want to delete:`)}
<br />
{itemsToDelete.map((item) => (
<span key={item.id}>
<strong>
{item.name}
</strong>
<br /> <br />
{itemsToDelete.map((item) => ( </span>
<span key={item.id}> ))}
<strong> <br />
{item.name} </AlertModal>
</strong>
<br />
</span>
))}
<br />
</AlertModal>
)}
</Fragment>
)} )}
</I18n> </Fragment>
); );
} }
} }
export default ToolbarDeleteButton; export default withI18n()(ToolbarDeleteButton);

View File

@@ -1,7 +1,7 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { I18n } from '@lingui/react'; import { withI18n } from '@lingui/react';
import { Trans, t } from '@lingui/macro'; import { t } from '@lingui/macro';
import { import {
Button, Button,
Dropdown, Dropdown,
@@ -106,7 +106,8 @@ class Pagination extends Component {
page_size, page_size,
pageSizeOptions, pageSizeOptions,
showPageSizeOptions, showPageSizeOptions,
style style,
i18n
} = this.props; } = this.props;
const { value, isOpen } = this.state; const { value, isOpen } = this.state;
let opts = []; let opts = [];
@@ -135,98 +136,89 @@ class Pagination extends Component {
)); ));
return ( return (
<I18n> <div className="awx-pagination" style={style}>
{({ i18n }) => ( {showPageSizeOptions && (
<div className="awx-pagination" style={style}> <div className="awx-pagination__page-size-selection">
{showPageSizeOptions && ( {i18n._(t`Items Per Page`)}
<div className="awx-pagination__page-size-selection"> <Dropdown
<Trans>Items Per Page</Trans> onToggle={this.onTogglePageSize}
<Dropdown onSelect={this.onSelectPageSize}
direction={up}
isOpen={isOpen}
toggle={(
<DropdownToggle
className="togglePageSize"
onToggle={this.onTogglePageSize} onToggle={this.onTogglePageSize}
onSelect={this.onSelectPageSize} >
direction={up} {page_size}
isOpen={isOpen} </DropdownToggle>
toggle={(
<DropdownToggle
className="togglePageSize"
onToggle={this.onTogglePageSize}
>
{page_size}
</DropdownToggle>
)}
dropdownItems={dropdownItems}
/>
</div>
)}
<div className="awx-pagination__counts">
<div className="awx-pagination__item-count">
<Trans>{`Items ${itemMin} ${itemMax} of ${count}`}</Trans>
</div>
{pageCount !== 1 && (
<div className="awx-pagination__page-count">
<div className="pf-c-input-group pf-m-previous">
<Button
className="awx-pagination__page-button"
variant="tertiary"
aria-label={i18n._(t`First`)}
isDisabled={isOnFirst}
onClick={this.onFirst}
>
<i className="fas fa-angle-double-left" />
</Button>
<Button
className="awx-pagination__page-button"
variant="tertiary"
aria-label={i18n._(t`Previous`)}
isDisabled={isOnFirst}
onClick={this.onPrevious}
>
<i className="fas fa-angle-left" />
</Button>
</div>
<form
className="awx-pagination__page-input-form"
onSubmit={this.onSubmit}
>
<Trans>
{'Page '}
<TextInput
className="awx-pagination__page-input"
aria-label={i18n._(t`Page Number`)}
value={value}
type="text"
onChange={this.onPageChange}
/>
{' of '}
{pageCount}
</Trans>
</form>
<div className="pf-c-input-group">
<Button
className="awx-pagination__page-button"
variant="tertiary"
aria-label={i18n._(t`Next`)}
isDisabled={isOnLast}
onClick={this.onNext}
>
<i className="fas fa-angle-right" />
</Button>
<Button
className="awx-pagination__page-button"
variant="tertiary"
aria-label={i18n._(t`Last`)}
isDisabled={isOnLast}
onClick={this.onLast}
>
<i className="fas fa-angle-double-right" />
</Button>
</div>
</div>
)} )}
</div> dropdownItems={dropdownItems}
/>
</div> </div>
)} )}
</I18n> <div className="awx-pagination__counts">
<div className="awx-pagination__item-count">
{i18n._(t`Items ${itemMin} ${itemMax} of ${count}`)}
</div>
{pageCount !== 1 && (
<div className="awx-pagination__page-count">
<div className="pf-c-input-group pf-m-previous">
<Button
className="awx-pagination__page-button"
variant="tertiary"
aria-label={i18n._(t`First`)}
isDisabled={isOnFirst}
onClick={this.onFirst}
>
<i className="fas fa-angle-double-left" />
</Button>
<Button
className="awx-pagination__page-button"
variant="tertiary"
aria-label={i18n._(t`Previous`)}
isDisabled={isOnFirst}
onClick={this.onPrevious}
>
<i className="fas fa-angle-left" />
</Button>
</div>
<form
className="awx-pagination__page-input-form"
onSubmit={this.onSubmit}
>
{i18n._(t`Page ${(<TextInput
className="awx-pagination__page-input"
aria-label={i18n._(t`Page Number`)}
value={value}
type="text"
onChange={this.onPageChange}
/>)} of ${pageCount}`)}
</form>
<div className="pf-c-input-group">
<Button
className="awx-pagination__page-button"
variant="tertiary"
aria-label={i18n._(t`Next`)}
isDisabled={isOnLast}
onClick={this.onNext}
>
<i className="fas fa-angle-right" />
</Button>
<Button
className="awx-pagination__page-button"
variant="tertiary"
aria-label={i18n._(t`Last`)}
isDisabled={isOnLast}
onClick={this.onLast}
>
<i className="fas fa-angle-double-right" />
</Button>
</div>
</div>
)}
</div>
</div>
); );
} }
} }
@@ -248,4 +240,4 @@ Pagination.defaultProps = {
showPageSizeOptions: true showPageSizeOptions: true
}; };
export default Pagination; export default withI18n()(Pagination);

View File

@@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { I18n } from '@lingui/react'; import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro'; import { t } from '@lingui/macro';
import { import {
Button as PFButton, Button as PFButton,
@@ -90,7 +90,8 @@ class Search extends React.Component {
render () { render () {
const { up } = DropdownPosition; const { up } = DropdownPosition;
const { const {
columns columns,
i18n
} = this.props; } = this.props;
const { const {
isSearchDropdownOpen, isSearchDropdownOpen,
@@ -109,41 +110,37 @@ class Search extends React.Component {
)); ));
return ( return (
<I18n> <div className="pf-c-input-group">
{({ i18n }) => ( <Dropdown
<div className="pf-c-input-group"> onToggle={this.handleDropdownToggle}
<Dropdown onSelect={this.handleDropdownSelect}
direction={up}
isOpen={isSearchDropdownOpen}
toggle={(
<DropdownToggle
id="awx-search"
onToggle={this.handleDropdownToggle} onToggle={this.handleDropdownToggle}
onSelect={this.handleDropdownSelect}
direction={up}
isOpen={isSearchDropdownOpen}
toggle={(
<DropdownToggle
id="awx-search"
onToggle={this.handleDropdownToggle}
>
{searchColumnName}
</DropdownToggle>
)}
dropdownItems={searchDropdownItems}
/>
<TextInput
type="search"
aria-label="Search text input"
value={searchValue}
onChange={this.handleSearchInputChange}
style={{ height: '30px' }}
/>
<Button
variant="tertiary"
aria-label={i18n._(t`Search`)}
onClick={this.handleSearch}
> >
<SearchIcon /> {searchColumnName}
</Button> </DropdownToggle>
</div> )}
)} dropdownItems={searchDropdownItems}
</I18n> />
<TextInput
type="search"
aria-label={i18n._(t`Search text input`)}
value={searchValue}
onChange={this.handleSearchInputChange}
style={{ height: '30px' }}
/>
<Button
variant="tertiary"
aria-label={i18n._(t`Search`)}
onClick={this.handleSearch}
>
<SearchIcon />
</Button>
</div>
); );
} }
} }
@@ -159,4 +156,4 @@ Search.defaultProps = {
sortedColumnKey: 'name' sortedColumnKey: 'name'
}; };
export default Search; export default withI18n()(Search);

View File

@@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { I18n } from '@lingui/react'; import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro'; import { t } from '@lingui/macro';
import { import {
Button, Button,
@@ -85,7 +85,8 @@ class Sort extends React.Component {
const { const {
columns, columns,
sortedColumnKey, sortedColumnKey,
sortOrder sortOrder,
i18n
} = this.props; } = this.props;
const { const {
isSortDropdownOpen isSortDropdownOpen
@@ -109,40 +110,36 @@ class Sort extends React.Component {
} }
return ( return (
<I18n> <React.Fragment>
{({ i18n }) => ( { sortDropdownItems.length > 1 && (
<React.Fragment> <Dropdown
{ sortDropdownItems.length > 1 && ( style={{ marginRight: '20px' }}
<Dropdown onToggle={this.handleDropdownToggle}
style={{ marginRight: '20px' }} onSelect={this.handleDropdownSelect}
direction={up}
isOpen={isSortDropdownOpen}
toggle={(
<DropdownToggle
id="awx-sort"
onToggle={this.handleDropdownToggle} onToggle={this.handleDropdownToggle}
onSelect={this.handleDropdownSelect} >
direction={up} {sortedColumnName}
isOpen={isSortDropdownOpen} </DropdownToggle>
toggle={(
<DropdownToggle
id="awx-sort"
onToggle={this.handleDropdownToggle}
>
{sortedColumnName}
</DropdownToggle>
)}
dropdownItems={sortDropdownItems}
/>
)} )}
<Button dropdownItems={sortDropdownItems}
onClick={this.handleSort} />
variant="plain"
aria-label={i18n._(t`Sort`)}
css="padding: 0;"
>
<IconWrapper>
<SortIcon />
</IconWrapper>
</Button>
</React.Fragment>
)} )}
</I18n> <Button
onClick={this.handleSort}
variant="plain"
aria-label={i18n._(t`Sort`)}
css="padding: 0;"
>
<IconWrapper>
<SortIcon />
</IconWrapper>
</Button>
</React.Fragment>
); );
} }
} }
@@ -160,4 +157,4 @@ Sort.defaultProps = {
sortedColumnKey: 'name' sortedColumnKey: 'name'
}; };
export default Sort; export default withI18n()(Sort);

View File

@@ -1,7 +1,7 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { withRouter } from 'react-router-dom'; import { withRouter } from 'react-router-dom';
import { I18n } from '@lingui/react'; import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro'; import { t } from '@lingui/macro';
import { Brand } from '@patternfly/react-core'; import { Brand } from '@patternfly/react-core';
@@ -34,6 +34,7 @@ class TowerLogo extends Component {
render () { render () {
const { hover } = this.state; const { hover } = this.state;
const { i18n } = this.props;
let src = TowerLogoHeader; let src = TowerLogoHeader;
@@ -42,19 +43,15 @@ class TowerLogo extends Component {
} }
return ( return (
<I18n> <Brand
{({ i18n }) => ( src={src}
<Brand alt={i18n._(t`Tower Brand Image`)}
src={src} onMouseOut={this.onHover}
alt={i18n._(t`Tower Brand Image`)} onMouseOver={this.onHover}
onMouseOut={this.onHover} onBlur={this.onHover}
onMouseOver={this.onHover} onFocus={this.onHover}
onBlur={this.onHover} onClick={this.onClick}
onFocus={this.onHover} />
onClick={this.onClick}
/>
)}
</I18n>
); );
} }
} }
@@ -67,4 +64,4 @@ TowerLogo.defaultProps = {
linkTo: null, linkTo: null,
}; };
export default withRouter(TowerLogo); export default withI18n()(withRouter(TowerLogo));

View File

@@ -4,7 +4,8 @@ import React, { Component } from 'react';
import { withRouter } from 'react-router-dom'; import { withRouter } from 'react-router-dom';
import { i18nMark } from '@lingui/react'; import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import { withRootDialog } from './RootDialog'; import { withRootDialog } from './RootDialog';
@@ -33,27 +34,27 @@ class Provider extends Component {
} }
handle401 () { handle401 () {
const { handle401, history, setRootDialogMessage } = this.props; const { handle401, history, setRootDialogMessage, i18n } = this.props;
if (handle401) { if (handle401) {
handle401(); handle401();
return; return;
} }
history.replace('/login'); history.replace('/login');
setRootDialogMessage({ setRootDialogMessage({
bodyText: i18nMark('You have been logged out.') bodyText: i18n._(t`You have been logged out.`)
}); });
} }
handle404 () { handle404 () {
const { handle404, history, setRootDialogMessage } = this.props; const { handle404, history, setRootDialogMessage, i18n } = this.props;
if (handle404) { if (handle404) {
handle404(); handle404();
return; return;
} }
history.replace('/home'); history.replace('/home');
setRootDialogMessage({ setRootDialogMessage({
title: i18nMark('404'), title: i18n._(t`404`),
bodyText: i18nMark('Cannot find resource.'), bodyText: i18n._(t`Cannot find resource.`),
variant: 'warning' variant: 'warning'
}); });
} }
@@ -72,7 +73,7 @@ class Provider extends Component {
} }
export { Provider as _NetworkProvider }; export { Provider as _NetworkProvider };
export const NetworkProvider = withRootDialog(withRouter(Provider)); export const NetworkProvider = withI18n()(withRootDialog(withRouter(Provider)));
export function withNetwork (Child) { export function withNetwork (Child) {
return (props) => ( return (props) => (

View File

@@ -1,5 +1,6 @@
import React, { Component, Fragment } from 'react'; import React, { Component, Fragment } from 'react';
import { Trans } from '@lingui/macro'; import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import { import {
PageSection, PageSection,
PageSectionVariants, PageSectionVariants,
@@ -8,13 +9,14 @@ import {
class Applications extends Component { class Applications extends Component {
render () { render () {
const { i18n } = this.props;
const { light, medium } = PageSectionVariants; const { light, medium } = PageSectionVariants;
return ( return (
<Fragment> <Fragment>
<PageSection variant={light} className="pf-m-condensed"> <PageSection variant={light} className="pf-m-condensed">
<Title size="2xl"> <Title size="2xl">
<Trans>Applications</Trans> {i18n._(t`Applications`)}
</Title> </Title>
</PageSection> </PageSection>
<PageSection variant={medium} /> <PageSection variant={medium} />
@@ -23,4 +25,4 @@ class Applications extends Component {
} }
} }
export default Applications; export default withI18n()(Applications);

View File

@@ -1,5 +1,6 @@
import React, { Component, Fragment } from 'react'; import React, { Component, Fragment } from 'react';
import { Trans } from '@lingui/macro'; import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import { import {
PageSection, PageSection,
PageSectionVariants, PageSectionVariants,
@@ -8,13 +9,14 @@ import {
class AuthSettings extends Component { class AuthSettings extends Component {
render () { render () {
const { i18n } = this.props;
const { light, medium } = PageSectionVariants; const { light, medium } = PageSectionVariants;
return ( return (
<Fragment> <Fragment>
<PageSection variant={light} className="pf-m-condensed"> <PageSection variant={light} className="pf-m-condensed">
<Title size="2xl"> <Title size="2xl">
<Trans>Authentication Settings</Trans> {i18n._(t`Authentication Settings`)}
</Title> </Title>
</PageSection> </PageSection>
<PageSection variant={medium} /> <PageSection variant={medium} />
@@ -23,4 +25,4 @@ class AuthSettings extends Component {
} }
} }
export default AuthSettings; export default withI18n()(AuthSettings);

View File

@@ -1,5 +1,6 @@
import React, { Component, Fragment } from 'react'; import React, { Component, Fragment } from 'react';
import { Trans } from '@lingui/macro'; import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import { import {
PageSection, PageSection,
PageSectionVariants, PageSectionVariants,
@@ -8,13 +9,14 @@ import {
class CredentialTypes extends Component { class CredentialTypes extends Component {
render () { render () {
const { i18n } = this.props;
const { light, medium } = PageSectionVariants; const { light, medium } = PageSectionVariants;
return ( return (
<Fragment> <Fragment>
<PageSection variant={light} className="pf-m-condensed"> <PageSection variant={light} className="pf-m-condensed">
<Title size="2xl"> <Title size="2xl">
<Trans>Credential Types</Trans> {i18n._(t`Credential Types`)}
</Title> </Title>
</PageSection> </PageSection>
<PageSection variant={medium} /> <PageSection variant={medium} />
@@ -23,4 +25,4 @@ class CredentialTypes extends Component {
} }
} }
export default CredentialTypes; export default withI18n()(CredentialTypes);

View File

@@ -1,5 +1,6 @@
import React, { Component, Fragment } from 'react'; import React, { Component, Fragment } from 'react';
import { Trans } from '@lingui/macro'; import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import { import {
PageSection, PageSection,
PageSectionVariants, PageSectionVariants,
@@ -8,13 +9,14 @@ import {
class Credentials extends Component { class Credentials extends Component {
render () { render () {
const { i18n } = this.props;
const { light, medium } = PageSectionVariants; const { light, medium } = PageSectionVariants;
return ( return (
<Fragment> <Fragment>
<PageSection variant={light} className="pf-m-condensed"> <PageSection variant={light} className="pf-m-condensed">
<Title size="2xl"> <Title size="2xl">
<Trans>Credentials</Trans> {i18n._(t`Credentials`)}
</Title> </Title>
</PageSection> </PageSection>
<PageSection variant={medium} /> <PageSection variant={medium} />
@@ -23,4 +25,4 @@ class Credentials extends Component {
} }
} }
export default Credentials; export default withI18n()(Credentials);

View File

@@ -1,5 +1,6 @@
import React, { Component, Fragment } from 'react'; import React, { Component, Fragment } from 'react';
import { Trans } from '@lingui/macro'; import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import { import {
PageSection, PageSection,
PageSectionVariants, PageSectionVariants,
@@ -8,13 +9,14 @@ import {
class Dashboard extends Component { class Dashboard extends Component {
render () { render () {
const { i18n } = this.props;
const { light, medium } = PageSectionVariants; const { light, medium } = PageSectionVariants;
return ( return (
<Fragment> <Fragment>
<PageSection variant={light} className="pf-m-condensed"> <PageSection variant={light} className="pf-m-condensed">
<Title size="2xl"> <Title size="2xl">
<Trans>Dashboard</Trans> {i18n._(t`Dashboard`)}
</Title> </Title>
</PageSection> </PageSection>
<PageSection variant={medium} /> <PageSection variant={medium} />
@@ -23,4 +25,4 @@ class Dashboard extends Component {
} }
} }
export default Dashboard; export default withI18n()(Dashboard);

View File

@@ -1,5 +1,6 @@
import React, { Component, Fragment } from 'react'; import React, { Component, Fragment } from 'react';
import { Trans } from '@lingui/macro'; import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import { import {
PageSection, PageSection,
PageSectionVariants, PageSectionVariants,
@@ -8,13 +9,14 @@ import {
class InstanceGroups extends Component { class InstanceGroups extends Component {
render () { render () {
const { i18n } = this.props;
const { light, medium } = PageSectionVariants; const { light, medium } = PageSectionVariants;
return ( return (
<Fragment> <Fragment>
<PageSection variant={light} className="pf-m-condensed"> <PageSection variant={light} className="pf-m-condensed">
<Title size="2xl"> <Title size="2xl">
<Trans>Instance Groups</Trans> {i18n._(t`Instance Groups`)}
</Title> </Title>
</PageSection> </PageSection>
<PageSection variant={medium} /> <PageSection variant={medium} />
@@ -23,4 +25,4 @@ class InstanceGroups extends Component {
} }
} }
export default InstanceGroups; export default withI18n()(InstanceGroups);

View File

@@ -1,5 +1,6 @@
import React, { Component, Fragment } from 'react'; import React, { Component, Fragment } from 'react';
import { Trans } from '@lingui/macro'; import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import { import {
PageSection, PageSection,
PageSectionVariants, PageSectionVariants,
@@ -8,13 +9,14 @@ import {
class Inventories extends Component { class Inventories extends Component {
render () { render () {
const { i18n } = this.props;
const { light, medium } = PageSectionVariants; const { light, medium } = PageSectionVariants;
return ( return (
<Fragment> <Fragment>
<PageSection variant={light} className="pf-m-condensed"> <PageSection variant={light} className="pf-m-condensed">
<Title size="2xl"> <Title size="2xl">
<Trans>Inventories</Trans> {i18n._(t`Inventories`)}
</Title> </Title>
</PageSection> </PageSection>
<PageSection variant={medium} /> <PageSection variant={medium} />
@@ -23,4 +25,4 @@ class Inventories extends Component {
} }
} }
export default Inventories; export default withI18n()(Inventories);

View File

@@ -1,5 +1,6 @@
import React, { Component, Fragment } from 'react'; import React, { Component, Fragment } from 'react';
import { Trans } from '@lingui/macro'; import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import { import {
PageSection, PageSection,
PageSectionVariants, PageSectionVariants,
@@ -8,13 +9,14 @@ import {
class InventoryScripts extends Component { class InventoryScripts extends Component {
render () { render () {
const { i18n } = this.props;
const { light, medium } = PageSectionVariants; const { light, medium } = PageSectionVariants;
return ( return (
<Fragment> <Fragment>
<PageSection variant={light} className="pf-m-condensed"> <PageSection variant={light} className="pf-m-condensed">
<Title size="2xl"> <Title size="2xl">
<Trans>Inventory Scripts</Trans> {i18n._(t`Inventory Scripts`)}
</Title> </Title>
</PageSection> </PageSection>
<PageSection variant={medium} /> <PageSection variant={medium} />
@@ -23,4 +25,4 @@ class InventoryScripts extends Component {
} }
} }
export default InventoryScripts; export default withI18n()(InventoryScripts);

View File

@@ -1,5 +1,6 @@
import React, { Component, Fragment } from 'react'; import React, { Component, Fragment } from 'react';
import { Trans } from '@lingui/macro'; import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import { import {
PageSection, PageSection,
PageSectionVariants, PageSectionVariants,
@@ -8,13 +9,14 @@ import {
class Jobs extends Component { class Jobs extends Component {
render () { render () {
const { i18n } = this.props;
const { light, medium } = PageSectionVariants; const { light, medium } = PageSectionVariants;
return ( return (
<Fragment> <Fragment>
<PageSection variant={light} className="pf-m-condensed"> <PageSection variant={light} className="pf-m-condensed">
<Title size="2xl"> <Title size="2xl">
<Trans>Jobs</Trans> {i18n._(t`Jobs`)}
</Title> </Title>
</PageSection> </PageSection>
<PageSection variant={medium} /> <PageSection variant={medium} />
@@ -23,4 +25,4 @@ class Jobs extends Component {
} }
} }
export default Jobs; export default withI18n()(Jobs);

View File

@@ -1,5 +1,6 @@
import React, { Component, Fragment } from 'react'; import React, { Component, Fragment } from 'react';
import { Trans } from '@lingui/macro'; import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import { import {
PageSection, PageSection,
PageSectionVariants, PageSectionVariants,
@@ -8,13 +9,14 @@ import {
class JobsSettings extends Component { class JobsSettings extends Component {
render () { render () {
const { i18n } = this.props;
const { light, medium } = PageSectionVariants; const { light, medium } = PageSectionVariants;
return ( return (
<Fragment> <Fragment>
<PageSection variant={light} className="pf-m-condensed"> <PageSection variant={light} className="pf-m-condensed">
<Title size="2xl"> <Title size="2xl">
<Trans>Jobs Settings</Trans> {i18n._(t`Jobs Settings`)}
</Title> </Title>
</PageSection> </PageSection>
<PageSection variant={medium} /> <PageSection variant={medium} />
@@ -23,4 +25,4 @@ class JobsSettings extends Component {
} }
} }
export default JobsSettings; export default withI18n()(JobsSettings);

View File

@@ -1,5 +1,6 @@
import React, { Component, Fragment } from 'react'; import React, { Component, Fragment } from 'react';
import { Trans } from '@lingui/macro'; import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import { import {
PageSection, PageSection,
PageSectionVariants, PageSectionVariants,
@@ -8,13 +9,14 @@ import {
class License extends Component { class License extends Component {
render () { render () {
const { i18n } = this.props;
const { light, medium } = PageSectionVariants; const { light, medium } = PageSectionVariants;
return ( return (
<Fragment> <Fragment>
<PageSection variant={light} className="pf-m-condensed"> <PageSection variant={light} className="pf-m-condensed">
<Title size="2xl"> <Title size="2xl">
<Trans>License</Trans> {i18n._(t`License`)}
</Title> </Title>
</PageSection> </PageSection>
<PageSection variant={medium} /> <PageSection variant={medium} />
@@ -23,4 +25,4 @@ class License extends Component {
} }
} }
export default License; export default withI18n()(License);

View File

@@ -1,6 +1,6 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import { Redirect, withRouter } from 'react-router-dom'; import { Redirect, withRouter } from 'react-router-dom';
import { I18n } from '@lingui/react'; import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro'; import { t } from '@lingui/macro';
import { import {
LoginForm, LoginForm,
@@ -62,7 +62,7 @@ class AWXLogin extends Component {
render () { render () {
const { username, password, isInputValid, isAuthenticated } = this.state; const { username, password, isInputValid, isAuthenticated } = this.state;
const { alt, loginInfo, logo, bodyText: errorMessage } = this.props; const { alt, loginInfo, logo, bodyText: errorMessage, i18n } = this.props;
const logoSrc = logo ? `data:image/jpeg;${logo}` : towerLogo; const logoSrc = logo ? `data:image/jpeg;${logo}` : towerLogo;
if (isAuthenticated) { if (isAuthenticated) {
@@ -70,34 +70,30 @@ class AWXLogin extends Component {
} }
return ( return (
<I18n> <LoginPage
{({ i18n }) => ( brandImgSrc={logoSrc}
<LoginPage brandImgAlt={alt || 'Ansible Tower'}
brandImgSrc={logoSrc} loginTitle={i18n._(t`Welcome to Ansible Tower! Please Sign In.`)}
brandImgAlt={alt || 'Ansible Tower'} textContent={loginInfo}
loginTitle={i18n._(t`Welcome to Ansible Tower! Please Sign In.`)} >
textContent={loginInfo} <LoginForm
> className={errorMessage && 'pf-m-error'}
<LoginForm usernameLabel={i18n._(t`Username`)}
className={errorMessage && 'pf-m-error'} passwordLabel={i18n._(t`Password`)}
usernameLabel={i18n._(t`Username`)} showHelperText={!isInputValid || !!errorMessage}
passwordLabel={i18n._(t`Password`)} helperText={errorMessage || i18n._(t`Invalid username or password. Please try again.`)}
showHelperText={!isInputValid || !!errorMessage} usernameValue={username}
helperText={errorMessage || i18n._(t`Invalid username or password. Please try again.`)} passwordValue={password}
usernameValue={username} isValidUsername={isInputValid}
passwordValue={password} isValidPassword={isInputValid}
isValidUsername={isInputValid} onChangeUsername={this.onChangeUsername}
isValidPassword={isInputValid} onChangePassword={this.onChangePassword}
onChangeUsername={this.onChangeUsername} onLoginButtonClick={this.onLoginButtonClick}
onChangePassword={this.onChangePassword} />
onLoginButtonClick={this.onLoginButtonClick} </LoginPage>
/>
</LoginPage>
)}
</I18n>
); );
} }
} }
export { AWXLogin as _AWXLogin }; export { AWXLogin as _AWXLogin };
export default withNetwork(withRootDialog(withRouter(AWXLogin))); export default withI18n()(withNetwork(withRootDialog(withRouter(AWXLogin))));

View File

@@ -1,5 +1,6 @@
import React, { Component, Fragment } from 'react'; import React, { Component, Fragment } from 'react';
import { Trans } from '@lingui/macro'; import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import { import {
PageSection, PageSection,
PageSectionVariants, PageSectionVariants,
@@ -8,13 +9,14 @@ import {
class ManagementJobs extends Component { class ManagementJobs extends Component {
render () { render () {
const { i18n } = this.props;
const { light, medium } = PageSectionVariants; const { light, medium } = PageSectionVariants;
return ( return (
<Fragment> <Fragment>
<PageSection variant={light} className="pf-m-condensed"> <PageSection variant={light} className="pf-m-condensed">
<Title size="2xl"> <Title size="2xl">
<Trans>Management Jobs</Trans> {i18n._(t`Management Jobs`)}
</Title> </Title>
</PageSection> </PageSection>
<PageSection variant={medium} /> <PageSection variant={medium} />
@@ -23,4 +25,4 @@ class ManagementJobs extends Component {
} }
} }
export default ManagementJobs; export default withI18n()(ManagementJobs);

View File

@@ -1,5 +1,6 @@
import React, { Component, Fragment } from 'react'; import React, { Component, Fragment } from 'react';
import { Trans } from '@lingui/macro'; import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import { import {
PageSection, PageSection,
PageSectionVariants, PageSectionVariants,
@@ -8,13 +9,14 @@ import {
class NotificationTemplates extends Component { class NotificationTemplates extends Component {
render () { render () {
const { i18n } = this.props;
const { light, medium } = PageSectionVariants; const { light, medium } = PageSectionVariants;
return ( return (
<Fragment> <Fragment>
<PageSection variant={light} className="pf-m-condensed"> <PageSection variant={light} className="pf-m-condensed">
<Title size="2xl"> <Title size="2xl">
<Trans>Notification Templates</Trans> {i18n._(t`Notification Templates`)}
</Title> </Title>
</PageSection> </PageSection>
<PageSection variant={medium} /> <PageSection variant={medium} />
@@ -23,4 +25,4 @@ class NotificationTemplates extends Component {
} }
} }
export default NotificationTemplates; export default withI18n()(NotificationTemplates);

View File

@@ -1,7 +1,7 @@
import React, { Component, Fragment } from 'react'; import React, { Component, Fragment } from 'react';
import { Route, withRouter, Switch } from 'react-router-dom'; import { Route, withRouter, Switch } from 'react-router-dom';
import { i18nMark } from '@lingui/react'; import { withI18n } from '@lingui/react';
import { Trans } from '@lingui/macro'; import { t } from '@lingui/macro';
import { Config } from '../../contexts/Config'; import { Config } from '../../contexts/Config';
import { NetworkProvider } from '../../contexts/Network'; import { NetworkProvider } from '../../contexts/Network';
@@ -14,34 +14,42 @@ import OrganizationAdd from './screens/OrganizationAdd';
import Organization from './screens/Organization/Organization'; import Organization from './screens/Organization/Organization';
class Organizations extends Component { class Organizations extends Component {
state = { constructor (props) {
breadcrumbConfig: { super(props);
'/organizations': i18nMark('Organizations'),
'/organizations/add': i18nMark('Create New Organization') const { i18n } = props;
}
}; this.state = {
breadcrumbConfig: {
'/organizations': i18n._(t`Organizations`),
'/organizations/add': i18n._(t`Create New Organization`)
}
};
}
setBreadcrumbConfig = (organization) => { setBreadcrumbConfig = (organization) => {
const { i18n } = this.props;
if (!organization) { if (!organization) {
return; return;
} }
const breadcrumbConfig = { const breadcrumbConfig = {
'/organizations': i18nMark('Organizations'), '/organizations': i18n._(t`Organizations`),
'/organizations/add': i18nMark('Create New Organization'), '/organizations/add': i18n._(t`Create New Organization`),
[`/organizations/${organization.id}`]: `${organization.name}`, [`/organizations/${organization.id}`]: `${organization.name}`,
[`/organizations/${organization.id}/edit`]: i18nMark('Edit Details'), [`/organizations/${organization.id}/edit`]: i18n._(t`Edit Details`),
[`/organizations/${organization.id}/details`]: i18nMark('Details'), [`/organizations/${organization.id}/details`]: i18n._(t`Details`),
[`/organizations/${organization.id}/access`]: i18nMark('Access'), [`/organizations/${organization.id}/access`]: i18n._(t`Access`),
[`/organizations/${organization.id}/teams`]: i18nMark('Teams'), [`/organizations/${organization.id}/teams`]: i18n._(t`Teams`),
[`/organizations/${organization.id}/notifications`]: i18nMark('Notifications'), [`/organizations/${organization.id}/notifications`]: i18n._(t`Notifications`),
}; };
this.setState({ breadcrumbConfig }); this.setState({ breadcrumbConfig });
} }
render () { render () {
const { match, history, location, setRootDialogMessage } = this.props; const { match, history, location, setRootDialogMessage, i18n } = this.props;
const { breadcrumbConfig } = this.state; const { breadcrumbConfig } = this.state;
return ( return (
@@ -65,11 +73,11 @@ class Organizations extends Component {
setRootDialogMessage({ setRootDialogMessage({
title: '404', title: '404',
bodyText: ( bodyText: (
<Trans> <Fragment>
Cannot find organization with ID {i18n._(t`Cannot find organization with ID`)}
<strong>{` ${newRouteMatch.params.id}`}</strong> <strong>{` ${newRouteMatch.params.id}`}</strong>
. .
</Trans> </Fragment>
), ),
variant: 'warning' variant: 'warning'
}); });
@@ -101,4 +109,4 @@ class Organizations extends Component {
} }
export { Organizations as _Organizations }; export { Organizations as _Organizations };
export default withRootDialog(withRouter(Organizations)); export default withI18n()(withRootDialog(withRouter(Organizations)));

View File

@@ -1,8 +1,8 @@
import React from 'react'; import React, { Fragment } from 'react';
import { func, string } from 'prop-types'; import { func, string } from 'prop-types';
import { Button } from '@patternfly/react-core'; import { Button } from '@patternfly/react-core';
import { I18n, i18nMark } from '@lingui/react'; import { withI18n } from '@lingui/react';
import { t, Trans } from '@lingui/macro'; import { t } from '@lingui/macro';
import AlertModal from '../../../components/AlertModal'; import AlertModal from '../../../components/AlertModal';
import { Role } from '../../../types'; import { Role } from '../../../types';
@@ -24,57 +24,43 @@ class DeleteRoleConfirmationModal extends React.Component {
} }
render () { render () {
const { role, username, onCancel, onConfirm } = this.props; const { role, username, onCancel, onConfirm, i18n } = this.props;
const title = `Remove ${this.isTeamRole() ? 'Team' : 'User'} Access`; const title = i18n._(t`Remove ${this.isTeamRole() ? i18n._(t`Team`) : i18n._(t`User`)} Access`);
return ( return (
<I18n> <AlertModal
{({ i18n }) => ( variant="danger"
<AlertModal title={title}
isOpen
onClose={onCancel}
actions={[
<Button
key="delete"
variant="danger" variant="danger"
title={i18nMark(title)} aria-label="Confirm delete"
isOpen onClick={onConfirm}
onClose={onCancel}
actions={[
<Button
key="delete"
variant="danger"
aria-label="Confirm delete"
onClick={onConfirm}
>
{i18n._(t`Delete`)}
</Button>,
<Button key="cancel" variant="secondary" onClick={onCancel}>
{i18n._(t`Cancel`)}
</Button>
]}
> >
{this.isTeamRole() ? ( {i18n._(t`Delete`)}
<Trans> </Button>,
Are you sure you want to remove <Button key="cancel" variant="secondary" onClick={onCancel}>
<b>{` ${role.name} `}</b> {i18n._(t`Cancel`)}
access from </Button>
<b>{` ${role.team_name}`}</b> ]}
? Doing so affects all members of the team. >
<br /> {this.isTeamRole() ? (
<br /> <Fragment>
If you {i18n._(t`Are you sure you want to remove ${role.name} access from ${role.team_name}? Doing so affects all members of the team.`)}
<b><i> only </i></b> <br />
want to remove access for this particular user, please remove them from the team. <br />
</Trans> {i18n._(t`If you ${(<b><i>only</i></b>)} want to remove access for this particular user, please remove them from the team.`)}
) : ( </Fragment>
<Trans> ) : (
Are you sure you want to remove <Fragment>
<b>{` ${role.name} `}</b> {i18n._(t`Are you sure you want to remove ${role.name} access from ${username}?`)}
access from </Fragment>
<b>{` ${username}`}</b>
?
</Trans>
)}
</AlertModal>
)} )}
</I18n> </AlertModal>
); );
} }
} }
export default DeleteRoleConfirmationModal; export default withI18n()(DeleteRoleConfirmationModal);

View File

@@ -1,20 +1,14 @@
import React, { Fragment } from 'react'; import React, { Fragment } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { I18n, i18nMark } from '@lingui/react'; import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import { FormGroup, Tooltip } from '@patternfly/react-core'; import { FormGroup, Tooltip } from '@patternfly/react-core';
import { QuestionCircleIcon } from '@patternfly/react-icons'; import { QuestionCircleIcon } from '@patternfly/react-icons';
import { t } from '@lingui/macro';
import Lookup from '../../../components/Lookup'; import Lookup from '../../../components/Lookup';
import { withNetwork } from '../../../contexts/Network'; import { withNetwork } from '../../../contexts/Network';
const INSTANCE_GROUPS_LOOKUP_COLUMNS = [
{ name: i18nMark('Name'), key: 'name', isSortable: true },
{ name: i18nMark('Modified'), key: 'modified', isSortable: false, isNumeric: true },
{ name: i18nMark('Created'), key: 'created', isSortable: false, isNumeric: true }
];
class InstanceGroupsLookup extends React.Component { class InstanceGroupsLookup extends React.Component {
constructor (props) { constructor (props) {
super(props); super(props);
@@ -29,43 +23,43 @@ class InstanceGroupsLookup extends React.Component {
} }
render () { render () {
const { value, tooltip, onChange } = this.props; const { value, tooltip, onChange, i18n } = this.props;
return ( return (
<I18n> <FormGroup
{({ i18n }) => ( label={(
<FormGroup <Fragment>
label={( {i18n._(t`Instance Groups`)}
<Fragment> {' '}
{i18n._(t`Instance Groups`)} {
{' '} tooltip && (
{ <Tooltip
tooltip && ( position="right"
<Tooltip content={tooltip}
position="right" >
content={tooltip} <QuestionCircleIcon />
> </Tooltip>
<QuestionCircleIcon /> )
</Tooltip> }
) </Fragment>
}
</Fragment>
)}
fieldId="org-instance-groups"
>
<Lookup
id="org-instance-groups"
lookupHeader={i18n._(t`Instance Groups`)}
name="instanceGroups"
value={value}
onLookupSave={onChange}
getItems={this.getInstanceGroups}
columns={INSTANCE_GROUPS_LOOKUP_COLUMNS}
sortedColumnKey="name"
/>
</FormGroup>
)} )}
</I18n> fieldId="org-instance-groups"
>
<Lookup
id="org-instance-groups"
lookupHeader={i18n._(t`Instance Groups`)}
name="instanceGroups"
value={value}
onLookupSave={onChange}
getItems={this.getInstanceGroups}
columns={[
{ name: i18n._(t`Name`), key: 'name', isSortable: true },
{ name: i18n._(t`Modified`), key: 'modified', isSortable: false, isNumeric: true },
{ name: i18n._(t`Created`), key: 'created', isSortable: false, isNumeric: true }
]}
sortedColumnKey="name"
/>
</FormGroup>
); );
} }
} }
@@ -80,4 +74,4 @@ InstanceGroupsLookup.defaultProps = {
tooltip: '', tooltip: '',
}; };
export default withNetwork(InstanceGroupsLookup); export default withI18n()(withNetwork(InstanceGroupsLookup));

View File

@@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import { func } from 'prop-types'; import { func } from 'prop-types';
import { I18n } from '@lingui/react'; import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro'; import { t } from '@lingui/macro';
import { import {
DataListItem, DataListItem,
@@ -81,96 +81,92 @@ class OrganizationAccessItem extends React.Component {
} }
render () { render () {
const { accessRecord, onRoleDelete } = this.props; const { accessRecord, onRoleDelete, i18n } = this.props;
const [teamRoles, userRoles] = this.getRoleLists(); const [teamRoles, userRoles] = this.getRoleLists();
return ( return (
<I18n> <DataListItem aria-labelledby="access-list-item" key={accessRecord.id}>
{({ i18n }) => ( <DataListItemRow>
<DataListItem aria-labelledby="access-list-item" key={accessRecord.id}> <DataListItemCells dataListCells={[
<DataListItemRow> <DataListCell key="name">
<DataListItemCells dataListCells={[ {accessRecord.username && (
<DataListCell key="name"> <TextContent style={detailWrapperStyle}>
{accessRecord.username && ( {accessRecord.url ? (
<TextContent style={detailWrapperStyle}> <Link to={{ pathname: accessRecord.url }}>
{accessRecord.url ? ( <Text component={TextVariants.h6} style={detailLabelStyle}>
<Link to={{ pathname: accessRecord.url }}> {accessRecord.username}
<Text component={TextVariants.h6} style={detailLabelStyle}> </Text>
{accessRecord.username} </Link>
</Text>
</Link>
) : (
<Text component={TextVariants.h6} style={detailLabelStyle}>
{accessRecord.username}
</Text>
)}
</TextContent>
)}
{accessRecord.first_name || accessRecord.last_name ? (
<Detail
label={i18n._(t`Name`)}
value={`${accessRecord.first_name} ${accessRecord.last_name}`}
url={null}
customStyles={null}
/>
) : ( ) : (
null <Text component={TextVariants.h6} style={detailLabelStyle}>
{accessRecord.username}
</Text>
)} )}
</DataListCell>, </TextContent>
<DataListCell key="roles"> )}
{userRoles.length > 0 && ( {accessRecord.first_name || accessRecord.last_name ? (
<ul style={userRolesWrapperStyle}> <Detail
<Text component={TextVariants.h6} style={detailLabelStyle}> label={i18n._(t`Name`)}
{i18n._(t`User Roles`)} value={`${accessRecord.first_name} ${accessRecord.last_name}`}
</Text> url={null}
{userRoles.map(role => ( customStyles={null}
role.user_capabilities.unattach ? ( />
<Chip ) : (
key={role.id} null
className="awx-c-chip" )}
onClick={() => { onRoleDelete(role, accessRecord); }} </DataListCell>,
> <DataListCell key="roles">
{role.name} {userRoles.length > 0 && (
</Chip> <ul style={userRolesWrapperStyle}>
) : ( <Text component={TextVariants.h6} style={detailLabelStyle}>
<BasicChip key={role.id}> {i18n._(t`User Roles`)}
{role.name} </Text>
</BasicChip> {userRoles.map(role => (
) role.user_capabilities.unattach ? (
))} <Chip
</ul> key={role.id}
)} className="awx-c-chip"
{teamRoles.length > 0 && ( onClick={() => { onRoleDelete(role, accessRecord); }}
<ul style={userRolesWrapperStyle}> >
<Text component={TextVariants.h6} style={detailLabelStyle}> {role.name}
{i18n._(t`Team Roles`)} </Chip>
</Text> ) : (
{teamRoles.map(role => ( <BasicChip key={role.id}>
role.user_capabilities.unattach ? ( {role.name}
<Chip </BasicChip>
key={role.id} )
className="awx-c-chip" ))}
onClick={() => { onRoleDelete(role, accessRecord); }} </ul>
> )}
{role.name} {teamRoles.length > 0 && (
</Chip> <ul style={userRolesWrapperStyle}>
) : ( <Text component={TextVariants.h6} style={detailLabelStyle}>
<BasicChip key={role.id}> {i18n._(t`Team Roles`)}
{role.name} </Text>
</BasicChip> {teamRoles.map(role => (
) role.user_capabilities.unattach ? (
))} <Chip
</ul> key={role.id}
)} className="awx-c-chip"
</DataListCell> onClick={() => { onRoleDelete(role, accessRecord); }}
]} >
/> {role.name}
</DataListItemRow> </Chip>
</DataListItem> ) : (
)} <BasicChip key={role.id}>
</I18n> {role.name}
</BasicChip>
)
))}
</ul>
)}
</DataListCell>
]}
/>
</DataListItemRow>
</DataListItem>
); );
} }
} }
export default OrganizationAccessItem; export default withI18n()(OrganizationAccessItem);

View File

@@ -2,7 +2,7 @@ import React, { Component } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { withRouter } from 'react-router-dom'; import { withRouter } from 'react-router-dom';
import { Formik, Field } from 'formik'; import { Formik, Field } from 'formik';
import { I18n } from '@lingui/react'; import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro'; import { t } from '@lingui/macro';
import { import {
Form, Form,
@@ -83,76 +83,72 @@ class OrganizationForm extends Component {
} }
render () { render () {
const { organization, handleCancel } = this.props; const { organization, handleCancel, i18n } = this.props;
const { instanceGroups, formIsValid, error } = this.state; const { instanceGroups, formIsValid, error } = this.state;
const defaultVenv = '/venv/ansible/'; const defaultVenv = '/venv/ansible/';
return ( return (
<I18n> <Formik
{({ i18n }) => ( initialValues={{
<Formik name: organization.name,
initialValues={{ description: organization.description,
name: organization.name, custom_virtualenv: organization.custom_virtualenv || '',
description: organization.description, }}
custom_virtualenv: organization.custom_virtualenv || '', onSubmit={this.handleSubmit}
}} render={formik => (
onSubmit={this.handleSubmit} <Form autoComplete="off" onSubmit={formik.handleSubmit}>
render={formik => ( <FormRow>
<Form autoComplete="off" onSubmit={formik.handleSubmit}> <FormField
<FormRow> id="org-name"
<FormField name="name"
id="org-name" type="text"
name="name" label={i18n._(t`Name`)}
type="text" validate={required(null, i18n)}
label={i18n._(t`Name`)} isRequired
validate={required()} />
isRequired <FormField
/> id="org-description"
<FormField name="description"
id="org-description" type="text"
name="description" label={i18n._(t`Description`)}
type="text" />
label={i18n._(t`Description`)} <Config>
/> {({ custom_virtualenvs }) => (
<Config> custom_virtualenvs && custom_virtualenvs.length > 1 && (
{({ custom_virtualenvs }) => ( <Field
custom_virtualenvs && custom_virtualenvs.length > 1 && ( name="custom_virtualenv"
<Field render={({ field }) => (
name="custom_virtualenv" <FormGroup
render={({ field }) => ( fieldId="org-custom-virtualenv"
<FormGroup label={i18n._(t`Ansible Environment`)}
fieldId="org-custom-virtualenv" >
label={i18n._(t`Ansible Environment`)} <AnsibleSelect
> data={custom_virtualenvs}
<AnsibleSelect defaultSelected={defaultVenv}
data={custom_virtualenvs} label={i18n._(t`Ansible Environment`)}
defaultSelected={defaultVenv} {...field}
label={i18n._(t`Ansible Environment`)} />
{...field} </FormGroup>
/> )}
</FormGroup> />
)} )
/> )}
) </Config>
)} </FormRow>
</Config> <InstanceGroupsLookup
</FormRow> value={instanceGroups}
<InstanceGroupsLookup onChange={this.handleInstanceGroupsChange}
value={instanceGroups} tooltip={i18n._(t`Select the Instance Groups for this Organization to run on.`)}
onChange={this.handleInstanceGroupsChange} />
tooltip={i18n._(t`Select the Instance Groups for this Organization to run on.`)} <FormActionGroup
/> onCancel={handleCancel}
<FormActionGroup onSubmit={formik.handleSubmit}
onCancel={handleCancel} submitDisabled={!formIsValid}
onSubmit={formik.handleSubmit} />
submitDisabled={!formIsValid} {error ? <div>error</div> : null}
/> </Form>
{error ? <div>error</div> : null}
</Form>
)}
/>
)} )}
</I18n> />
); );
} }
} }
@@ -176,4 +172,4 @@ OrganizationForm.contextTypes = {
}; };
export { OrganizationForm as _OrganizationForm }; export { OrganizationForm as _OrganizationForm };
export default withNetwork(withRouter(OrganizationForm)); export default withI18n()(withNetwork(withRouter(OrganizationForm)));

View File

@@ -1,6 +1,7 @@
import React from 'react'; import React from 'react';
import { string, bool, func } from 'prop-types'; import { string, bool, func } from 'prop-types';
import { Trans } from '@lingui/macro'; import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import { import {
Badge as PFBadge, Badge as PFBadge,
DataListItem, DataListItem,
@@ -62,6 +63,7 @@ class OrganizationListItem extends React.Component {
isSelected, isSelected,
onSelect, onSelect,
detailUrl, detailUrl,
i18n
} = this.props; } = this.props;
const labelId = `check-action-${organization.id}`; const labelId = `check-action-${organization.id}`;
return ( return (
@@ -86,13 +88,15 @@ class OrganizationListItem extends React.Component {
</DataListCell>, </DataListCell>,
<DataListCell key="org-members" righthalf="true" width={2}> <DataListCell key="org-members" righthalf="true" width={2}>
<ListGroup> <ListGroup>
<Trans>Members</Trans> {i18n._(t`Members`)}
<Badge isRead> <Badge isRead>
{organization.summary_fields.related_field_counts.users} {organization.summary_fields.related_field_counts.users}
</Badge> </Badge>
</ListGroup> </ListGroup>
</DataListCell>,
<DataListCell>
<ListGroup> <ListGroup>
<Trans>Teams</Trans> {i18n._(t`Teams`)}
<Badge isRead> <Badge isRead>
{organization.summary_fields.related_field_counts.teams} {organization.summary_fields.related_field_counts.teams}
</Badge> </Badge>
@@ -105,4 +109,4 @@ class OrganizationListItem extends React.Component {
); );
} }
} }
export default OrganizationListItem; export default withI18n()(OrganizationListItem);

View File

@@ -1,5 +1,5 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import { I18n, i18nMark } from '@lingui/react'; import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro'; import { t } from '@lingui/macro';
import { Switch, Route, withRouter, Redirect } from 'react-router-dom'; import { Switch, Route, withRouter, Redirect } from 'react-router-dom';
import { Card, CardHeader, PageSection } from '@patternfly/react-core'; import { Card, CardHeader, PageSection } from '@patternfly/react-core';
@@ -100,7 +100,8 @@ class Organization extends Component {
location, location,
match, match,
me, me,
history history,
i18n
} = this.props; } = this.props;
const { const {
@@ -126,14 +127,14 @@ class Organization extends Component {
); );
const tabsArray = [ const tabsArray = [
{ name: i18nMark('Details'), link: `${match.url}/details`, id: 0 }, { name: i18n._(t`Details`), link: `${match.url}/details`, id: 0 },
{ name: i18nMark('Access'), link: `${match.url}/access`, id: 1 }, { name: i18n._(t`Access`), link: `${match.url}/access`, id: 1 },
{ name: i18nMark('Teams'), link: `${match.url}/teams`, id: 2 } { name: i18n._(t`Teams`), link: `${match.url}/teams`, id: 2 }
]; ];
if (canSeeNotificationsTab) { if (canSeeNotificationsTab) {
tabsArray.push({ tabsArray.push({
name: i18nMark('Notifications'), name: i18n._(t`Notifications`),
link: `${match.url}/notifications`, link: `${match.url}/notifications`,
id: 3 id: 3
}); });
@@ -145,24 +146,18 @@ class Organization extends Component {
<CardHeader <CardHeader
style={tabsStyle} style={tabsStyle}
> >
<I18n> <div className="awx-orgTabs-container">
{({ i18n }) => ( <RoutedTabs
<React.Fragment> match={match}
<div className="awx-orgTabs-container"> history={history}
<RoutedTabs labeltext={i18n._(t`Organization detail tabs`)}
match={match} tabsArray={tabsArray}
history={history} />
labeltext={i18n._(t`Organization detail tabs`)} <CardCloseButton linkTo="/organizations" />
tabsArray={tabsArray} <div
/> className="awx-orgTabs__bottom-border"
<CardCloseButton linkTo="/organizations" /> />
<div </div>
className="awx-orgTabs__bottom-border"
/>
</div>
</React.Fragment>
)}
</I18n>
</CardHeader> </CardHeader>
)); ));
if (!match) { if (!match) {
@@ -245,5 +240,5 @@ class Organization extends Component {
); );
} }
} }
export default withNetwork(withRouter(Organization)); export default withI18n()(withNetwork(withRouter(Organization)));
export { Organization as _Organization }; export { Organization as _Organization };

View File

@@ -1,6 +1,7 @@
import React, { Fragment } from 'react'; import React, { Fragment } from 'react';
import { withRouter } from 'react-router-dom'; import { withRouter } from 'react-router-dom';
import { i18nMark } from '@lingui/react'; import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import PaginatedDataList, { ToolbarAddButton } from '../../../../components/PaginatedDataList'; import PaginatedDataList, { ToolbarAddButton } from '../../../../components/PaginatedDataList';
import OrganizationAccessItem from '../../components/OrganizationAccessItem'; import OrganizationAccessItem from '../../components/OrganizationAccessItem';
import DeleteRoleConfirmationModal from '../../components/DeleteRoleConfirmationModal'; import DeleteRoleConfirmationModal from '../../components/DeleteRoleConfirmationModal';
@@ -130,7 +131,7 @@ class OrganizationAccess extends React.Component {
} }
render () { render () {
const { api, organization } = this.props; const { api, organization, i18n } = this.props;
const { const {
isLoading, isLoading,
isInitialized, isInitialized,
@@ -167,9 +168,9 @@ class OrganizationAccess extends React.Component {
itemName="role" itemName="role"
qsConfig={QS_CONFIG} qsConfig={QS_CONFIG}
toolbarColumns={[ toolbarColumns={[
{ name: i18nMark('Name'), key: 'first_name', isSortable: true }, { name: i18n._(t`Name`), key: 'first_name', isSortable: true },
{ name: i18nMark('Username'), key: 'username', isSortable: true }, { name: i18n._(t`Username`), key: 'username', isSortable: true },
{ name: i18nMark('Last Name'), key: 'last_name', isSortable: true }, { name: i18n._(t`Last Name`), key: 'last_name', isSortable: true },
]} ]}
additionalControls={canEdit ? [ additionalControls={canEdit ? [
<ToolbarAddButton key="add" onClick={this.toggleAddModal} /> <ToolbarAddButton key="add" onClick={this.toggleAddModal} />
@@ -197,4 +198,4 @@ class OrganizationAccess extends React.Component {
} }
export { OrganizationAccess as _OrganizationAccess }; export { OrganizationAccess as _OrganizationAccess };
export default withNetwork(withRouter(OrganizationAccess)); export default withI18n()(withNetwork(withRouter(OrganizationAccess)));

View File

@@ -1,7 +1,7 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import { Link, withRouter } from 'react-router-dom'; import { Link, withRouter } from 'react-router-dom';
import { I18n } from '@lingui/react'; import { withI18n } from '@lingui/react';
import { Trans, t } from '@lingui/macro'; import { t } from '@lingui/macro';
import { import {
CardBody, CardBody,
@@ -103,7 +103,8 @@ class OrganizationDetail extends Component {
modified, modified,
summary_fields summary_fields
}, },
match match,
i18n
} = this.props; } = this.props;
const showOverflowChipAfter = 5; const showOverflowChipAfter = 5;
@@ -127,58 +128,54 @@ class OrganizationDetail extends Component {
) : null; ) : null;
return ( return (
<I18n> <CardBody>
{({ i18n }) => ( <div className="pf-l-grid pf-m-gutter pf-m-all-12-col-on-md pf-m-all-6-col-on-lg pf-m-all-4-col-on-xl">
<CardBody> <Detail
<div className="pf-l-grid pf-m-gutter pf-m-all-12-col-on-md pf-m-all-6-col-on-lg pf-m-all-4-col-on-xl"> label={i18n._(t`Name`)}
<Detail value={name}
label={i18n._(t`Name`)} />
value={name} <Detail
/> label={i18n._(t`Description`)}
<Detail value={description}
label={i18n._(t`Description`)} />
value={description} <Detail
/> label={i18n._(t`Ansible Environment`)}
<Detail value={custom_virtualenv}
label={i18n._(t`Ansible Environment`)} />
value={custom_virtualenv} <Detail
/> label={i18n._(t`Created`)}
<Detail value={created}
label={i18n._(t`Created`)} />
value={created} <Detail
/> label={i18n._(t`Last Modified`)}
<Detail value={modified}
label={i18n._(t`Last Modified`)} />
value={modified} {(instanceGroups && instanceGroups.length > 0) && (
/> <TextContent style={{ display: 'flex', gridColumn: '1 / -1' }}>
{(instanceGroups && instanceGroups.length > 0) && ( <Text
<TextContent style={{ display: 'flex', gridColumn: '1 / -1' }}> component={TextVariants.h6}
<Text style={detailLabelStyle}
component={TextVariants.h6} >
style={detailLabelStyle} {i18n._(t`Instance Groups`)}
> </Text>
<Trans>Instance Groups</Trans> <div style={detailValueStyle}>
</Text> {instanceGroupChips}
<div style={detailValueStyle}> {overflowChip}
{instanceGroupChips}
{overflowChip}
</div>
</TextContent>
)}
</div>
{summary_fields.user_capabilities.edit && (
<div style={{ display: 'flex', flexDirection: 'row-reverse', marginTop: '20px' }}>
<Link to={`/organizations/${match.params.id}/edit`}>
<Button><Trans>Edit</Trans></Button>
</Link>
</div> </div>
)} </TextContent>
{error ? 'error!' : ''} )}
</CardBody> </div>
{summary_fields.user_capabilities.edit && (
<div style={{ display: 'flex', flexDirection: 'row-reverse', marginTop: '20px' }}>
<Link to={`/organizations/${match.params.id}/edit`}>
<Button>{i18n._(t`Edit`)}</Button>
</Link>
</div>
)} )}
</I18n> {error ? 'error!' : ''}
</CardBody>
); );
} }
} }
export default withRouter(withNetwork(OrganizationDetail)); export default withI18n()(withRouter(withNetwork(OrganizationDetail)));

View File

@@ -1,7 +1,7 @@
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { withRouter } from 'react-router-dom'; import { withRouter } from 'react-router-dom';
import { I18n } from '@lingui/react'; import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro'; import { t } from '@lingui/macro';
import { import {
PageSection, PageSection,
@@ -57,30 +57,27 @@ class OrganizationAdd extends React.Component {
render () { render () {
const { error } = this.state; const { error } = this.state;
const { i18n } = this.props;
return ( return (
<PageSection> <PageSection>
<I18n> <Card>
{({ i18n }) => ( <CardHeader className="at-u-textRight">
<Card> <Tooltip
<CardHeader className="at-u-textRight"> content={i18n._(t`Close`)}
<Tooltip position="top"
content={i18n._(t`Close`)} >
position="top" <CardCloseButton onClick={this.handleCancel} />
> </Tooltip>
<CardCloseButton onClick={this.handleCancel} /> </CardHeader>
</Tooltip> <CardBody>
</CardHeader> <OrganizationForm
<CardBody> handleSubmit={this.handleSubmit}
<OrganizationForm handleCancel={this.handleCancel}
handleSubmit={this.handleSubmit} />
handleCancel={this.handleCancel} {error ? <div>error</div> : ''}
/> </CardBody>
{error ? <div>error</div> : ''} </Card>
</CardBody>
</Card>
)}
</I18n>
</PageSection> </PageSection>
); );
} }
@@ -95,4 +92,4 @@ OrganizationAdd.contextTypes = {
}; };
export { OrganizationAdd as _OrganizationAdd }; export { OrganizationAdd as _OrganizationAdd };
export default withNetwork(withRouter(OrganizationAdd)); export default withI18n()(withNetwork(withRouter(OrganizationAdd)));

View File

@@ -1,6 +1,7 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import { withRouter } from 'react-router-dom'; import { withRouter } from 'react-router-dom';
import { i18nMark } from '@lingui/react'; import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import { import {
Card, Card,
PageSection, PageSection,
@@ -15,12 +16,6 @@ import PaginatedDataList, {
import OrganizationListItem from '../components/OrganizationListItem'; import OrganizationListItem from '../components/OrganizationListItem';
import { getQSConfig, parseNamespacedQueryString } from '../../../util/qs'; import { getQSConfig, parseNamespacedQueryString } from '../../../util/qs';
const COLUMNS = [
{ name: i18nMark('Name'), key: 'name', isSortable: true },
{ name: i18nMark('Modified'), key: 'modified', isSortable: true, isNumeric: true },
{ name: i18nMark('Created'), key: 'created', isSortable: true, isNumeric: true },
];
const QS_CONFIG = getQSConfig('organization', { const QS_CONFIG = getQSConfig('organization', {
page: 1, page: 1,
page_size: 5, page_size: 5,
@@ -36,7 +31,7 @@ class OrganizationsList extends Component {
isLoading: true, isLoading: true,
isInitialized: false, isInitialized: false,
organizations: [], organizations: [],
selected: [], selected: []
}; };
this.handleSelectAll = this.handleSelectAll.bind(this); this.handleSelectAll = this.handleSelectAll.bind(this);
@@ -148,9 +143,9 @@ class OrganizationsList extends Component {
isLoading, isLoading,
isInitialized, isInitialized,
selected, selected,
organizations, organizations
} = this.state; } = this.state;
const { match } = this.props; const { match, i18n } = this.props;
const isAllSelected = selected.length === organizations.length; const isAllSelected = selected.length === organizations.length;
@@ -163,7 +158,11 @@ class OrganizationsList extends Component {
itemCount={itemCount} itemCount={itemCount}
itemName="organization" itemName="organization"
qsConfig={QS_CONFIG} qsConfig={QS_CONFIG}
toolbarColumns={COLUMNS} toolbarColumns={[
{ name: i18n._(t`Name`), key: 'name', isSortable: true },
{ name: i18n._(t`Modified`), key: 'modified', isSortable: true, isNumeric: true },
{ name: i18n._(t`Created`), key: 'created', isSortable: true, isNumeric: true },
]}
showSelectAll showSelectAll
isAllSelected={isAllSelected} isAllSelected={isAllSelected}
onSelectAll={this.handleSelectAll} onSelectAll={this.handleSelectAll}
@@ -198,4 +197,4 @@ class OrganizationsList extends Component {
} }
export { OrganizationsList as _OrganizationsList }; export { OrganizationsList as _OrganizationsList };
export default withNetwork(withRouter(OrganizationsList)); export default withI18n()(withNetwork(withRouter(OrganizationsList)));

View File

@@ -1,5 +1,6 @@
import React, { Component, Fragment } from 'react'; import React, { Component, Fragment } from 'react';
import { Trans } from '@lingui/macro'; import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import { import {
PageSection, PageSection,
PageSectionVariants, PageSectionVariants,
@@ -8,13 +9,14 @@ import {
class Portal extends Component { class Portal extends Component {
render () { render () {
const { i18n } = this.props;
const { light, medium } = PageSectionVariants; const { light, medium } = PageSectionVariants;
return ( return (
<Fragment> <Fragment>
<PageSection variant={light} className="pf-m-condensed"> <PageSection variant={light} className="pf-m-condensed">
<Title size="2xl"> <Title size="2xl">
<Trans>My View</Trans> {i18n._(t`My View`)}
</Title> </Title>
</PageSection> </PageSection>
<PageSection variant={medium} /> <PageSection variant={medium} />
@@ -23,4 +25,4 @@ class Portal extends Component {
} }
} }
export default Portal; export default withI18n()(Portal);

View File

@@ -1,5 +1,6 @@
import React, { Component, Fragment } from 'react'; import React, { Component, Fragment } from 'react';
import { Trans } from '@lingui/macro'; import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import { import {
PageSection, PageSection,
PageSectionVariants, PageSectionVariants,
@@ -8,13 +9,14 @@ import {
class Projects extends Component { class Projects extends Component {
render () { render () {
const { i18n } = this.props;
const { light, medium } = PageSectionVariants; const { light, medium } = PageSectionVariants;
return ( return (
<Fragment> <Fragment>
<PageSection variant={light} className="pf-m-condensed"> <PageSection variant={light} className="pf-m-condensed">
<Title size="2xl"> <Title size="2xl">
<Trans>Projects</Trans> {i18n._(t`Projects`)}
</Title> </Title>
</PageSection> </PageSection>
<PageSection variant={medium} /> <PageSection variant={medium} />
@@ -23,4 +25,4 @@ class Projects extends Component {
} }
} }
export default Projects; export default withI18n()(Projects);

View File

@@ -1,5 +1,6 @@
import React, { Component, Fragment } from 'react'; import React, { Component, Fragment } from 'react';
import { Trans } from '@lingui/macro'; import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import { import {
PageSection, PageSection,
PageSectionVariants, PageSectionVariants,
@@ -8,13 +9,14 @@ import {
class Schedules extends Component { class Schedules extends Component {
render () { render () {
const { i18n } = this.props;
const { light, medium } = PageSectionVariants; const { light, medium } = PageSectionVariants;
return ( return (
<Fragment> <Fragment>
<PageSection variant={light} className="pf-m-condensed"> <PageSection variant={light} className="pf-m-condensed">
<Title size="2xl"> <Title size="2xl">
<Trans>Schedules</Trans> {i18n._(t`Schedules`)}
</Title> </Title>
</PageSection> </PageSection>
<PageSection variant={medium} /> <PageSection variant={medium} />
@@ -23,4 +25,4 @@ class Schedules extends Component {
} }
} }
export default Schedules; export default withI18n()(Schedules);

View File

@@ -1,5 +1,6 @@
import React, { Component, Fragment } from 'react'; import React, { Component, Fragment } from 'react';
import { Trans } from '@lingui/macro'; import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import { import {
PageSection, PageSection,
PageSectionVariants, PageSectionVariants,
@@ -8,13 +9,14 @@ import {
class SystemSettings extends Component { class SystemSettings extends Component {
render () { render () {
const { i18n } = this.props;
const { light, medium } = PageSectionVariants; const { light, medium } = PageSectionVariants;
return ( return (
<Fragment> <Fragment>
<PageSection variant={light} className="pf-m-condensed"> <PageSection variant={light} className="pf-m-condensed">
<Title size="2xl"> <Title size="2xl">
<Trans>System Settings</Trans> {i18n._(t`System Settings`)}
</Title> </Title>
</PageSection> </PageSection>
<PageSection variant={medium} /> <PageSection variant={medium} />
@@ -23,4 +25,4 @@ class SystemSettings extends Component {
} }
} }
export default SystemSettings; export default withI18n()(SystemSettings);

View File

@@ -1,5 +1,6 @@
import React, { Component, Fragment } from 'react'; import React, { Component, Fragment } from 'react';
import { Trans } from '@lingui/macro'; import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import { import {
PageSection, PageSection,
PageSectionVariants, PageSectionVariants,
@@ -8,13 +9,14 @@ import {
class Teams extends Component { class Teams extends Component {
render () { render () {
const { i18n } = this.props;
const { light, medium } = PageSectionVariants; const { light, medium } = PageSectionVariants;
return ( return (
<Fragment> <Fragment>
<PageSection variant={light} className="pf-m-condensed"> <PageSection variant={light} className="pf-m-condensed">
<Title size="2xl"> <Title size="2xl">
<Trans>Teams</Trans> {i18n._(t`Teams`)}
</Title> </Title>
</PageSection> </PageSection>
<PageSection variant={medium} /> <PageSection variant={medium} />
@@ -23,4 +25,4 @@ class Teams extends Component {
} }
} }
export default Teams; export default withI18n()(Teams);

View File

@@ -1,5 +1,6 @@
import React, { Component, Fragment } from 'react'; import React, { Component, Fragment } from 'react';
import { Trans } from '@lingui/macro'; import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import { import {
PageSection, PageSection,
PageSectionVariants, PageSectionVariants,
@@ -8,13 +9,14 @@ import {
class Templates extends Component { class Templates extends Component {
render () { render () {
const { i18n } = this.props;
const { light, medium } = PageSectionVariants; const { light, medium } = PageSectionVariants;
return ( return (
<Fragment> <Fragment>
<PageSection variant={light} className="pf-m-condensed"> <PageSection variant={light} className="pf-m-condensed">
<Title size="2xl"> <Title size="2xl">
<Trans>Templates</Trans> {i18n._(t`Templates`)}
</Title> </Title>
</PageSection> </PageSection>
<PageSection variant={medium} /> <PageSection variant={medium} />
@@ -23,4 +25,4 @@ class Templates extends Component {
} }
} }
export default Templates; export default withI18n()(Templates);

View File

@@ -1,5 +1,6 @@
import React, { Component, Fragment } from 'react'; import React, { Component, Fragment } from 'react';
import { Trans } from '@lingui/macro'; import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import { import {
PageSection, PageSection,
PageSectionVariants, PageSectionVariants,
@@ -8,13 +9,14 @@ import {
class UISettings extends Component { class UISettings extends Component {
render () { render () {
const { i18n } = this.props;
const { light, medium } = PageSectionVariants; const { light, medium } = PageSectionVariants;
return ( return (
<Fragment> <Fragment>
<PageSection variant={light} className="pf-m-condensed"> <PageSection variant={light} className="pf-m-condensed">
<Title size="2xl"> <Title size="2xl">
<Trans>User Interface Settings</Trans> {i18n._(t`User Interface Settings`)}
</Title> </Title>
</PageSection> </PageSection>
<PageSection variant={medium} /> <PageSection variant={medium} />
@@ -23,4 +25,4 @@ class UISettings extends Component {
} }
} }
export default UISettings; export default withI18n()(UISettings);

View File

@@ -1,5 +1,6 @@
import React, { Component, Fragment } from 'react'; import React, { Component, Fragment } from 'react';
import { Trans } from '@lingui/macro'; import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import { import {
PageSection, PageSection,
PageSectionVariants, PageSectionVariants,
@@ -8,13 +9,14 @@ import {
class Users extends Component { class Users extends Component {
render () { render () {
const { i18n } = this.props;
const { light, medium } = PageSectionVariants; const { light, medium } = PageSectionVariants;
return ( return (
<Fragment> <Fragment>
<PageSection variant={light} className="pf-m-condensed"> <PageSection variant={light} className="pf-m-condensed">
<Title size="2xl"> <Title size="2xl">
<Trans>Users</Trans> {i18n._(t`Users`)}
</Title> </Title>
</PageSection> </PageSection>
<PageSection variant={medium} /> <PageSection variant={medium} />
@@ -23,4 +25,4 @@ class Users extends Component {
} }
} }
export default Users; export default withI18n()(Users);

View File

@@ -1,20 +0,0 @@
import { i18nMark } from '@lingui/react';
export function required (message) {
return value => {
if (!value.trim()) {
return message || i18nMark('This field must not be blank');
}
return undefined;
};
}
export function maxLength (max) {
return value => {
if (value.trim().length
> max) {
return i18nMark(`This field must not exceed ${max} characters`);
}
return undefined;
};
}

20
src/util/validators.jsx Normal file
View File

@@ -0,0 +1,20 @@
import { t } from '@lingui/macro';
export function required (message, i18n) {
return value => {
if (!value.trim()) {
return message || i18n._(t`This field must not be blank`);
}
return undefined;
};
}
export function maxLength (max, i18n) {
return value => {
if (value.trim().length
> max) {
return i18n._(t`This field must not exceed ${max} characters`);
}
return undefined;
};
}