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:
softwarefactory-project-zuul[bot]
2019-09-24 15:55:11 +00:00
committed by GitHub
16 changed files with 33 additions and 95 deletions

View File

@@ -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>

View File

@@ -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 };

View File

@@ -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 => (

View File

@@ -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} />,

View File

@@ -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={[

View File

@@ -3,9 +3,9 @@
exports[`<ToolbarDeleteButton /> should render button 1`] = `
<ToolbarDeleteButton
i18n={"/i18n/"}
itemName="item"
itemsToDelete={Array []}
onDelete={[Function]}
pluralizedItemName="Items"
>
<Tooltip
appendTo={[Function]}

View File

@@ -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"
/>,
]}
/>

View File

@@ -165,7 +165,7 @@ class OrganizationAccess extends React.Component {
hasContentLoading={hasContentLoading}
items={accessRecords}
itemCount={itemCount}
itemName="role"
pluralizedItemName="Roles"
qsConfig={QS_CONFIG}
toolbarColumns={[
{

View File

@@ -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 [

View File

@@ -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`} />

View File

@@ -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 => (

View File

@@ -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

View File

@@ -65,7 +65,7 @@ class OrganizationTeams extends React.Component {
hasContentLoading={hasContentLoading}
items={teams}
itemCount={itemCount}
itemName="team"
pluralizedItemName="Notifications"
qsConfig={QS_CONFIG}
/>
);

View File

@@ -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

View File

@@ -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 '';

View File

@@ -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');