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
} from '@patternfly/react-core';
import { I18n } from '@lingui/react';
import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import { RootDialog } from './contexts/RootDialog';
@@ -66,92 +66,88 @@ class App extends Component {
render () {
const { isAboutModalOpen, isNavOpen } = this.state;
const { render, routeGroups = [], navLabel = '' } = this.props;
const { render, routeGroups = [], navLabel = '', i18n } = this.props;
return (
<Config>
{({ ansible_version, version, me }) => (
<I18n>
{({ i18n }) => (
<RootDialog>
{({
title,
bodyText,
variant = 'info',
clearRootDialogMessage
}) => (
<Fragment>
{(title || bodyText) && (
<AlertModal
variant={variant}
isOpen={!!(title || bodyText)}
onClose={clearRootDialogMessage}
title={title}
actions={[
<Button
key="close"
variant="secondary"
onClick={clearRootDialogMessage}
>
{i18n._(t`Close`)}
</Button>
]}
<RootDialog>
{({
title,
bodyText,
variant = 'info',
clearRootDialogMessage
}) => (
<Fragment>
{(title || bodyText) && (
<AlertModal
variant={variant}
isOpen={!!(title || bodyText)}
onClose={clearRootDialogMessage}
title={title}
actions={[
<Button
key="close"
variant="secondary"
onClick={clearRootDialogMessage}
>
{bodyText}
</AlertModal>
)}
<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._(t`Close`)}
</Button>
]}
>
{bodyText}
</AlertModal>
)}
</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>
);
@@ -159,4 +155,4 @@ class App extends Component {
}
export { App as _App };
export default withNetwork(App);
export default withI18n()(withNetwork(App));

View File

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

View File

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

View File

@@ -1,7 +1,8 @@
import React, { Fragment } from 'react';
import PropTypes from 'prop-types';
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 CheckboxListItem from '../ListItem';
import SelectedList from '../SelectedList';
@@ -87,11 +88,12 @@ class SelectResourceStep extends React.Component {
selectedLabel,
selectedResourceRows,
itemName,
i18n
} = this.props;
return (
<Fragment>
{isLoading && (<div>Loading...</div>)}
{isLoading && (<div>{i18n._(t`Loading...`)}</div>)}
{isInitialized && (
<Fragment>
{selectedResourceRows.length > 0 && (
@@ -146,11 +148,11 @@ SelectResourceStep.propTypes = {
SelectResourceStep.defaultProps = {
displayKey: 'name',
onRowClick: () => {},
selectedLabel: i18nMark('Selected Items'),
selectedLabel: null,
selectedResourceRows: [],
sortedColumnKey: 'name',
itemName: 'item',
};
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 PropTypes from 'prop-types';
import { i18nMark } from '@lingui/react';
import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import CheckboxCard from './CheckboxCard';
import SelectedList from '../SelectedList';
@@ -14,7 +15,8 @@ class RolesStep extends React.Component {
selectedListKey,
selectedListLabel,
selectedResourceRows,
selectedRoleRows
selectedRoleRows,
i18n
} = this.props;
return (
@@ -24,7 +26,7 @@ class RolesStep extends React.Component {
<SelectedList
displayKey={selectedListKey}
isReadOnly
label={selectedListLabel}
label={selectedListLabel || i18n._(t`Selected`)}
selected={selectedResourceRows}
showOverflowAfter={5}
/>
@@ -61,9 +63,9 @@ RolesStep.propTypes = {
RolesStep.defaultProps = {
onRolesClick: () => {},
selectedListKey: 'name',
selectedListLabel: i18nMark('Selected'),
selectedListLabel: null,
selectedResourceRows: [],
selectedRoleRows: []
};
export default RolesStep;
export default withI18n()(RolesStep);

View File

@@ -1,6 +1,6 @@
import React from 'react';
import PropTypes from 'prop-types';
import { I18n } from '@lingui/react';
import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import {
FormSelect,
@@ -20,29 +20,25 @@ class AnsibleSelect extends React.Component {
}
render () {
const { label, value, data, defaultSelected } = this.props;
const { label, value, data, defaultSelected, i18n } = this.props;
return (
<I18n>
{({ i18n }) => (
<FormSelect
value={value}
onChange={this.onSelectChange}
aria-label={i18n._(t`Select Input`)}
>
{data.map((datum) => (
datum === defaultSelected ? (
<FormSelectOption
key=""
value=""
label={i18n._(t`Use Default ${label}`)}
/>
) : (
<FormSelectOption key={datum} value={datum} label={datum} />
)
))}
</FormSelect>
)}
</I18n>
<FormSelect
value={value}
onChange={this.onSelectChange}
aria-label={i18n._(t`Select Input`)}
>
{data.map((datum) => (
datum === defaultSelected ? (
<FormSelectOption
key=""
value=""
label={i18n._(t`Use Default ${label}`)}
/>
) : (
<FormSelectOption key={datum} value={datum} label={datum} />
)
))}
</FormSelect>
);
}
}
@@ -62,4 +58,4 @@ AnsibleSelect.propTypes = {
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 { Button } from '@patternfly/react-core';
import { TimesIcon } from '@patternfly/react-icons';
import { I18n } from '@lingui/react';
import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
function CardCloseButton ({ linkTo, ...props }) {
function CardCloseButton ({ linkTo, i18n, i18nHash, ...props }) {
if (linkTo) {
return (
<I18n>
{({ i18n }) => (
<Link
className="pf-c-button pf-c-card__close"
aria-label={i18n._(t`Close`)}
title={i18n._(t`Close`)}
to={linkTo}
{...props}
>
<TimesIcon />
</Link>
)}
</I18n>
<Link
className="pf-c-button pf-c-card__close"
aria-label={i18n._(t`Close`)}
title={i18n._(t`Close`)}
to={linkTo}
{...props}
>
<TimesIcon />
</Link>
);
}
return (
<I18n>
{({ i18n }) => (
<Button
variant="plain"
className="pf-c-card__close"
aria-label={i18n._(t`Close`)}
{...props}
>
<TimesIcon />
</Button>
)}
</I18n>
<Button
variant="plain"
className="pf-c-card__close"
aria-label={i18n._(t`Close`)}
{...props}
>
<TimesIcon />
</Button>
);
}
CardCloseButton.propTypes = {
@@ -46,4 +38,4 @@ CardCloseButton.defaultProps = {
linkTo: null,
};
export default CardCloseButton;
export default withI18n()(CardCloseButton);

View File

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

View File

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

View File

@@ -1,6 +1,6 @@
import React from 'react';
import PropTypes from 'prop-types';
import { I18n } from '@lingui/react';
import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import {
ActionGroup,
@@ -20,21 +20,17 @@ const buttonGroupStyle = {
marginRight: '20px'
};
const FormActionGroup = ({ onSubmit, submitDisabled, onCancel }) => (
<I18n>
{({ i18n }) => (
<ActionGroup style={formActionGroupStyle}>
<Toolbar>
<ToolbarGroup style={buttonGroupStyle}>
<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>
</Toolbar>
</ActionGroup>
)}
</I18n>
const FormActionGroup = ({ onSubmit, submitDisabled, onCancel, i18n }) => (
<ActionGroup style={formActionGroupStyle}>
<Toolbar>
<ToolbarGroup style={buttonGroupStyle}>
<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>
</Toolbar>
</ActionGroup>
);
FormActionGroup.propTypes = {
@@ -47,4 +43,4 @@ FormActionGroup.defaultProps = {
submitDisabled: false,
};
export default FormActionGroup;
export default withI18n()(FormActionGroup);

View File

@@ -9,7 +9,7 @@ import {
InputGroup,
Modal,
} from '@patternfly/react-core';
import { I18n } from '@lingui/react';
import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import { withNetwork } from '../../contexts/Network';
@@ -130,7 +130,9 @@ class Lookup extends React.Component {
results,
count,
} = 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 ? (
<div className="pf-c-chip-group">
@@ -143,64 +145,60 @@ class Lookup extends React.Component {
) : null;
return (
<I18n>
{({ i18n }) => (
<Fragment>
<InputGroup className="awx-lookup">
<Button
aria-label="Search"
id={id}
onClick={this.handleModalToggle}
variant={ButtonVariant.tertiary}
>
<SearchIcon />
</Button>
<div className="pf-c-form-control">
{chips}
</div>
</InputGroup>
<Modal
className="awx-c-modal"
title={`Select ${lookupHeader}`}
isOpen={isModalOpen}
onClose={this.handleModalToggle}
actions={[
<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}
itemCount={count}
itemName={lookupHeader}
qsConfig={this.qsConfig}
toolbarColumns={columns}
renderItem={item => (
<CheckboxListItem
key={item.id}
itemId={item.id}
name={item.name}
isSelected={lookupSelectedItems.some(i => i.id === item.id)}
onSelect={() => this.toggleSelected(item)}
/>
)}
alignToolbarLeft
showPageSizeOptions={false}
paginationStyling={paginationStyling}
<Fragment>
<InputGroup className="awx-lookup">
<Button
aria-label="Search"
id={id}
onClick={this.handleModalToggle}
variant={ButtonVariant.tertiary}
>
<SearchIcon />
</Button>
<div className="pf-c-form-control">
{chips}
</div>
</InputGroup>
<Modal
className="awx-c-modal"
title={i18n._(t`Select ${header}`)}
isOpen={isModalOpen}
onClose={this.handleModalToggle}
actions={[
<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}
itemCount={count}
itemName={lookupHeader}
qsConfig={this.qsConfig}
toolbarColumns={columns}
renderItem={item => (
<CheckboxListItem
key={item.id}
itemId={item.id}
name={item.name}
isSelected={lookupSelectedItems.some(i => i.id === item.id)}
onSelect={() => this.toggleSelected(item)}
/>
{lookupSelectedItems.length > 0 && (
<SelectedList
label={i18n._(t`Selected`)}
selected={lookupSelectedItems}
showOverflowAfter={5}
onRemove={this.toggleSelected}
/>
)}
{ error ? <div>error</div> : '' }
</Modal>
</Fragment>
)}
</I18n>
)}
alignToolbarLeft
showPageSizeOptions={false}
paginationStyling={paginationStyling}
/>
{lookupSelectedItems.length > 0 && (
<SelectedList
label={i18n._(t`Selected`)}
selected={lookupSelectedItems}
showOverflowAfter={5}
onRemove={this.toggleSelected}
/>
)}
{ error ? <div>error</div> : '' }
</Modal>
</Fragment>
);
}
}
@@ -217,9 +215,9 @@ Lookup.propTypes = {
Lookup.defaultProps = {
id: 'lookup-search',
lookupHeader: 'items',
lookupHeader: null,
name: null,
};
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 { shape, number, string, bool, func } from 'prop-types';
import { I18n } from '@lingui/react';
import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import { Link } from 'react-router-dom';
import {
@@ -37,66 +37,75 @@ function NotificationListItem (props) {
detailUrl,
successTurnedOn,
errorTurnedOn,
toggleNotification
toggleNotification,
i18n
} = props;
return (
<I18n>
{({ i18n }) => (
<DataListItem
aria-labelledby={`items-list-item-${notification.id}`}
key={notification.id}
>
<DataListItemRow>
<DataListItemCells dataListCells={[
<DataListCell key="name">
<Link
to={{
pathname: detailUrl
}}
css="margin-right: 1.5em;"
>
<b id={`items-list-item-${notification.id}`}>{notification.name}</b>
</Link>
<Badge
css="text-transform: capitalize;"
isRead
>
{notification.notification_type}
</Badge>
</DataListCell>,
<DataListCell righthalf="true" key="toggles">
<Switch
id={`notification-${notification.id}-success-toggle`}
label={i18n._(t`Successful`)}
isChecked={successTurnedOn}
isDisabled={!canToggleNotifications}
onChange={() => toggleNotification(
notification.id,
successTurnedOn,
'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>
]}
<DataListItem
aria-labelledby={`items-list-item-${notification.id}`}
key={notification.id}
>
<DataListItemRow>
<DataListItemCells dataListCells={[
<DataListCell key="name">
<Link
to={{
pathname: detailUrl
}}
css="margin-right: 1.5em;"
>
<b id={`items-list-item-${notification.id}`}>{notification.name}</b>
</Link>
<Badge
css="text-transform: capitalize;"
isRead
>
{notification.notification_type}
</Badge>
</DataListCell>,
<DataListCell righthalf="true" key="toggles">
<Switch
id={`notification-${notification.id}-success-toggle`}
label={i18n._(t`Successful`)}
isChecked={successTurnedOn}
isDisabled={!canToggleNotifications}
onChange={() => toggleNotification(
notification.id,
successTurnedOn,
'success'
)}
aria-label={i18n._(t`Toggle notification success`)}
/>
</DataListItemRow>
</DataListItem>
)}
</I18n>
<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>
]}
/>
<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,
};
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 { Trans } from '@lingui/macro';
import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import { withRootDialog } from '../contexts/RootDialog';
@@ -14,16 +14,13 @@ const NotifyAndRedirect = ({
strict,
sensitive,
setRootDialogMessage,
location
location,
i18n
}) => {
setRootDialogMessage({
title: '404',
bodyText: (
<Trans>
Cannot find route
<strong>{` ${location.pathname}`}</strong>
.
</Trans>
<Fragment>{i18n._(t`Cannot find route ${(<strong>{location.pathname}</strong>)}.`)}</Fragment>
),
variant: 'warning'
});
@@ -41,4 +38,4 @@ const 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 PropTypes from 'prop-types';
import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import { I18n } from '@lingui/react';
import {
Dropdown,
DropdownItem,
@@ -57,78 +56,75 @@ class PageHeaderToolbar extends Component {
isAboutDisabled,
onAboutClick,
onLogoutClick,
loggedInUser
loggedInUser,
i18n
} = this.props;
return (
<I18n>
{({ i18n }) => (
<Toolbar>
<ToolbarGroup>
<Tooltip position="left" content={<div>{i18n._(t`Info`)}</div>}>
<ToolbarItem>
<Dropdown
isPlain
isOpen={isHelpOpen}
position={DropdownPosition.right}
onSelect={this.handleHelpSelect}
toggle={(
<DropdownToggle onToggle={this.handleHelpToggle}>
<QuestionCircleIcon />
</DropdownToggle>
<Toolbar>
<ToolbarGroup>
<Tooltip position="left" content={<div>{i18n._(t`Info`)}</div>}>
<ToolbarItem>
<Dropdown
isPlain
isOpen={isHelpOpen}
position={DropdownPosition.right}
onSelect={this.handleHelpSelect}
toggle={(
<DropdownToggle onToggle={this.handleHelpToggle}>
<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={[
<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>
)}
</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>
</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>
);
}
}
@@ -143,4 +139,4 @@ PageHeaderToolbar.defaultProps = {
isAboutDisabled: false
};
export default PageHeaderToolbar;
export default withI18n()(PageHeaderToolbar);

View File

@@ -14,8 +14,8 @@ import {
EmptyStateBody,
} from '@patternfly/react-core';
import { CubesIcon } from '@patternfly/react-icons';
import { I18n, i18nMark } from '@lingui/react';
import { Trans, t } from '@lingui/macro';
import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import { withRouter, Link } from 'react-router-dom';
import Pagination from '../Pagination';
@@ -108,13 +108,15 @@ class PaginatedDataList extends React.Component {
showPageSizeOptions,
paginationStyling,
location,
i18n
} = this.props;
const { error } = this.state;
const [orderBy, sortOrder] = this.getSortOrder();
const queryParams = parseNamespacedQueryString(qsConfig, location.search);
const columns = toolbarColumns || [{ name: i18n._(t`Name`), key: 'name', isSortable: true }];
return (
<I18n>
{({ i18n }) => (
<Fragment>
{error && (
<Fragment>
{error && (
<Fragment>
@@ -128,24 +130,10 @@ class PaginatedDataList extends React.Component {
<EmptyState>
<EmptyStateIcon icon={CubesIcon} />
<Title size="lg">
<Trans>
No
{' '}
{ucFirst(itemNamePlural || pluralize(itemName))}
{' '}
Found
</Trans>
{i18n._(t`No ${ucFirst(itemNamePlural || pluralize(itemName))} Found`)}
</Title>
<EmptyStateBody>
<Trans>
Please add
{' '}
{getArticle(itemName)}
{' '}
{itemName}
{' '}
to populate this list
</Trans>
{i18n._(t`Please add ${getArticle(itemName)} ${itemName} to populate this list`)}
</EmptyStateBody>
</EmptyState>
) : (
@@ -199,9 +187,67 @@ class PaginatedDataList extends React.Component {
/>
</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>
)}
</I18n>
</Fragment>
);
}
}
@@ -235,9 +281,7 @@ PaginatedDataList.propTypes = {
PaginatedDataList.defaultProps = {
renderItem: null,
toolbarColumns: [
{ name: i18nMark('Name'), key: 'name', isSortable: true },
],
toolbarColumns: [],
additionalControls: [],
itemName: 'item',
itemNamePlural: '',
@@ -250,4 +294,4 @@ PaginatedDataList.defaultProps = {
};
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 { Button as PFButton } from '@patternfly/react-core';
import { PlusIcon } from '@patternfly/react-icons';
import { I18n } from '@lingui/react';
import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
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) {
throw new Error('ToolbarAddButton requires either `linkTo` or `onClick` prop');
}
if (linkTo) {
// TODO: This should only be a <Link> (no <Button>) but CSS is off
return (
<I18n>
{({ i18n }) => (
<Link to={linkTo}>
<Button
variant="primary"
aria-label={i18n._(t`Add`)}
>
<PlusIcon />
</Button>
</Link>
)}
</I18n>
);
}
return (
<I18n>
{({ i18n }) => (
<Link to={linkTo}>
<Button
variant="primary"
aria-label={i18n._(t`Add`)}
onClick={onClick}
>
<PlusIcon />
</Button>
)}
</I18n>
</Link>
);
}
return (
<Button
variant="primary"
aria-label={i18n._(t`Add`)}
onClick={onClick}
>
<PlusIcon />
</Button>
);
}
ToolbarAddButton.propTypes = {
@@ -64,4 +57,4 @@ ToolbarAddButton.defaultProps = {
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 { Button as PFButton, Tooltip } from '@patternfly/react-core';
import { TrashAltIcon } from '@patternfly/react-icons';
import { I18n, i18nMark } from '@lingui/react';
import { Trans, t } from '@lingui/macro';
import styled from 'styled-components';
import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import AlertModal from '../AlertModal';
import { pluralize } from '../../util/strings';
@@ -89,103 +89,95 @@ class ToolbarDeleteButton extends React.Component {
}
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)) {
return (
<div>
<Trans>
You dont have permission to delete the following
{' '}
{pluralize(itemName)}
:
</Trans>
{itemsToDelete
.filter(cannotDelete)
.map(item => (
<div key={item.id}>
{item.name}
</div>
))
}
{i18n._(t`You do not have permission to delete the following ${pluralize(itemName)}: ${itemsUnableToDelete}`)}
</div>
);
}
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 () {
const { itemsToDelete, itemName } = this.props;
const { itemsToDelete, itemName, i18n } = this.props;
const { isModalOpen } = this.state;
const isDisabled = itemsToDelete.length === 0
|| itemsToDelete.some(cannotDelete);
return (
<I18n>
{({ i18n }) => (
<Fragment>
<Tooltip
content={this.renderTooltip()}
position="left"
>
<Fragment>
<Tooltip
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
variant="plain"
aria-label={i18n._(t`Delete`)}
onClick={this.handleConfirmDelete}
isDisabled={isDisabled}
>
<TrashAltIcon />
</Button>
</Tooltip>
{ isModalOpen && (
<AlertModal
key="delete"
variant="danger"
title={itemsToDelete === 1
? i18n._(t`Delete ${itemName}`)
: 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>
]}
aria-label={i18n._(t`confirm delete`)}
onClick={this.handleDelete}
>
{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 />
{itemsToDelete.map((item) => (
<span key={item.id}>
<strong>
{item.name}
</strong>
<br />
</span>
))}
<br />
</AlertModal>
)}
</Fragment>
</span>
))}
<br />
</AlertModal>
)}
</I18n>
</Fragment>
);
}
}
export default ToolbarDeleteButton;
export default withI18n()(ToolbarDeleteButton);

View File

@@ -1,7 +1,7 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { I18n } from '@lingui/react';
import { Trans, t } from '@lingui/macro';
import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import {
Button,
Dropdown,
@@ -106,7 +106,8 @@ class Pagination extends Component {
page_size,
pageSizeOptions,
showPageSizeOptions,
style
style,
i18n
} = this.props;
const { value, isOpen } = this.state;
let opts = [];
@@ -135,98 +136,89 @@ class Pagination extends Component {
));
return (
<I18n>
{({ i18n }) => (
<div className="awx-pagination" style={style}>
{showPageSizeOptions && (
<div className="awx-pagination__page-size-selection">
<Trans>Items Per Page</Trans>
<Dropdown
<div className="awx-pagination" style={style}>
{showPageSizeOptions && (
<div className="awx-pagination__page-size-selection">
{i18n._(t`Items Per Page`)}
<Dropdown
onToggle={this.onTogglePageSize}
onSelect={this.onSelectPageSize}
direction={up}
isOpen={isOpen}
toggle={(
<DropdownToggle
className="togglePageSize"
onToggle={this.onTogglePageSize}
onSelect={this.onSelectPageSize}
direction={up}
isOpen={isOpen}
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>
>
{page_size}
</DropdownToggle>
)}
</div>
dropdownItems={dropdownItems}
/>
</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
};
export default Pagination;
export default withI18n()(Pagination);

View File

@@ -1,6 +1,6 @@
import React from 'react';
import PropTypes from 'prop-types';
import { I18n } from '@lingui/react';
import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import {
Button as PFButton,
@@ -90,7 +90,8 @@ class Search extends React.Component {
render () {
const { up } = DropdownPosition;
const {
columns
columns,
i18n
} = this.props;
const {
isSearchDropdownOpen,
@@ -109,41 +110,37 @@ class Search extends React.Component {
));
return (
<I18n>
{({ i18n }) => (
<div className="pf-c-input-group">
<Dropdown
<div className="pf-c-input-group">
<Dropdown
onToggle={this.handleDropdownToggle}
onSelect={this.handleDropdownSelect}
direction={up}
isOpen={isSearchDropdownOpen}
toggle={(
<DropdownToggle
id="awx-search"
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 />
</Button>
</div>
)}
</I18n>
{searchColumnName}
</DropdownToggle>
)}
dropdownItems={searchDropdownItems}
/>
<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'
};
export default Search;
export default withI18n()(Search);

View File

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

View File

@@ -1,7 +1,7 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { withRouter } from 'react-router-dom';
import { I18n } from '@lingui/react';
import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import { Brand } from '@patternfly/react-core';
@@ -34,6 +34,7 @@ class TowerLogo extends Component {
render () {
const { hover } = this.state;
const { i18n } = this.props;
let src = TowerLogoHeader;
@@ -42,19 +43,15 @@ class TowerLogo extends Component {
}
return (
<I18n>
{({ i18n }) => (
<Brand
src={src}
alt={i18n._(t`Tower Brand Image`)}
onMouseOut={this.onHover}
onMouseOver={this.onHover}
onBlur={this.onHover}
onFocus={this.onHover}
onClick={this.onClick}
/>
)}
</I18n>
<Brand
src={src}
alt={i18n._(t`Tower Brand Image`)}
onMouseOut={this.onHover}
onMouseOver={this.onHover}
onBlur={this.onHover}
onFocus={this.onHover}
onClick={this.onClick}
/>
);
}
}
@@ -67,4 +64,4 @@ TowerLogo.defaultProps = {
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 { i18nMark } from '@lingui/react';
import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import { withRootDialog } from './RootDialog';
@@ -33,27 +34,27 @@ class Provider extends Component {
}
handle401 () {
const { handle401, history, setRootDialogMessage } = this.props;
const { handle401, history, setRootDialogMessage, i18n } = this.props;
if (handle401) {
handle401();
return;
}
history.replace('/login');
setRootDialogMessage({
bodyText: i18nMark('You have been logged out.')
bodyText: i18n._(t`You have been logged out.`)
});
}
handle404 () {
const { handle404, history, setRootDialogMessage } = this.props;
const { handle404, history, setRootDialogMessage, i18n } = this.props;
if (handle404) {
handle404();
return;
}
history.replace('/home');
setRootDialogMessage({
title: i18nMark('404'),
bodyText: i18nMark('Cannot find resource.'),
title: i18n._(t`404`),
bodyText: i18n._(t`Cannot find resource.`),
variant: 'warning'
});
}
@@ -72,7 +73,7 @@ class Provider extends Component {
}
export { Provider as _NetworkProvider };
export const NetworkProvider = withRootDialog(withRouter(Provider));
export const NetworkProvider = withI18n()(withRootDialog(withRouter(Provider)));
export function withNetwork (Child) {
return (props) => (

View File

@@ -1,5 +1,6 @@
import React, { Component, Fragment } from 'react';
import { Trans } from '@lingui/macro';
import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import {
PageSection,
PageSectionVariants,
@@ -8,13 +9,14 @@ import {
class Applications extends Component {
render () {
const { i18n } = this.props;
const { light, medium } = PageSectionVariants;
return (
<Fragment>
<PageSection variant={light} className="pf-m-condensed">
<Title size="2xl">
<Trans>Applications</Trans>
{i18n._(t`Applications`)}
</Title>
</PageSection>
<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 { Trans } from '@lingui/macro';
import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import {
PageSection,
PageSectionVariants,
@@ -8,13 +9,14 @@ import {
class AuthSettings extends Component {
render () {
const { i18n } = this.props;
const { light, medium } = PageSectionVariants;
return (
<Fragment>
<PageSection variant={light} className="pf-m-condensed">
<Title size="2xl">
<Trans>Authentication Settings</Trans>
{i18n._(t`Authentication Settings`)}
</Title>
</PageSection>
<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 { Trans } from '@lingui/macro';
import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import {
PageSection,
PageSectionVariants,
@@ -8,13 +9,14 @@ import {
class CredentialTypes extends Component {
render () {
const { i18n } = this.props;
const { light, medium } = PageSectionVariants;
return (
<Fragment>
<PageSection variant={light} className="pf-m-condensed">
<Title size="2xl">
<Trans>Credential Types</Trans>
{i18n._(t`Credential Types`)}
</Title>
</PageSection>
<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 { Trans } from '@lingui/macro';
import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import {
PageSection,
PageSectionVariants,
@@ -8,13 +9,14 @@ import {
class Credentials extends Component {
render () {
const { i18n } = this.props;
const { light, medium } = PageSectionVariants;
return (
<Fragment>
<PageSection variant={light} className="pf-m-condensed">
<Title size="2xl">
<Trans>Credentials</Trans>
{i18n._(t`Credentials`)}
</Title>
</PageSection>
<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 { Trans } from '@lingui/macro';
import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import {
PageSection,
PageSectionVariants,
@@ -8,13 +9,14 @@ import {
class Dashboard extends Component {
render () {
const { i18n } = this.props;
const { light, medium } = PageSectionVariants;
return (
<Fragment>
<PageSection variant={light} className="pf-m-condensed">
<Title size="2xl">
<Trans>Dashboard</Trans>
{i18n._(t`Dashboard`)}
</Title>
</PageSection>
<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 { Trans } from '@lingui/macro';
import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import {
PageSection,
PageSectionVariants,
@@ -8,13 +9,14 @@ import {
class InstanceGroups extends Component {
render () {
const { i18n } = this.props;
const { light, medium } = PageSectionVariants;
return (
<Fragment>
<PageSection variant={light} className="pf-m-condensed">
<Title size="2xl">
<Trans>Instance Groups</Trans>
{i18n._(t`Instance Groups`)}
</Title>
</PageSection>
<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 { Trans } from '@lingui/macro';
import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import {
PageSection,
PageSectionVariants,
@@ -8,13 +9,14 @@ import {
class Inventories extends Component {
render () {
const { i18n } = this.props;
const { light, medium } = PageSectionVariants;
return (
<Fragment>
<PageSection variant={light} className="pf-m-condensed">
<Title size="2xl">
<Trans>Inventories</Trans>
{i18n._(t`Inventories`)}
</Title>
</PageSection>
<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 { Trans } from '@lingui/macro';
import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import {
PageSection,
PageSectionVariants,
@@ -8,13 +9,14 @@ import {
class InventoryScripts extends Component {
render () {
const { i18n } = this.props;
const { light, medium } = PageSectionVariants;
return (
<Fragment>
<PageSection variant={light} className="pf-m-condensed">
<Title size="2xl">
<Trans>Inventory Scripts</Trans>
{i18n._(t`Inventory Scripts`)}
</Title>
</PageSection>
<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 { Trans } from '@lingui/macro';
import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import {
PageSection,
PageSectionVariants,
@@ -8,13 +9,14 @@ import {
class Jobs extends Component {
render () {
const { i18n } = this.props;
const { light, medium } = PageSectionVariants;
return (
<Fragment>
<PageSection variant={light} className="pf-m-condensed">
<Title size="2xl">
<Trans>Jobs</Trans>
{i18n._(t`Jobs`)}
</Title>
</PageSection>
<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 { Trans } from '@lingui/macro';
import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import {
PageSection,
PageSectionVariants,
@@ -8,13 +9,14 @@ import {
class JobsSettings extends Component {
render () {
const { i18n } = this.props;
const { light, medium } = PageSectionVariants;
return (
<Fragment>
<PageSection variant={light} className="pf-m-condensed">
<Title size="2xl">
<Trans>Jobs Settings</Trans>
{i18n._(t`Jobs Settings`)}
</Title>
</PageSection>
<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 { Trans } from '@lingui/macro';
import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import {
PageSection,
PageSectionVariants,
@@ -8,13 +9,14 @@ import {
class License extends Component {
render () {
const { i18n } = this.props;
const { light, medium } = PageSectionVariants;
return (
<Fragment>
<PageSection variant={light} className="pf-m-condensed">
<Title size="2xl">
<Trans>License</Trans>
{i18n._(t`License`)}
</Title>
</PageSection>
<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 { Redirect, withRouter } from 'react-router-dom';
import { I18n } from '@lingui/react';
import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import {
LoginForm,
@@ -62,7 +62,7 @@ class AWXLogin extends Component {
render () {
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;
if (isAuthenticated) {
@@ -70,34 +70,30 @@ class AWXLogin extends Component {
}
return (
<I18n>
{({ i18n }) => (
<LoginPage
brandImgSrc={logoSrc}
brandImgAlt={alt || 'Ansible Tower'}
loginTitle={i18n._(t`Welcome to Ansible Tower! Please Sign In.`)}
textContent={loginInfo}
>
<LoginForm
className={errorMessage && 'pf-m-error'}
usernameLabel={i18n._(t`Username`)}
passwordLabel={i18n._(t`Password`)}
showHelperText={!isInputValid || !!errorMessage}
helperText={errorMessage || i18n._(t`Invalid username or password. Please try again.`)}
usernameValue={username}
passwordValue={password}
isValidUsername={isInputValid}
isValidPassword={isInputValid}
onChangeUsername={this.onChangeUsername}
onChangePassword={this.onChangePassword}
onLoginButtonClick={this.onLoginButtonClick}
/>
</LoginPage>
)}
</I18n>
<LoginPage
brandImgSrc={logoSrc}
brandImgAlt={alt || 'Ansible Tower'}
loginTitle={i18n._(t`Welcome to Ansible Tower! Please Sign In.`)}
textContent={loginInfo}
>
<LoginForm
className={errorMessage && 'pf-m-error'}
usernameLabel={i18n._(t`Username`)}
passwordLabel={i18n._(t`Password`)}
showHelperText={!isInputValid || !!errorMessage}
helperText={errorMessage || i18n._(t`Invalid username or password. Please try again.`)}
usernameValue={username}
passwordValue={password}
isValidUsername={isInputValid}
isValidPassword={isInputValid}
onChangeUsername={this.onChangeUsername}
onChangePassword={this.onChangePassword}
onLoginButtonClick={this.onLoginButtonClick}
/>
</LoginPage>
);
}
}
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 { Trans } from '@lingui/macro';
import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import {
PageSection,
PageSectionVariants,
@@ -8,13 +9,14 @@ import {
class ManagementJobs extends Component {
render () {
const { i18n } = this.props;
const { light, medium } = PageSectionVariants;
return (
<Fragment>
<PageSection variant={light} className="pf-m-condensed">
<Title size="2xl">
<Trans>Management Jobs</Trans>
{i18n._(t`Management Jobs`)}
</Title>
</PageSection>
<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 { Trans } from '@lingui/macro';
import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import {
PageSection,
PageSectionVariants,
@@ -8,13 +9,14 @@ import {
class NotificationTemplates extends Component {
render () {
const { i18n } = this.props;
const { light, medium } = PageSectionVariants;
return (
<Fragment>
<PageSection variant={light} className="pf-m-condensed">
<Title size="2xl">
<Trans>Notification Templates</Trans>
{i18n._(t`Notification Templates`)}
</Title>
</PageSection>
<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 { Route, withRouter, Switch } from 'react-router-dom';
import { i18nMark } from '@lingui/react';
import { Trans } from '@lingui/macro';
import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import { Config } from '../../contexts/Config';
import { NetworkProvider } from '../../contexts/Network';
@@ -14,34 +14,42 @@ import OrganizationAdd from './screens/OrganizationAdd';
import Organization from './screens/Organization/Organization';
class Organizations extends Component {
state = {
breadcrumbConfig: {
'/organizations': i18nMark('Organizations'),
'/organizations/add': i18nMark('Create New Organization')
}
};
constructor (props) {
super(props);
const { i18n } = props;
this.state = {
breadcrumbConfig: {
'/organizations': i18n._(t`Organizations`),
'/organizations/add': i18n._(t`Create New Organization`)
}
};
}
setBreadcrumbConfig = (organization) => {
const { i18n } = this.props;
if (!organization) {
return;
}
const breadcrumbConfig = {
'/organizations': i18nMark('Organizations'),
'/organizations/add': i18nMark('Create New Organization'),
'/organizations': i18n._(t`Organizations`),
'/organizations/add': i18n._(t`Create New Organization`),
[`/organizations/${organization.id}`]: `${organization.name}`,
[`/organizations/${organization.id}/edit`]: i18nMark('Edit Details'),
[`/organizations/${organization.id}/details`]: i18nMark('Details'),
[`/organizations/${organization.id}/access`]: i18nMark('Access'),
[`/organizations/${organization.id}/teams`]: i18nMark('Teams'),
[`/organizations/${organization.id}/notifications`]: i18nMark('Notifications'),
[`/organizations/${organization.id}/edit`]: i18n._(t`Edit Details`),
[`/organizations/${organization.id}/details`]: i18n._(t`Details`),
[`/organizations/${organization.id}/access`]: i18n._(t`Access`),
[`/organizations/${organization.id}/teams`]: i18n._(t`Teams`),
[`/organizations/${organization.id}/notifications`]: i18n._(t`Notifications`),
};
this.setState({ breadcrumbConfig });
}
render () {
const { match, history, location, setRootDialogMessage } = this.props;
const { match, history, location, setRootDialogMessage, i18n } = this.props;
const { breadcrumbConfig } = this.state;
return (
@@ -65,11 +73,11 @@ class Organizations extends Component {
setRootDialogMessage({
title: '404',
bodyText: (
<Trans>
Cannot find organization with ID
<Fragment>
{i18n._(t`Cannot find organization with ID`)}
<strong>{` ${newRouteMatch.params.id}`}</strong>
.
</Trans>
</Fragment>
),
variant: 'warning'
});
@@ -101,4 +109,4 @@ class Organizations extends Component {
}
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 { Button } from '@patternfly/react-core';
import { I18n, i18nMark } from '@lingui/react';
import { t, Trans } from '@lingui/macro';
import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import AlertModal from '../../../components/AlertModal';
import { Role } from '../../../types';
@@ -24,57 +24,43 @@ class DeleteRoleConfirmationModal extends React.Component {
}
render () {
const { role, username, onCancel, onConfirm } = this.props;
const title = `Remove ${this.isTeamRole() ? 'Team' : 'User'} Access`;
const { role, username, onCancel, onConfirm, i18n } = this.props;
const title = i18n._(t`Remove ${this.isTeamRole() ? i18n._(t`Team`) : i18n._(t`User`)} Access`);
return (
<I18n>
{({ i18n }) => (
<AlertModal
<AlertModal
variant="danger"
title={title}
isOpen
onClose={onCancel}
actions={[
<Button
key="delete"
variant="danger"
title={i18nMark(title)}
isOpen
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>
]}
aria-label="Confirm delete"
onClick={onConfirm}
>
{this.isTeamRole() ? (
<Trans>
Are you sure you want to remove
<b>{` ${role.name} `}</b>
access from
<b>{` ${role.team_name}`}</b>
? Doing so affects all members of the team.
<br />
<br />
If you
<b><i> only </i></b>
want to remove access for this particular user, please remove them from the team.
</Trans>
) : (
<Trans>
Are you sure you want to remove
<b>{` ${role.name} `}</b>
access from
<b>{` ${username}`}</b>
?
</Trans>
)}
</AlertModal>
{i18n._(t`Delete`)}
</Button>,
<Button key="cancel" variant="secondary" onClick={onCancel}>
{i18n._(t`Cancel`)}
</Button>
]}
>
{this.isTeamRole() ? (
<Fragment>
{i18n._(t`Are you sure you want to remove ${role.name} access from ${role.team_name}? Doing so affects all members of the team.`)}
<br />
<br />
{i18n._(t`If you ${(<b><i>only</i></b>)} want to remove access for this particular user, please remove them from the team.`)}
</Fragment>
) : (
<Fragment>
{i18n._(t`Are you sure you want to remove ${role.name} access from ${username}?`)}
</Fragment>
)}
</I18n>
</AlertModal>
);
}
}
export default DeleteRoleConfirmationModal;
export default withI18n()(DeleteRoleConfirmationModal);

View File

@@ -1,20 +1,14 @@
import React, { Fragment } from 'react';
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 { QuestionCircleIcon } from '@patternfly/react-icons';
import { t } from '@lingui/macro';
import Lookup from '../../../components/Lookup';
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 {
constructor (props) {
super(props);
@@ -29,43 +23,43 @@ class InstanceGroupsLookup extends React.Component {
}
render () {
const { value, tooltip, onChange } = this.props;
const { value, tooltip, onChange, i18n } = this.props;
return (
<I18n>
{({ i18n }) => (
<FormGroup
label={(
<Fragment>
{i18n._(t`Instance Groups`)}
{' '}
{
tooltip && (
<Tooltip
position="right"
content={tooltip}
>
<QuestionCircleIcon />
</Tooltip>
)
}
</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>
<FormGroup
label={(
<Fragment>
{i18n._(t`Instance Groups`)}
{' '}
{
tooltip && (
<Tooltip
position="right"
content={tooltip}
>
<QuestionCircleIcon />
</Tooltip>
)
}
</Fragment>
)}
</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: '',
};
export default withNetwork(InstanceGroupsLookup);
export default withI18n()(withNetwork(InstanceGroupsLookup));

View File

@@ -1,6 +1,6 @@
import React from 'react';
import { func } from 'prop-types';
import { I18n } from '@lingui/react';
import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import {
DataListItem,
@@ -81,96 +81,92 @@ class OrganizationAccessItem extends React.Component {
}
render () {
const { accessRecord, onRoleDelete } = this.props;
const { accessRecord, onRoleDelete, i18n } = this.props;
const [teamRoles, userRoles] = this.getRoleLists();
return (
<I18n>
{({ i18n }) => (
<DataListItem aria-labelledby="access-list-item" key={accessRecord.id}>
<DataListItemRow>
<DataListItemCells dataListCells={[
<DataListCell key="name">
{accessRecord.username && (
<TextContent style={detailWrapperStyle}>
{accessRecord.url ? (
<Link to={{ pathname: accessRecord.url }}>
<Text component={TextVariants.h6} style={detailLabelStyle}>
{accessRecord.username}
</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}
/>
<DataListItem aria-labelledby="access-list-item" key={accessRecord.id}>
<DataListItemRow>
<DataListItemCells dataListCells={[
<DataListCell key="name">
{accessRecord.username && (
<TextContent style={detailWrapperStyle}>
{accessRecord.url ? (
<Link to={{ pathname: accessRecord.url }}>
<Text component={TextVariants.h6} style={detailLabelStyle}>
{accessRecord.username}
</Text>
</Link>
) : (
null
<Text component={TextVariants.h6} style={detailLabelStyle}>
{accessRecord.username}
</Text>
)}
</DataListCell>,
<DataListCell key="roles">
{userRoles.length > 0 && (
<ul style={userRolesWrapperStyle}>
<Text component={TextVariants.h6} style={detailLabelStyle}>
{i18n._(t`User Roles`)}
</Text>
{userRoles.map(role => (
role.user_capabilities.unattach ? (
<Chip
key={role.id}
className="awx-c-chip"
onClick={() => { onRoleDelete(role, accessRecord); }}
>
{role.name}
</Chip>
) : (
<BasicChip key={role.id}>
{role.name}
</BasicChip>
)
))}
</ul>
)}
{teamRoles.length > 0 && (
<ul style={userRolesWrapperStyle}>
<Text component={TextVariants.h6} style={detailLabelStyle}>
{i18n._(t`Team Roles`)}
</Text>
{teamRoles.map(role => (
role.user_capabilities.unattach ? (
<Chip
key={role.id}
className="awx-c-chip"
onClick={() => { onRoleDelete(role, accessRecord); }}
>
{role.name}
</Chip>
) : (
<BasicChip key={role.id}>
{role.name}
</BasicChip>
)
))}
</ul>
)}
</DataListCell>
]}
/>
</DataListItemRow>
</DataListItem>
)}
</I18n>
</TextContent>
)}
{accessRecord.first_name || accessRecord.last_name ? (
<Detail
label={i18n._(t`Name`)}
value={`${accessRecord.first_name} ${accessRecord.last_name}`}
url={null}
customStyles={null}
/>
) : (
null
)}
</DataListCell>,
<DataListCell key="roles">
{userRoles.length > 0 && (
<ul style={userRolesWrapperStyle}>
<Text component={TextVariants.h6} style={detailLabelStyle}>
{i18n._(t`User Roles`)}
</Text>
{userRoles.map(role => (
role.user_capabilities.unattach ? (
<Chip
key={role.id}
className="awx-c-chip"
onClick={() => { onRoleDelete(role, accessRecord); }}
>
{role.name}
</Chip>
) : (
<BasicChip key={role.id}>
{role.name}
</BasicChip>
)
))}
</ul>
)}
{teamRoles.length > 0 && (
<ul style={userRolesWrapperStyle}>
<Text component={TextVariants.h6} style={detailLabelStyle}>
{i18n._(t`Team Roles`)}
</Text>
{teamRoles.map(role => (
role.user_capabilities.unattach ? (
<Chip
key={role.id}
className="awx-c-chip"
onClick={() => { onRoleDelete(role, accessRecord); }}
>
{role.name}
</Chip>
) : (
<BasicChip key={role.id}>
{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 { withRouter } from 'react-router-dom';
import { Formik, Field } from 'formik';
import { I18n } from '@lingui/react';
import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import {
Form,
@@ -83,76 +83,72 @@ class OrganizationForm extends Component {
}
render () {
const { organization, handleCancel } = this.props;
const { organization, handleCancel, i18n } = this.props;
const { instanceGroups, formIsValid, error } = this.state;
const defaultVenv = '/venv/ansible/';
return (
<I18n>
{({ i18n }) => (
<Formik
initialValues={{
name: organization.name,
description: organization.description,
custom_virtualenv: organization.custom_virtualenv || '',
}}
onSubmit={this.handleSubmit}
render={formik => (
<Form autoComplete="off" onSubmit={formik.handleSubmit}>
<FormRow>
<FormField
id="org-name"
name="name"
type="text"
label={i18n._(t`Name`)}
validate={required()}
isRequired
/>
<FormField
id="org-description"
name="description"
type="text"
label={i18n._(t`Description`)}
/>
<Config>
{({ custom_virtualenvs }) => (
custom_virtualenvs && custom_virtualenvs.length > 1 && (
<Field
name="custom_virtualenv"
render={({ field }) => (
<FormGroup
fieldId="org-custom-virtualenv"
label={i18n._(t`Ansible Environment`)}
>
<AnsibleSelect
data={custom_virtualenvs}
defaultSelected={defaultVenv}
label={i18n._(t`Ansible Environment`)}
{...field}
/>
</FormGroup>
)}
/>
)
)}
</Config>
</FormRow>
<InstanceGroupsLookup
value={instanceGroups}
onChange={this.handleInstanceGroupsChange}
tooltip={i18n._(t`Select the Instance Groups for this Organization to run on.`)}
/>
<FormActionGroup
onCancel={handleCancel}
onSubmit={formik.handleSubmit}
submitDisabled={!formIsValid}
/>
{error ? <div>error</div> : null}
</Form>
)}
/>
<Formik
initialValues={{
name: organization.name,
description: organization.description,
custom_virtualenv: organization.custom_virtualenv || '',
}}
onSubmit={this.handleSubmit}
render={formik => (
<Form autoComplete="off" onSubmit={formik.handleSubmit}>
<FormRow>
<FormField
id="org-name"
name="name"
type="text"
label={i18n._(t`Name`)}
validate={required(null, i18n)}
isRequired
/>
<FormField
id="org-description"
name="description"
type="text"
label={i18n._(t`Description`)}
/>
<Config>
{({ custom_virtualenvs }) => (
custom_virtualenvs && custom_virtualenvs.length > 1 && (
<Field
name="custom_virtualenv"
render={({ field }) => (
<FormGroup
fieldId="org-custom-virtualenv"
label={i18n._(t`Ansible Environment`)}
>
<AnsibleSelect
data={custom_virtualenvs}
defaultSelected={defaultVenv}
label={i18n._(t`Ansible Environment`)}
{...field}
/>
</FormGroup>
)}
/>
)
)}
</Config>
</FormRow>
<InstanceGroupsLookup
value={instanceGroups}
onChange={this.handleInstanceGroupsChange}
tooltip={i18n._(t`Select the Instance Groups for this Organization to run on.`)}
/>
<FormActionGroup
onCancel={handleCancel}
onSubmit={formik.handleSubmit}
submitDisabled={!formIsValid}
/>
{error ? <div>error</div> : null}
</Form>
)}
</I18n>
/>
);
}
}
@@ -176,4 +172,4 @@ OrganizationForm.contextTypes = {
};
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 { string, bool, func } from 'prop-types';
import { Trans } from '@lingui/macro';
import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import {
Badge as PFBadge,
DataListItem,
@@ -62,6 +63,7 @@ class OrganizationListItem extends React.Component {
isSelected,
onSelect,
detailUrl,
i18n
} = this.props;
const labelId = `check-action-${organization.id}`;
return (
@@ -86,13 +88,15 @@ class OrganizationListItem extends React.Component {
</DataListCell>,
<DataListCell key="org-members" righthalf="true" width={2}>
<ListGroup>
<Trans>Members</Trans>
{i18n._(t`Members`)}
<Badge isRead>
{organization.summary_fields.related_field_counts.users}
</Badge>
</ListGroup>
</DataListCell>,
<DataListCell>
<ListGroup>
<Trans>Teams</Trans>
{i18n._(t`Teams`)}
<Badge isRead>
{organization.summary_fields.related_field_counts.teams}
</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 { I18n, i18nMark } from '@lingui/react';
import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import { Switch, Route, withRouter, Redirect } from 'react-router-dom';
import { Card, CardHeader, PageSection } from '@patternfly/react-core';
@@ -100,7 +100,8 @@ class Organization extends Component {
location,
match,
me,
history
history,
i18n
} = this.props;
const {
@@ -126,14 +127,14 @@ class Organization extends Component {
);
const tabsArray = [
{ name: i18nMark('Details'), link: `${match.url}/details`, id: 0 },
{ name: i18nMark('Access'), link: `${match.url}/access`, id: 1 },
{ name: i18nMark('Teams'), link: `${match.url}/teams`, id: 2 }
{ name: i18n._(t`Details`), link: `${match.url}/details`, id: 0 },
{ name: i18n._(t`Access`), link: `${match.url}/access`, id: 1 },
{ name: i18n._(t`Teams`), link: `${match.url}/teams`, id: 2 }
];
if (canSeeNotificationsTab) {
tabsArray.push({
name: i18nMark('Notifications'),
name: i18n._(t`Notifications`),
link: `${match.url}/notifications`,
id: 3
});
@@ -145,24 +146,18 @@ class Organization extends Component {
<CardHeader
style={tabsStyle}
>
<I18n>
{({ i18n }) => (
<React.Fragment>
<div className="awx-orgTabs-container">
<RoutedTabs
match={match}
history={history}
labeltext={i18n._(t`Organization detail tabs`)}
tabsArray={tabsArray}
/>
<CardCloseButton linkTo="/organizations" />
<div
className="awx-orgTabs__bottom-border"
/>
</div>
</React.Fragment>
)}
</I18n>
<div className="awx-orgTabs-container">
<RoutedTabs
match={match}
history={history}
labeltext={i18n._(t`Organization detail tabs`)}
tabsArray={tabsArray}
/>
<CardCloseButton linkTo="/organizations" />
<div
className="awx-orgTabs__bottom-border"
/>
</div>
</CardHeader>
));
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 };

View File

@@ -1,6 +1,7 @@
import React, { Fragment } from 'react';
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 OrganizationAccessItem from '../../components/OrganizationAccessItem';
import DeleteRoleConfirmationModal from '../../components/DeleteRoleConfirmationModal';
@@ -130,7 +131,7 @@ class OrganizationAccess extends React.Component {
}
render () {
const { api, organization } = this.props;
const { api, organization, i18n } = this.props;
const {
isLoading,
isInitialized,
@@ -167,9 +168,9 @@ class OrganizationAccess extends React.Component {
itemName="role"
qsConfig={QS_CONFIG}
toolbarColumns={[
{ name: i18nMark('Name'), key: 'first_name', isSortable: true },
{ name: i18nMark('Username'), key: 'username', isSortable: true },
{ name: i18nMark('Last Name'), key: 'last_name', isSortable: true },
{ name: i18n._(t`Name`), key: 'first_name', isSortable: true },
{ name: i18n._(t`Username`), key: 'username', isSortable: true },
{ name: i18n._(t`Last Name`), key: 'last_name', isSortable: true },
]}
additionalControls={canEdit ? [
<ToolbarAddButton key="add" onClick={this.toggleAddModal} />
@@ -197,4 +198,4 @@ class OrganizationAccess extends React.Component {
}
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 { Link, withRouter } from 'react-router-dom';
import { I18n } from '@lingui/react';
import { Trans, t } from '@lingui/macro';
import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import {
CardBody,
@@ -103,7 +103,8 @@ class OrganizationDetail extends Component {
modified,
summary_fields
},
match
match,
i18n
} = this.props;
const showOverflowChipAfter = 5;
@@ -127,58 +128,54 @@ class OrganizationDetail extends Component {
) : null;
return (
<I18n>
{({ i18n }) => (
<CardBody>
<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">
<Detail
label={i18n._(t`Name`)}
value={name}
/>
<Detail
label={i18n._(t`Description`)}
value={description}
/>
<Detail
label={i18n._(t`Ansible Environment`)}
value={custom_virtualenv}
/>
<Detail
label={i18n._(t`Created`)}
value={created}
/>
<Detail
label={i18n._(t`Last Modified`)}
value={modified}
/>
{(instanceGroups && instanceGroups.length > 0) && (
<TextContent style={{ display: 'flex', gridColumn: '1 / -1' }}>
<Text
component={TextVariants.h6}
style={detailLabelStyle}
>
<Trans>Instance Groups</Trans>
</Text>
<div style={detailValueStyle}>
{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>
<CardBody>
<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">
<Detail
label={i18n._(t`Name`)}
value={name}
/>
<Detail
label={i18n._(t`Description`)}
value={description}
/>
<Detail
label={i18n._(t`Ansible Environment`)}
value={custom_virtualenv}
/>
<Detail
label={i18n._(t`Created`)}
value={created}
/>
<Detail
label={i18n._(t`Last Modified`)}
value={modified}
/>
{(instanceGroups && instanceGroups.length > 0) && (
<TextContent style={{ display: 'flex', gridColumn: '1 / -1' }}>
<Text
component={TextVariants.h6}
style={detailLabelStyle}
>
{i18n._(t`Instance Groups`)}
</Text>
<div style={detailValueStyle}>
{instanceGroupChips}
{overflowChip}
</div>
)}
{error ? 'error!' : ''}
</CardBody>
</TextContent>
)}
</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 PropTypes from 'prop-types';
import { withRouter } from 'react-router-dom';
import { I18n } from '@lingui/react';
import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import {
PageSection,
@@ -57,30 +57,27 @@ class OrganizationAdd extends React.Component {
render () {
const { error } = this.state;
const { i18n } = this.props;
return (
<PageSection>
<I18n>
{({ i18n }) => (
<Card>
<CardHeader className="at-u-textRight">
<Tooltip
content={i18n._(t`Close`)}
position="top"
>
<CardCloseButton onClick={this.handleCancel} />
</Tooltip>
</CardHeader>
<CardBody>
<OrganizationForm
handleSubmit={this.handleSubmit}
handleCancel={this.handleCancel}
/>
{error ? <div>error</div> : ''}
</CardBody>
</Card>
)}
</I18n>
<Card>
<CardHeader className="at-u-textRight">
<Tooltip
content={i18n._(t`Close`)}
position="top"
>
<CardCloseButton onClick={this.handleCancel} />
</Tooltip>
</CardHeader>
<CardBody>
<OrganizationForm
handleSubmit={this.handleSubmit}
handleCancel={this.handleCancel}
/>
{error ? <div>error</div> : ''}
</CardBody>
</Card>
</PageSection>
);
}
@@ -95,4 +92,4 @@ OrganizationAdd.contextTypes = {
};
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 { withRouter } from 'react-router-dom';
import { i18nMark } from '@lingui/react';
import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import {
Card,
PageSection,
@@ -15,12 +16,6 @@ import PaginatedDataList, {
import OrganizationListItem from '../components/OrganizationListItem';
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', {
page: 1,
page_size: 5,
@@ -36,7 +31,7 @@ class OrganizationsList extends Component {
isLoading: true,
isInitialized: false,
organizations: [],
selected: [],
selected: []
};
this.handleSelectAll = this.handleSelectAll.bind(this);
@@ -148,9 +143,9 @@ class OrganizationsList extends Component {
isLoading,
isInitialized,
selected,
organizations,
organizations
} = this.state;
const { match } = this.props;
const { match, i18n } = this.props;
const isAllSelected = selected.length === organizations.length;
@@ -163,7 +158,11 @@ class OrganizationsList extends Component {
itemCount={itemCount}
itemName="organization"
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
isAllSelected={isAllSelected}
onSelectAll={this.handleSelectAll}
@@ -198,4 +197,4 @@ class OrganizationsList extends Component {
}
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 { Trans } from '@lingui/macro';
import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import {
PageSection,
PageSectionVariants,
@@ -8,13 +9,14 @@ import {
class Portal extends Component {
render () {
const { i18n } = this.props;
const { light, medium } = PageSectionVariants;
return (
<Fragment>
<PageSection variant={light} className="pf-m-condensed">
<Title size="2xl">
<Trans>My View</Trans>
{i18n._(t`My View`)}
</Title>
</PageSection>
<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 { Trans } from '@lingui/macro';
import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import {
PageSection,
PageSectionVariants,
@@ -8,13 +9,14 @@ import {
class Projects extends Component {
render () {
const { i18n } = this.props;
const { light, medium } = PageSectionVariants;
return (
<Fragment>
<PageSection variant={light} className="pf-m-condensed">
<Title size="2xl">
<Trans>Projects</Trans>
{i18n._(t`Projects`)}
</Title>
</PageSection>
<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 { Trans } from '@lingui/macro';
import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import {
PageSection,
PageSectionVariants,
@@ -8,13 +9,14 @@ import {
class Schedules extends Component {
render () {
const { i18n } = this.props;
const { light, medium } = PageSectionVariants;
return (
<Fragment>
<PageSection variant={light} className="pf-m-condensed">
<Title size="2xl">
<Trans>Schedules</Trans>
{i18n._(t`Schedules`)}
</Title>
</PageSection>
<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 { Trans } from '@lingui/macro';
import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import {
PageSection,
PageSectionVariants,
@@ -8,13 +9,14 @@ import {
class SystemSettings extends Component {
render () {
const { i18n } = this.props;
const { light, medium } = PageSectionVariants;
return (
<Fragment>
<PageSection variant={light} className="pf-m-condensed">
<Title size="2xl">
<Trans>System Settings</Trans>
{i18n._(t`System Settings`)}
</Title>
</PageSection>
<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 { Trans } from '@lingui/macro';
import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import {
PageSection,
PageSectionVariants,
@@ -8,13 +9,14 @@ import {
class Teams extends Component {
render () {
const { i18n } = this.props;
const { light, medium } = PageSectionVariants;
return (
<Fragment>
<PageSection variant={light} className="pf-m-condensed">
<Title size="2xl">
<Trans>Teams</Trans>
{i18n._(t`Teams`)}
</Title>
</PageSection>
<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 { Trans } from '@lingui/macro';
import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import {
PageSection,
PageSectionVariants,
@@ -8,13 +9,14 @@ import {
class Templates extends Component {
render () {
const { i18n } = this.props;
const { light, medium } = PageSectionVariants;
return (
<Fragment>
<PageSection variant={light} className="pf-m-condensed">
<Title size="2xl">
<Trans>Templates</Trans>
{i18n._(t`Templates`)}
</Title>
</PageSection>
<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 { Trans } from '@lingui/macro';
import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import {
PageSection,
PageSectionVariants,
@@ -8,13 +9,14 @@ import {
class UISettings extends Component {
render () {
const { i18n } = this.props;
const { light, medium } = PageSectionVariants;
return (
<Fragment>
<PageSection variant={light} className="pf-m-condensed">
<Title size="2xl">
<Trans>User Interface Settings</Trans>
{i18n._(t`User Interface Settings`)}
</Title>
</PageSection>
<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 { Trans } from '@lingui/macro';
import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import {
PageSection,
PageSectionVariants,
@@ -8,13 +9,14 @@ import {
class Users extends Component {
render () {
const { i18n } = this.props;
const { light, medium } = PageSectionVariants;
return (
<Fragment>
<PageSection variant={light} className="pf-m-condensed">
<Title size="2xl">
<Trans>Users</Trans>
{i18n._(t`Users`)}
</Title>
</PageSection>
<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;
};
}