Skip to content

Commit

Permalink
[EuiDataGrid] use schema information when sorting (#2419)
Browse files Browse the repository at this point in the history
* cell expansion working mostly

* fix double import

* add search to field selector

* euitext

* cell epansion is now optional through a config

* keydown event for cells

* remove tabbables

* Clean up some code & tests

* Remove unused line of code

* Center popover against cell

* Update euidatagridcell popover placement, trigger, dom structure, and auto focusing

* Restore focus to grid cell when popover was in response to mouse click

* Allow grid column selection to be searchable

* Refactor expansion popover formatting, allow custom ones

* schema-based sort comparators

* reverse boolean sort to be true-false

* adds json schema sorting, fixes issue with popover

* Weaken the currency type detector when values have a period in their first few characters, and fix test
  • Loading branch information
chandlerprall authored Oct 11, 2019
1 parent 09e6a63 commit 9568a93
Show file tree
Hide file tree
Showing 6 changed files with 287 additions and 152 deletions.
43 changes: 27 additions & 16 deletions src-docs/src/views/datagrid/schema.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,21 +43,9 @@ const columns = [
const data = [];

for (let i = 1; i < 5; i++) {
data.push({
name: fake('{{name.lastName}}, {{name.firstName}} {{name.suffix}}'),
email: <EuiLink href="">{fake('{{internet.email}}')}</EuiLink>,
location: (
<Fragment>
{`${fake('{{address.city}}')}, `}
<EuiLink href="https://google.com">
{fake('{{address.country}}')}
</EuiLink>
</Fragment>
),
date: fake('{{date.past}}'),
account: fake('{{finance.account}}'),
amount: fake('${{finance.amount}}'),
json: JSON.stringify([
let json;
if (i < 3) {
json = JSON.stringify([
{
name: fake('{{name.lastName}}, {{name.firstName}} {{name.suffix}}'),
email: fake('{{internet.email}}'),
Expand All @@ -76,7 +64,30 @@ for (let i = 1; i < 5; i++) {
},
],
},
]),
]);
} else {
json = JSON.stringify([
{
name: fake('{{name.lastName}}, {{name.firstName}} {{name.suffix}}'),
},
]);
}

data.push({
name: fake('{{name.lastName}}, {{name.firstName}} {{name.suffix}}'),
email: <EuiLink href="">{fake('{{internet.email}}')}</EuiLink>,
location: (
<Fragment>
{`${fake('{{address.city}}')}, `}
<EuiLink href="https://google.com">
{fake('{{address.country}}')}
</EuiLink>
</Fragment>
),
date: fake('{{date.past}}'),
account: fake('{{finance.account}}'),
amount: fake('${{finance.amount}}'),
json: json,
version: fake('{{system.semver}}'),
});
}
Expand Down
192 changes: 99 additions & 93 deletions src/components/datagrid/column_sorting.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -149,104 +149,110 @@ export const useColumnSorting = (
</p>
</EuiText>
)}
<EuiPopoverFooter>
<EuiFlexGroup
gutterSize="m"
justifyContent="spaceBetween"
responsive={false}>
<EuiFlexItem grow={false}>
<EuiPopover
data-test-subj="dataGridColumnSortingPopoverColumnSelection"
isOpen={avilableColumnsisOpen}
closePopover={() => setAvailableColumnsIsOpen(false)}
anchorPosition="downLeft"
ownFocus
panelPaddingSize="s"
button={
{(inactiveColumns.length > 0 || sorting.columns.length > 0) && (
<EuiPopoverFooter>
<EuiFlexGroup
gutterSize="m"
justifyContent="spaceBetween"
responsive={false}>
<EuiFlexItem grow={false}>
{inactiveColumns.length > 0 && (
<EuiPopover
data-test-subj="dataGridColumnSortingPopoverColumnSelection"
isOpen={avilableColumnsisOpen}
closePopover={() => setAvailableColumnsIsOpen(false)}
anchorPosition="downLeft"
ownFocus
panelPaddingSize="s"
button={
<EuiButtonEmpty
size="xs"
flush="left"
iconType="arrowDown"
iconSide="right"
onClick={() =>
setAvailableColumnsIsOpen(!avilableColumnsisOpen)
}>
<EuiI18n
token="euiColumnSorting.pickFields"
default="Pick fields to sort by"
/>
</EuiButtonEmpty>
}>
<EuiI18n
token="euiColumnSorting.sortFieldAriaLabel"
default="Sort by: ">
{(sortFieldAriaLabel: string) => (
<div
className="euiDataGridColumnSorting__fieldList"
role="listbox">
{inactiveColumns.map(({ id }) => (
<button
key={id}
className="euiDataGridColumnSorting__field"
aria-label={`${sortFieldAriaLabel} ${id}`}
role="option"
aria-selected="false"
data-test-subj={`dataGridColumnSortingPopoverColumnSelection-${id}`}
onClick={() => {
const nextColumns = [...sorting.columns];
nextColumns.push({ id, direction: 'asc' });
sorting.onSort(nextColumns);
}}>
<EuiFlexGroup
alignItems="center"
gutterSize="s"
component="span">
<EuiFlexItem grow={false}>
<EuiIcon
color={
schema.hasOwnProperty(id) &&
schema[id].columnType != null
? getDetailsForSchema(
schema[id].columnType
).color
: defaultSchemaColor
}
type={
schema.hasOwnProperty(id) &&
schema[id].columnType != null
? getDetailsForSchema(
schema[id].columnType
).icon
: 'string'
}
/>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiText size="xs">
<span>{id}</span>
</EuiText>
</EuiFlexItem>
</EuiFlexGroup>
</button>
))}
</div>
)}
</EuiI18n>
</EuiPopover>
)}
</EuiFlexItem>
{sorting.columns.length > 0 ? (
<EuiFlexItem grow={false}>
<EuiButtonEmpty
size="xs"
flush="left"
iconType="arrowDown"
iconSide="right"
onClick={() =>
setAvailableColumnsIsOpen(!avilableColumnsisOpen)
}>
flush="right"
onClick={() => sorting.onSort([])}>
<EuiI18n
token="euiColumnSorting.pickFields"
default="Pick fields to sort by"
token="euiColumnSorting.clearAll"
default="Clear sorting"
/>
</EuiButtonEmpty>
}>
<EuiI18n
token="euiColumnSorting.sortFieldAriaLabel"
default="Sort by: ">
{(sortFieldAriaLabel: string) => (
<div
className="euiDataGridColumnSorting__fieldList"
role="listbox">
{inactiveColumns.map(({ id }) => (
<button
key={id}
className="euiDataGridColumnSorting__field"
aria-label={`${sortFieldAriaLabel} ${id}`}
role="option"
aria-selected="false"
data-test-subj={`dataGridColumnSortingPopoverColumnSelection-${id}`}
onClick={() => {
const nextColumns = [...sorting.columns];
nextColumns.push({ id, direction: 'asc' });
sorting.onSort(nextColumns);
}}>
<EuiFlexGroup
alignItems="center"
gutterSize="s"
component="span">
<EuiFlexItem grow={false}>
<EuiIcon
color={
schema.hasOwnProperty(id) &&
schema[id].columnType != null
? getDetailsForSchema(schema[id].columnType)
.color
: defaultSchemaColor
}
type={
schema.hasOwnProperty(id) &&
schema[id].columnType != null
? getDetailsForSchema(schema[id].columnType)
.icon
: 'string'
}
/>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiText size="xs">
<span>{id}</span>
</EuiText>
</EuiFlexItem>
</EuiFlexGroup>
</button>
))}
</div>
)}
</EuiI18n>
</EuiPopover>
</EuiFlexItem>
{sorting.columns.length > 0 ? (
<EuiFlexItem grow={false}>
<EuiButtonEmpty
size="xs"
flush="right"
onClick={() => sorting.onSort([])}>
<EuiI18n
token="euiColumnSorting.clearAll"
default="Clear sorting"
/>
</EuiButtonEmpty>
</EuiFlexItem>
) : null}
</EuiFlexGroup>
</EuiPopoverFooter>
</EuiFlexItem>
) : null}
</EuiFlexGroup>
</EuiPopoverFooter>
)}
</EuiPopover>
);

Expand Down
57 changes: 44 additions & 13 deletions src/components/datagrid/data_grid.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -116,21 +116,24 @@ function getColumnSortDirection(
columnSelectionPopover = datagrid.find(
'EuiPopover[data-test-subj="dataGridColumnSortingPopoverColumnSelection"]'
);
expect(columnSelectionPopover).euiPopoverToBeOpen();
// popover will go away if all of the columns are selected
if (columnSelectionPopover.length > 0) {
expect(columnSelectionPopover).euiPopoverToBeOpen();

popoverButton = columnSelectionPopover
.find('div[className="euiPopover__anchor"]')
.find('[onClick]')
.first();
// @ts-ignore-next-line
act(() => popoverButton.props().onClick());

popoverButton = columnSelectionPopover
.find('div[className="euiPopover__anchor"]')
.find('[onClick]')
.first();
// @ts-ignore-next-line
act(() => popoverButton.props().onClick());
datagrid.update();

datagrid.update();

columnSelectionPopover = datagrid.find(
'EuiPopover[data-test-subj="dataGridColumnSortingPopoverColumnSelection"]'
);
expect(columnSelectionPopover).not.euiPopoverToBeOpen();
columnSelectionPopover = datagrid.find(
'EuiPopover[data-test-subj="dataGridColumnSortingPopoverColumnSelection"]'
);
expect(columnSelectionPopover).not.euiPopoverToBeOpen();
}

// find the column sorter
columnSelectionPopover = datagrid.find(
Expand Down Expand Up @@ -1234,6 +1237,34 @@ Array [
]);
});
});

it('uses schema information to sort', () => {
const component = mount(
<EuiDataGrid
aria-label="test"
columns={[{ id: 'A' }, { id: 'B' }]}
rowCount={5}
renderCellValue={({ rowIndex, columnId }) =>
// render A 0->4 and B 12->8
columnId === 'A' ? rowIndex : 12 - rowIndex
}
inMemory={{ level: 'sorting' }}
sorting={{
columns: [{ id: 'B', direction: 'asc' }],
onSort: () => {},
}}
/>
);

expect(extractGridData(component)).toEqual([
['A', 'B'],
['4', '8'],
['3', '9'],
['2', '10'],
['1', '11'],
['0', '12'],
]);
});
});

describe('keyboard controls', () => {
Expand Down
9 changes: 8 additions & 1 deletion src/components/datagrid/data_grid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import React, {
useEffect,
Fragment,
ReactChild,
useMemo,
} from 'react';
import classNames from 'classnames';
import { EuiI18n } from '../i18n';
Expand Down Expand Up @@ -44,6 +45,7 @@ import {
getMergedSchema,
SchemaDetector,
useDetectSchema,
schemaDetectors as providedSchemaDetectors,
} from './data_grid_schema';
import { useColumnSorting } from './column_sorting';

Expand Down Expand Up @@ -317,9 +319,13 @@ export const EuiDataGrid: FunctionComponent<EuiDataGridProps> = props => {

const [inMemoryValues, onCellRender] = useInMemoryValues(inMemory, rowCount);

const allSchemaDetetors = useMemo(
() => [...providedSchemaDetectors, ...(schemaDetectors || [])],
[schemaDetectors]
);
const detectedSchema = useDetectSchema(
inMemoryValues,
schemaDetectors,
allSchemaDetetors,
inMemory != null
);
const mergedSchema = getMergedSchema(detectedSchema, columns);
Expand Down Expand Up @@ -465,6 +471,7 @@ export const EuiDataGrid: FunctionComponent<EuiDataGridProps> = props => {
inMemory={inMemory}
columns={visibleColumns}
schema={mergedSchema}
schemaDetectors={allSchemaDetetors}
expansionFormatters={expansionFormatters}
focusedCell={focusedCell}
onCellFocus={setFocusedCell}
Expand Down
Loading

0 comments on commit 9568a93

Please sign in to comment.