mirror of
https://github.com/ansible/awx.git
synced 2026-03-13 23:17:32 -02:30
Merge pull request #4770 from AlexSCorey/Pluralization
Requires individual components to pluralize Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
This commit is contained in:
@@ -212,7 +212,6 @@ class AddResourceRole extends React.Component {
|
||||
selectedLabel={i18n._(t`Selected`)}
|
||||
selectedResourceRows={selectedResourceRows}
|
||||
sortedColumnKey="username"
|
||||
itemName="user"
|
||||
/>
|
||||
)}
|
||||
{selectedResource === 'teams' && (
|
||||
@@ -222,7 +221,6 @@ class AddResourceRole extends React.Component {
|
||||
onSearch={readTeams}
|
||||
selectedLabel={i18n._(t`Selected`)}
|
||||
selectedResourceRows={selectedResourceRows}
|
||||
itemName="team"
|
||||
/>
|
||||
)}
|
||||
</Fragment>
|
||||
|
||||
@@ -74,7 +74,6 @@ class SelectResourceStep extends React.Component {
|
||||
onRowClick,
|
||||
selectedLabel,
|
||||
selectedResourceRows,
|
||||
itemName,
|
||||
i18n,
|
||||
} = this.props;
|
||||
|
||||
@@ -100,7 +99,6 @@ class SelectResourceStep extends React.Component {
|
||||
<PaginatedDataList
|
||||
items={resources}
|
||||
itemCount={count}
|
||||
itemName={itemName}
|
||||
qsConfig={this.qsConfig}
|
||||
toolbarColumns={columns}
|
||||
renderItem={item => (
|
||||
@@ -132,7 +130,6 @@ SelectResourceStep.propTypes = {
|
||||
selectedLabel: PropTypes.string,
|
||||
selectedResourceRows: PropTypes.arrayOf(PropTypes.object),
|
||||
sortedColumnKey: PropTypes.string,
|
||||
itemName: PropTypes.string,
|
||||
};
|
||||
|
||||
SelectResourceStep.defaultProps = {
|
||||
@@ -141,7 +138,6 @@ SelectResourceStep.defaultProps = {
|
||||
selectedLabel: null,
|
||||
selectedResourceRows: [],
|
||||
sortedColumnKey: 'name',
|
||||
itemName: 'item',
|
||||
};
|
||||
|
||||
export { SelectResourceStep as _SelectResourceStep };
|
||||
|
||||
@@ -212,7 +212,7 @@ class Lookup extends React.Component {
|
||||
i18n,
|
||||
} = this.props;
|
||||
|
||||
const header = lookupHeader || i18n._(t`items`);
|
||||
const header = lookupHeader || i18n._(t`Items`);
|
||||
const canDelete = !required || (multiple && value.length > 1);
|
||||
|
||||
const chips = value ? (
|
||||
@@ -268,8 +268,7 @@ class Lookup extends React.Component {
|
||||
<PaginatedDataList
|
||||
items={results}
|
||||
itemCount={count}
|
||||
itemName={lookupHeader}
|
||||
itemNamePlural={lookupHeader}
|
||||
pluralizedItemName={lookupHeader}
|
||||
qsConfig={this.qsConfig}
|
||||
toolbarColumns={columns}
|
||||
renderItem={item => (
|
||||
|
||||
@@ -17,7 +17,6 @@ import {
|
||||
parseQueryString,
|
||||
replaceParams,
|
||||
} from '@util/qs';
|
||||
import { pluralize, ucFirst } from '@util/strings';
|
||||
|
||||
import { QSConfig } from '@types';
|
||||
|
||||
@@ -61,8 +60,7 @@ class PaginatedDataList extends React.Component {
|
||||
qsConfig,
|
||||
renderItem,
|
||||
toolbarColumns,
|
||||
itemName,
|
||||
itemNamePlural,
|
||||
pluralizedItemName,
|
||||
showPageSizeOptions,
|
||||
location,
|
||||
i18n,
|
||||
@@ -80,16 +78,11 @@ class PaginatedDataList extends React.Component {
|
||||
];
|
||||
const queryParams = parseQueryString(qsConfig, location.search);
|
||||
|
||||
const itemDisplayName = ucFirst(pluralize(itemName));
|
||||
const itemDisplayNamePlural = ucFirst(
|
||||
itemNamePlural || pluralize(itemName)
|
||||
);
|
||||
|
||||
const dataListLabel = i18n._(t`${itemDisplayName} List`);
|
||||
const dataListLabel = i18n._(t`${pluralizedItemName} List`);
|
||||
const emptyContentMessage = i18n._(
|
||||
t`Please add ${itemDisplayNamePlural} to populate this list `
|
||||
t`Please add ${pluralizedItemName} to populate this list `
|
||||
);
|
||||
const emptyContentTitle = i18n._(t`No ${itemDisplayNamePlural} Found `);
|
||||
const emptyContentTitle = i18n._(t`No ${pluralizedItemName} Found `);
|
||||
|
||||
let Content;
|
||||
if (hasContentLoading && items.length <= 0) {
|
||||
@@ -161,8 +154,7 @@ const Item = PropTypes.shape({
|
||||
PaginatedDataList.propTypes = {
|
||||
items: PropTypes.arrayOf(Item).isRequired,
|
||||
itemCount: PropTypes.number.isRequired,
|
||||
itemName: PropTypes.string,
|
||||
itemNamePlural: PropTypes.string,
|
||||
pluralizedItemName: PropTypes.string,
|
||||
qsConfig: QSConfig.isRequired,
|
||||
renderItem: PropTypes.func,
|
||||
toolbarColumns: arrayOf(
|
||||
@@ -182,8 +174,7 @@ PaginatedDataList.defaultProps = {
|
||||
hasContentLoading: false,
|
||||
contentError: null,
|
||||
toolbarColumns: [],
|
||||
itemName: 'item',
|
||||
itemNamePlural: '',
|
||||
pluralizedItemName: 'Items',
|
||||
showPageSizeOptions: true,
|
||||
renderItem: item => <PaginatedDataListItem key={item.id} item={item} />,
|
||||
renderToolbar: props => <DataListToolbar {...props} />,
|
||||
|
||||
@@ -6,7 +6,6 @@ import styled from 'styled-components';
|
||||
import { withI18n } from '@lingui/react';
|
||||
import { t } from '@lingui/macro';
|
||||
import AlertModal from '../AlertModal';
|
||||
import { pluralize } from '../../util/strings';
|
||||
|
||||
const DeleteButton = styled(Button)`
|
||||
padding: 5px 8px;
|
||||
@@ -41,11 +40,11 @@ class ToolbarDeleteButton extends React.Component {
|
||||
static propTypes = {
|
||||
onDelete: func.isRequired,
|
||||
itemsToDelete: arrayOf(ItemToDelete).isRequired,
|
||||
itemName: string,
|
||||
pluralizedItemName: string,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
itemName: 'item',
|
||||
pluralizedItemName: 'Items',
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
@@ -75,7 +74,7 @@ class ToolbarDeleteButton extends React.Component {
|
||||
}
|
||||
|
||||
renderTooltip() {
|
||||
const { itemsToDelete, itemName, i18n } = this.props;
|
||||
const { itemsToDelete, pluralizedItemName, i18n } = this.props;
|
||||
|
||||
const itemsUnableToDelete = itemsToDelete
|
||||
.filter(cannotDelete)
|
||||
@@ -85,9 +84,7 @@ class ToolbarDeleteButton extends React.Component {
|
||||
return (
|
||||
<div>
|
||||
{i18n._(
|
||||
t`You do not have permission to delete the following ${pluralize(
|
||||
itemName
|
||||
)}: ${itemsUnableToDelete}`
|
||||
t`You do not have permission to delete the following ${pluralizedItemName}: ${itemsUnableToDelete}`
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
@@ -99,7 +96,7 @@ class ToolbarDeleteButton extends React.Component {
|
||||
}
|
||||
|
||||
render() {
|
||||
const { itemsToDelete, itemName, i18n } = this.props;
|
||||
const { itemsToDelete, pluralizedItemName, i18n } = this.props;
|
||||
const { isModalOpen } = this.state;
|
||||
|
||||
const isDisabled =
|
||||
@@ -125,11 +122,7 @@ class ToolbarDeleteButton extends React.Component {
|
||||
{isModalOpen && (
|
||||
<AlertModal
|
||||
variant="danger"
|
||||
title={
|
||||
itemsToDelete === 1
|
||||
? i18n._(t`Delete ${itemName}`)
|
||||
: i18n._(t`Delete ${pluralize(itemName)}`)
|
||||
}
|
||||
title={pluralizedItemName}
|
||||
isOpen={isModalOpen}
|
||||
onClose={this.handleCancelDelete}
|
||||
actions={[
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
exports[`<ToolbarDeleteButton /> should render button 1`] = `
|
||||
<ToolbarDeleteButton
|
||||
i18n={"/i18n/"}
|
||||
itemName="item"
|
||||
itemsToDelete={Array []}
|
||||
onDelete={[Function]}
|
||||
pluralizedItemName="Items"
|
||||
>
|
||||
<Tooltip
|
||||
appendTo={[Function]}
|
||||
|
||||
@@ -151,7 +151,6 @@ class JobList extends Component {
|
||||
} = this.state;
|
||||
const { match, i18n } = this.props;
|
||||
const isAllSelected = selected.length === jobs.length;
|
||||
const itemName = i18n._(t`Job`);
|
||||
return (
|
||||
<PageSection>
|
||||
<Card>
|
||||
@@ -160,7 +159,7 @@ class JobList extends Component {
|
||||
hasContentLoading={hasContentLoading}
|
||||
items={jobs}
|
||||
itemCount={itemCount}
|
||||
itemName={itemName}
|
||||
pluralizedItemName="Jobs"
|
||||
qsConfig={QS_CONFIG}
|
||||
toolbarColumns={[
|
||||
{
|
||||
@@ -189,7 +188,7 @@ class JobList extends Component {
|
||||
key="delete"
|
||||
onDelete={this.handleJobDelete}
|
||||
itemsToDelete={selected}
|
||||
itemName={itemName}
|
||||
pluralizedItemName="Jobs"
|
||||
/>,
|
||||
]}
|
||||
/>
|
||||
|
||||
@@ -165,7 +165,7 @@ class OrganizationAccess extends React.Component {
|
||||
hasContentLoading={hasContentLoading}
|
||||
items={accessRecords}
|
||||
itemCount={itemCount}
|
||||
itemName="role"
|
||||
pluralizedItemName="Roles"
|
||||
qsConfig={QS_CONFIG}
|
||||
toolbarColumns={[
|
||||
{
|
||||
|
||||
@@ -37,8 +37,8 @@ exports[`<OrganizationAccess /> initially renders succesfully 1`] = `
|
||||
error={null}
|
||||
hasContentLoading={true}
|
||||
itemCount={0}
|
||||
itemName="role"
|
||||
items={Array []}
|
||||
pluralizedItemName="Roles"
|
||||
qsConfig={
|
||||
Object {
|
||||
"dateFields": Array [
|
||||
@@ -91,8 +91,8 @@ exports[`<OrganizationAccess /> initially renders succesfully 1`] = `
|
||||
hasContentLoading={true}
|
||||
i18n={"/i18n/"}
|
||||
itemCount={0}
|
||||
itemName="role"
|
||||
items={Array []}
|
||||
pluralizedItemName="Roles"
|
||||
qsConfig={
|
||||
Object {
|
||||
"dateFields": Array [
|
||||
@@ -144,8 +144,6 @@ exports[`<OrganizationAccess /> initially renders succesfully 1`] = `
|
||||
history={"/history/"}
|
||||
i18n={"/i18n/"}
|
||||
itemCount={0}
|
||||
itemName="role"
|
||||
itemNamePlural=""
|
||||
items={Array []}
|
||||
location={
|
||||
Object {
|
||||
@@ -163,6 +161,7 @@ exports[`<OrganizationAccess /> initially renders succesfully 1`] = `
|
||||
"url": "",
|
||||
}
|
||||
}
|
||||
pluralizedItemName="Roles"
|
||||
qsConfig={
|
||||
Object {
|
||||
"dateFields": Array [
|
||||
|
||||
@@ -153,7 +153,7 @@ class OrganizationsList extends Component {
|
||||
hasContentLoading={hasContentLoading}
|
||||
items={organizations}
|
||||
itemCount={itemCount}
|
||||
itemName="organization"
|
||||
pluralizedItemName="Organizations"
|
||||
qsConfig={QS_CONFIG}
|
||||
toolbarColumns={[
|
||||
{
|
||||
@@ -187,7 +187,7 @@ class OrganizationsList extends Component {
|
||||
key="delete"
|
||||
onDelete={this.handleOrgDelete}
|
||||
itemsToDelete={selected}
|
||||
itemName="Organization"
|
||||
pluralizedItemName="Organizations"
|
||||
/>,
|
||||
canAdd ? (
|
||||
<ToolbarAddButton key="add" linkTo={`${match.url}/add`} />
|
||||
|
||||
@@ -204,7 +204,7 @@ class OrganizationNotifications extends Component {
|
||||
hasContentLoading={hasContentLoading}
|
||||
items={notifications}
|
||||
itemCount={itemCount}
|
||||
itemName="notification"
|
||||
pluralizedItemName="Notifications"
|
||||
qsConfig={QS_CONFIG}
|
||||
toolbarColumns={COLUMNS}
|
||||
renderItem={notification => (
|
||||
|
||||
@@ -42,7 +42,6 @@ exports[`<OrganizationNotifications /> initially renders succesfully 1`] = `
|
||||
contentError={null}
|
||||
hasContentLoading={false}
|
||||
itemCount={2}
|
||||
itemName="notification"
|
||||
items={
|
||||
Array [
|
||||
Object {
|
||||
@@ -65,6 +64,7 @@ exports[`<OrganizationNotifications /> initially renders succesfully 1`] = `
|
||||
},
|
||||
]
|
||||
}
|
||||
pluralizedItemName="Notifications"
|
||||
qsConfig={
|
||||
Object {
|
||||
"dateFields": Array [
|
||||
@@ -116,7 +116,6 @@ exports[`<OrganizationNotifications /> initially renders succesfully 1`] = `
|
||||
hasContentLoading={false}
|
||||
i18n={"/i18n/"}
|
||||
itemCount={2}
|
||||
itemName="notification"
|
||||
items={
|
||||
Array [
|
||||
Object {
|
||||
@@ -139,6 +138,7 @@ exports[`<OrganizationNotifications /> initially renders succesfully 1`] = `
|
||||
},
|
||||
]
|
||||
}
|
||||
pluralizedItemName="Notifications"
|
||||
qsConfig={
|
||||
Object {
|
||||
"dateFields": Array [
|
||||
@@ -188,8 +188,6 @@ exports[`<OrganizationNotifications /> initially renders succesfully 1`] = `
|
||||
history={"/history/"}
|
||||
i18n={"/i18n/"}
|
||||
itemCount={2}
|
||||
itemName="notification"
|
||||
itemNamePlural=""
|
||||
items={
|
||||
Array [
|
||||
Object {
|
||||
@@ -228,6 +226,7 @@ exports[`<OrganizationNotifications /> initially renders succesfully 1`] = `
|
||||
"url": "",
|
||||
}
|
||||
}
|
||||
pluralizedItemName="Notifications"
|
||||
qsConfig={
|
||||
Object {
|
||||
"dateFields": Array [
|
||||
@@ -1828,10 +1827,10 @@ exports[`<OrganizationNotifications /> initially renders succesfully 1`] = `
|
||||
</Route>
|
||||
</withRouter(ListHeader)>
|
||||
<DataList
|
||||
aria-label="{itemDisplayName} List"
|
||||
aria-label="{pluralizedItemName} List"
|
||||
>
|
||||
<ul
|
||||
aria-label="{itemDisplayName} List"
|
||||
aria-label="{pluralizedItemName} List"
|
||||
className="pf-c-data-list"
|
||||
>
|
||||
<WithI18n
|
||||
|
||||
@@ -65,7 +65,7 @@ class OrganizationTeams extends React.Component {
|
||||
hasContentLoading={hasContentLoading}
|
||||
items={teams}
|
||||
itemCount={itemCount}
|
||||
itemName="team"
|
||||
pluralizedItemName="Notifications"
|
||||
qsConfig={QS_CONFIG}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -178,7 +178,7 @@ class TemplatesList extends Component {
|
||||
hasContentLoading={hasContentLoading}
|
||||
items={templates}
|
||||
itemCount={itemCount}
|
||||
itemName={i18n._(t`Template`)}
|
||||
pluralizedItemName="Templates"
|
||||
qsConfig={QS_CONFIG}
|
||||
toolbarColumns={[
|
||||
{
|
||||
@@ -213,7 +213,7 @@ class TemplatesList extends Component {
|
||||
key="delete"
|
||||
onDelete={this.handleTemplateDelete}
|
||||
itemsToDelete={selected}
|
||||
itemName={i18n._(t`Template`)}
|
||||
pluralizedItemName="Templates"
|
||||
/>,
|
||||
canAdd && (
|
||||
<Dropdown
|
||||
|
||||
@@ -1,15 +1,3 @@
|
||||
// TODO: switch to using Lingui i18n for pluralization
|
||||
export function pluralize(str) {
|
||||
const lastChar = str[str.length - 1];
|
||||
if (lastChar === 's') {
|
||||
return `${str}es`;
|
||||
}
|
||||
if (lastChar === 'y') {
|
||||
return `${str.substr(0, str.length - 1)}ies`;
|
||||
}
|
||||
return `${str}s`;
|
||||
}
|
||||
|
||||
// TODO: switch to using Lingui i18n for articles
|
||||
export function getArticle(str) {
|
||||
const first = str[0];
|
||||
@@ -19,10 +7,6 @@ export function getArticle(str) {
|
||||
return 'a';
|
||||
}
|
||||
|
||||
export function ucFirst(str) {
|
||||
return `${str[0].toUpperCase()}${str.substr(1)}`;
|
||||
}
|
||||
|
||||
export const toTitleCase = string => {
|
||||
if (!string) {
|
||||
return '';
|
||||
|
||||
@@ -1,20 +1,6 @@
|
||||
import { pluralize, getArticle, ucFirst, toTitleCase } from './strings';
|
||||
import { getArticle, toTitleCase } from './strings';
|
||||
|
||||
describe('string utils', () => {
|
||||
describe('pluralize', () => {
|
||||
test('should add an "s"', () => {
|
||||
expect(pluralize('team')).toEqual('teams');
|
||||
});
|
||||
|
||||
test('should add an "es"', () => {
|
||||
expect(pluralize('class')).toEqual('classes');
|
||||
});
|
||||
|
||||
test('should handle word ending in y', () => {
|
||||
expect(pluralize('inventory')).toEqual('inventories');
|
||||
});
|
||||
});
|
||||
|
||||
describe('getArticle', () => {
|
||||
test('should return "a"', () => {
|
||||
expect(getArticle('team')).toEqual('a');
|
||||
@@ -30,12 +16,6 @@ describe('string utils', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('ucFirst', () => {
|
||||
test('should capitalize first character', () => {
|
||||
expect(ucFirst('team')).toEqual('Team');
|
||||
});
|
||||
});
|
||||
|
||||
describe('toTitleCase', () => {
|
||||
test('should upper case each word', () => {
|
||||
expect(toTitleCase('a_string_of_words')).toEqual('A String Of Words');
|
||||
|
||||
Reference in New Issue
Block a user