Optimize table loading (#866)

* wip

* wip

* Ok

* Deleted unused code

* Fixed lint

* Minor fixes

* Minor fixes

* Minor Fixes

* Minor merge fixes

* Ok

* Fix storybook tests

* Removed console.log

* Fix login

* asd

* Fixed storybook

* Added await

* Fixed await

* Added sleep for failing test

* Fix sleep

* Fix test

* Fix tests

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
Lucas Bordeau
2023-07-25 20:00:15 +02:00
committed by GitHub
parent c2d6abde65
commit a2ccb643ff
85 changed files with 846 additions and 904 deletions

View File

@ -19,8 +19,8 @@ type OwnProps = {
>
| null
| undefined;
onChange: (firstName: string, lastName: string) => void;
onSubmit?: () => void;
onChange?: (firstName: string, lastName: string) => void;
onSubmit?: (firstName: string, lastName: string) => void;
onCancel?: () => void;
};
@ -37,20 +37,12 @@ export function EditablePeopleFullName({
onSubmit,
onCancel,
}: OwnProps) {
function handleDoubleTextChange(
firstValue: string,
secondValue: string,
): void {
onChange(firstValue, secondValue);
}
return (
<EditableCellDoubleText
firstValue={person?.firstName ?? ''}
secondValue={person?.lastName ?? ''}
firstValuePlaceholder="First name"
secondValuePlaceholder="Last name"
onChange={handleDoubleTextChange}
onSubmit={onSubmit}
onCancel={onCancel}
nonEditModeContent={

View File

@ -16,6 +16,8 @@ import {
useUpdateOnePersonMutation,
} from '~/generated/graphql';
import { EntityForSelect } from '../../ui/relation-picker/types/EntityForSelect';
export type OwnProps = {
people: Pick<Person, 'id'> & { company?: Pick<Company, 'id'> | null };
};
@ -37,17 +39,21 @@ export function PeopleCompanyPicker({ people }: OwnProps) {
selectedIds: people.company?.id ? [people.company.id] : [],
});
async function handleEntitySelected(entity: any) {
await updatePerson({
variables: {
where: {
id: people.id,
async function handleEntitySelected(
entity: EntityForSelect | null | undefined,
) {
if (entity) {
await updatePerson({
variables: {
where: {
id: people.id,
},
data: {
company: { connect: { id: entity.id } },
},
},
data: {
company: { connect: { id: entity.id } },
},
},
});
});
}
closeEditableCell();
}
@ -67,6 +73,7 @@ export function PeopleCompanyPicker({ people }: OwnProps) {
return (
<SingleEntitySelect
onCreate={handleCreate}
onCancel={() => closeEditableCell()}
onEntitySelected={handleEntitySelected}
entities={{
entitiesToSelect: companies.entitiesToSelect,

View File

@ -27,17 +27,22 @@ export function PeopleCompanyEditableFieldEditMode({ people }: OwnProps) {
selectedIds: people.company?.id ? [people.company.id] : [],
});
async function handleEntitySelected(entity: EntityForSelect) {
await updatePerson({
variables: {
where: {
id: people.id,
async function handleEntitySelected(
entity: EntityForSelect | null | undefined,
) {
if (entity) {
await updatePerson({
variables: {
where: {
id: people.id,
},
data: {
company: { connect: { id: entity.id } },
},
},
data: {
company: { connect: { id: entity.id } },
},
},
});
});
}
closeEditableField();
}

View File

@ -1,7 +1,17 @@
import { useLocation } from 'react-router-dom';
import { useRecoilCallback } from 'recoil';
import { GetPeopleQuery } from '~/generated/graphql';
import { peopleFilters } from '../../../pages/people/people-filters';
import { availableFiltersScopedState } from '../../ui/filter-n-sort/states/availableFiltersScopedState';
import { useContextScopeId } from '../../ui/recoil-scope/hooks/useContextScopeId';
import { currentPageLocationState } from '../../ui/states/currentPageLocationState';
import { useResetTableRowSelection } from '../../ui/table/hooks/useResetTableRowSelection';
import { entityTableDimensionsState } from '../../ui/table/states/entityTableDimensionsState';
import { isFetchingEntityTableDataState } from '../../ui/table/states/isFetchingEntityTableDataState';
import { TableContext } from '../../ui/table/states/TableContext';
import { tableRowIdsState } from '../../ui/table/states/tableRowIdsState';
import { peopleCityFamilyState } from '../states/peopleCityFamilyState';
import { peopleCompanyFamilyState } from '../states/peopleCompanyFamilyState';
import { peopleCreatedAtFamilyState } from '../states/peopleCreatedAtFamilyState';
@ -10,8 +20,15 @@ import { peopleJobTitleFamilyState } from '../states/peopleJobTitleFamilyState';
import { peopleLinkedinUrlFamilyState } from '../states/peopleLinkedinUrlFamilyState';
import { peopleNameCellFamilyState } from '../states/peopleNamesFamilyState';
import { peoplePhoneFamilyState } from '../states/peoplePhoneFamilyState';
import { peopleColumns } from '../table/components/peopleColumns';
export function useSetPeopleEntityTable() {
const resetTableRowSelection = useResetTableRowSelection();
const tableContextScopeId = useContextScopeId(TableContext);
const currentLocation = useLocation().pathname;
return useRecoilCallback(
({ set, snapshot }) =>
(newPeopleArray: GetPeopleQuery['people']) => {
@ -94,6 +111,29 @@ export function useSetPeopleEntityTable() {
});
}
}
const peopleIds = newPeopleArray.map((people) => people.id);
set(tableRowIdsState, (currentRowIds) => {
if (JSON.stringify(currentRowIds) !== JSON.stringify(peopleIds)) {
return peopleIds;
}
return currentRowIds;
});
resetTableRowSelection();
set(entityTableDimensionsState, {
numberOfColumns: peopleColumns.length,
numberOfRows: peopleIds.length,
});
set(availableFiltersScopedState(tableContextScopeId), peopleFilters);
set(currentPageLocationState, currentLocation);
set(isFetchingEntityTableDataState, false);
},
[],
);

View File

@ -1,4 +1,3 @@
import { useEffect, useState } from 'react';
import { useRecoilValue } from 'recoil';
import { peopleCityFamilyState } from '@/people/states/peopleCityFamilyState';
@ -13,29 +12,21 @@ export function EditablePeopleCityCell() {
const city = useRecoilValue(peopleCityFamilyState(currentRowEntityId ?? ''));
const [internalValue, setInternalValue] = useState(city ?? '');
useEffect(() => {
setInternalValue(city ?? '');
}, [city]);
return (
<EditableCellText
value={internalValue}
onChange={setInternalValue}
onSubmit={() =>
value={city ?? ''}
onSubmit={(newText) =>
updatePerson({
variables: {
where: {
id: currentRowEntityId,
},
data: {
city: internalValue,
city: newText,
},
},
})
}
onCancel={() => setInternalValue(city ?? '')}
/>
);
}

View File

@ -1,4 +1,3 @@
import { useEffect, useState } from 'react';
import { getOperationName } from '@apollo/client/utilities';
import { useRecoilValue } from 'recoil';
@ -18,45 +17,29 @@ export function EditablePeopleFullNameCell() {
peopleNameCellFamilyState(currentRowEntityId ?? ''),
);
const [internalFirstName, setInternalFirstName] = useState(firstName ?? '');
const [internalLastName, setInternalLastName] = useState(lastName ?? '');
useEffect(() => {
setInternalFirstName(firstName ?? '');
setInternalLastName(lastName ?? '');
}, [firstName, lastName]);
return (
<EditablePeopleFullName
person={{
id: currentRowEntityId ?? undefined,
_commentThreadCount: commentCount ?? undefined,
firstName: internalFirstName,
lastName: internalLastName,
firstName,
lastName,
displayName: displayName ?? undefined,
}}
onChange={(firstName, lastName) => {
setInternalFirstName(firstName);
setInternalLastName(lastName);
}}
onSubmit={() =>
onSubmit={(newFirstValue, newSecondValue) =>
updatePerson({
variables: {
where: {
id: currentRowEntityId,
},
data: {
firstName: internalFirstName,
lastName: internalLastName,
firstName: newFirstValue,
lastName: newSecondValue,
},
},
refetchQueries: [getOperationName(GET_PERSON) ?? ''],
})
}
onCancel={() => {
setInternalFirstName(firstName ?? '');
setInternalLastName(lastName ?? '');
}}
/>
);
}

View File

@ -1,4 +1,3 @@
import { useEffect, useState } from 'react';
import { useRecoilValue } from 'recoil';
import { peopleJobTitleFamilyState } from '@/people/states/peopleJobTitleFamilyState';
@ -15,29 +14,21 @@ export function EditablePeopleJobTitleCell() {
peopleJobTitleFamilyState(currentRowEntityId ?? ''),
);
const [internalValue, setInternalValue] = useState(jobTitle ?? '');
useEffect(() => {
setInternalValue(jobTitle ?? '');
}, [jobTitle]);
return (
<EditableCellText
value={internalValue}
onChange={setInternalValue}
onSubmit={() =>
value={jobTitle ?? ''}
onSubmit={(newText) =>
updatePerson({
variables: {
where: {
id: currentRowEntityId,
},
data: {
jobTitle: internalValue,
jobTitle: newText,
},
},
})
}
onCancel={() => setInternalValue(jobTitle ?? '')}
/>
);
}

View File

@ -1,4 +1,3 @@
import { useEffect, useState } from 'react';
import { useRecoilValue } from 'recoil';
import { peopleLinkedinUrlFamilyState } from '@/people/states/peopleLinkedinUrlFamilyState';
@ -16,29 +15,21 @@ export function EditablePeopleLinkedinUrlCell() {
peopleLinkedinUrlFamilyState(currentRowEntityId ?? ''),
);
const [internalValue, setInternalValue] = useState(linkedinUrl ?? '');
useEffect(() => {
setInternalValue(linkedinUrl ?? '');
}, [linkedinUrl]);
return (
<EditableCellURL
url={internalValue}
onChange={setInternalValue}
onSubmit={() =>
url={linkedinUrl ?? ''}
onSubmit={(newURL) =>
updatePerson({
variables: {
where: {
id: currentRowEntityId,
},
data: {
linkedinUrl: internalValue,
linkedinUrl: newURL,
},
},
})
}
onCancel={() => setInternalValue(linkedinUrl ?? '')}
/>
);
}

View File

@ -1,4 +1,3 @@
import { useEffect, useState } from 'react';
import { useRecoilValue } from 'recoil';
import { peoplePhoneFamilyState } from '@/people/states/peoplePhoneFamilyState';
@ -15,29 +14,21 @@ export function EditablePeoplePhoneCell() {
peoplePhoneFamilyState(currentRowEntityId ?? ''),
);
const [internalValue, setInternalValue] = useState(phone ?? '');
useEffect(() => {
setInternalValue(phone ?? '');
}, [phone]);
return (
<EditableCellPhone
value={internalValue}
onChange={setInternalValue}
onSubmit={() =>
value={phone?.toString() ?? ''}
onSubmit={(newPhone) =>
updatePerson({
variables: {
where: {
id: currentRowEntityId,
},
data: {
phone: internalValue,
phone: newPhone,
},
},
})
}
onCancel={() => setInternalValue(phone ?? '')}
/>
);
}

View File

@ -10,10 +10,8 @@ import { turnFilterIntoWhereClause } from '@/ui/filter-n-sort/utils/turnFilterIn
import { IconList } from '@/ui/icon';
import { useRecoilScopedValue } from '@/ui/recoil-scope/hooks/useRecoilScopedValue';
import { EntityTable } from '@/ui/table/components/EntityTable';
import { HooksEntityTable } from '@/ui/table/components/HooksEntityTable';
import { TableContext } from '@/ui/table/states/TableContext';
import { PersonOrderByWithRelationInput } from '~/generated/graphql';
import { peopleFilters } from '~/pages/people/people-filters';
import { availableSorts } from '~/pages/people/people-sorts';
export function PeopleTable() {
@ -33,10 +31,6 @@ export function PeopleTable() {
return (
<>
<PeopleEntityTableData orderBy={orderBy} whereFilters={whereFilters} />
<HooksEntityTable
numberOfColumns={peopleColumns.length}
availableFilters={peopleFilters}
/>
<EntityTable
columns={peopleColumns}
viewName="All People"