Skip to content

Commit

Permalink
feat(manager-react-components): add filters in datagrid
Browse files Browse the repository at this point in the history
ref: MANAGER-15088

Signed-off-by: Alex Boungnaseng <[email protected]>
  • Loading branch information
aboungnaseng-ovhcloud committed Nov 26, 2024
1 parent 6dcda33 commit 6df366e
Show file tree
Hide file tree
Showing 12 changed files with 353 additions and 60 deletions.
Original file line number Diff line number Diff line change
@@ -1,42 +1,30 @@
import React, { useState } from 'react';
import { ColumnSort } from '@tanstack/react-table';
import { withRouter } from 'storybook-addon-react-router-v6';
import { applyFilters } from '@ovh-ux/manager-core-api';
import { useSearchParams } from 'react-router-dom';
import { Datagrid } from './datagrid.component';
import { DataGridTextCell } from './text-cell.component';
import { useColumnFilters } from '../filters';
import { columsTmp, columsFilters } from './datagrid.stories';

interface Item {
label: string;
price: number;
}

const columns = [
{
id: 'label',
cell: (item: Item) => {
return <DataGridTextCell>{item.label}</DataGridTextCell>;
},
label: 'Label',
},
{
id: 'price',
cell: (item: Item) => {
return <DataGridTextCell>{item.price}</DataGridTextCell>;
},
label: 'Price',
},
];

const DatagridStory = ({
items,
isSortable,
columns = columsTmp,
}: {
items: Item[];
isSortable: boolean;
columns?: any;
}) => {
const [sorting, setSorting] = useState<ColumnSort>();
const [data, setData] = useState(items);
const [searchParams] = useSearchParams();
const { filters, addFilter, removeFilter } = useColumnFilters();

const fetchNextPage = () => {
const itemsIndex = data.length;
Expand All @@ -57,10 +45,11 @@ const DatagridStory = ({
)}
<Datagrid
columns={columns}
items={data}
items={applyFilters(data, filters)}
totalItems={data.length}
hasNextPage={data.length > 0 && data.length < 30}
onFetchNextPage={fetchNextPage}
filters={{ filters: filters, add: addFilter, remove: removeFilter }}

Check failure on line 52 in packages/manager-react-components/src/components/datagrid/datagrid-cursor.stories.tsx

View workflow job for this annotation

GitHub Actions / Lint Code Base

Expected property shorthand

Check failure on line 52 in packages/manager-react-components/src/components/datagrid/datagrid-cursor.stories.tsx

View workflow job for this annotation

GitHub Actions / Lint Code Base

Expected property shorthand
{...(isSortable
? {
sorting,
Expand Down Expand Up @@ -99,6 +88,17 @@ export const Sortable = {
},
};

export const Filters = {
args: {
items: [...Array(10).keys()].map((_, i) => ({
label: `Item #${i}`,
price: Math.floor(1 + Math.random() * 100),
})),
isSortable: true,
columns: columsFilters,
},
};

export default {
title: 'Components/Datagrid Cursor',
component: DatagridStory,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React from 'react';
import React, { useEffect, useState } from 'react';
import {
ColumnDef,
ColumnSort as TanstackColumnSort,
Expand All @@ -8,15 +8,23 @@ import {
useReactTable,
getSortedRowModel,
} from '@tanstack/react-table';
import { ODS_ICON_NAME, ODS_BUTTON_VARIANT } from '@ovhcloud/ods-components';
import {
ODS_ICON_NAME,
ODS_BUTTON_VARIANT,
ODS_BUTTON_SIZE,
} from '@ovhcloud/ods-components';
import {
OdsPopover,
OdsButton,
OdsIcon,
OdsPagination,
OdsTable,
} from '@ovhcloud/ods-components/react';
import { useTranslation } from 'react-i18next';
import { FilterAdd, FilterList } from '../filters';
import { FilterWithLabel } from '../filters/interface';
import { DataGridTextCell } from './text-cell.component';
import { FilterComparator } from '@ovh-ux/manager-core-api';

Check failure on line 27 in packages/manager-react-components/src/components/datagrid/datagrid.component.tsx

View workflow job for this annotation

GitHub Actions / Lint Code Base

`@ovh-ux/manager-core-api` import should occur before import of `../filters`

Check failure on line 27 in packages/manager-react-components/src/components/datagrid/datagrid.component.tsx

View workflow job for this annotation

GitHub Actions / Lint Code Base

`@ovh-ux/manager-core-api` import should occur before import of `../filters`
import './translations';

export type ColumnSort = TanstackColumnSort;
Expand All @@ -35,6 +43,21 @@ export interface DatagridColumn<T> {
label: string;
/** is the column sortable ? (defaults is true) */
isSortable?: boolean;
/** set column filter */
comparator?: FilterComparator;
}

type ColumnFilterProps = {
key: string;
value: string | string[];
comparator: FilterComparator;
label: string;
};

export interface FilterProps {
filters: FilterWithLabel[];
add: (filters: ColumnFilterProps) => void;
remove: (filter: FilterWithLabel) => void;
}

export interface DatagridProps<T> {
Expand Down Expand Up @@ -68,6 +91,7 @@ export interface DatagridProps<T> {
/** setSorting?: OnChangeFn<SortingState>; */
/** label displayed if there is no item in the datagrid */
noResultLabel?: string;
filters?: FilterProps;
}

export const Datagrid = <T,>({
Expand All @@ -85,6 +109,7 @@ export const Datagrid = <T,>({
manualSorting = true,
manualPagination = true,
noResultLabel,
filters,
}: DatagridProps<T>) => {
const { t } = useTranslation('datagrid');
const pageCount = pagination
Expand Down Expand Up @@ -131,8 +156,53 @@ export const Datagrid = <T,>({
}),
});

const [columnsFilters, setColumnsFilters] = useState([]);
useEffect(() => {
const clmFilters = columns
.filter((item) => 'comparator' in item)
.map((column) => ({
id: column.id,
label: column.label,
comparators: column.comparator,
}));
setColumnsFilters(clmFilters);
}, [columns]);

return (
<div>
{columnsFilters.length > 0 && (
<div className="flex flex-row-reverse pb-[5px]">
<div id="datagrid-filter-popover-trigger">
<OdsButton
slot="datagrid-filter-popover-trigger"
size={ODS_BUTTON_SIZE.sm}
variant={ODS_BUTTON_VARIANT.outline}
icon={ODS_ICON_NAME.filter}
label="Filter"
/>
</div>
<OdsPopover triggerId="datagrid-filter-popover-trigger" with-arrow>
<FilterAdd
columns={columnsFilters}
onAddFilter={(addedFilter, column) => {
filters.add({
...addedFilter,
label: column.label,
});
}}
/>
</OdsPopover>
</div>
)}
{filters?.filters && (
<div id="datagrid-filter-list" className="my-5">
<FilterList
filters={filters.filters}
onRemoveFilter={filters.remove}
/>
</div>
)}

<div className={`contents px-[1px] ${className || ''}`}>
<OdsTable className="overflow-x-visible">
<table className="w-full border-collapse">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { vitest } from 'vitest';
import React, { useState } from 'react';
import { fireEvent, render, screen } from '@testing-library/react';
import { FilterCategories } from '@ovh-ux/manager-core-api';
import {
ColumnSort,
Datagrid,
DatagridColumn,
PaginationState,
FilterProps,
} from './datagrid.component';
import DataGridTextCell from './text-cell.component';

Expand All @@ -32,11 +33,13 @@ const sampleColumns = [
return <span>{name}</span>;
},
label: 'Name',
comparator: FilterCategories.String,
},
{
id: 'another-column',
label: 'test',
cell: () => <DataGridTextCell />,
comparator: FilterCategories.String,
},
];

Expand All @@ -46,12 +49,14 @@ const DatagridTest = ({
pageIndex,
className,
noResultLabel,
filters,
}: {
columns: DatagridColumn<string>[];
columns: any;
items: string[];
pageIndex: number;
className?: string;
noResultLabel?: string;
filters?: FilterProps;
}) => {
const [pagination, setPagination] = useState<PaginationState>({
pageIndex,
Expand All @@ -70,6 +75,7 @@ const DatagridTest = ({
onSortChange={() => {}}
className={className || ''}
noResultLabel={noResultLabel}
filters={filters}
/>
);
};
Expand Down Expand Up @@ -220,3 +226,44 @@ it('should disable overflow of table', async () => {
);
expect(container.querySelectorAll('.overflow-hidden').length).toBe(1);
});

it('should disable overflow of table', async () => {
const { container } = render(
<DatagridTest
columns={sampleColumns}
items={[]}
pageIndex={0}
className={'overflow-hidden'}
/>,
);
expect(container.querySelectorAll('.overflow-hidden').length).toBe(1);
});

it('should display filter add and filter list', async () => {
const filters = {
filters: [
{
key: 'customName',
comparator: 'includes',
value: 'coucou',
label: 'customName',
},
],
add: null,
remove: null,
} as FilterProps;
console.info('sampleColumns : ', sampleColumns);
const { container } = render(
<DatagridTest
columns={sampleColumns}
items={[]}
pageIndex={0}
className={'overflow-hidden'}
filters={filters}
/>,
);
expect(
container.querySelectorAll('#datagrid-filter-popover-trigger').length,
).toBe(1);
expect(container.querySelectorAll('#datagrid-filter-list').length).toBe(1);
});
Loading

0 comments on commit 6df366e

Please sign in to comment.