Skip to content

Commit 7f48a9c

Browse files
authored
Merge pull request #26 from fhlavac/loading
Add loading state to the DataViewTable
2 parents ddc98cf + 8818def commit 7f48a9c

File tree

22 files changed

+391
-200
lines changed

22 files changed

+391
-200
lines changed

cypress/component/DataViewTableBasic.cy.tsx

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import React from 'react';
2-
import DataViewTableBasic from '@patternfly/react-data-view/dist/dynamic/DataViewTableBasic';
3-
import DataView from '@patternfly/react-data-view/dist/dynamic/DataView';
2+
import { DataViewTableBasic } from '@patternfly/react-data-view/dist/dynamic/DataViewTableBasic';
3+
import { DataView } from '@patternfly/react-data-view/dist/dynamic/DataView';
44

55
interface Repository {
66
name: string;
@@ -50,7 +50,7 @@ describe('DataViewTableBasic', () => {
5050

5151
cy.mount(
5252
<DataView activeState="empty">
53-
<DataViewTableBasic aria-label='Repositories table' ouiaId={ouiaId} columns={columns} rows={[]} states={{ empty: "No data found" }} />
53+
<DataViewTableBasic aria-label='Repositories table' ouiaId={ouiaId} columns={columns} rows={[]} bodyStates={{ empty: <div data-ouia-component-id="data-tr-empty">No data found</div> }} />
5454
</DataView>
5555
);
5656

@@ -69,7 +69,7 @@ describe('DataViewTableBasic', () => {
6969

7070
cy.mount(
7171
<DataView activeState="error">
72-
<DataViewTableBasic aria-label='Repositories table' ouiaId={ouiaId} columns={columns} rows={[]} states={{ error: "Some error" }} />
72+
<DataViewTableBasic aria-label='Repositories table' ouiaId={ouiaId} columns={columns} rows={[]} bodyStates={{ error: <div data-ouia-component-id="data-tr-error">Some error</div> }} />
7373
</DataView>
7474
);
7575

@@ -82,4 +82,24 @@ describe('DataViewTableBasic', () => {
8282
cy.get('[data-ouia-component-id="data-tr-error"]').should('be.visible');
8383
cy.get('[data-ouia-component-id="data-tr-error"]').contains('Some error');
8484
});
85+
86+
it('renders a basic data view table with a loading state', () => {
87+
const ouiaId = 'data';
88+
89+
cy.mount(
90+
<DataView activeState="loading">
91+
<DataViewTableBasic aria-label='Repositories table' ouiaId={ouiaId} columns={columns} rows={[]} bodyStates={{ loading: <div data-ouia-component-id="data-tr-loading">Data is loading</div> }} />
92+
</DataView>
93+
);
94+
95+
cy.get('[data-ouia-component-id="data-th-0"]').contains('Repositories');
96+
cy.get('[data-ouia-component-id="data-th-1"]').contains('Branches');
97+
cy.get('[data-ouia-component-id="data-th-2"]').contains('Pull requests');
98+
cy.get('[data-ouia-component-id="data-th-3"]').contains('Workspaces');
99+
cy.get('[data-ouia-component-id="data-th-4"]').contains('Last commit');
100+
101+
cy.get('[data-ouia-component-id="data-tr-loading"]').should('be.visible');
102+
cy.get('[data-ouia-component-id="data-tr-loading"]').contains('Data is loading');
103+
});
104+
85105
});

cypress/component/DataViewTableHeader.cy.tsx renamed to cypress/component/DataViewTableHead.cy.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
import React from 'react';
2-
import { DataViewTableHeader } from '@patternfly/react-data-view/dist/dynamic/DataViewTableHeader';
2+
import { DataViewTableHead } from '@patternfly/react-data-view/dist/dynamic/DataViewTableHead';
33

44
const columns = [ 'Repositories', 'Branches', 'Pull requests', 'Workspaces', 'Last commit' ];
55

6-
describe('DataViewTableHeader', () => {
6+
describe('DataViewTableHead', () => {
77

8-
it('renders a data view table header', () => {
8+
it('renders a data view table head', () => {
99
const ouiaId = 'data';
1010

1111
cy.mount(
12-
<DataViewTableHeader ouiaId={ouiaId} columns={columns} />
12+
<DataViewTableHead ouiaId={ouiaId} columns={columns} />
1313
);
1414

1515
cy.get('[data-ouia-component-id="data-th-0"]').contains('Repositories');

cypress/component/DataViewTableTree.cy.tsx

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import React from 'react';
2+
import { DataView } from '@patternfly/react-data-view/dist/dynamic/DataView';
23
import { DataViewTable, DataViewTrTree } from '@patternfly/react-data-view/dist/dynamic/DataViewTable';
3-
import DataView from '@patternfly/react-data-view/dist/dynamic/DataView';
44

55
interface Repository {
66
name: string;
@@ -132,7 +132,7 @@ describe('DataViewTableTree', () => {
132132

133133
cy.mount(
134134
<DataView activeState="empty">
135-
<DataViewTable isTreeTable aria-label='Repositories table' ouiaId={ouiaId} columns={columns} rows={[]} states={{ empty: "No data found" }} />
135+
<DataViewTable isTreeTable aria-label='Repositories table' ouiaId={ouiaId} columns={columns} rows={[]} bodyStates={{ empty: <div data-ouia-component-id="tree-tr-empty">No data found</div> }} />
136136
</DataView>
137137
);
138138

@@ -151,7 +151,7 @@ describe('DataViewTableTree', () => {
151151

152152
cy.mount(
153153
<DataView activeState="error">
154-
<DataViewTable isTreeTable aria-label='Repositories table' ouiaId={ouiaId} columns={columns} rows={[]} states={{ error:"Some error" }} />
154+
<DataViewTable isTreeTable aria-label='Repositories table' ouiaId={ouiaId} columns={columns} rows={[]} bodyStates={{ error: <div data-ouia-component-id="tree-tr-error">Some error</div> }} />
155155
</DataView>
156156
);
157157

@@ -161,7 +161,26 @@ describe('DataViewTableTree', () => {
161161
cy.get('[data-ouia-component-id="data-th-3"]').contains('Workspaces');
162162
cy.get('[data-ouia-component-id="data-th-4"]').contains('Last commit');
163163

164-
cy.get('[data-ouia-component-id="data-tr-error"]').should('be.visible');
165-
cy.get('[data-ouia-component-id="data-tr-error"]').contains('Some error');
164+
cy.get('[data-ouia-component-id="tree-tr-error"]').should('be.visible');
165+
cy.get('[data-ouia-component-id="tree-tr-error"]').contains('Some error');
166+
});
167+
168+
it('renders a tree data view table with a loading state', () => {
169+
const ouiaId = 'tree';
170+
171+
cy.mount(
172+
<DataView activeState="loading">
173+
<DataViewTable isTreeTable aria-label='Repositories table' ouiaId={ouiaId} columns={columns} rows={[]} bodyStates={{ loading: <div data-ouia-component-id="tree-tr-loading">Data is loading</div> }} />
174+
</DataView>
175+
);
176+
177+
cy.get('[data-ouia-component-id="tree-th-0"]').contains('Repositories');
178+
cy.get('[data-ouia-component-id="tree-th-1"]').contains('Branches');
179+
cy.get('[data-ouia-component-id="tree-th-2"]').contains('Pull requests');
180+
cy.get('[data-ouia-component-id="tree-th-3"]').contains('Workspaces');
181+
cy.get('[data-ouia-component-id="tree-th-4"]').contains('Last commit');
182+
183+
cy.get('[data-ouia-component-id="tree-tr-loading"]').should('be.visible');
184+
cy.get('[data-ouia-component-id="tree-tr-loading"]').contains('Data is loading');
166185
});
167186
});

packages/module/patternfly-docs/content/extensions/data-view/examples/Components/Components.md

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ sourceLink: https://github.com/patternfly/react-data-view/blob/main/packages/mod
1616
---
1717
import { Button, EmptyState, EmptyStateActions, EmptyStateBody, EmptyStateFooter, EmptyStateHeader, EmptyStateIcon } from '@patternfly/react-core';
1818
import { CubesIcon, FolderIcon, FolderOpenIcon, LeafIcon, ExclamationCircleIcon } from '@patternfly/react-icons';
19-
import { BulkSelect, ErrorState, ResponsiveAction, ResponsiveActions } from '@patternfly/react-component-groups';
19+
import { BulkSelect, ErrorState, ResponsiveAction, ResponsiveActions, SkeletonTableHead, SkeletonTableBody } from '@patternfly/react-component-groups';
2020
import { DataViewToolbar } from '@patternfly/react-data-view/dist/dynamic/DataViewToolbar';
2121
import { DataViewTable } from '@patternfly/react-data-view/dist/dynamic/DataViewTable';
2222
import { useDataViewSelection } from '@patternfly/react-data-view/dist/dynamic/Hooks';
@@ -51,17 +51,17 @@ The **data view table** component renders your columns and rows definition into
5151

5252
### Rows and columns customization
5353

54-
This example shows possible formats of `rows` and `columns` passed to the `DataViewTable` which allow you various customizations of the table header and body.
54+
This example shows possible formats of `rows` and `columns` passed to the `DataViewTable` which allow you various customizations of the table head and body.
5555

5656
```js file="./DataViewTableExample.tsx"
5757

5858
```
5959

6060
The `DataViewTable` component accepts the following props:
6161

62-
- `columns` defining the column headers of the table. Each item in the array can be a `ReactNode` (for simple headers) or an object with the following properties:
63-
- `cell` (`ReactNode`) content to display in the column header.
64-
- optional `props` (`ThProps`) to pass to the `<Th>` component, such as `width`, `sort`, and other table header cell properties.
62+
- `columns` defining the column heads of the table. Each item in the array can be a `ReactNode` (for simple heads) or an object with the following properties:
63+
- `cell` (`ReactNode`) content to display in the column head.
64+
- optional `props` (`ThProps`) to pass to the `<Th>` component, such as `width`, `sort`, and other table head cell properties.
6565

6666
- `rows` defining the rows to be displayed in the table. Each item in the array can be either an array of `DataViewTd` (for simple rows) or an object with the following properties:
6767
- `row` (`DataViewTd[]`) defining the content for each cell in the row.
@@ -85,15 +85,22 @@ It is also possible to disable row selection using the `isSelectDisabled` functi
8585
```
8686

8787
### Empty state example
88-
The data view table supports displaying a custom empty state. You can pass it using the `states` property and `empty` key. It will be automatically displayed in case there are no rows to be rendered.
88+
The data view table supports displaying a custom empty state. You can pass it using the the `headStates` and `bodyStates` properties and their `empty` key. It will be automatically displayed in case there are no rows to be rendered.
8989

9090
```js file="./DataViewTableEmptyExample.tsx"
9191

9292
```
9393

9494
### Error state example
95-
The data view table also supports displaying an error state. You can pass it using the `states` property and `error` key. It will be displayed in case the data view recieves its `state` property set to `error`.
95+
The data view table also supports displaying an error state. You can pass it using the the `headStates` and `bodyStates` properties and their `error` key. It will be displayed in case the data view recieves its `state` property set to `error`.
9696

9797
```js file="./DataViewTableErrorExample.tsx"
9898

9999
```
100+
101+
### Loading state example
102+
The data view table also supports displaying a custom loading state. You can pass it using the `headStates` and `bodyStates` properties and their `loading` key. Your state will be displayed in case the data view recieves its `state` property set to `loading`.
103+
104+
```js file="./DataViewTableLoadingExample.tsx"
105+
106+
```

packages/module/patternfly-docs/content/extensions/data-view/examples/Components/DataViewTableEmptyExample.tsx

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { DataView, DataViewState } from '@patternfly/react-data-view/dist/dynami
33
import { DataViewTable, DataViewTr, DataViewTh } from '@patternfly/react-data-view/dist/dynamic/DataViewTable';
44
import { CubesIcon } from '@patternfly/react-icons';
55
import { Button, EmptyState, EmptyStateActions, EmptyStateBody, EmptyStateFooter, EmptyStateHeader, EmptyStateIcon } from '@patternfly/react-core';
6+
import { Tbody, Td, Tr } from '@patternfly/react-table';
67

78
interface Repository {
89
id: number;
@@ -23,19 +24,25 @@ const columns: DataViewTh[] = [ 'Repositories', 'Branches', 'Pull requests', 'Wo
2324
const ouiaId = 'TableExample';
2425

2526
const empty = (
26-
<EmptyState>
27-
<EmptyStateHeader titleText="No data found" headingLevel="h4" icon={<EmptyStateIcon icon={CubesIcon} />} />
28-
<EmptyStateBody>There are no matching data to be displayed.</EmptyStateBody>
29-
<EmptyStateFooter>
30-
<EmptyStateActions>
31-
<Button variant="primary">Primary action</Button>
32-
</EmptyStateActions>
33-
<EmptyStateActions>
34-
<Button variant="link">Multiple</Button>
35-
<Button variant="link">Action Buttons</Button>
36-
</EmptyStateActions>
37-
</EmptyStateFooter>
38-
</EmptyState>
27+
<Tbody>
28+
<Tr key="loading" ouiaId={`${ouiaId}-tr-loading`}>
29+
<Td colSpan={columns.length}>
30+
<EmptyState>
31+
<EmptyStateHeader titleText="No data found" headingLevel="h4" icon={<EmptyStateIcon icon={CubesIcon} />} />
32+
<EmptyStateBody>There are no matching data to be displayed.</EmptyStateBody>
33+
<EmptyStateFooter>
34+
<EmptyStateActions>
35+
<Button variant="primary">Primary action</Button>
36+
</EmptyStateActions>
37+
<EmptyStateActions>
38+
<Button variant="link">Multiple</Button>
39+
<Button variant="link">Action Buttons</Button>
40+
</EmptyStateActions>
41+
</EmptyStateFooter>
42+
</EmptyState>
43+
</Td>
44+
</Tr>
45+
</Tbody>
3946
);
4047

4148
export const BasicExample: React.FunctionComponent = () => (
@@ -45,7 +52,7 @@ export const BasicExample: React.FunctionComponent = () => (
4552
ouiaId={ouiaId}
4653
columns={columns}
4754
rows={rows}
48-
states={{ empty }}
55+
bodyStates={{ empty }}
4956
/>
5057
</DataView>
5158
);

packages/module/patternfly-docs/content/extensions/data-view/examples/Components/DataViewTableErrorExample.tsx

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import React from 'react';
22
import { DataView, DataViewState } from '@patternfly/react-data-view/dist/dynamic/DataView';
33
import { DataViewTable, DataViewTr, DataViewTh } from '@patternfly/react-data-view/dist/dynamic/DataViewTable';
44
import { ErrorState } from '@patternfly/react-component-groups';
5+
import { Tbody, Td, Tr } from '@patternfly/react-table';
56

67
interface Repository {
78
id: number;
@@ -22,7 +23,13 @@ const columns: DataViewTh[] = [ 'Repositories', 'Branches', 'Pull requests', 'Wo
2223
const ouiaId = 'TableErrorExample';
2324

2425
const error = (
25-
<ErrorState errorTitle='Unable to load data' errorDescription='There was an error retrieving data. Check your connection and reload the page.' />
26+
<Tbody>
27+
<Tr key="loading" ouiaId={`${ouiaId}-tr-loading`}>
28+
<Td colSpan={columns.length}>
29+
<ErrorState errorTitle='Unable to load data' errorDescription='There was an error retrieving data. Check your connection and reload the page.' />
30+
</Td>
31+
</Tr>
32+
</Tbody>
2633
);
2734

2835
export const BasicExample: React.FunctionComponent = () => (
@@ -32,7 +39,7 @@ export const BasicExample: React.FunctionComponent = () => (
3239
ouiaId={ouiaId}
3340
columns={columns}
3441
rows={rows}
35-
states={{ error }}
42+
bodyStates={{ error }}
3643
/>
3744
</DataView>
3845
);
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import React from 'react';
2+
import { DataView, DataViewState } from '@patternfly/react-data-view/dist/dynamic/DataView';
3+
import { DataViewTable, DataViewTr, DataViewTh } from '@patternfly/react-data-view/dist/dynamic/DataViewTable';
4+
import { SkeletonTableBody, SkeletonTableHead } from '@patternfly/react-component-groups';
5+
6+
// you can also pass props to Tr by returning { row: DataViewTd[], props: TrProps } }
7+
const rows: DataViewTr[] = [];
8+
9+
const columns: DataViewTh[] = [ 'Repositories', 'Branches', 'Pull requests', 'Workspaces', 'Last commit' ];
10+
11+
const ouiaId = 'TableExample';
12+
13+
const headLoading = <SkeletonTableHead columns={columns} />
14+
const bodyLoading = <SkeletonTableBody rowsCount={5} columnsCount={columns.length} />;
15+
16+
export const BasicExample: React.FunctionComponent = () => (
17+
<DataView activeState={DataViewState.loading}>
18+
<DataViewTable
19+
aria-label='Repositories table'
20+
ouiaId={ouiaId}
21+
columns={columns}
22+
rows={rows}
23+
headStates={{ loading: headLoading }}
24+
bodyStates={{ loading: bodyLoading }}
25+
/>
26+
</DataView>
27+
);

packages/module/src/DataView/DataView.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ export interface DataViewProps {
1818
/** Selection context configuration */
1919
selection?: DataViewSelection;
2020
/** Currently active state */
21-
activeState?: DataViewState;
21+
activeState?: DataViewState | string;
2222
}
2323

2424
export type DataViewImpementationProps = Omit<DataViewProps, 'onSelect' | 'isItemSelected' | 'isItemSelectDisabled'>;

packages/module/src/DataViewTable/DataViewTable.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import {
77
import { DataViewTableTree, DataViewTableTreeProps } from '../DataViewTableTree';
88
import { DataViewTableBasic, DataViewTableBasicProps } from '../DataViewTableBasic';
99

10-
// Table header typings
10+
// Table head typings
1111
export type DataViewTh = ReactNode | { cell: ReactNode; props?: ThProps };
1212
export const isDataViewThObject = (value: DataViewTh): value is { cell: ReactNode; props?: ThProps } => value != null && typeof value === 'object' && 'cell' in value;
1313

packages/module/src/DataViewTableBasic/DataViewTableBasic.test.tsx

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React from 'react';
22
import { render } from '@testing-library/react';
3+
import { DataView } from '../DataView';
34
import { DataViewTableBasic } from './DataViewTableBasic';
4-
import DataView from '../DataView/DataView';
55

66
interface Repository {
77
name: string;
@@ -39,7 +39,7 @@ describe('DataViewTable component', () => {
3939
test('should render with an empty state', () => {
4040
const { container } = render(
4141
<DataView activeState="empty">
42-
<DataViewTableBasic aria-label='Repositories table' ouiaId={ouiaId} columns={columns} states={{ empty:"No data found" }} rows={[]} />
42+
<DataViewTableBasic aria-label='Repositories table' ouiaId={ouiaId} columns={columns} bodyStates={{ empty: "No data found" }} rows={[]} />
4343
</DataView>
4444
);
4545
expect(container).toMatchSnapshot();
@@ -48,9 +48,18 @@ describe('DataViewTable component', () => {
4848
test('should render with an error state', () => {
4949
const { container } = render(
5050
<DataView activeState="error">
51-
<DataViewTableBasic aria-label='Repositories table' ouiaId={ouiaId} columns={columns} states={{ error:"Some error" }} rows={[]} />
51+
<DataViewTableBasic aria-label='Repositories table' ouiaId={ouiaId} columns={columns} bodyStates={{ error: "Some error" }} rows={[]} />
5252
</DataView>
5353
);
5454
expect(container).toMatchSnapshot();
5555
});
56+
57+
test('should render with a loading state', () => {
58+
const { container } = render(
59+
<DataView activeState="loading">
60+
<DataViewTableBasic aria-label='Repositories table' ouiaId={ouiaId} columns={columns} bodyStates={{ loading: "Data is loading" }} rows={[]} />
61+
</DataView>
62+
);
63+
expect(container).toMatchSnapshot();
64+
});
5665
});

0 commit comments

Comments
 (0)