Refactor/remove react table (#642)

* Refactored tables without tan stack
* Fixed checkbox behavior with multiple handlers on click
* Fixed hotkeys scope
* Fix debounce in editable cells
* Lowered coverage

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
Lucas Bordeau
2023-07-13 19:08:13 +02:00
committed by GitHub
parent e7d48d5373
commit 734e18e01a
88 changed files with 1789 additions and 671 deletions

View File

@ -4,8 +4,9 @@ import { IconList } from '@tabler/icons-react';
import {
CompaniesSelectedSortType,
defaultOrderBy,
useCompaniesQuery,
} from '@/companies/services';
import { companyColumns } from '@/companies/table/components/companyColumns';
import { CompanyEntityTableData } from '@/companies/table/components/CompanyEntityTableData';
import { reduceSortsToOrderBy } from '@/lib/filters-and-sorts/helpers';
import { filtersScopedState } from '@/lib/filters-and-sorts/states/filtersScopedState';
import { turnFilterIntoWhereClause } from '@/lib/filters-and-sorts/utils/turnFilterIntoWhereClause';
@ -15,7 +16,6 @@ import { HooksEntityTable } from '@/ui/components/table/HooksEntityTable';
import { TableContext } from '@/ui/tables/states/TableContext';
import { CompanyOrderByWithRelationInput } from '~/generated/graphql';
import { useCompaniesColumns } from './companies-columns';
import { companiesFilters } from './companies-filters';
import { availableSorts } from './companies-sorts';
@ -30,27 +30,18 @@ export function CompanyTable() {
const filters = useRecoilScopedValue(filtersScopedState, TableContext);
const whereFilters = useMemo(() => {
if (!filters.length) return undefined;
return { AND: filters.map(turnFilterIntoWhereClause) };
}, [filters]) as any;
const companiesColumns = useCompaniesColumns();
const { data } = useCompaniesQuery(orderBy, whereFilters);
const companies = data?.companies ?? [];
return (
<>
<CompanyEntityTableData orderBy={orderBy} whereFilters={whereFilters} />
<HooksEntityTable
numberOfColumns={companiesColumns.length}
numberOfRows={companies.length}
availableTableFilters={companiesFilters}
numberOfColumns={companyColumns.length}
availableFilters={companiesFilters}
/>
<EntityTable
data={companies}
columns={companiesColumns}
columns={companyColumns}
viewName="All Companies"
viewIcon={<IconList size={16} />}
availableSorts={availableSorts}

View File

@ -1,28 +1,21 @@
import { IconList } from '@tabler/icons-react';
import { companyColumns } from '@/companies/table/components/companyColumns';
import { EntityTable } from '@/ui/components/table/EntityTable';
import { HooksEntityTable } from '@/ui/components/table/HooksEntityTable';
import { mockedCompaniesData } from '~/testing/mock-data/companies';
import { useCompaniesColumns } from './companies-columns';
import { companiesFilters } from './companies-filters';
import { availableSorts } from './companies-sorts';
export function CompanyTableMockMode() {
const companiesColumns = useCompaniesColumns();
const companies = mockedCompaniesData;
return (
<>
<HooksEntityTable
numberOfColumns={companiesColumns.length}
numberOfRows={companies.length}
availableTableFilters={companiesFilters}
numberOfColumns={companyColumns.length}
availableFilters={companiesFilters}
/>
<EntityTable
data={companies}
columns={companiesColumns}
columns={companyColumns}
viewName="All Companies"
viewIcon={<IconList size={16} />}
availableSorts={availableSorts}

View File

@ -31,12 +31,6 @@ export const SortByName: Story = {
expect(await canvas.findByText('Airbnb')).toBeInTheDocument();
expect(
(await canvas.findAllByRole('checkbox')).map((item) => {
return item.getAttribute('id');
})[1],
).toStrictEqual('checkbox-selected-89bb825c-171e-4bcc-9cf7-43448d6fb278');
const cancelButton = canvas.getByText('Cancel');
await userEvent.click(cancelButton);

View File

@ -1,150 +0,0 @@
import { useMemo } from 'react';
import { createColumnHelper } from '@tanstack/react-table';
import { CompanyAccountOwnerCell } from '@/companies/components/CompanyAccountOwnerCell';
import { CompanyEditableNameChipCell } from '@/companies/components/CompanyEditableNameCell';
import { EditableCellDate } from '@/ui/components/editable-cell/types/EditableCellDate';
import { EditableCellText } from '@/ui/components/editable-cell/types/EditableCellText';
import { ColumnHead } from '@/ui/components/table/ColumnHead';
import {
IconBuildingSkyscraper,
IconCalendarEvent,
IconLink,
IconMap,
IconUser,
IconUsers,
} from '@/ui/icons/index';
import { getCheckBoxColumn } from '@/ui/tables/utils/getCheckBoxColumn';
import {
GetCompaniesQuery,
useUpdateCompanyMutation,
} from '~/generated/graphql';
const columnHelper = createColumnHelper<GetCompaniesQuery['companies'][0]>();
export const useCompaniesColumns = () => {
const [updateCompany] = useUpdateCompanyMutation();
return useMemo(() => {
return [
getCheckBoxColumn(),
columnHelper.accessor('name', {
header: () => (
<ColumnHead
viewName="Name"
viewIcon={<IconBuildingSkyscraper size={16} />}
/>
),
cell: (props) => (
<CompanyEditableNameChipCell company={props.row.original} />
),
size: 180,
}),
columnHelper.accessor('domainName', {
header: () => (
<ColumnHead viewName="URL" viewIcon={<IconLink size={16} />} />
),
cell: (props) => (
<EditableCellText
value={props.row.original.domainName || ''}
placeholder="Domain name"
onChange={(value) => {
const company = { ...props.row.original };
company.domainName = value;
updateCompany({
variables: {
...company,
accountOwnerId: company.accountOwner?.id,
},
});
}}
/>
),
size: 100,
}),
columnHelper.accessor('employees', {
header: () => (
<ColumnHead viewName="Employees" viewIcon={<IconUsers size={16} />} />
),
cell: (props) => (
<EditableCellText
value={props.row.original.employees?.toString() || ''}
placeholder="Employees"
onChange={(value) => {
const company = { ...props.row.original };
updateCompany({
variables: {
...company,
employees: value === '' ? null : Number(value),
accountOwnerId: company.accountOwner?.id,
},
});
}}
/>
),
size: 150,
}),
columnHelper.accessor('address', {
header: () => (
<ColumnHead viewName="Address" viewIcon={<IconMap size={16} />} />
),
cell: (props) => (
<EditableCellText
value={props.row.original.address || ''}
placeholder="Address"
onChange={(value) => {
const company = { ...props.row.original };
company.address = value;
updateCompany({
variables: {
...company,
accountOwnerId: company.accountOwner?.id,
},
});
}}
/>
),
size: 170,
}),
columnHelper.accessor('createdAt', {
header: () => (
<ColumnHead
viewName="Creation"
viewIcon={<IconCalendarEvent size={16} />}
/>
),
cell: (props) => (
<EditableCellDate
value={
props.row.original.createdAt
? new Date(props.row.original.createdAt)
: new Date()
}
onChange={(value: Date) => {
const company = { ...props.row.original };
company.createdAt = value.toISOString();
updateCompany({
variables: {
...company,
accountOwnerId: company.accountOwner?.id,
},
});
}}
/>
),
size: 150,
}),
columnHelper.accessor('accountOwner', {
header: () => (
<ColumnHead
viewName="Account owner"
viewIcon={<IconUser size={16} />}
/>
),
cell: (props) => (
<CompanyAccountOwnerCell company={props.row.original} />
),
}),
];
}, [updateCompany]);
};

View File

@ -13,30 +13,25 @@ export const availableSorts = [
key: 'name',
label: 'Name',
icon: <IconBuildingSkyscraper size={16} />,
_type: 'default_sort',
},
{
key: 'employees',
label: 'Employees',
icon: <IconUsers size={16} />,
_type: 'default_sort',
},
{
key: 'domainName',
label: 'Url',
icon: <IconLink size={16} />,
_type: 'default_sort',
},
{
key: 'address',
label: 'Address',
icon: <IconMap size={16} />,
_type: 'default_sort',
},
{
key: 'createdAt',
label: 'Creation',
icon: <IconCalendarEvent size={16} />,
_type: 'default_sort',
},
] satisfies Array<SortType<Companies_Order_By>>;