feat: apply RecordDetailSection style on RecordDuplicatesSection and … (#4241)

feat: apply RecordDetailSection style on RecordDuplicatesSection and add stories

Closes #3963, Closes #4240
This commit is contained in:
Thaïs
2024-02-29 10:10:07 -03:00
committed by GitHub
parent 68a8502920
commit 6ad3880696
28 changed files with 395 additions and 240 deletions

View File

@ -3,6 +3,7 @@ import { useQuery } from '@apollo/client';
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
import { ObjectMetadataItemIdentifier } from '@/object-metadata/types/ObjectMetadataItemIdentifier';
import { getFindDuplicateRecordsQueryResponseField } from '@/object-record/hooks/useGenerateFindDuplicateRecordsQuery';
import { useMapConnectionToRecords } from '@/object-record/hooks/useMapConnectionToRecords';
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
import { ObjectRecordConnection } from '@/object-record/types/ObjectRecordConnection';
@ -29,6 +30,10 @@ export const useFindDuplicateRecords = <T extends ObjectRecord = ObjectRecord>({
const { enqueueSnackBar } = useSnackBar();
const queryResponseField = getFindDuplicateRecordsQueryResponseField(
objectMetadataItem.nameSingular,
);
const { data, loading, error } = useQuery<ObjectRecordQueryResult<T>>(
findDuplicateRecordsQuery,
{
@ -36,7 +41,7 @@ export const useFindDuplicateRecords = <T extends ObjectRecord = ObjectRecord>({
id: objectRecordId,
},
onCompleted: (data) => {
onCompleted?.(data[objectMetadataItem.nameSingular]);
onCompleted?.(data[queryResponseField]);
},
onError: (error) => {
logError(
@ -53,8 +58,7 @@ export const useFindDuplicateRecords = <T extends ObjectRecord = ObjectRecord>({
},
);
const objectRecordConnection =
data?.[`${objectMetadataItem.nameSingular}Duplicates`];
const objectRecordConnection = data?.[queryResponseField];
const mapConnectionToRecords = useMapConnectionToRecords();

View File

@ -4,6 +4,10 @@ import { useMapFieldMetadataToGraphQLQuery } from '@/object-metadata/hooks/useMa
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
import { capitalize } from '~/utils/string/capitalize';
export const getFindDuplicateRecordsQueryResponseField = (
objectNameSingular: string,
) => `${objectNameSingular}Duplicates`;
export const useGenerateFindDuplicateRecordsQuery = () => {
const mapFieldMetadataToGraphQLQuery = useMapFieldMetadataToGraphQLQuery();
@ -15,7 +19,9 @@ export const useGenerateFindDuplicateRecordsQuery = () => {
depth?: number;
}) => gql`
query FindDuplicate${capitalize(objectMetadataItem.nameSingular)}($id: ID) {
${objectMetadataItem.nameSingular}Duplicates(id: $id){
${getFindDuplicateRecordsQueryResponseField(
objectMetadataItem.nameSingular,
)}(id: $id) {
edges {
node {
id

View File

@ -18,7 +18,7 @@ const mockedPersonObjectMetadataItem = {
...mockedPeopleMetadata.node,
fields: mockedPeopleMetadata.node.fields.edges.map(({ node }) => node),
};
const mockedCompanyObjectMetadataItem = {
export const mockedCompanyObjectMetadataItem = {
...mockedCompaniesMetadata.node,
fields: mockedCompaniesMetadata.node.fields.edges.map(({ node }) => node),
};

View File

@ -1,13 +1,12 @@
import { useEffect } from 'react';
import { MemoryRouter } from 'react-router-dom';
import { Meta, StoryObj } from '@storybook/react';
import { useSetRecoilState } from 'recoil';
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
import { ChipFieldDisplay } from '@/object-record/record-field/meta-types/display/components/ChipFieldDisplay';
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
import { FieldContext } from '../../../../contexts/FieldContext';
import { MemoryRouterDecorator } from '~/testing/decorators/MemoryRouterDecorator';
const ChipFieldValueSetterEffect = () => {
const setEntityFields = useSetRecoilState(recordStoreFamilyState('123'));
@ -28,30 +27,29 @@ const ChipFieldValueSetterEffect = () => {
const meta: Meta = {
title: 'UI/Data/Field/Display/ChipFieldDisplay',
decorators: [
MemoryRouterDecorator,
(Story) => (
<MemoryRouter>
<FieldContext.Provider
value={{
entityId: '123',
basePathToShowPage: '/object-record/',
isLabelIdentifier: false,
fieldDefinition: {
fieldMetadataId: 'full name',
label: 'Henry Cavill',
type: 'FULL_NAME',
iconName: 'IconCalendarEvent',
metadata: {
fieldName: 'full name',
objectMetadataNameSingular: 'person',
},
<FieldContext.Provider
value={{
entityId: '123',
basePathToShowPage: '/object-record/',
isLabelIdentifier: false,
fieldDefinition: {
fieldMetadataId: 'full name',
label: 'Henry Cavill',
type: 'FULL_NAME',
iconName: 'IconCalendarEvent',
metadata: {
fieldName: 'full name',
objectMetadataNameSingular: 'person',
},
hotkeyScope: 'hotkey-scope',
}}
>
<ChipFieldValueSetterEffect />
<Story />
</FieldContext.Provider>
</MemoryRouter>
},
hotkeyScope: 'hotkey-scope',
}}
>
<ChipFieldValueSetterEffect />
<Story />
</FieldContext.Provider>
),
ComponentDecorator,
],

View File

@ -1,11 +1,11 @@
import { useEffect } from 'react';
import { MemoryRouter } from 'react-router-dom';
import { Meta, StoryObj } from '@storybook/react';
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
import { useEmailField } from '@/object-record/record-field/meta-types/hooks/useEmailField';
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
import { MemoryRouterDecorator } from '~/testing/decorators/MemoryRouterDecorator';
import { FieldContext } from '../../../../contexts/FieldContext';
import { useEmailField } from '../../../hooks/useEmailField';
import { EmailFieldDisplay } from '../EmailFieldDisplay';
const EmailFieldValueSetterEffect = ({ value }: { value: string }) => {
@ -21,6 +21,7 @@ const EmailFieldValueSetterEffect = ({ value }: { value: string }) => {
const meta: Meta = {
title: 'UI/Data/Field/Display/EmailFieldDisplay',
decorators: [
MemoryRouterDecorator,
(Story, { args }) => (
<FieldContext.Provider
value={{
@ -39,10 +40,8 @@ const meta: Meta = {
hotkeyScope: 'hotkey-scope',
}}
>
<MemoryRouter>
<EmailFieldValueSetterEffect value={args.value} />
<Story />
</MemoryRouter>
<EmailFieldValueSetterEffect value={args.value} />
<Story />
</FieldContext.Provider>
),
ComponentDecorator,

View File

@ -1,11 +1,11 @@
import { useEffect } from 'react';
import { MemoryRouter } from 'react-router-dom';
import { Meta, StoryObj } from '@storybook/react';
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
import { usePhoneField } from '@/object-record/record-field/meta-types/hooks/usePhoneField';
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
import { MemoryRouterDecorator } from '~/testing/decorators/MemoryRouterDecorator';
import { FieldContext } from '../../../../contexts/FieldContext';
import { usePhoneField } from '../../../hooks/usePhoneField';
import { PhoneFieldDisplay } from '../PhoneFieldDisplay';
const PhoneFieldValueSetterEffect = ({ value }: { value: string }) => {
@ -21,6 +21,7 @@ const PhoneFieldValueSetterEffect = ({ value }: { value: string }) => {
const meta: Meta = {
title: 'UI/Data/Field/Display/PhoneFieldDisplay',
decorators: [
MemoryRouterDecorator,
(Story, { args }) => (
<FieldContext.Provider
value={{
@ -41,10 +42,8 @@ const meta: Meta = {
useUpdateRecord: () => [() => undefined, {}],
}}
>
<MemoryRouter>
<PhoneFieldValueSetterEffect value={args.value} />
<Story />
</MemoryRouter>
<PhoneFieldValueSetterEffect value={args.value} />
<Story />
</FieldContext.Provider>
),
ComponentDecorator,

View File

@ -13,8 +13,8 @@ import {
import { RecordInlineCell } from '@/object-record/record-inline-cell/components/RecordInlineCell';
import { PropertyBox } from '@/object-record/record-inline-cell/property-box/components/PropertyBox';
import { InlineCellHotkeyScope } from '@/object-record/record-inline-cell/types/InlineCellHotkeyScope';
import { RecordDuplicatesFieldCardSection } from '@/object-record/record-show/record-detail-section/components/RecordDuplicatesFieldCardSection';
import { RecordRelationFieldCardSection } from '@/object-record/record-show/record-detail-section/components/RecordRelationFieldCardSection';
import { RecordDetailDuplicatesSection } from '@/object-record/record-show/record-detail-section/components/RecordDetailDuplicatesSection';
import { RecordDetailRelationSection } from '@/object-record/record-show/record-detail-section/components/RecordDetailRelationSection';
import { recordLoadingFamilyState } from '@/object-record/record-store/states/recordLoadingFamilyState';
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
import { recordStoreIdentifierFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreIdentifierSelector';
@ -194,7 +194,7 @@ export const RecordShowContainer = ({
</FieldContext.Provider>
))}
</PropertyBox>
<RecordDuplicatesFieldCardSection
<RecordDetailDuplicatesSection
objectRecordId={objectRecordId}
objectNameSingular={objectNameSingular}
/>
@ -229,7 +229,7 @@ export const RecordShowContainer = ({
hotkeyScope: InlineCellHotkeyScope.InlineCell,
}}
>
<RecordRelationFieldCardSection />
<RecordDetailRelationSection />
</FieldContext.Provider>
))}
</>

View File

@ -0,0 +1,37 @@
import { RecordChip } from '@/object-record/components/RecordChip';
import { useFindDuplicateRecords } from '@/object-record/hooks/useFindDuplicateRecords';
import { RecordDetailRecordsList } from '@/object-record/record-show/record-detail-section/components/RecordDetailRecordsList';
import { RecordDetailRecordsListItem } from '@/object-record/record-show/record-detail-section/components/RecordDetailRecordsListItem';
import { RecordDetailSection } from '@/object-record/record-show/record-detail-section/components/RecordDetailSection';
import { RecordDetailSectionHeader } from '@/object-record/record-show/record-detail-section/components/RecordDetailSectionHeader';
export const RecordDetailDuplicatesSection = ({
objectRecordId,
objectNameSingular,
}: {
objectRecordId: string;
objectNameSingular: string;
}) => {
const { records: duplicateRecords } = useFindDuplicateRecords({
objectRecordId,
objectNameSingular,
});
if (!duplicateRecords.length) return null;
return (
<RecordDetailSection>
<RecordDetailSectionHeader title="Duplicates" />
<RecordDetailRecordsList>
{duplicateRecords.slice(0, 5).map((duplicateRecord) => (
<RecordDetailRecordsListItem key={duplicateRecord.id}>
<RecordChip
record={duplicateRecord}
objectNameSingular={objectNameSingular}
/>
</RecordDetailRecordsListItem>
))}
</RecordDetailRecordsList>
</RecordDetailSection>
);
};

View File

@ -0,0 +1,8 @@
import styled from '@emotion/styled';
const StyledRecordsList = styled.div`
color: ${({ theme }) => theme.font.color.secondary};
overflow: hidden;
`;
export { StyledRecordsList as RecordDetailRecordsList };

View File

@ -0,0 +1,11 @@
import styled from '@emotion/styled';
const StyledListItem = styled.div`
align-items: center;
justify-content: space-between;
gap: ${({ theme }) => theme.spacing(1)};
display: flex;
height: ${({ theme }) => theme.spacing(10)};
`;
export { StyledListItem as RecordDetailRecordsListItem };

View File

@ -0,0 +1,20 @@
import { RecordDetailRecordsList } from '@/object-record/record-show/record-detail-section/components/RecordDetailRecordsList';
import { RecordDetailRelationRecordsListItem } from '@/object-record/record-show/record-detail-section/components/RecordDetailRelationRecordsListItem';
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
type RecordDetailRelationRecordsListProps = {
relationRecords: ObjectRecord[];
};
export const RecordDetailRelationRecordsList = ({
relationRecords,
}: RecordDetailRelationRecordsListProps) => (
<RecordDetailRecordsList>
{relationRecords.slice(0, 5).map((relationRecord) => (
<RecordDetailRelationRecordsListItem
key={relationRecord.id}
relationRecord={relationRecord}
/>
))}
</RecordDetailRecordsList>
);

View File

@ -0,0 +1,35 @@
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
import { useIcons } from '@/ui/display/icon/hooks/useIcons';
type RecordDetailRelationRecordsListEmptyStateProps = {
relationObjectMetadataItem: ObjectMetadataItem;
};
const StyledRelationRecordsListEmptyState = styled.div`
color: ${({ theme }) => theme.font.color.light};
align-items: center;
justify-content: center;
gap: ${({ theme }) => theme.spacing(2)};
display: flex;
height: ${({ theme }) => theme.spacing(10)};
text-transform: capitalize;
`;
export const RecordDetailRelationRecordsListEmptyState = ({
relationObjectMetadataItem,
}: RecordDetailRelationRecordsListEmptyStateProps) => {
const theme = useTheme();
const { getIcon } = useIcons();
const Icon = getIcon(relationObjectMetadataItem.icon);
return (
<StyledRelationRecordsListEmptyState>
<Icon size={theme.icon.size.sm} />
<div>No {relationObjectMetadataItem.labelSingular}</div>
</StyledRelationRecordsListEmptyState>
);
};

View File

@ -11,35 +11,26 @@ import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord';
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
import { usePersistField } from '@/object-record/record-field/hooks/usePersistField';
import { FieldRelationMetadata } from '@/object-record/record-field/types/FieldMetadata';
import { RecordDetailRecordsListItem } from '@/object-record/record-show/record-detail-section/components/RecordDetailRecordsListItem';
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
import { IconDotsVertical, IconTrash, IconUnlink } from '@/ui/display/icon';
import { CardContent } from '@/ui/layout/card/components/CardContent';
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
import { DropdownScope } from '@/ui/layout/dropdown/scopes/DropdownScope';
const StyledCardContent = styled(CardContent)<{
const StyledListItem = styled(RecordDetailRecordsListItem)<{
isDropdownOpen?: boolean;
}>`
align-items: center;
justify-content: space-between;
gap: ${({ theme }) => theme.spacing(1)};
display: flex;
height: ${({ theme }) => theme.spacing(10)};
padding: 0;
border: 0;
${({ isDropdownOpen, theme }) =>
isDropdownOpen
? ''
: css`
.displayOnHover {
opacity: 0;
pointer-events: none;
transition: opacity ${theme.animation.duration.instant}s ease;
}
`}
!isDropdownOpen &&
css`
.displayOnHover {
opacity: 0;
pointer-events: none;
transition: opacity ${theme.animation.duration.instant}s ease;
}
`}
&:hover {
.displayOnHover {
@ -49,15 +40,13 @@ const StyledCardContent = styled(CardContent)<{
}
`;
type RecordRelationFieldCardContentProps = {
divider?: boolean;
type RecordDetailRelationRecordsListItemProps = {
relationRecord: ObjectRecord;
};
export const RecordRelationFieldCardContent = ({
divider,
export const RecordDetailRelationRecordsListItem = ({
relationRecord,
}: RecordRelationFieldCardContentProps) => {
}: RecordDetailRelationRecordsListItemProps) => {
const { fieldDefinition } = useContext(FieldContext);
const {
@ -124,7 +113,7 @@ export const RecordRelationFieldCardContent = ({
CoreObjectNameSingular.WorkspaceMember;
return (
<StyledCardContent isDropdownOpen={isDropdownOpen} divider={divider}>
<StyledListItem isDropdownOpen={isDropdownOpen}>
<RecordChip
record={relationRecord}
objectNameSingular={relationObjectMetadataItem.nameSingular}
@ -165,6 +154,6 @@ export const RecordRelationFieldCardContent = ({
/>
</DropdownScope>
)}
</StyledCardContent>
</StyledListItem>
);
};

View File

@ -1,5 +1,4 @@
import { useCallback, useContext } from 'react';
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import qs from 'qs';
import { useRecoilValue } from 'recoil';
@ -9,8 +8,10 @@ import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord';
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
import { usePersistField } from '@/object-record/record-field/hooks/usePersistField';
import { FieldRelationMetadata } from '@/object-record/record-field/types/FieldMetadata';
import { RecordDetailRelationRecordsList } from '@/object-record/record-show/record-detail-section/components/RecordDetailRelationRecordsList';
import { RecordDetailRelationRecordsListEmptyState } from '@/object-record/record-show/record-detail-section/components/RecordDetailRelationRecordsListEmptyState';
import { RecordDetailSection } from '@/object-record/record-show/record-detail-section/components/RecordDetailSection';
import { RecordDetailSectionHeader } from '@/object-record/record-show/record-detail-section/components/RecordDetailSectionHeader';
import { RecordRelationFieldCardContent } from '@/object-record/record-show/record-detail-section/components/RecordRelationFieldCardContent';
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector';
import { SingleEntitySelectMenuItemsWithSearch } from '@/object-record/relation-picker/components/SingleEntitySelectMenuItemsWithSearch';
@ -19,12 +20,10 @@ import { RelationPickerScope } from '@/object-record/relation-picker/scopes/Rela
import { EntityForSelect } from '@/object-record/relation-picker/types/EntityForSelect';
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
import { IconForbid, IconPencil, IconPlus } from '@/ui/display/icon';
import { useIcons } from '@/ui/display/icon/hooks/useIcons';
import { LightIconButton } from '@/ui/input/button/components/LightIconButton';
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
import { DropdownScope } from '@/ui/layout/dropdown/scopes/DropdownScope';
import { Section } from '@/ui/layout/section/components/Section';
import { FilterQueryParams } from '@/views/hooks/internal/useFiltersFromQueryParams';
import { ViewFilterOperand } from '@/views/types/ViewFilterOperand';
@ -32,30 +31,7 @@ const StyledAddDropdown = styled(Dropdown)`
margin-left: auto;
`;
const StyledCardNoContent = styled.div`
color: ${({ theme }) => theme.font.color.light};
align-items: center;
justify-content: center;
gap: ${({ theme }) => theme.spacing(2)};
display: flex;
height: ${({ theme }) => theme.spacing(10)};
text-transform: capitalize;
`;
const StyledCard = styled.div`
color: ${({ theme }) => theme.font.color.secondary};
overflow: hidden;
`;
const StyledSection = styled(Section)`
padding: ${({ theme }) => theme.spacing(3)};
border-top: 1px solid ${({ theme }) => theme.border.color.light};
width: unset;
`;
export const RecordRelationFieldCardSection = () => {
const theme = useTheme();
export const RecordDetailRelationSection = () => {
const { entityId, fieldDefinition } = useContext(FieldContext);
const {
fieldName,
@ -65,12 +41,10 @@ export const RecordRelationFieldCardSection = () => {
} = fieldDefinition.metadata as FieldRelationMetadata;
const record = useRecoilValue(recordStoreFamilyState(entityId));
const {
labelIdentifierFieldMetadata: relationLabelIdentifierFieldMetadata,
objectMetadataItem: relationObjectMetadataItem,
} = useObjectMetadataItem({
objectNameSingular: relationObjectMetadataNameSingular,
});
const { objectMetadataItem: relationObjectMetadataItem } =
useObjectMetadataItem({
objectNameSingular: relationObjectMetadataNameSingular,
});
const relationFieldMetadataItem = relationObjectMetadataItem.fields.find(
({ id }) => id === relationFieldMetadataId,
@ -137,11 +111,8 @@ export const RecordRelationFieldCardSection = () => {
relationObjectMetadataItem.namePlural
}?${qs.stringify(filterQueryParams)}`;
const { getIcon } = useIcons();
const Icon = getIcon(relationObjectMetadataItem.icon);
return (
<StyledSection>
<RecordDetailSection>
<RecordDetailSectionHeader
title={fieldDefinition.label}
link={
@ -186,23 +157,13 @@ export const RecordRelationFieldCardSection = () => {
</DropdownScope>
}
/>
{relationRecords.length === 0 && (
<StyledCardNoContent>
<Icon size={theme.icon.size.sm} />
<div>No {relationObjectMetadataItem.labelSingular}</div>
</StyledCardNoContent>
{relationRecords.length ? (
<RecordDetailRelationRecordsList relationRecords={relationRecords} />
) : (
<RecordDetailRelationRecordsListEmptyState
relationObjectMetadataItem={relationObjectMetadataItem}
/>
)}
{!!relationRecords.length && (
<StyledCard>
{relationRecords.slice(0, 5).map((relationRecord, index) => (
<RecordRelationFieldCardContent
key={`${relationRecord.id}${relationLabelIdentifierFieldMetadata?.id}`}
divider={index < relationRecords.length - 1}
relationRecord={relationRecord}
/>
))}
</StyledCard>
)}
</StyledSection>
</RecordDetailSection>
);
};

View File

@ -0,0 +1,11 @@
import styled from '@emotion/styled';
import { Section } from '@/ui/layout/section/components/Section';
const StyledRecordDetailSection = styled(Section)`
border-top: 1px solid ${({ theme }) => theme.border.color.light};
padding: ${({ theme }) => theme.spacing(3)};
width: auto;
`;
export { StyledRecordDetailSection as RecordDetailSection };

View File

@ -1,51 +0,0 @@
import styled from '@emotion/styled';
import { RecordChip } from '@/object-record/components/RecordChip';
import { useFindDuplicateRecords } from '@/object-record/hooks/useFindDuplicateRecords';
import { RecordDetailSectionHeader } from '@/object-record/record-show/record-detail-section/components/RecordDetailSectionHeader';
import { Card } from '@/ui/layout/card/components/Card';
import { CardContent } from '@/ui/layout/card/components/CardContent';
import { Section } from '@/ui/layout/section/components/Section';
const StyledCardContent = styled(CardContent)`
align-items: center;
display: flex;
gap: ${({ theme }) => theme.spacing(4)};
padding: ${({ theme }) => theme.spacing(3)};
`;
export const RecordDuplicatesFieldCardSection = ({
objectRecordId,
objectNameSingular,
}: {
objectRecordId: string;
objectNameSingular: string;
}) => {
const { records: duplicateRecords } = useFindDuplicateRecords({
objectRecordId,
objectNameSingular,
});
if (duplicateRecords.length === 0) {
return null;
}
return (
<Section>
<RecordDetailSectionHeader title="Duplicates" />
<Card>
{duplicateRecords.slice(0, 5).map((duplicateRecord, index) => (
<StyledCardContent
key={`${objectNameSingular}${duplicateRecord.id}`}
divider={index < duplicateRecords.length - 1}
>
<RecordChip
record={duplicateRecord}
objectNameSingular={objectNameSingular}
/>
</StyledCardContent>
))}
</Card>
</Section>
);
};

View File

@ -0,0 +1,35 @@
import { Meta, StoryObj } from '@storybook/react';
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
import { MemoryRouterDecorator } from '~/testing/decorators/MemoryRouterDecorator';
import { ObjectMetadataItemsDecorator } from '~/testing/decorators/ObjectMetadataItemsDecorator';
import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator';
import { graphqlMocks } from '~/testing/graphqlMocks';
import { mockedCompaniesData } from '~/testing/mock-data/companies';
import { RecordDetailDuplicatesSection } from '../RecordDetailDuplicatesSection';
const meta: Meta<typeof RecordDetailDuplicatesSection> = {
title:
'Modules/ObjectRecord/RecordShow/RecordDetailSection/RecordDetailDuplicatesSection',
component: RecordDetailDuplicatesSection,
decorators: [
ComponentDecorator,
ObjectMetadataItemsDecorator,
SnackBarDecorator,
MemoryRouterDecorator,
],
args: {
objectRecordId: mockedCompaniesData[0].id,
objectNameSingular: CoreObjectNameSingular.Company,
},
parameters: {
msw: graphqlMocks,
},
};
export default meta;
type Story = StoryObj<typeof RecordDetailDuplicatesSection>;
export const Default: Story = {};

View File

@ -0,0 +1,67 @@
import { Meta, StoryObj } from '@storybook/react';
import { formatFieldMetadataItemAsFieldDefinition } from '@/object-metadata/utils/formatFieldMetadataItemAsFieldDefinition';
import { mockedCompanyObjectMetadataItem } from '@/object-record/record-field/__mocks__/fieldDefinitions';
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
import { MemoryRouterDecorator } from '~/testing/decorators/MemoryRouterDecorator';
import { ObjectMetadataItemsDecorator } from '~/testing/decorators/ObjectMetadataItemsDecorator';
import { RecordStoreDecorator } from '~/testing/decorators/RecordStoreDecorator';
import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator';
import { graphqlMocks } from '~/testing/graphqlMocks';
import { mockedCompaniesData } from '~/testing/mock-data/companies';
import { mockedPeopleData } from '~/testing/mock-data/people';
import { RecordDetailRelationSection } from '../RecordDetailRelationSection';
const meta: Meta<typeof RecordDetailRelationSection> = {
title:
'Modules/ObjectRecord/RecordShow/RecordDetailSection/RecordDetailRelationSection',
component: RecordDetailRelationSection,
decorators: [
(Story) => (
<FieldContext.Provider
value={{
entityId: mockedCompaniesData[0].id,
basePathToShowPage: '/object-record/',
isLabelIdentifier: false,
fieldDefinition: formatFieldMetadataItemAsFieldDefinition({
field: mockedCompanyObjectMetadataItem.fields.find(
({ name }) => name === 'people',
)!,
objectMetadataItem: mockedCompanyObjectMetadataItem,
}),
hotkeyScope: 'hotkey-scope',
}}
>
<Story />
</FieldContext.Provider>
),
ComponentDecorator,
ObjectMetadataItemsDecorator,
SnackBarDecorator,
MemoryRouterDecorator,
],
parameters: {
msw: graphqlMocks,
records: mockedCompaniesData,
},
};
export default meta;
type Story = StoryObj<typeof RecordDetailRelationSection>;
export const EmptyState: Story = {};
export const WithRecords: Story = {
decorators: [RecordStoreDecorator],
parameters: {
records: [
{
...mockedCompaniesData[0],
people: { edges: mockedPeopleData.map((person) => ({ node: person })) },
},
...mockedPeopleData,
],
},
};