Add optimistic rendering for table relations (#1296)

* Add optimistic rendering for table relations

* fix pr

* fix pr

* fix pr

* Fix PR

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
Emilien Chauvet
2023-08-24 17:29:26 +02:00
committed by GitHub
parent 00f1d2b739
commit 615018654a
4 changed files with 74 additions and 21 deletions

View File

@ -12,12 +12,16 @@ import { useInsertOneCompanyMutation } from '~/generated/graphql';
export type OwnProps = { export type OwnProps = {
companyId: string | null; companyId: string | null;
onSubmit: (newCompany: EntityForSelect | null) => void; onSubmit: (newCompany: CompanyPickerSelectedCompany | null) => void;
onCancel?: () => void; onCancel?: () => void;
createModeEnabled?: boolean; createModeEnabled?: boolean;
width?: number; width?: number;
}; };
export type CompanyPickerSelectedCompany = EntityForSelect & {
domainName: string;
};
export function CompanyPickerCell({ export function CompanyPickerCell({
companyId, companyId,
onSubmit, onSubmit,
@ -42,10 +46,10 @@ export function CompanyPickerCell({
selectedIds: [companyId ?? ''], selectedIds: [companyId ?? ''],
}); });
async function handleEntitySelected( async function handleCompanySelected(
entity: EntityForSelect | null | undefined, company: CompanyPickerSelectedCompany | null | undefined,
) { ) {
onSubmit(entity ?? null); onSubmit(company ?? null);
} }
function handleStartCreation() { function handleStartCreation() {
@ -69,6 +73,7 @@ export function CompanyPickerCell({
id: companyCreated.id, id: companyCreated.id,
name: companyCreated.name, name: companyCreated.name,
entityType: Entity.Company, entityType: Entity.Company,
domainName: companyCreated.domainName,
}); });
setIsCreating(false); setIsCreating(false);
} }
@ -86,7 +91,7 @@ export function CompanyPickerCell({
width={width} width={width}
onCreate={createModeEnabled ? handleStartCreation : undefined} onCreate={createModeEnabled ? handleStartCreation : undefined}
onCancel={onCancel} onCancel={onCancel}
onEntitySelected={handleEntitySelected} onEntitySelected={handleCompanySelected}
entities={{ entities={{
entitiesToSelect: companies.entitiesToSelect, entitiesToSelect: companies.entitiesToSelect,
selectedEntity: companies.selectedEntities[0], selectedEntity: companies.selectedEntities[0],

View File

@ -1,5 +1,4 @@
import { ActivityTargetableEntityType } from '@/activities/types/ActivityTargetableEntity'; import { ActivityTargetableEntityType } from '@/activities/types/ActivityTargetableEntity';
import { ActivityTargetableEntityForSelect } from '@/activities/types/ActivityTargetableEntityForSelect';
import { useFilteredSearchEntityQuery } from '@/search/hooks/useFilteredSearchEntityQuery'; import { useFilteredSearchEntityQuery } from '@/search/hooks/useFilteredSearchEntityQuery';
import { useSearchCompanyQuery } from '~/generated/graphql'; import { useSearchCompanyQuery } from '~/generated/graphql';
import { getLogoUrlFromDomainName } from '~/utils'; import { getLogoUrlFromDomainName } from '~/utils';
@ -18,14 +17,14 @@ export function useFilteredSearchCompanyQuery({
searchOnFields: ['name'], searchOnFields: ['name'],
orderByField: 'name', orderByField: 'name',
selectedIds: selectedIds, selectedIds: selectedIds,
mappingFunction: (company) => mappingFunction: (company) => ({
({ id: company.id,
id: company.id, entityType: ActivityTargetableEntityType.Company,
entityType: ActivityTargetableEntityType.Company, name: company.name,
name: company.name, avatarUrl: getLogoUrlFromDomainName(company.domainName),
avatarUrl: getLogoUrlFromDomainName(company.domainName), domainName: company.domainName,
avatarType: 'squared', avatarType: 'squared',
} as ActivityTargetableEntityForSelect), }),
searchFilter, searchFilter,
limit, limit,
}); });

View File

@ -1,6 +1,9 @@
import { useRecoilState } from 'recoil'; import { useRecoilState } from 'recoil';
import { CompanyPickerCell } from '@/companies/components/CompanyPickerCell'; import {
CompanyPickerCell,
CompanyPickerSelectedCompany,
} from '@/companies/components/CompanyPickerCell';
import { import {
ViewFieldDefinition, ViewFieldDefinition,
ViewFieldRelationMetadata, ViewFieldRelationMetadata,
@ -22,21 +25,67 @@ export function GenericEditableRelationCellEditMode({ viewField }: OwnProps) {
const { closeEditableCell } = useEditableCell(); const { closeEditableCell } = useEditableCell();
const [fieldValueEntity] = useRecoilState<any | null>( const [fieldValueEntity, setFieldValueEntity] = useRecoilState<any | null>(
tableEntityFieldFamilySelector({ tableEntityFieldFamilySelector({
entityId: currentRowEntityId ?? '', entityId: currentRowEntityId ?? '',
fieldName: viewField.metadata.fieldName, fieldName: viewField.metadata.fieldName,
}), }),
); );
const updateEntityField = useUpdateEntityField(); const updateEntityField = useUpdateEntityField();
function handleEntitySubmit(newFieldEntity: EntityForSelect | null) { function updateCachedPersonField(newFieldEntity: EntityForSelect | null) {
if (newFieldEntity === null) {
return;
}
setFieldValueEntity({
avatarUrl: newFieldEntity?.avatarUrl ?? '',
entityType: Entity.Company,
id: newFieldEntity?.id ?? '',
displayName: newFieldEntity?.name ?? '',
});
}
function updateCachedCompanyField(
newFieldEntity: CompanyPickerSelectedCompany | null,
) {
if (newFieldEntity === null) {
return;
}
setFieldValueEntity({
id: newFieldEntity?.id ?? '',
name: newFieldEntity?.name ?? '',
domainName: newFieldEntity?.domainName ?? '',
});
}
function handleCompanySubmit(
newFieldEntity: CompanyPickerSelectedCompany | null,
) {
if (
newFieldEntity &&
newFieldEntity?.id !== fieldValueEntity?.id &&
currentRowEntityId &&
updateEntityField
) {
updateCachedCompanyField(newFieldEntity);
updateEntityField<ViewFieldRelationMetadata, EntityForSelect>(
currentRowEntityId,
viewField,
newFieldEntity,
);
}
closeEditableCell();
}
function handlePersonSubmit(newFieldEntity: EntityForSelect | null) {
if ( if (
newFieldEntity?.id !== fieldValueEntity?.id && newFieldEntity?.id !== fieldValueEntity?.id &&
currentRowEntityId && currentRowEntityId &&
updateEntityField updateEntityField
) { ) {
updateCachedPersonField(newFieldEntity);
updateEntityField(currentRowEntityId, viewField, newFieldEntity); updateEntityField(currentRowEntityId, viewField, newFieldEntity);
} }
@ -52,7 +101,7 @@ export function GenericEditableRelationCellEditMode({ viewField }: OwnProps) {
return ( return (
<CompanyPickerCell <CompanyPickerCell
companyId={fieldValueEntity?.id ?? null} companyId={fieldValueEntity?.id ?? null}
onSubmit={handleEntitySubmit} onSubmit={handleCompanySubmit}
onCancel={handleCancel} onCancel={handleCancel}
width={viewField.columnSize} width={viewField.columnSize}
createModeEnabled createModeEnabled
@ -63,7 +112,7 @@ export function GenericEditableRelationCellEditMode({ viewField }: OwnProps) {
return ( return (
<UserPicker <UserPicker
userId={fieldValueEntity?.id ?? null} userId={fieldValueEntity?.id ?? null}
onSubmit={handleEntitySubmit} onSubmit={handlePersonSubmit}
onCancel={handleCancel} onCancel={handleCancel}
width={viewField.columnSize} width={viewField.columnSize}
/> />

View File

@ -46,7 +46,7 @@ import { EntityUpdateMutationContext } from '../contexts/EntityUpdateMutationHoo
export function useUpdateEntityField() { export function useUpdateEntityField() {
const updateEntity = useContext(EntityUpdateMutationContext); const updateEntity = useContext(EntityUpdateMutationContext);
return function updatePeopleField< return function updateEntityField<
MetadataType extends ViewFieldMetadata, MetadataType extends ViewFieldMetadata,
ValueType extends MetadataType extends ViewFieldDoubleTextMetadata ValueType extends MetadataType extends ViewFieldDoubleTextMetadata
? ViewFieldDoubleTextValue ? ViewFieldDoubleTextValue