Add rowKey prop to table for allowing custom keys in rows (https://github.com/woocommerce/woocommerce-admin/pull/7196)

* Add rowKey prop to table for allowing custom keys in rows

* Add changelog

* Add test

* Fix lint errors
This commit is contained in:
louwie17 2021-06-18 09:18:19 -03:00 committed by GitHub
parent d9daed0a4f
commit 2443b857f6
6 changed files with 58 additions and 4 deletions

View File

@ -1,6 +1,7 @@
# Unreleased # Unreleased
- Revert Card component removal #7167. - Revert Card component removal #7167.
- Add rowKey prop to Table and TableCard component. #7196
# 7.0.0 # 7.0.0

View File

@ -76,6 +76,7 @@ Name | Type | Default | Description
`title` | String | `null` | (required) The title used in the card header, also used as the caption for the content in this table `title` | String | `null` | (required) The title used in the card header, also used as the caption for the content in this table
`totalRows` | Number | `null` | (required) The total number of rows (across all pages) `totalRows` | Number | `null` | (required) The total number of rows (across all pages)
`baseSearchQuery` | Object | `{}` | Pass in query parameters to be included in the path when onSearch creates a new url `baseSearchQuery` | Object | `{}` | Pass in query parameters to be included in the path when onSearch creates a new url
`rowKey` | Function(row, index): string | `null` | Function used for the row key.
### `labels` structure ### `labels` structure
@ -213,6 +214,7 @@ const rows = [
caption="Revenue Last Week" caption="Revenue Last Week"
rows={ rows } rows={ rows }
headers={ headers } headers={ headers }
rowKey={ row => row.display }
/> />
``` ```
@ -228,6 +230,7 @@ Name | Type | Default | Description
`query` | Object | `{}` | The query string represented in object form `query` | Object | `{}` | The query string represented in object form
`rows` | Array | `null` | (required) An array of arrays of display/value object pairs `rows` | Array | `null` | (required) An array of arrays of display/value object pairs
`rowHeader` | One of type: number, bool | `0` | Which column should be the row header, defaults to the first item (`0`) (but could be set to `1`, if the first col is checkboxes, for example). Set to false to disable row headers `rowHeader` | One of type: number, bool | `0` | Which column should be the row header, defaults to the first item (`0`) (but could be set to `1`, if the first col is checkboxes, for example). Set to false to disable row headers
`rowKey` | Function(row, index): string | `null` | Function used to get the row key.
### `headers` structure ### `headers` structure

View File

@ -152,6 +152,7 @@ class TableCard extends Component {
summary, summary,
title, title,
totalRows, totalRows,
rowKey,
} = this.props; } = this.props;
const { showCols } = this.state; const { showCols } = this.state;
const allHeaders = this.props.headers; const allHeaders = this.props.headers;
@ -238,6 +239,7 @@ class TableCard extends Component {
caption={ title } caption={ title }
query={ query } query={ query }
onSort={ onSort || onQueryChange( 'sort' ) } onSort={ onSort || onQueryChange( 'sort' ) }
rowKey={ rowKey }
/> />
) } ) }
</CardBody> </CardBody>
@ -350,6 +352,11 @@ TableCard.propTypes = {
* The total number of rows (across all pages). * The total number of rows (across all pages).
*/ */
totalRows: PropTypes.number.isRequired, totalRows: PropTypes.number.isRequired,
/**
* The rowKey used for the key value on each row, this can be a string of the key or a function that returns the value.
* This uses the index if not defined.
*/
rowKey: PropTypes.func,
}; };
TableCard.defaultProps = { TableCard.defaultProps = {

View File

@ -11,7 +11,12 @@ import { rows, headers } from './index';
export const Basic = () => ( export const Basic = () => (
<Card size={ null }> <Card size={ null }>
<Table caption="Revenue Last Week" rows={ rows } headers={ headers } /> <Table
caption="Revenue Last Week"
rows={ rows }
headers={ headers }
rowKey={ ( row ) => row[ 0 ].value }
/>
</Card> </Card>
); );

View File

@ -60,6 +60,7 @@ class Table extends Component {
this.container = createRef(); this.container = createRef();
this.sortBy = this.sortBy.bind( this ); this.sortBy = this.sortBy.bind( this );
this.updateTableShadow = this.updateTableShadow.bind( this ); this.updateTableShadow = this.updateTableShadow.bind( this );
this.getRowKey = this.getRowKey.bind( this );
} }
componentDidMount() { componentDidMount() {
@ -123,6 +124,13 @@ class Table extends Component {
} }
} }
getRowKey( row, index ) {
if ( this.props.rowKey && typeof this.props.rowKey === 'function' ) {
return this.props.rowKey( row, index );
}
return index;
}
render() { render() {
const { const {
ariaHidden, ariaHidden,
@ -245,7 +253,7 @@ class Table extends Component {
<th <th
role="columnheader" role="columnheader"
scope="col" scope="col"
key={ i } key={ header.key || i }
{ ...thProps } { ...thProps }
> >
{ isSortable ? ( { isSortable ? (
@ -286,7 +294,7 @@ class Table extends Component {
</tr> </tr>
{ hasData ? ( { hasData ? (
rows.map( ( row, i ) => ( rows.map( ( row, i ) => (
<tr key={ i }> <tr key={ this.getRowKey( row, i ) }>
{ row.map( ( cell, j ) => { { row.map( ( cell, j ) => {
const { const {
cellClassName, cellClassName,
@ -306,12 +314,17 @@ class Table extends Component {
headers[ j ].key, headers[ j ].key,
} }
); );
const cellKey =
this.getRowKey(
row,
i
).toString() + j;
return ( return (
<Cell <Cell
scope={ scope={
isHeader ? 'row' : null isHeader ? 'row' : null
} }
key={ j } key={ cellKey }
className={ cellClasses } className={ cellClasses }
> >
{ getDisplay( cell ) } { getDisplay( cell ) }
@ -431,6 +444,11 @@ Table.propTypes = {
* is checkboxes, for example). Set to false to disable row headers. * is checkboxes, for example). Set to false to disable row headers.
*/ */
rowHeader: PropTypes.oneOfType( [ PropTypes.number, PropTypes.bool ] ), rowHeader: PropTypes.oneOfType( [ PropTypes.number, PropTypes.bool ] ),
/**
* The rowKey used for the key value on each row, a function that returns the key.
* Defaults to index.
*/
rowKey: PropTypes.func,
}; };
Table.defaultProps = { Table.defaultProps = {

View File

@ -74,4 +74,24 @@ describe( 'TableCard', () => {
// We shouldn't get here if an error occurred. // We shouldn't get here if an error occurred.
expect( true ).toBe( true ); expect( true ).toBe( true );
} ); } );
it( 'should render rows correctly with custom rowKey prop', () => {
render(
<TableCard
title="Revenue"
headers={ mockHeaders }
isLoading={ false }
rows={ mockData }
rowsPerPage={ 1 }
totalRows={ 5 }
rowKey={ ( row ) => row[ 1 ].value }
/>
);
for ( const row of mockData ) {
expect(
screen.queryByText( row[ 0 ].display )
).toBeInTheDocument();
}
} );
} ); } );