Add support for custom empty state of Table components

This commit is contained in:
Oliver Sand
2021-02-04 10:54:58 +01:00
parent 10a0124e0c
commit 96f378d108
4 changed files with 109 additions and 9 deletions
+8
View File
@@ -0,0 +1,8 @@
---
'@backstage/core': patch
---
Add support for custom empty state of `Table` components.
You can now optionally pass `emptyComponent` to `Table` that is displayed
if the table has now rows.
@@ -14,8 +14,10 @@
* limitations under the License.
*/
import { makeStyles } from '@material-ui/core';
import React from 'react';
import { Table, SubvalueCell, TableColumn } from './';
import { Link } from '../Link';
import { SubvalueCell, Table, TableColumn } from './';
import { TableFilter } from './Table';
export default {
@@ -23,7 +25,16 @@ export default {
component: Table,
};
const containerStyle = { width: 850 };
const useStyles = makeStyles(theme => ({
container: {
width: 850,
},
empty: {
padding: theme.spacing(2),
display: 'flex',
justifyContent: 'center',
},
}));
const generateTestData: (number: number) => Array<{}> = (rows = 10) => {
const data: Array<{}> = [];
@@ -43,6 +54,7 @@ const generateTestData: (number: number) => Array<{}> = (rows = 10) => {
const testData10 = generateTestData(10);
export const DefaultTable = () => {
const classes = useStyles();
const columns: TableColumn[] = [
{
title: 'Column 1',
@@ -66,7 +78,7 @@ export const DefaultTable = () => {
];
return (
<div style={containerStyle}>
<div className={classes.container}>
<Table
options={{ paging: false }}
data={testData10}
@@ -77,7 +89,8 @@ export const DefaultTable = () => {
);
};
export const SubtitleTable = () => {
export const EmptyTable = () => {
const classes = useStyles();
const columns: TableColumn[] = [
{
title: 'Column 1',
@@ -101,7 +114,49 @@ export const SubtitleTable = () => {
];
return (
<div style={containerStyle}>
<div className={classes.container}>
<Table
options={{ paging: false }}
data={[]}
columns={columns}
emptyComponent={
<div className={classes.empty}>
No data was added yet,&nbsp;
<Link to="http://backstage.io/">learn how to add data</Link>.
</div>
}
title="Backstage Table"
/>
</div>
);
};
export const SubtitleTable = () => {
const classes = useStyles();
const columns: TableColumn[] = [
{
title: 'Column 1',
field: 'col1',
highlight: true,
},
{
title: 'Column 2',
field: 'col2',
},
{
title: 'Numeric value',
field: 'number',
type: 'numeric',
},
{
title: 'A Date',
field: 'date',
type: 'date',
},
];
return (
<div className={classes.container}>
<Table
options={{ paging: false }}
data={testData10}
@@ -114,6 +169,7 @@ export const SubtitleTable = () => {
};
export const HiddenSearchTable = () => {
const classes = useStyles();
const columns: TableColumn[] = [
{
title: 'Column 1',
@@ -137,7 +193,7 @@ export const HiddenSearchTable = () => {
];
return (
<div style={containerStyle}>
<div className={classes.container}>
<Table
options={{ paging: false, search: false }}
data={testData10}
@@ -148,6 +204,7 @@ export const HiddenSearchTable = () => {
};
export const SubvalueTable = () => {
const classes = useStyles();
const columns: TableColumn[] = [
{
title: 'Column 1',
@@ -181,13 +238,14 @@ export const SubvalueTable = () => {
];
return (
<div style={containerStyle}>
<div className={classes.container}>
<Table options={{ paging: false }} data={testData10} columns={columns} />
</div>
);
};
export const DenseTable = () => {
const classes = useStyles();
const columns: TableColumn[] = [
{
title: 'Column 1',
@@ -211,7 +269,7 @@ export const DenseTable = () => {
];
return (
<div style={containerStyle}>
<div className={classes.container}>
<Table
options={{ paging: false, padding: 'dense' }}
data={testData10}
@@ -223,6 +281,7 @@ export const DenseTable = () => {
};
export const FilterTable = () => {
const classes = useStyles();
const columns: TableColumn[] = [
{
title: 'Column 1',
@@ -261,7 +320,7 @@ export const FilterTable = () => {
];
return (
<div style={containerStyle}>
<div className={classes.container}>
<Table
options={{ paging: false, padding: 'dense' }}
data={testData10}
@@ -53,4 +53,16 @@ describe('<Table />', () => {
);
expect(rendered.getByText('subtitle')).toBeInTheDocument();
});
it('renders custom empty component if empty', async () => {
const rendered = await renderInTestApp(
<Table
subtitle="subtitle"
emptyComponent={<div>EMPTY</div>}
columns={minProps.columns}
data={[]}
/>,
);
expect(rendered.getByText('EMPTY')).toBeInTheDocument();
});
});
@@ -42,6 +42,7 @@ import MTable, {
Column,
Icons,
MaterialTableProps,
MTableBody,
MTableHeader,
MTableToolbar,
Options,
@@ -202,6 +203,7 @@ export interface TableProps<T extends object = {}>
subtitle?: string;
filters?: TableFilter[];
initialState?: TableState;
emptyComponent?: JSX.Element;
onStateChange?: (state: TableState) => any;
}
@@ -212,6 +214,7 @@ export function Table<T extends object = {}>({
subtitle,
filters,
initialState,
emptyComponent,
onStateChange,
...props
}: TableProps<T>) {
@@ -423,6 +426,23 @@ export function Table<T extends object = {}>({
],
);
const Body = useCallback(
bodyProps => {
if (emptyComponent && data.length === 0) {
return (
<tbody>
<tr>
<td colSpan={columns.length}>{emptyComponent}</td>
</tr>
</tbody>
);
}
return <MTableBody {...bodyProps} />;
},
[data, emptyComponent, columns],
);
return (
<div className={tableClasses.root}>
{filtersOpen && data && filters?.length && (
@@ -438,6 +458,7 @@ export function Table<T extends object = {}>({
<MTableHeader classes={headerClasses} {...headerProps} />
),
Toolbar,
Body,
}}
options={{ ...defaultOptions, ...options }}
columns={MTColumns}