Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow sorting by computed columns in EuiInMemoryTable #2044

Merged
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
- Fixed `EuiFlyout` scrolling in Safari ([#2033](https://github.com/elastic/eui/pull/2033))
- Fixed `EuiCallOut` header icon alignment ([#2006](https://github.com/elastic/eui/pull/2006))
- Fixed `EuiInMemoryTable` sort value persistence through lifecycle updates ([#2035](https://github.com/elastic/eui/pull/2035))
- Fixed `EuiInMemoryTable` to allow sorting on computed columns ([#2044](https://github.com/elastic/eui/pull/2044))

**Breaking changes**

Expand Down
11 changes: 9 additions & 2 deletions src-docs/src/views/tables/basic/props_info.js
Original file line number Diff line number Diff line change
Expand Up @@ -237,10 +237,11 @@ export const propsInfo = {
type: { name: 'string (e.g. "30%", "100px", etc..)' },
},
sortable: {
description: 'Defines whether the user can sort on this column',
description:
'Defines whether the user can sort on this column. If a function is provided, this function returns the value to sort against.',
required: false,
defaultValue: { value: 'false' },
type: { name: 'boolean' },
type: { name: '"boolean" | "function"' },
},
align: {
description: 'Defines the horizontal alignment of the column',
Expand Down Expand Up @@ -303,6 +304,12 @@ export const propsInfo = {
required: false,
type: { name: 'string (e.g. "30%", "100px", etc..)' },
},
sortable: {
description:
'If provided, allows this column to be sorted on. Must return the value to sort against.',
required: false,
type: { name: 'function' },
},
truncateText: {
description:
"Indicates whether this column should truncate its content when it doesn't fit",
Expand Down
21 changes: 13 additions & 8 deletions src-docs/src/views/tables/in_memory/in_memory_custom_sorting.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ import React from 'react';
import { EuiInMemoryTable } from '../../../../../src/components';

const data = [
{ animal: 'snail', weight: 25, humanFriendlyWeight: '25g' },
{ animal: 'peregrine falcon', weight: 900, humanFriendlyWeight: '0.9kg' },
{ animal: 'small dog', weight: 4500, humanFriendlyWeight: '4.5kg' },
{ animal: 'brown bear', weight: 180000, humanFriendlyWeight: '180kg' },
{ animal: 'elephant', weight: 5440000, humanFriendlyWeight: '5440kg' },
{ animal: 'giraffe', weight: 1180000, humanFriendlyWeight: '1180kg' },
{ animal: 'snail', weight: 25 },
{ animal: 'peregrine falcon', weight: 900 },
{ animal: 'small dog', weight: 4500 },
{ animal: 'brown bear', weight: 180000 },
{ animal: 'elephant', weight: 5440000 },
{ animal: 'giraffe', weight: 1180000 },
];

export const Table = () => {
Expand All @@ -18,15 +18,20 @@ export const Table = () => {
sortable: true,
},
{
field: 'humanFriendlyWeight',
name: 'Weight',
render: ({ weight }) => `${weight / 1000}kg`,
sortable: ({ weight }) => weight,
},
{
field: 'weight',
name: 'Weight (grams)',
sortable: true,
},
];

const sorting = {
sort: {
field: 'humanFriendlyWeight',
field: 'Weight',
direction: 'asc',
},
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ exports[`EuiInMemoryTable behavior pagination 1`] = `
"description": "description",
"field": "name",
"name": "Name",
"sortable": false,
},
]
}
Expand Down Expand Up @@ -652,7 +651,6 @@ exports[`EuiInMemoryTable empty array 1`] = `
"description": "description",
"field": "name",
"name": "Name",
"sortable": false,
},
]
}
Expand All @@ -674,7 +672,6 @@ exports[`EuiInMemoryTable with executeQueryOptions 1`] = `
"description": "description",
"field": "name",
"name": "Name",
"sortable": false,
},
]
}
Expand Down Expand Up @@ -725,7 +722,7 @@ exports[`EuiInMemoryTable with initial sorting 1`] = `
"allowNeutralSort": true,
"sort": Object {
"direction": "desc",
"field": "name",
"field": "Name",
},
}
}
Expand All @@ -742,7 +739,6 @@ exports[`EuiInMemoryTable with items 1`] = `
"description": "description",
"field": "name",
"name": "Name",
"sortable": false,
},
]
}
Expand Down Expand Up @@ -779,7 +775,6 @@ exports[`EuiInMemoryTable with items and expanded item 1`] = `
"description": "description",
"field": "name",
"name": "Name",
"sortable": false,
},
]
}
Expand Down Expand Up @@ -824,7 +819,6 @@ exports[`EuiInMemoryTable with items and message - expecting to show the items 1
"description": "description",
"field": "name",
"name": "Name",
"sortable": false,
},
]
}
Expand Down Expand Up @@ -861,7 +855,6 @@ exports[`EuiInMemoryTable with message 1`] = `
"description": "description",
"field": "name",
"name": "Name",
"sortable": false,
},
]
}
Expand All @@ -883,7 +876,6 @@ exports[`EuiInMemoryTable with message and loading 1`] = `
"description": "description",
"field": "name",
"name": "Name",
"sortable": false,
},
]
}
Expand All @@ -906,7 +898,6 @@ exports[`EuiInMemoryTable with pagination 1`] = `
"description": "description",
"field": "name",
"name": "Name",
"sortable": false,
},
]
}
Expand Down Expand Up @@ -952,7 +943,6 @@ exports[`EuiInMemoryTable with pagination and default page size and index 1`] =
"description": "description",
"field": "name",
"name": "Name",
"sortable": false,
},
]
}
Expand Down Expand Up @@ -994,7 +984,6 @@ exports[`EuiInMemoryTable with pagination and selection 1`] = `
"description": "description",
"field": "name",
"name": "Name",
"sortable": false,
},
]
}
Expand Down Expand Up @@ -1050,7 +1039,6 @@ exports[`EuiInMemoryTable with pagination, default page size and error 1`] = `
"description": "description",
"field": "name",
"name": "Name",
"sortable": false,
},
]
}
Expand Down Expand Up @@ -1093,7 +1081,6 @@ exports[`EuiInMemoryTable with pagination, hiding the per page options 1`] = `
"description": "description",
"field": "name",
"name": "Name",
"sortable": false,
},
]
}
Expand Down Expand Up @@ -1224,7 +1211,6 @@ exports[`EuiInMemoryTable with pagination, selection, sorting and simple search
},
],
"name": "Actions",
"sortable": false,
},
]
}
Expand Down Expand Up @@ -1299,7 +1285,6 @@ exports[`EuiInMemoryTable with pagination, selection, sorting and a single recor
},
],
"name": "Actions",
"sortable": false,
},
]
}
Expand Down Expand Up @@ -1459,7 +1444,6 @@ exports[`EuiInMemoryTable with pagination, selection, sorting and configured sea
},
],
"name": "Actions",
"sortable": false,
},
]
}
Expand Down Expand Up @@ -1503,46 +1487,3 @@ exports[`EuiInMemoryTable with pagination, selection, sorting and configured sea
/>
</div>
`;

exports[`EuiInMemoryTable with sorting 1`] = `
<EuiBasicTable
aria-label="aria-label"
className="testClass1 testClass2"
columns={
Array [
Object {
"description": "description",
"field": "name",
"name": "Name",
"sortable": true,
},
]
}
data-test-subj="test subject string"
items={
Array [
Object {
"id": "1",
"name": "name1",
},
Object {
"id": "2",
"name": "name2",
},
Object {
"id": "3",
"name": "name3",
},
]
}
noItemsMessage="No items found"
onChange={[Function]}
responsive={true}
sorting={
Object {
"allowNeutralSort": true,
"sort": undefined,
}
}
/>
`;
30 changes: 24 additions & 6 deletions src/components/basic_table/basic_table.js
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ export const FieldDataColumnTypeShape = {
description: PropTypes.string,
dataType: PropTypes.oneOf(DATA_TYPES),
width: PropTypes.string,
sortable: PropTypes.bool,
sortable: PropTypes.oneOfType([PropTypes.bool, PropTypes.func]),
align: PropTypes.oneOf([LEFT_ALIGNMENT, RIGHT_ALIGNMENT]),
truncateText: PropTypes.bool,
render: PropTypes.func, // ((value, record) => PropTypes.node (also see [services/value_renderer] for basic implementations)
Expand All @@ -128,6 +128,7 @@ export const ComputedColumnType = PropTypes.shape({
render: PropTypes.func.isRequired, // (record) => PropTypes.node
name: PropTypes.node,
description: PropTypes.string,
sortable: PropTypes.func,
width: PropTypes.string,
truncateText: PropTypes.bool,
});
Expand Down Expand Up @@ -326,7 +327,8 @@ export class EuiBasicTable extends Component {
if (
currentCriteria &&
currentCriteria.sort &&
currentCriteria.sort.field === column.field
(currentCriteria.sort.field === column.field ||
currentCriteria.sort.field === column.name)
) {
direction = SortDirection.reverse(currentCriteria.sort.direction);
}
Expand All @@ -340,7 +342,7 @@ export class EuiBasicTable extends Component {
size: currentCriteria.page.size,
},
sort: {
field: column.field,
field: column.field || column.name,
direction,
},
};
Expand Down Expand Up @@ -563,12 +565,25 @@ export class EuiBasicTable extends Component {

// computed column
if (!field) {
const sorting = {};
// computed columns are only sortable if their `sortable` is a function
if (this.props.sorting && typeof sortable === 'function') {
const sortDirection = this.resolveColumnSortDirection(column);
sorting.isSorted = !!sortDirection;
sorting.isSortAscending = sortDirection
? SortDirection.isAsc(sortDirection)
: undefined;
sorting.onSort = this.resolveColumnOnSort(column);
sorting.allowNeutralSort = this.props.sorting.allowNeutralSort;
}
headers.push(
<EuiTableHeaderCell
key={`_computed_column_h_${index}`}
align={columnAlign}
width={width}
mobileOptions={mobileOptions}>
mobileOptions={mobileOptions}
data-test-subj={`tableHeaderCell_${name}_${index}`}
{...sorting}>
{name}
</EuiTableHeaderCell>
);
Expand Down Expand Up @@ -982,7 +997,10 @@ export class EuiBasicTable extends Component {
if (!sorting || !sorting.sort || !column.sortable) {
return;
}
if (sorting.sort.field === column.field) {
if (
sorting.sort.field === column.field ||
sorting.sort.field === column.name
) {
return sorting.sort.direction;
}
};
Expand All @@ -994,7 +1012,7 @@ export class EuiBasicTable extends Component {
}
if (!this.props.onChange) {
throw new Error(`BasicTable is configured to be sortable on column [${
column.field
column.name
}] but
[onChange] is not configured. This callback must be implemented to handle the sort requests`);
}
Expand Down
Loading