Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 61 additions & 4 deletions cypress/component/DataView.cy.tsx
Original file line number Diff line number Diff line change
@@ -1,29 +1,86 @@
import React from 'react';
import { Pagination } from '@patternfly/react-core';
import { Table, Tbody, Th, Thead, Tr, Td } from '@patternfly/react-table';
import DataView from '../../packages/module/dist/dynamic/DataView';
import DataViewToolbar from '../../packages/module/dist/esm/DataViewToolbar';

interface Repository {
name: string;
branches: string | null;
prs: string | null;
workspaces: string;
lastCommit: string;
}

const PAGINATION = {
page: 1,
perPage: 1
perPage: 10
}

const repositories: Repository[] = [
{ name: 'one', branches: 'two', prs: 'three', workspaces: 'four', lastCommit: 'five' },
{ name: 'one - 2', branches: null, prs: null, workspaces: 'four - 2', lastCommit: 'five - 2' },
{ name: 'one - 3', branches: 'two - 3', prs: 'three - 3', workspaces: 'four - 3', lastCommit: 'five - 3' },
{ name: 'one - 4', branches: 'two - 4', prs: 'null', workspaces: 'four - 4', lastCommit: 'five - 4' },
{ name: 'one - 5', branches: 'two - 5', prs: 'three - 5', workspaces: 'four - 5', lastCommit: 'five - 5' },
{ name: 'one - 6', branches: 'two - 6', prs: 'three - 6', workspaces: 'four - 6', lastCommit: 'five - 6' }
];

const cols: Record<keyof Repository, string> = {
name: 'Repositories',
branches: 'Branches',
prs: 'Pull requests',
workspaces: 'Workspaces',
lastCommit: 'Last commit'
};

describe('DataView', () => {
it('renders the data view layout', () => {
cy.mount(<DataView><>Data view content</></DataView>)
cy.get('[data-ouia-component-id="DataView-stack-item-0"]').contains('Data view content');
});

it('renders the data view with toolbar, data section and footer', () => {
it('renders the data view with toolbar, tabular data section and footer', () => {
const ouiaId = 'data';

cy.mount(
<DataView>
<DataViewToolbar pagination={<Pagination {...PAGINATION} ouiaId="DataViewToolbar-pagination" />} />
<>Data section</>
<Table aria-label="Repositories table" ouiaId={ouiaId}>
<Thead data-ouia-component-id={`${ouiaId}-thead`}>
<Tr ouiaId={`${ouiaId}-tr-head`}>
{Object.values(cols).map((column, index) => <Th key={index} data-ouia-component-id={`${ouiaId}-th-${index}`}>{column}</Th>)}
</Tr>
</Thead>
<Tbody>
{repositories.map((repo, rowIndex) => (
<Tr key={repo.name}>
<Td data-ouia-component-id={`${ouiaId}-td-${rowIndex}-name`} dataLabel={cols.name}>{repo.name}</Td>
<Td data-ouia-component-id={`${ouiaId}-td-${rowIndex}-branches`} dataLabel={cols.branches}>{repo.branches}</Td>
<Td data-ouia-component-id={`${ouiaId}-td-${rowIndex}-prs`} dataLabel={cols.prs}>{repo.prs}</Td>
<Td data-ouia-component-id={`${ouiaId}-td-${rowIndex}-workspaces`} dataLabel={cols.workspaces}>{repo.workspaces}</Td>
<Td data-ouia-component-id={`${ouiaId}-td-${rowIndex}-last-commit`} dataLabel={cols.lastCommit}>{repo.lastCommit}</Td>
</Tr>
))}
</Tbody>
</Table>
<DataViewToolbar pagination={<Pagination isCompact {...PAGINATION} ouiaId="DataViewFooter-pagination" />} ouiaId="DataViewFooter" />
</DataView>
);
cy.get('[data-ouia-component-id="DataViewToolbar-pagination"]').should('exist');
cy.get('[data-ouia-component-id="DataView-stack-item-1"]').contains('Data section');

cy.get('[data-ouia-component-id="data-th-0"]').contains('Repositories');
cy.get('[data-ouia-component-id="data-th-1"]').contains('Branches');
cy.get('[data-ouia-component-id="data-th-2"]').contains('Pull requests');
cy.get('[data-ouia-component-id="data-th-3"]').contains('Workspaces');
cy.get('[data-ouia-component-id="data-th-4"]').contains('Last commit');

cy.get('[data-ouia-component-id="data-td-0-name"]').contains('one');
cy.get('[data-ouia-component-id="data-td-2-branches"]').contains('two - 3');
cy.get('[data-ouia-component-id="data-td-3-prs"]').contains('null');
cy.get('[data-ouia-component-id="data-td-4-workspaces"]').contains('four - 5');
cy.get('[data-ouia-component-id="data-td-5-last-commit"]').contains('five - 6');

cy.get('[data-ouia-component-id="DataViewFooter-pagination"]').should('exist');
});
});
25 changes: 23 additions & 2 deletions cypress/e2e/DataView.spec.cy.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,27 @@
describe('Test the Data view docs page', () => {

it.skip('renders the docs', () => {
cy.visit('http://localhost:8006/extensions/data-view/data-view');
it('displays a layout with a table and paginates', () => {
const ouiaId = 'LayoutExample';

cy.visit('http://localhost:8006/extensions/data-view/data-view-layout');

cy.get(`[data-ouia-component-id="${ouiaId}Header-pagination"]`).should('exist');

cy.get(`[data-ouia-component-id="${ouiaId}Footer-pagination"]`).should('exist');

cy.get(`[data-ouia-component-id="${ouiaId}-th-0"]`).contains('Repositories');
cy.get(`[data-ouia-component-id="${ouiaId}-th-4"]`).contains('Last commit');

cy.get(`[data-ouia-component-id="${ouiaId}-td-0-0"]`).contains('one');
cy.get(`[data-ouia-component-id="${ouiaId}-td-4-4"]`).contains('five - 5');
cy.get(`[data-ouia-component-id="${ouiaId}-td-5-4"]`).should('not.exist');

// move to the next page
cy.get(`[data-action="next"`).first().click({ force: true });
cy.get(`[data-ouia-component-id="${ouiaId}-td-0-4"]`).contains('five - 6');

// move to previous page
cy.get(`[data-action="previous"`).eq(1).click({ force: true });
cy.get(`[data-ouia-component-id="${ouiaId}-td-0-4"]`).contains('five');
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ source: react
propComponents: ['DataView']
sourceLink: https://github.com/patternfly/react-data-view/blob/main/packages/module/patternfly-docs/content/extensions/data-view/examples/DataView/DataView.md
---
import { Pagination } from '@patternfly/react-core';
import { useMemo } from 'react';
import { useDataViewPagination } from '@patternfly/react-data-view/dist/dynamic/Hooks';
import DataView from '@patternfly/react-data-view/dist/dynamic/DataView';
import DataViewToolbar from '@patternfly/react-data-view/dist/dynamic/DataViewToolbar';

Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,65 @@
import React from 'react';
import React, { useMemo } from 'react';
import { Pagination } from '@patternfly/react-core';
import { Table, Tbody, Th, Thead, Tr, Td } from '@patternfly/react-table';
import { useDataViewPagination } from '@patternfly/react-data-view/dist/dynamic/Hooks';
import DataView from '@patternfly/react-data-view/dist/dynamic/DataView';
import DataViewToolbar from '@patternfly/react-data-view/dist/dynamic/DataViewToolbar';

const layoutItemStyling = {
width: '100%',
height: '5rem',
padding: 'var(--pf-t--global--spacer--md)',
border: 'var(--pf-t--global--border--width--box--default) dashed var(--pf-t--global--border--color--default)'
};
const perPageOptions = [
{ title: '5', value: 5 },
{ title: '10', value: 10 }
]

const PAGINATION = {
page: 1,
perPage: 1
interface Repository {
name: string;
branches: string | null;
prs: string | null;
workspaces: string;
lastCommit: string;
}

export const BasicExample: React.FunctionComponent = () => (
<DataView>
<DataViewToolbar pagination={<Pagination {...PAGINATION} />} />
<div style={layoutItemStyling}>Data representation</div>
<DataViewToolbar pagination={<Pagination isCompact {...PAGINATION} ouiaId="DataViewFooter" />} />
</DataView>
)
const repositories: Repository[] = [
{ name: 'one', branches: 'two', prs: 'three', workspaces: 'four', lastCommit: 'five' },
{ name: 'one - 2', branches: null, prs: null, workspaces: 'four - 2', lastCommit: 'five - 2' },
{ name: 'one - 3', branches: 'two - 3', prs: 'three - 3', workspaces: 'four - 3', lastCommit: 'five - 3' },
{ name: 'one - 4', branches: 'two - 4', prs: 'null', workspaces: 'four - 4', lastCommit: 'five - 4' },
{ name: 'one - 5', branches: 'two - 5', prs: 'three - 5', workspaces: 'four - 5', lastCommit: 'five - 5' },
{ name: 'one - 6', branches: 'two - 6', prs: 'three - 6', workspaces: 'four - 6', lastCommit: 'five - 6' }
];

const cols = {
name: 'Repositories',
branches: 'Branches',
prs: 'Pull requests',
workspaces: 'Workspaces',
lastCommit: 'Last commit'
};

const ouiaId = 'LayoutExample';

export const BasicExample: React.FunctionComponent = () => {
const pagination = useDataViewPagination({ perPage: 5 });
const { page, perPage } = pagination;

const data = useMemo(() => repositories.slice((page - 1) * perPage, ((page - 1) * perPage) + perPage), [ page, perPage ]);

return (
<DataView>
<DataViewToolbar pagination={<Pagination ouiaId={`${ouiaId}Header-pagination`} perPageOptions={perPageOptions} itemCount={repositories.length} {...pagination} />} />
<Table aria-label="Repositories table" ouiaId={ouiaId}>
<Thead data-ouia-component-id={`${ouiaId}-thead`}>
<Tr ouiaId={`${ouiaId}-tr-head`}>
{Object.values(cols).map((column, index) => <Th key={index} data-ouia-component-id={`${ouiaId}-th-${index}`}>{column}</Th>)}
</Tr>
</Thead>
<Tbody>
{data.map((repo, rowIndex) => (
<Tr key={repo.name} ouiaId={`${ouiaId}-tr-${rowIndex}`}>
{Object.keys(cols).map((column, colIndex) => <Td key={colIndex} data-ouia-component-id={`${ouiaId}-td-${rowIndex}-${colIndex}`}>{repo[column]}</Td>)}
</Tr>
))}
</Tbody>
</Table>
<DataViewToolbar pagination={<Pagination isCompact ouiaId={`${ouiaId}Footer-pagination`} perPageOptions={perPageOptions} itemCount={repositories.length} {...pagination} />} />
</DataView>
)}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,4 @@ Data view hooks provide a predefined solution to manage state of the data view.

### useDataViewPagination()

The `useDataViewPagination` hook manages the pagination state of the data view. It retrieves the current `page` and `perPage` values together with functions to set them (`setPage`, `setPerPage`)

Coming soon...

The `useDataViewPagination` hook manages the pagination state of the data view. It retrieves the current `page` and `perPage` values together with functions to set them (`onSetPage`, `onPerPageSelect`). You can easily spread the retrieved values to the PatternFly [pagination](/components/pagination) component and make it live.
13 changes: 0 additions & 13 deletions packages/module/src/DataView/DataView.test.tsx

This file was deleted.

2 changes: 1 addition & 1 deletion packages/module/src/Hooks/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export * from './useDataViewPagination';
export * from './pagination';
57 changes: 57 additions & 0 deletions packages/module/src/Hooks/pagination.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import '@testing-library/jest-dom';
import { renderHook, act } from '@testing-library/react';
import { useDataViewPagination } from './pagination';

describe('useDataViewPagination', () => {

it('should get initial state correctly - no page', () => {
const { result } = renderHook(() => useDataViewPagination({ perPage: 7 }))
expect(result.current).toEqual({
onPerPageSelect: expect.any(Function),
onSetPage: expect.any(Function),
page: 1,
perPage: 7
})
});

it('should get initial state correctly - page set', () => {
const { result } = renderHook(() => useDataViewPagination({ page: 3, perPage: 5 }))
expect(result.current).toEqual({
onPerPageSelect: expect.any(Function),
onSetPage: expect.any(Function),
page: 3,
perPage: 5
})
});

it('should set page correctly', () => {
const { result } = renderHook(() => useDataViewPagination({ page: 3, perPage: 5 }))

act(() => {
result.current.onSetPage(undefined, 8);
});

expect(result.current).toEqual({
onPerPageSelect: expect.any(Function),
onSetPage: expect.any(Function),
page: 8,
perPage: 5
})
});

it('should set perPage correctly', () => {
const { result } = renderHook(() => useDataViewPagination({ page: 3, perPage: 5 }))

act(() => {
result.current.onPerPageSelect(undefined, 50);
});

expect(result.current).toEqual({
onPerPageSelect: expect.any(Function),
onSetPage: expect.any(Function),
page: 3,
perPage: 50
})
});

});
28 changes: 28 additions & 0 deletions packages/module/src/Hooks/pagination.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { useState } from "react";

export interface UseDataViewPaginationProps {
page?: number;
perPage: number;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is perPage required but page optional? I think both should be optional IMO.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we don't want to introduce default values for perPage - they can vary from use case to use case. For page I think it is fine to keep it optional since it is usually 1 at the beginning.


export interface DataViewPaginationProps extends UseDataViewPaginationProps {
page: number;
}

export const useDataViewPagination = ({ page = 1, perPage }: UseDataViewPaginationProps) => {
const [ state, setState ] = useState({ page, perPage });

const onPerPageSelect = (_event: React.MouseEvent | React.KeyboardEvent | MouseEvent | undefined, newPerPage: number) => {
setState(prev => ({ ...prev, perPage: newPerPage }));
}

const onSetPage = (_event: React.MouseEvent | React.KeyboardEvent | MouseEvent | undefined, newPage: number) => {
setState(prev => ({ ...prev, page: newPage }));
}

return {
...state,
onPerPageSelect,
onSetPage
}
}
4 changes: 0 additions & 4 deletions packages/module/src/Hooks/useDataViewPagination.ts

This file was deleted.