Skip to content

Commit

Permalink
Merge pull request #131 from fhlavac/checkbox
Browse files Browse the repository at this point in the history
Add DataViewCheckbox component
  • Loading branch information
Hyperkid123 authored Nov 19, 2024
2 parents e122f5f + d8e4684 commit 6d8dfcd
Show file tree
Hide file tree
Showing 11 changed files with 540 additions and 39 deletions.
66 changes: 66 additions & 0 deletions cypress/component/DataViewCheckboxFilter.cy.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import React from 'react';
import { DataViewCheckboxFilter, DataViewCheckboxFilterProps } from '@patternfly/react-data-view/dist/dynamic/DataViewCheckboxFilter';
import { DataViewToolbar } from '@patternfly/react-data-view/dist/dynamic/DataViewToolbar';

describe('DataViewCheckboxFilter component', () => {
const defaultProps: DataViewCheckboxFilterProps = {
filterId: 'test-checkbox-filter',
title: 'Test checkbox filter',
value: [ 'workspace-one' ],
options: [
{ label: 'Workspace one', value: 'workspace-one' },
{ label: 'Workspace two', value: 'workspace-two' },
{ label: 'Workspace three', value: 'workspace-three' },
],
};

it('renders a checkbox filter with options', () => {
const onChange = cy.stub().as('onChange');

cy.mount(
<DataViewToolbar filters={<DataViewCheckboxFilter {...defaultProps} onChange={onChange} />} />
);

cy.get('[data-ouia-component-id="DataViewCheckboxFilter-toggle"]')
.contains('Test checkbox filter')
.should('be.visible');

cy.get('[data-ouia-component-id="DataViewCheckboxFilter-badge"]')
.should('exist')
.contains('1');

cy.get('[data-ouia-component-id="DataViewCheckboxFilter-toggle"]').click();
cy.get('[data-ouia-component-id="DataViewCheckboxFilter-menu"]').should('be.visible');

cy.get('[data-ouia-component-id="DataViewCheckboxFilter-menu"]')
.find('li')
.should('have.length', 3)
.first()
.contains('Workspace one');

cy.get('[data-ouia-component-id="DataViewCheckboxFilter-menu"]')
.find('li')
.first()
.find('input[type="checkbox"]')
.should('be.checked');

cy.get('[data-ouia-component-id="DataViewCheckboxFilter-menu"]')
.find('li')
.eq(1)
.find('input[type="checkbox"]')
.click();

cy.get('@onChange').should('have.been.calledWith', Cypress.sinon.match.object, [ 'workspace-two', 'workspace-one' ]);
});

it('renders a checkbox filter with no options selected', () => {
const emptyProps = { ...defaultProps, value: [] };

cy.mount(
<DataViewToolbar filters={<DataViewCheckboxFilter {...emptyProps} />} />
);

cy.get('[data-ouia-component-id="DataViewCheckboxFilter-toggle"]').contains('Test checkbox filter');
cy.get('[data-ouia-component-id="DataViewCheckboxFilter-badge"]').should('not.exist');
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ import { useDataViewFilters, useDataViewPagination } from '@patternfly/react-dat
import { DataView } from '@patternfly/react-data-view/dist/dynamic/DataView';
import { DataViewTable } from '@patternfly/react-data-view/dist/dynamic/DataViewTable';
import { DataViewToolbar } from '@patternfly/react-data-view/dist/dynamic/DataViewToolbar';
import { DataViewFilters } from '@patternfly/react-data-view/dist/dynamic/DataViewFilters';
import { DataViewFilterOption, DataViewFilters } from '@patternfly/react-data-view/dist/dynamic/DataViewFilters';
import { DataViewTextFilter } from '@patternfly/react-data-view/dist/dynamic/DataViewTextFilter';
import { DataViewCheckboxFilter } from '@patternfly/react-data-view/dist/dynamic/DataViewCheckboxFilter';

const perPageOptions = [
{ title: '5', value: 5 },
Expand All @@ -17,38 +18,51 @@ interface Repository {
name: string;
branch: string | null;
prs: string | null;
workspaces: string;
workspace: string;
lastCommit: string;
}

interface RepositoryFilters {
name: string,
branch: string
branch: string,
workspace: string[]
}

const repositories: Repository[] = [
{ name: 'Repository one', branch: 'Branch one', prs: 'Pull request one', workspaces: 'Workspace one', lastCommit: 'Timestamp one' },
{ name: 'Repository two', branch: 'Branch two', prs: 'Pull request two', workspaces: 'Workspace two', lastCommit: 'Timestamp two' },
{ name: 'Repository three', branch: 'Branch three', prs: 'Pull request three', workspaces: 'Workspace three', lastCommit: 'Timestamp three' },
{ name: 'Repository four', branch: 'Branch four', prs: 'Pull request four', workspaces: 'Workspace four', lastCommit: 'Timestamp four' },
{ name: 'Repository five', branch: 'Branch five', prs: 'Pull request five', workspaces: 'Workspace five', lastCommit: 'Timestamp five' },
{ name: 'Repository six', branch: 'Branch six', prs: 'Pull request six', workspaces: 'Workspace six', lastCommit: 'Timestamp six' }
{ name: 'Repository one', branch: 'Branch one', prs: 'Pull request one', workspace: 'Workspace one', lastCommit: 'Timestamp one' },
{ name: 'Repository two', branch: 'Branch two', prs: 'Pull request two', workspace: 'Workspace two', lastCommit: 'Timestamp two' },
{ name: 'Repository three', branch: 'Branch three', prs: 'Pull request three', workspace: 'Workspace one', lastCommit: 'Timestamp three' },
{ name: 'Repository four', branch: 'Branch four', prs: 'Pull request four', workspace: 'Workspace one', lastCommit: 'Timestamp four' },
{ name: 'Repository five', branch: 'Branch five', prs: 'Pull request five', workspace: 'Workspace two', lastCommit: 'Timestamp five' },
{ name: 'Repository six', branch: 'Branch six', prs: 'Pull request six', workspace: 'Workspace three', lastCommit: 'Timestamp six' }
];

const columns = [ 'Name', 'Branch', 'Pull requests', 'Workspaces', 'Last commit' ];
const filterOptions: DataViewFilterOption[] = [
{ label: 'Workspace one', value: 'workspace-one' },
{ label: 'Workspace two', value: 'workspace-two' },
{ label: 'Workspace three', value: 'workspace-three' }
];

const columns = [ 'Name', 'Branch', 'Pull requests', 'Workspace', 'Last commit' ];

const ouiaId = 'LayoutExample';

const MyTable: React.FunctionComponent = () => {
const [ searchParams, setSearchParams ] = useSearchParams();
const { filters, onSetFilters, clearAllFilters } = useDataViewFilters<RepositoryFilters>({ initialFilters: { name: '', branch: '', workspace: [] }, searchParams, setSearchParams });
const pagination = useDataViewPagination({ perPage: 5 });
const { page, perPage } = pagination;
const { filters, onSetFilters, clearAllFilters } = useDataViewFilters<RepositoryFilters>({ initialFilters: { name: '', branch: '' }, searchParams, setSearchParams });

const pageRows = useMemo(() => repositories
.filter(item => (!filters.name || item.name?.toLocaleLowerCase().includes(filters.name?.toLocaleLowerCase())) && (!filters.branch || item.branch?.toLocaleLowerCase().includes(filters.branch?.toLocaleLowerCase())))
const filteredData = useMemo(() => repositories.filter(item =>
(!filters.name || item.name?.toLocaleLowerCase().includes(filters.name?.toLocaleLowerCase())) &&
(!filters.branch || item.branch?.toLocaleLowerCase().includes(filters.branch?.toLocaleLowerCase())) &&
(!filters.workspace || filters.workspace.length === 0 || filters.workspace.includes(String(filterOptions.find(option => option.label === item.workspace)?.value)))
), [ filters ]);

const pageRows = useMemo(() => filteredData
.slice((page - 1) * perPage, ((page - 1) * perPage) + perPage)
.map(item => Object.values(item)), [ page, perPage, filters ]);
.map(item => Object.values(item)),
[ page, perPage, filteredData ]);

return (
<DataView>
Expand All @@ -58,14 +72,15 @@ const MyTable: React.FunctionComponent = () => {
pagination={
<Pagination
perPageOptions={perPageOptions}
itemCount={repositories.length}
itemCount={filteredData.length}
{...pagination}
/>
}
filters={
<DataViewFilters onChange={(_e, values) => onSetFilters(values)} values={filters}>
<DataViewTextFilter filterId="name" title='Name' placeholder='Filter by name' />
<DataViewTextFilter filterId="branch" title='Branch' placeholder='Filter by branch' />
<DataViewCheckboxFilter filterId="workspace" title='Workspace' placeholder='Filter by workspace' options={filterOptions} />
</DataViewFilters>
}
/>
Expand All @@ -76,7 +91,7 @@ const MyTable: React.FunctionComponent = () => {
<Pagination
isCompact
perPageOptions={perPageOptions}
itemCount={repositories.length}
itemCount={filteredData.length}
{...pagination}
/>
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ source: react
# If you use typescript, the name of the interface to display props for
# These are found through the sourceProps function provided in patternfly-docs.source.js
sortValue: 3
propComponents: ['DataViewFilters', 'DataViewTextFilter']
propComponents: ['DataViewFilters', 'DataViewTextFilter', 'DataViewCheckboxFilter']
sourceLink: https://github.com/patternfly/react-data-view/blob/main/packages/module/patternfly-docs/content/extensions/data-view/examples/Functionality/Functionality.md
---
import { useMemo } from 'react';
Expand All @@ -23,6 +23,7 @@ import { DataViewToolbar } from '@patternfly/react-data-view/dist/dynamic/DataVi
import { DataViewTable } from '@patternfly/react-data-view/dist/dynamic/DataViewTable';
import { DataViewFilters } from '@patternfly/react-data-view/dist/dynamic/DataViewFilters';
import { DataViewTextFilter } from '@patternfly/react-data-view/dist/dynamic/DataViewTextFilter';
import { DataViewCheckboxFilter } from '@patternfly/react-data-view/dist/dynamic/DataViewCheckboxFilter';

This is a list of functionality you can use to manage data displayed in the **data view**.

Expand Down Expand Up @@ -92,7 +93,7 @@ The `useDataViewSelection` hook manages the selection state of the data view.
Enables filtering of data records in the data view and displays the applied filter chips.

### Toolbar usage
The data view toolbar can include a set of filters by passing a React node to the `filters` property. You can use predefined components `DataViewFilters` and `DataViewTextFilter` to customize and handle filtering directly in the toolbar. The `DataViewFilters` is a wrapper allowing conditional filtering using multiple attributes. If you need just a single filter, you can use `DataViewTextFilter` or a different filter component alone. Props of these filter components are listed at the bottom of this page.
The data view toolbar can include a set of filters by passing a React node to the `filters` property. You can use predefined components `DataViewFilters`, `DataViewTextFilter` and `DataViewCheckboxFilter` to customize and handle filtering directly in the toolbar. The `DataViewFilters` is a wrapper allowing conditional filtering using multiple attributes. If you need just a single filter, you can use `DataViewTextFilter`, `DataViewCheckboxFilter` or a different filter component alone. Props of these filter components are listed at the bottom of this page.

You can decide between passing `value` and `onChange` event to every filter separately or pass `values` and `onChange` to the `DataViewFilters` wrapper which make them available to its children. Props directly passed to child filters have a higher priority than the "inherited" ones.

Expand All @@ -101,7 +102,7 @@ You can decide between passing `value` and `onChange` event to every filter sepa
The `useDataViewFilters` hook manages the filter state of the data view. It allows you to define default filter values, synchronize filter state with URL parameters, and handle filter changes efficiently.

**Initial values:**
- `initialFilters` object with default filter values
- `initialFilters` object with default filter values (if the filter param allows multiple values, pass an array)
- optional `searchParams` object for managing URL-based filter state
- optional `setSearchParams` function to update the URL when filters are modified

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import React from 'react';
import { render } from '@testing-library/react';
import DataViewCheckboxFilter, { DataViewCheckboxFilterProps } from './DataViewCheckboxFilter';
import DataViewToolbar from '../DataViewToolbar';

describe('DataViewCheckboxFilter component', () => {
const defaultProps: DataViewCheckboxFilterProps = {
filterId: 'test-checkbox-filter',
title: 'Test Checkbox Filter',
value: [ 'workspace-one' ],
options: [
{ label: 'Workspace one', value: 'workspace-one' },
{ label: 'Workspace two', value: 'workspace-two' },
{ label: 'Workspace three', value: 'workspace-three' },
],
};

it('should render correctly', () => {
const { container } = render(
<DataViewToolbar filters={<DataViewCheckboxFilter {...defaultProps} />} />
);
expect(container).toMatchSnapshot();
});
});
Loading

0 comments on commit 6d8dfcd

Please sign in to comment.