Feat/single entity select relation picker (#345)
* - Implemented recoil scoped state - Implemented SingleEntitySelect - Implemented keyboard shortcut up/down select * Added useRecoilScopedValue * Fix storybook * Fix storybook * Fix storybook * Fix storybook --------- Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
@ -1,10 +1,15 @@
|
||||
import { getOperationName } from '@apollo/client/utilities';
|
||||
import { expect } from '@storybook/jest';
|
||||
import type { Meta } from '@storybook/react';
|
||||
import { userEvent, within } from '@storybook/testing-library';
|
||||
import { graphql } from 'msw';
|
||||
|
||||
import { UPDATE_PERSON } from '@/people/services';
|
||||
import { SEARCH_COMPANY_QUERY } from '@/search/services/search';
|
||||
import { Company } from '~/generated/graphql';
|
||||
import { graphqlMocks } from '~/testing/graphqlMocks';
|
||||
import { fetchOneFromData } from '~/testing/mock-data';
|
||||
import { mockedCompaniesData } from '~/testing/mock-data/companies';
|
||||
import { mockedPeopleData } from '~/testing/mock-data/people';
|
||||
import { getRenderWrapperForPage } from '~/testing/renderWrappers';
|
||||
import { sleep } from '~/testing/sleep';
|
||||
@ -95,59 +100,121 @@ export const CheckCheckboxes: Story = {
|
||||
},
|
||||
};
|
||||
|
||||
const editRelationMocks = (
|
||||
initiallySelectedCompanyName: string,
|
||||
searchCompanyNames: Array<string>,
|
||||
updateSelectedCompany: Pick<Company, 'name' | 'domainName'>,
|
||||
) => [
|
||||
...graphqlMocks.filter((graphqlMock) => {
|
||||
if (
|
||||
typeof graphqlMock.info.operationName === 'string' &&
|
||||
[
|
||||
getOperationName(UPDATE_PERSON),
|
||||
getOperationName(SEARCH_COMPANY_QUERY),
|
||||
].includes(graphqlMock.info.operationName)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}),
|
||||
...[
|
||||
graphql.mutation(getOperationName(UPDATE_PERSON) ?? '', (req, res, ctx) => {
|
||||
return res(
|
||||
ctx.data({
|
||||
updateOnePerson: {
|
||||
...fetchOneFromData(mockedPeopleData, req.variables.id),
|
||||
...{
|
||||
company: {
|
||||
id: req.variables.companyId,
|
||||
name: updateSelectedCompany.name,
|
||||
domainName: updateSelectedCompany.domainName,
|
||||
__typename: 'Company',
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
);
|
||||
}),
|
||||
graphql.query(
|
||||
getOperationName(SEARCH_COMPANY_QUERY) ?? '',
|
||||
(req, res, ctx) => {
|
||||
if (!req.variables.where?.AND) {
|
||||
// Selected company case
|
||||
const searchResults = mockedCompaniesData.filter((company) =>
|
||||
[initiallySelectedCompanyName].includes(company.name),
|
||||
);
|
||||
return res(
|
||||
ctx.data({
|
||||
searchResults: searchResults,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
req.variables.where?.AND?.some(
|
||||
(where: { id?: { in: Array<string> } }) => where.id?.in,
|
||||
)
|
||||
) {
|
||||
// Selected company case
|
||||
const searchResults = mockedCompaniesData.filter((company) =>
|
||||
[initiallySelectedCompanyName].includes(company.name),
|
||||
);
|
||||
return res(
|
||||
ctx.data({
|
||||
searchResults: searchResults,
|
||||
}),
|
||||
);
|
||||
} else {
|
||||
// Search case
|
||||
|
||||
const searchResults = mockedCompaniesData.filter((company) =>
|
||||
searchCompanyNames.includes(company.name),
|
||||
);
|
||||
return res(
|
||||
ctx.data({
|
||||
searchResults: searchResults,
|
||||
}),
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
];
|
||||
|
||||
export const EditRelation: Story = {
|
||||
render: getRenderWrapperForPage(<People />, '/people'),
|
||||
play: async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
const secondRowCompanyCell = await canvas.findByText(
|
||||
const firstRowCompanyCell = await canvas.findByText(
|
||||
mockedPeopleData[1].company.name,
|
||||
);
|
||||
|
||||
await userEvent.click(secondRowCompanyCell);
|
||||
await userEvent.click(firstRowCompanyCell);
|
||||
|
||||
const relationInput = await canvas.findByPlaceholderText('Company');
|
||||
const relationInput = await canvas.findByPlaceholderText('Search');
|
||||
|
||||
await userEvent.type(relationInput, 'Air', {
|
||||
delay: 200,
|
||||
});
|
||||
|
||||
const airbnbChip = await canvas.findByText('Airbnb', {
|
||||
selector: 'div > span',
|
||||
selector: 'div',
|
||||
});
|
||||
|
||||
await userEvent.click(airbnbChip);
|
||||
|
||||
const newSecondRowCompanyCell = await canvas.findByText('Airbnb');
|
||||
const otherCell = await canvas.findByText('Janice Dane');
|
||||
await userEvent.click(otherCell);
|
||||
|
||||
await userEvent.click(newSecondRowCompanyCell);
|
||||
await canvas.findByText('Airbnb');
|
||||
},
|
||||
parameters: {
|
||||
actions: {},
|
||||
msw: [
|
||||
...graphqlMocks.filter((graphqlMock) => {
|
||||
return graphqlMock.info.operationName !== 'UpdatePeople';
|
||||
}),
|
||||
...[
|
||||
graphql.mutation('UpdatePeople', (req, res, ctx) => {
|
||||
return res(
|
||||
ctx.data({
|
||||
updateOnePerson: {
|
||||
...fetchOneFromData(mockedPeopleData, req.variables.id),
|
||||
...{
|
||||
company: {
|
||||
id: req.variables.companyId,
|
||||
name: 'Airbnb',
|
||||
domainName: 'airbnb.com',
|
||||
__typename: 'Company',
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
);
|
||||
}),
|
||||
],
|
||||
],
|
||||
msw: editRelationMocks('Qonto', ['Airbnb', 'Aircall'], {
|
||||
name: 'Airbnb',
|
||||
domainName: 'airbnb.com',
|
||||
}),
|
||||
},
|
||||
};
|
||||
|
||||
@ -157,51 +224,32 @@ export const SelectRelationWithKeys: Story = {
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
const thirdRowCompanyCell = await canvas.findByText(
|
||||
mockedPeopleData[2].company.name,
|
||||
mockedPeopleData[0].company.name,
|
||||
);
|
||||
|
||||
await userEvent.click(thirdRowCompanyCell);
|
||||
|
||||
const relationInput = await canvas.findByPlaceholderText('Company');
|
||||
const relationInput = await canvas.findByPlaceholderText('Search');
|
||||
|
||||
await userEvent.type(relationInput, 'Air', {
|
||||
delay: 200,
|
||||
});
|
||||
|
||||
await userEvent.type(relationInput, '{arrowdown}');
|
||||
await userEvent.type(relationInput, '{arrowdown}');
|
||||
await userEvent.type(relationInput, '{arrowup}');
|
||||
await userEvent.type(relationInput, '{arrowdown}');
|
||||
await userEvent.type(relationInput, '{arrowdown}');
|
||||
await userEvent.type(relationInput, '{enter}');
|
||||
sleep(25);
|
||||
|
||||
const newThirdRowCompanyCell = await canvas.findByText('Aircall');
|
||||
await userEvent.click(newThirdRowCompanyCell);
|
||||
const allAirbns = await canvas.findAllByText('Aircall');
|
||||
expect(allAirbns.length).toBe(1);
|
||||
},
|
||||
parameters: {
|
||||
actions: {},
|
||||
msw: [
|
||||
...graphqlMocks.filter((graphqlMock) => {
|
||||
return graphqlMock.info.operationName !== 'UpdatePeople';
|
||||
}),
|
||||
...[
|
||||
graphql.mutation('UpdatePeople', (req, res, ctx) => {
|
||||
return res(
|
||||
ctx.data({
|
||||
updateOnePerson: {
|
||||
...fetchOneFromData(mockedPeopleData, req.variables.id),
|
||||
...{
|
||||
company: {
|
||||
id: req.variables.companyId,
|
||||
name: 'Aircall',
|
||||
domainName: 'aircall.io',
|
||||
__typename: 'Company',
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
);
|
||||
}),
|
||||
],
|
||||
],
|
||||
msw: editRelationMocks('Qonto', ['Airbnb', 'Aircall'], {
|
||||
name: 'Aircall',
|
||||
domainName: 'aircall.io',
|
||||
}),
|
||||
},
|
||||
};
|
||||
|
||||
@ -7,6 +7,7 @@ import { EditableDate } from '@/ui/components/editable-cell/types/EditableDate';
|
||||
import { EditablePhone } from '@/ui/components/editable-cell/types/EditablePhone';
|
||||
import { EditableText } from '@/ui/components/editable-cell/types/EditableText';
|
||||
import { ColumnHead } from '@/ui/components/table/ColumnHead';
|
||||
import { RecoilScope } from '@/ui/hooks/RecoilScope';
|
||||
import {
|
||||
IconBuildingSkyscraper,
|
||||
IconCalendarEvent,
|
||||
@ -79,7 +80,11 @@ export const usePeopleColumns = () => {
|
||||
viewIcon={<IconBuildingSkyscraper size={16} />}
|
||||
/>
|
||||
),
|
||||
cell: (props) => <PeopleCompanyCell people={props.row.original} />,
|
||||
cell: (props) => (
|
||||
<RecoilScope>
|
||||
<PeopleCompanyCell people={props.row.original} />
|
||||
</RecoilScope>
|
||||
),
|
||||
size: 150,
|
||||
}),
|
||||
columnHelper.accessor('phone', {
|
||||
|
||||
Reference in New Issue
Block a user