Skip to content

Commit

Permalink
[Data Grid] Add custom actions to DataGridCells and cell popover (#3668)
Browse files Browse the repository at this point in the history
Co-authored-by: Andrea Del Rio <[email protected]>
Co-authored-by: Chandler Prall <[email protected]>
Co-authored-by: cchaos <[email protected]>
Co-authored-by: Dave Snider <[email protected]>
  • Loading branch information
5 people authored Oct 20, 2020
1 parent debcfea commit 5226ddb
Show file tree
Hide file tree
Showing 13 changed files with 763 additions and 171 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
## [`29.5.0`](https://github.com/elastic/eui/tree/v29.5.0)

- Added `plus` and `minus` glyphs to `EuiIcon` ([#4111](https://github.com/elastic/eui/pull/4111))
- Added `cellActions` to `EuiDataGrid` ([#3668](https://github.com/elastic/eui/pull/3668))

**Bug fixes**

Expand Down
152 changes: 152 additions & 0 deletions src-docs/src/views/datagrid/column_cell_actions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
import React, { useState, useCallback } from 'react';
import { fake } from 'faker';

import { EuiDataGrid, EuiAvatar } from '../../../../src/components/';

const columns = [
{
id: 'avatar',
initialWidth: 40,
isResizable: false,
actions: false,
},
{
id: 'name',
initialWidth: 100,
isSortable: true,
actions: {
showHide: false,
},
},
{
id: 'email',
isSortable: true,
cellActions: [
({ rowIndex, columnId, Component }) => {
const row = ++rowIndex;
return (
<Component
onClick={() =>
alert(`Love sent from row ${row}, column "${columnId}"`)
}
iconType="heart"
aria-label={`Send love to ${row}, column "${columnId}" `}>
Send love
</Component>
);
},
],
},
{
id: 'city',
isSortable: true,
cellActions: [
({ rowIndex, columnId, Component, isExpanded }) => {
const row = ++rowIndex;
const message = isExpanded
? `Cheers sent in Popover to row "${row}" column "${columnId}"`
: `Cheers sent from row ${row}, column "${columnId}"`;

return (
<Component
onClick={() => alert(message)}
iconType="cheer"
aria-label={message}>
Cheer
</Component>
);
},
],
},
{
id: 'country',
cellActions: [
({ rowIndex, columnId, Component }) => {
const row = ++rowIndex;
const label = `Love sent from row ${row}, column "${columnId}"`;
return (
<Component
onClick={() =>
alert(`Love sent from row ${row}, column "${columnId}"`)
}
iconType="heart"
aria-label={label}>
Love this city
</Component>
);
},
({ rowIndex, columnId, Component }) => {
const row = ++rowIndex;
const label = `Paint country at row ${row}, column "${columnId}"`;
return (
<Component
onClick={() =>
alert(`Paint sent from row ${row}, column "${columnId}"`)
}
iconType="brush"
aria-label={label}>
Paint this city
</Component>
);
},
],
},
{
id: 'account',
},
];

const data = [];

for (let i = 1; i < 5; i++) {
data.push({
avatar: (
<EuiAvatar
size="s"
imageUrl={fake('{{internet.avatar}}')}
name={fake('{{name.lastName}}, {{name.firstName}}')}
/>
),
name: fake('{{name.lastName}}, {{name.firstName}} {{name.suffix}}'),
email: fake('{{internet.email}}'),
city: fake('{{address.city}}'),
country: fake('{{address.country}}'),
account: fake('{{finance.account}}'),
});
}

export default () => {
const [pagination, setPagination] = useState({ pageIndex: 0, pageSize: 10 });

const [visibleColumns, setVisibleColumns] = useState(() =>
columns.map(({ id }) => id)
);

const setPageIndex = useCallback(
(pageIndex) => setPagination({ ...pagination, pageIndex }),
[pagination, setPagination]
);
const setPageSize = useCallback(
(pageSize) => setPagination({ ...pagination, pageSize, pageIndex: 0 }),
[pagination, setPagination]
);

return (
<EuiDataGrid
aria-label="DataGrid demonstrating column sizing constraints"
columns={columns}
columnVisibility={{
visibleColumns: visibleColumns,
setVisibleColumns: setVisibleColumns,
}}
rowCount={data.length}
renderCellValue={({ rowIndex, columnId }) => data[rowIndex][columnId]}
pagination={{
...pagination,
pageSizeOptions: [5, 10, 25],
onChangeItemsPerPage: setPageSize,
onChangePage: setPageIndex,
}}
/>
);
};
170 changes: 124 additions & 46 deletions src-docs/src/views/datagrid/datagrid.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import React, {
useEffect,
useMemo,
useState,
createContext,
useContext,
} from 'react';
import { fake } from 'faker';

Expand All @@ -17,15 +19,84 @@ import {
EuiButtonIcon,
EuiSpacer,
} from '../../../../src/components/';
const DataContext = createContext();

const raw_data = [];

for (let i = 1; i < 100; i++) {
const email = fake('{{internet.email}}');
const name = fake('{{name.lastName}}, {{name.firstName}}');
const suffix = fake('{{name.suffix}}');
raw_data.push({
name: {
formatted: `${name} ${suffix}`,
raw: name,
},
email: {
formatted: <EuiLink href="">{fake('{{internet.email}}')}</EuiLink>,
raw: email,
},
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('${{commerce.price}}'),
phone: fake('{{phone.phoneNumber}}'),
version: fake('{{system.semver}}'),
});
}

const columns = [
{
id: 'name',
displayAsText: 'Name',
defaultSortDirection: 'asc',
cellActions: [
({ rowIndex, columnId, Component }) => {
const data = useContext(DataContext);
return (
<Component
onClick={() => alert(`Hi ${data[rowIndex][columnId].raw}`)}
iconType="heart"
aria-label={`Say hi to ${data[rowIndex][columnId].raw}!`}>
Say hi
</Component>
);
},
({ rowIndex, columnId, Component }) => {
const data = useContext(DataContext);
return (
<Component
onClick={() => alert(`Bye ${data[rowIndex][columnId].raw}`)}
iconType="moon"
aria-label={`Say bye to ${data[rowIndex][columnId].raw}!`}>
Say bye
</Component>
);
},
],
},
{
id: 'email',
cellActions: [
({ rowIndex, columnId, Component }) => {
const data = useContext(DataContext);
return (
<Component
onClick={() => alert(data[rowIndex][columnId].raw)}
iconType="email"
aria-label={`Send email to ${data[rowIndex][columnId].raw}`}>
Send email
</Component>
);
},
],
},
{
id: 'location',
Expand All @@ -46,6 +117,26 @@ const columns = [
},
],
},
cellActions: [
({ rowIndex, columnId, Component, isExpanded }) => {
const data = useContext(DataContext);
const onClick = isExpanded
? () =>
alert(`Sent money to ${data[rowIndex][columnId]} when expanded`)
: () =>
alert(
`Sent money to ${data[rowIndex][columnId]} when not expanded`
);
return (
<Component
onClick={onClick}
iconType="faceHappy"
aria-label={`Send money to ${data[rowIndex][columnId]}`}>
Send money
</Component>
);
},
],
},
{
id: 'date',
Expand All @@ -67,28 +158,6 @@ const columns = [
},
];

const raw_data = [];

for (let i = 1; i < 100; i++) {
raw_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('${{commerce.price}}'),
phone: fake('{{phone.phoneNumber}}'),
version: fake('{{system.semver}}'),
});
}

const trailingControlColumns = [
{
id: 'actions',
Expand Down Expand Up @@ -186,11 +255,12 @@ export default () => {

const renderCellValue = useMemo(() => {
return ({ rowIndex, columnId, setCellProps }) => {
const data = useContext(DataContext);
useEffect(() => {
if (columnId === 'amount') {
if (raw_data.hasOwnProperty(rowIndex)) {
if (data.hasOwnProperty(rowIndex)) {
const numeric = parseFloat(
raw_data[rowIndex][columnId].match(/\d+\.\d+/)[0],
data[rowIndex][columnId].match(/\d+\.\d+/)[0],
10
);
setCellProps({
Expand All @@ -200,33 +270,41 @@ export default () => {
});
}
}
}, [rowIndex, columnId, setCellProps]);
}, [rowIndex, columnId, setCellProps, data]);

return raw_data.hasOwnProperty(rowIndex)
? raw_data[rowIndex][columnId]
function getFormatted() {
return data[rowIndex][columnId].formatted
? data[rowIndex][columnId].formatted
: data[rowIndex][columnId];
}

return data.hasOwnProperty(rowIndex)
? getFormatted(rowIndex, columnId)
: null;
};
}, []);

return (
<EuiDataGrid
aria-label="Data grid demo"
columns={columns}
columnVisibility={{ visibleColumns, setVisibleColumns }}
trailingControlColumns={trailingControlColumns}
rowCount={raw_data.length}
renderCellValue={renderCellValue}
inMemory={{ level: 'sorting' }}
sorting={{ columns: sortingColumns, onSort }}
pagination={{
...pagination,
pageSizeOptions: [10, 50, 100],
onChangeItemsPerPage: onChangeItemsPerPage,
onChangePage: onChangePage,
}}
onColumnResize={(eventData) => {
console.log(eventData);
}}
/>
<DataContext.Provider value={raw_data}>
<EuiDataGrid
aria-label="Data grid demo"
columns={columns}
columnVisibility={{ visibleColumns, setVisibleColumns }}
trailingControlColumns={trailingControlColumns}
rowCount={raw_data.length}
renderCellValue={renderCellValue}
inMemory={{ level: 'sorting' }}
sorting={{ columns: sortingColumns, onSort }}
pagination={{
...pagination,
pageSizeOptions: [10, 50, 100],
onChangeItemsPerPage: onChangeItemsPerPage,
onChangePage: onChangePage,
}}
onColumnResize={(eventData) => {
console.log(eventData);
}}
/>
</DataContext.Provider>
);
};
Loading

0 comments on commit 5226ddb

Please sign in to comment.