Pluralized modal titles and empty state strings

All itemNames used in empty state messages, and delete modal titles
need to be plural and capitalized.  Because of this change we no
longer need the ucFirst() in utils/strings.js.
This commit is contained in:
Alex Corey
2019-09-19 13:41:13 -04:00
parent 8dd4379bf2
commit b3b53a8ce4
16 changed files with 33 additions and 52 deletions

View File

@@ -212,7 +212,6 @@ class AddResourceRole extends React.Component {
selectedLabel={i18n._(t`Selected`)} selectedLabel={i18n._(t`Selected`)}
selectedResourceRows={selectedResourceRows} selectedResourceRows={selectedResourceRows}
sortedColumnKey="username" sortedColumnKey="username"
itemName="user"
/> />
)} )}
{selectedResource === 'teams' && ( {selectedResource === 'teams' && (
@@ -222,7 +221,6 @@ class AddResourceRole extends React.Component {
onSearch={readTeams} onSearch={readTeams}
selectedLabel={i18n._(t`Selected`)} selectedLabel={i18n._(t`Selected`)}
selectedResourceRows={selectedResourceRows} selectedResourceRows={selectedResourceRows}
itemName="team"
/> />
)} )}
</Fragment> </Fragment>

View File

@@ -74,7 +74,6 @@ class SelectResourceStep extends React.Component {
onRowClick, onRowClick,
selectedLabel, selectedLabel,
selectedResourceRows, selectedResourceRows,
itemName,
i18n, i18n,
} = this.props; } = this.props;
@@ -100,7 +99,6 @@ class SelectResourceStep extends React.Component {
<PaginatedDataList <PaginatedDataList
items={resources} items={resources}
itemCount={count} itemCount={count}
itemName={itemName}
qsConfig={this.qsConfig} qsConfig={this.qsConfig}
toolbarColumns={columns} toolbarColumns={columns}
renderItem={item => ( renderItem={item => (
@@ -132,7 +130,6 @@ SelectResourceStep.propTypes = {
selectedLabel: PropTypes.string, selectedLabel: PropTypes.string,
selectedResourceRows: PropTypes.arrayOf(PropTypes.object), selectedResourceRows: PropTypes.arrayOf(PropTypes.object),
sortedColumnKey: PropTypes.string, sortedColumnKey: PropTypes.string,
itemName: PropTypes.string,
}; };
SelectResourceStep.defaultProps = { SelectResourceStep.defaultProps = {
@@ -141,7 +138,6 @@ SelectResourceStep.defaultProps = {
selectedLabel: null, selectedLabel: null,
selectedResourceRows: [], selectedResourceRows: [],
sortedColumnKey: 'name', sortedColumnKey: 'name',
itemName: 'item',
}; };
export { SelectResourceStep as _SelectResourceStep }; export { SelectResourceStep as _SelectResourceStep };

View File

@@ -212,7 +212,7 @@ class Lookup extends React.Component {
i18n, i18n,
} = this.props; } = this.props;
const header = lookupHeader || i18n._(t`items`); const header = lookupHeader || i18n._(t`Items`);
const canDelete = !required || (multiple && value.length > 1); const canDelete = !required || (multiple && value.length > 1);
const chips = value ? ( const chips = value ? (
@@ -268,7 +268,7 @@ class Lookup extends React.Component {
<PaginatedDataList <PaginatedDataList
items={results} items={results}
itemCount={count} itemCount={count}
itemName={lookupHeader} pluralizedItemName={lookupHeader}
qsConfig={this.qsConfig} qsConfig={this.qsConfig}
toolbarColumns={columns} toolbarColumns={columns}
renderItem={item => ( renderItem={item => (

View File

@@ -17,7 +17,6 @@ import {
parseQueryString, parseQueryString,
addParams, addParams,
} from '@util/qs'; } from '@util/qs';
import { ucFirst } from '@util/strings';
import { QSConfig } from '@types'; import { QSConfig } from '@types';
@@ -63,7 +62,7 @@ class PaginatedDataList extends React.Component {
qsConfig, qsConfig,
renderItem, renderItem,
toolbarColumns, toolbarColumns,
itemName, pluralizedItemName,
showPageSizeOptions, showPageSizeOptions,
location, location,
i18n, i18n,
@@ -81,11 +80,11 @@ class PaginatedDataList extends React.Component {
]; ];
const queryParams = parseQueryString(qsConfig, location.search); const queryParams = parseQueryString(qsConfig, location.search);
const dataListLabel = i18n._(t`${itemName} List`); const dataListLabel = i18n._(t`${pluralizedItemName} List`);
const emptyContentMessage = i18n._( const emptyContentMessage = i18n._(
t`Please add ${itemName} to populate this list ` t`Please add ${pluralizedItemName} to populate this list `
); );
const emptyContentTitle = i18n._(t`No ${itemName} Found `); const emptyContentTitle = i18n._(t`No ${pluralizedItemName} Found `);
let Content; let Content;
if (hasContentLoading && items.length <= 0) { if (hasContentLoading && items.length <= 0) {
@@ -157,7 +156,7 @@ const Item = PropTypes.shape({
PaginatedDataList.propTypes = { PaginatedDataList.propTypes = {
items: PropTypes.arrayOf(Item).isRequired, items: PropTypes.arrayOf(Item).isRequired,
itemCount: PropTypes.number.isRequired, itemCount: PropTypes.number.isRequired,
itemName: PropTypes.string, pluralizedItemName: PropTypes.string,
qsConfig: QSConfig.isRequired, qsConfig: QSConfig.isRequired,
renderItem: PropTypes.func, renderItem: PropTypes.func,
toolbarColumns: arrayOf( toolbarColumns: arrayOf(
@@ -177,7 +176,7 @@ PaginatedDataList.defaultProps = {
hasContentLoading: false, hasContentLoading: false,
contentError: null, contentError: null,
toolbarColumns: [], toolbarColumns: [],
itemName: 'item', pluralizedItemName: 'Items',
showPageSizeOptions: true, showPageSizeOptions: true,
renderItem: item => <PaginatedDataListItem key={item.id} item={item} />, renderItem: item => <PaginatedDataListItem key={item.id} item={item} />,
renderToolbar: props => <DataListToolbar {...props} />, renderToolbar: props => <DataListToolbar {...props} />,

View File

@@ -6,7 +6,6 @@ import styled from 'styled-components';
import { withI18n } from '@lingui/react'; import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro'; import { t } from '@lingui/macro';
import AlertModal from '../AlertModal'; import AlertModal from '../AlertModal';
import { pluralize } from '../../util/strings';
const DeleteButton = styled(Button)` const DeleteButton = styled(Button)`
padding: 5px 8px; padding: 5px 8px;
@@ -41,11 +40,11 @@ class ToolbarDeleteButton extends React.Component {
static propTypes = { static propTypes = {
onDelete: func.isRequired, onDelete: func.isRequired,
itemsToDelete: arrayOf(ItemToDelete).isRequired, itemsToDelete: arrayOf(ItemToDelete).isRequired,
itemName: string, pluralizedItemName: string,
}; };
static defaultProps = { static defaultProps = {
itemName: 'item', pluralizedItemName: 'Items',
}; };
constructor(props) { constructor(props) {
@@ -75,7 +74,7 @@ class ToolbarDeleteButton extends React.Component {
} }
renderTooltip() { renderTooltip() {
const { itemsToDelete, itemName, i18n } = this.props; const { itemsToDelete, pluralizedItemName, i18n } = this.props;
const itemsUnableToDelete = itemsToDelete const itemsUnableToDelete = itemsToDelete
.filter(cannotDelete) .filter(cannotDelete)
@@ -85,7 +84,7 @@ class ToolbarDeleteButton extends React.Component {
return ( return (
<div> <div>
{i18n._( {i18n._(
t`You do not have permission to delete the following ${itemName}: ${itemsUnableToDelete}` t`You do not have permission to delete the following ${pluralizedItemName}: ${itemsUnableToDelete}`
)} )}
</div> </div>
); );
@@ -97,7 +96,7 @@ class ToolbarDeleteButton extends React.Component {
} }
render() { render() {
const { itemsToDelete, itemName, i18n } = this.props; const { itemsToDelete, pluralizedItemName, i18n } = this.props;
const { isModalOpen } = this.state; const { isModalOpen } = this.state;
const isDisabled = const isDisabled =
@@ -123,7 +122,7 @@ class ToolbarDeleteButton extends React.Component {
{isModalOpen && ( {isModalOpen && (
<AlertModal <AlertModal
variant="danger" variant="danger"
title={itemName} title={pluralizedItemName}
isOpen={isModalOpen} isOpen={isModalOpen}
onClose={this.handleCancelDelete} onClose={this.handleCancelDelete}
actions={[ actions={[

View File

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

View File

@@ -159,7 +159,7 @@ class JobList extends Component {
hasContentLoading={hasContentLoading} hasContentLoading={hasContentLoading}
items={jobs} items={jobs}
itemCount={itemCount} itemCount={itemCount}
itemName={itemCount === 1 ? 'Job' : 'Jobs'} pluralizedItemName="Jobs"
qsConfig={QS_CONFIG} qsConfig={QS_CONFIG}
toolbarColumns={[ toolbarColumns={[
{ {
@@ -188,7 +188,7 @@ class JobList extends Component {
key="delete" key="delete"
onDelete={this.handleJobDelete} onDelete={this.handleJobDelete}
itemsToDelete={selected} itemsToDelete={selected}
itemName={selected.length === 1 ? 'Job' : 'Jobs' } pluralizedItemName="Jobs"
/>, />,
]} ]}
/> />

View File

@@ -165,7 +165,7 @@ class OrganizationAccess extends React.Component {
hasContentLoading={hasContentLoading} hasContentLoading={hasContentLoading}
items={accessRecords} items={accessRecords}
itemCount={itemCount} itemCount={itemCount}
itemName={itemCount.length === 1 ? 'Role' : 'Roles'} pluralizedItemName="Roles"
qsConfig={QS_CONFIG} qsConfig={QS_CONFIG}
toolbarColumns={[ toolbarColumns={[
{ {

View File

@@ -37,8 +37,8 @@ exports[`<OrganizationAccess /> initially renders succesfully 1`] = `
error={null} error={null}
hasContentLoading={true} hasContentLoading={true}
itemCount={0} itemCount={0}
itemName="Roles"
items={Array []} items={Array []}
pluralizedItemName="Roles"
qsConfig={ qsConfig={
Object { Object {
"dateFields": Array [ "dateFields": Array [
@@ -91,8 +91,8 @@ exports[`<OrganizationAccess /> initially renders succesfully 1`] = `
hasContentLoading={true} hasContentLoading={true}
i18n={"/i18n/"} i18n={"/i18n/"}
itemCount={0} itemCount={0}
itemName="Roles"
items={Array []} items={Array []}
pluralizedItemName="Roles"
qsConfig={ qsConfig={
Object { Object {
"dateFields": Array [ "dateFields": Array [
@@ -144,7 +144,6 @@ exports[`<OrganizationAccess /> initially renders succesfully 1`] = `
history={"/history/"} history={"/history/"}
i18n={"/i18n/"} i18n={"/i18n/"}
itemCount={0} itemCount={0}
itemName="Roles"
items={Array []} items={Array []}
location={ location={
Object { Object {
@@ -162,6 +161,7 @@ exports[`<OrganizationAccess /> initially renders succesfully 1`] = `
"url": "", "url": "",
} }
} }
pluralizedItemName="Roles"
qsConfig={ qsConfig={
Object { Object {
"dateFields": Array [ "dateFields": Array [

View File

@@ -153,7 +153,7 @@ class OrganizationsList extends Component {
hasContentLoading={hasContentLoading} hasContentLoading={hasContentLoading}
items={organizations} items={organizations}
itemCount={itemCount} itemCount={itemCount}
itemName={itemCount === 1 ? 'Organization' : 'Organizations'} pluralizedItemName="Organizations"
qsConfig={QS_CONFIG} qsConfig={QS_CONFIG}
toolbarColumns={[ toolbarColumns={[
{ {
@@ -187,7 +187,7 @@ class OrganizationsList extends Component {
key="delete" key="delete"
onDelete={this.handleOrgDelete} onDelete={this.handleOrgDelete}
itemsToDelete={selected} itemsToDelete={selected}
itemName="Organization" pluralizedItemName="Organizations"
/>, />,
canAdd ? ( canAdd ? (
<ToolbarAddButton key="add" linkTo={`${match.url}/add`} /> <ToolbarAddButton key="add" linkTo={`${match.url}/add`} />

View File

@@ -204,7 +204,7 @@ class OrganizationNotifications extends Component {
hasContentLoading={hasContentLoading} hasContentLoading={hasContentLoading}
items={notifications} items={notifications}
itemCount={itemCount} itemCount={itemCount}
itemName={itemCount.length === 1 ? 'Notification' : 'Notifications'} pluralizedItemName="Notifications"
qsConfig={QS_CONFIG} qsConfig={QS_CONFIG}
toolbarColumns={COLUMNS} toolbarColumns={COLUMNS}
renderItem={notification => ( renderItem={notification => (

View File

@@ -42,7 +42,6 @@ exports[`<OrganizationNotifications /> initially renders succesfully 1`] = `
contentError={null} contentError={null}
hasContentLoading={false} hasContentLoading={false}
itemCount={2} itemCount={2}
itemName="Notifications"
items={ items={
Array [ Array [
Object { Object {
@@ -65,6 +64,7 @@ exports[`<OrganizationNotifications /> initially renders succesfully 1`] = `
}, },
] ]
} }
pluralizedItemName="Notifications"
qsConfig={ qsConfig={
Object { Object {
"dateFields": Array [ "dateFields": Array [
@@ -116,7 +116,6 @@ exports[`<OrganizationNotifications /> initially renders succesfully 1`] = `
hasContentLoading={false} hasContentLoading={false}
i18n={"/i18n/"} i18n={"/i18n/"}
itemCount={2} itemCount={2}
itemName="Notifications"
items={ items={
Array [ Array [
Object { Object {
@@ -139,6 +138,7 @@ exports[`<OrganizationNotifications /> initially renders succesfully 1`] = `
}, },
] ]
} }
pluralizedItemName="Notifications"
qsConfig={ qsConfig={
Object { Object {
"dateFields": Array [ "dateFields": Array [
@@ -188,7 +188,6 @@ exports[`<OrganizationNotifications /> initially renders succesfully 1`] = `
history={"/history/"} history={"/history/"}
i18n={"/i18n/"} i18n={"/i18n/"}
itemCount={2} itemCount={2}
itemName="Notifications"
items={ items={
Array [ Array [
Object { Object {
@@ -227,6 +226,7 @@ exports[`<OrganizationNotifications /> initially renders succesfully 1`] = `
"url": "", "url": "",
} }
} }
pluralizedItemName="Notifications"
qsConfig={ qsConfig={
Object { Object {
"dateFields": Array [ "dateFields": Array [
@@ -1827,10 +1827,10 @@ exports[`<OrganizationNotifications /> initially renders succesfully 1`] = `
</Route> </Route>
</withRouter(ListHeader)> </withRouter(ListHeader)>
<DataList <DataList
aria-label="{itemDisplayName} List" aria-label="{pluralizedItemName} List"
> >
<ul <ul
aria-label="{itemDisplayName} List" aria-label="{pluralizedItemName} List"
className="pf-c-data-list" className="pf-c-data-list"
> >
<WithI18n <WithI18n

View File

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

View File

@@ -178,7 +178,7 @@ class TemplatesList extends Component {
hasContentLoading={hasContentLoading} hasContentLoading={hasContentLoading}
items={templates} items={templates}
itemCount={itemCount} itemCount={itemCount}
itemName={itemCount === 1 ? 'Template' : 'Templates'} pluralizedItemName="Templates"
qsConfig={QS_CONFIG} qsConfig={QS_CONFIG}
toolbarColumns={[ toolbarColumns={[
{ {
@@ -213,7 +213,7 @@ class TemplatesList extends Component {
key="delete" key="delete"
onDelete={this.handleTemplateDelete} onDelete={this.handleTemplateDelete}
itemsToDelete={selected} itemsToDelete={selected}
itemName={selected.length === 1 ? 'Template' : 'Templates'} pluralizedItemName="Templates"
/>, />,
canAdd && ( canAdd && (
<Dropdown <Dropdown

View File

@@ -1,4 +1,3 @@
// TODO: switch to using Lingui i18n for articles // TODO: switch to using Lingui i18n for articles
export function getArticle(str) { export function getArticle(str) {
const first = str[0]; const first = str[0];
@@ -8,10 +7,6 @@ export function getArticle(str) {
return 'a'; return 'a';
} }
export function ucFirst(str) {
return `${str[0].toUpperCase()}${str.substr(1)}`;
}
export const toTitleCase = string => { export const toTitleCase = string => {
if (!string) { if (!string) {
return ''; return '';

View File

@@ -1,4 +1,4 @@
import { getArticle, ucFirst, toTitleCase } from './strings'; import { getArticle, toTitleCase } from './strings';
describe('string utils', () => { describe('string utils', () => {
describe('getArticle', () => { describe('getArticle', () => {
@@ -16,12 +16,6 @@ describe('string utils', () => {
}); });
}); });
describe('ucFirst', () => {
test('should capitalize first character', () => {
expect(ucFirst('team')).toEqual('Team');
});
});
describe('toTitleCase', () => { describe('toTitleCase', () => {
test('should upper case each word', () => { test('should upper case each word', () => {
expect(toTitleCase('a_string_of_words')).toEqual('A String Of Words'); expect(toTitleCase('a_string_of_words')).toEqual('A String Of Words');