diff --git a/package.json b/package.json index 90a056159b..ac7ff68ae5 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,8 @@ "@hello-pangea/dnd": "^16.2.0", "@hookform/resolvers": "^3.1.1", "@jsdevtools/rehype-toc": "^3.0.2", + "@linaria/core": "^6.2.0", + "@linaria/react": "^6.2.1", "@mdx-js/react": "^3.0.0", "@nestjs/apollo": "^11.0.5", "@nestjs/axios": "^3.0.1", @@ -61,6 +63,7 @@ "@types/lodash.pick": "^4.3.7", "@types/nodemailer": "^6.4.14", "@types/passport-microsoft": "^1.0.3", + "@wyw-in-js/vite": "^0.5.3", "add": "^2.0.6", "addressparser": "^1.0.1", "afterframe": "^1.0.2", @@ -192,6 +195,7 @@ "devDependencies": { "@babel/core": "^7.14.5", "@babel/preset-react": "^7.14.5", + "@babel/preset-typescript": "^7.24.6", "@crxjs/vite-plugin": "^1.0.14", "@docusaurus/module-type-aliases": "^3.1.0", "@docusaurus/tsconfig": "3.1.0", diff --git a/packages/twenty-front/nyc.config.cjs b/packages/twenty-front/nyc.config.cjs index 6155752651..3fbf2dfd62 100644 --- a/packages/twenty-front/nyc.config.cjs +++ b/packages/twenty-front/nyc.config.cjs @@ -8,7 +8,7 @@ const globalCoverage = { const modulesCoverage = { branches: 25, - statements: 50, + statements: 49, lines: 50, functions: 40, include: ['src/modules/**/*'], diff --git a/packages/twenty-front/src/modules/companies/types/Company.ts b/packages/twenty-front/src/modules/companies/types/Company.ts index f6fa70de63..43f2cfbc1a 100644 --- a/packages/twenty-front/src/modules/companies/types/Company.ts +++ b/packages/twenty-front/src/modules/companies/types/Company.ts @@ -2,15 +2,20 @@ export type Company = { __typename: 'Company'; id: string; createdAt: string; - updatedAt: string; - deletedAt: string | null; + updatedAt?: string; + deletedAt?: string | null; name: string; domainName: string; address: string; - accountOwnerId: string | null; - linkedinLink: { url: string; label: string }; - xLink: { url: string; label: string }; - annualRecurringRevenue: { amountMicros: number | null; currencyCode: string }; + accountOwnerId?: string | null; + position?: number; + linkedinLink: { __typename?: 'Link'; url: string; label: string }; + xLink?: { __typename?: 'Link'; url: string; label: string }; + annualRecurringRevenue: { + __typename?: 'Currency'; + amountMicros: number | null; + currencyCode: string; + }; employees: number | null; - idealCustomerProfile: boolean; + idealCustomerProfile?: boolean; }; diff --git a/packages/twenty-front/src/modules/object-metadata/components/ObjectMetadataItemsProvider.tsx b/packages/twenty-front/src/modules/object-metadata/components/ObjectMetadataItemsProvider.tsx index b374d13e1d..8071b00b65 100644 --- a/packages/twenty-front/src/modules/object-metadata/components/ObjectMetadataItemsProvider.tsx +++ b/packages/twenty-front/src/modules/object-metadata/components/ObjectMetadataItemsProvider.tsx @@ -1,9 +1,11 @@ -import React from 'react'; +import React, { useMemo } from 'react'; import { useRecoilValue } from 'recoil'; import { ObjectMetadataItemsLoadEffect } from '@/object-metadata/components/ObjectMetadataItemsLoadEffect'; +import { PreComputedChipGeneratorsContext } from '@/object-metadata/context/PreComputedChipGeneratorsContext'; import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; import { RelationPickerScope } from '@/object-record/relation-picker/scopes/RelationPickerScope'; +import { getRecordChipGeneratorPerObjectPerField } from '@/object-record/utils/getRecordChipGeneratorPerObjectPerField'; import { UserOrMetadataLoader } from '~/loading/components/UserOrMetadataLoader'; export const ObjectMetadataItemsProvider = ({ @@ -13,13 +15,23 @@ export const ObjectMetadataItemsProvider = ({ const shouldDisplayChildren = objectMetadataItems.length > 0; + const chipGeneratorPerObjectPerField = useMemo(() => { + return getRecordChipGeneratorPerObjectPerField(objectMetadataItems); + }, [objectMetadataItems]); + return ( <> {shouldDisplayChildren ? ( - - {children} - + + + {children} + + ) : ( )} diff --git a/packages/twenty-front/src/modules/object-metadata/context/PreComputedChipGeneratorsContext.ts b/packages/twenty-front/src/modules/object-metadata/context/PreComputedChipGeneratorsContext.ts new file mode 100644 index 0000000000..fcb5b7d46b --- /dev/null +++ b/packages/twenty-front/src/modules/object-metadata/context/PreComputedChipGeneratorsContext.ts @@ -0,0 +1,18 @@ +import { createContext } from 'react'; + +import { RecordChipData } from '@/object-record/record-field/types/RecordChipData'; +import { ObjectRecord } from '@/object-record/types/ObjectRecord'; + +export type ChipGeneratorPerObjectPerField = Record< + string, + Record RecordChipData> +>; + +export type PreComputedChipGeneratorsContextProps = { + chipGeneratorPerObjectPerField: ChipGeneratorPerObjectPerField; +}; + +export const PreComputedChipGeneratorsContext = + createContext( + {} as PreComputedChipGeneratorsContextProps, + ); diff --git a/packages/twenty-front/src/modules/object-record/record-field/components/FieldDisplay.tsx b/packages/twenty-front/src/modules/object-record/record-field/components/FieldDisplay.tsx index 454cdb949e..31a7692f21 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/components/FieldDisplay.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/components/FieldDisplay.tsx @@ -5,6 +5,7 @@ import { LinksFieldDisplay } from '@/object-record/record-field/meta-types/displ import { isFieldBoolean } from '@/object-record/record-field/types/guards/isFieldBoolean'; import { isFieldDisplayedAsPhone } from '@/object-record/record-field/types/guards/isFieldDisplayedAsPhone'; import { isFieldLinks } from '@/object-record/record-field/types/guards/isFieldLinks'; +import { isFieldChipDisplay } from '@/object-record/utils/getRecordChipGeneratorPerObjectPerField'; import { FieldContext } from '../contexts/FieldContext'; import { AddressFieldDisplay } from '../meta-types/display/components/AddressFieldDisplay'; @@ -42,11 +43,7 @@ import { isFieldUuid } from '../types/guards/isFieldUuid'; export const FieldDisplay = () => { const { fieldDefinition, isLabelIdentifier } = useContext(FieldContext); - const isChipDisplay = - isLabelIdentifier && - (isFieldText(fieldDefinition) || - isFieldFullName(fieldDefinition) || - isFieldNumber(fieldDefinition)); + const isChipDisplay = isFieldChipDisplay(fieldDefinition, isLabelIdentifier); return isChipDisplay ? ( diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/ChipFieldDisplay.tsx b/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/ChipFieldDisplay.tsx index f810590051..30fdcb7a77 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/ChipFieldDisplay.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/ChipFieldDisplay.tsx @@ -1,12 +1,24 @@ -import { RecordChip } from '@/object-record/components/RecordChip'; -import { useChipField } from '@/object-record/record-field/meta-types/hooks/useChipField'; +import { EntityChip } from 'twenty-ui'; + +import { useChipFieldDisplay } from '@/object-record/record-field/meta-types/hooks/useChipFieldDisplay'; +import { getImageAbsoluteURIOrBase64 } from '~/utils/image/getImageAbsoluteURIOrBase64'; export const ChipFieldDisplay = () => { - const { objectNameSingular, record } = useChipField(); + const { recordValue, generateRecordChipData } = useChipFieldDisplay(); - if (!record) return null; + if (!recordValue) { + return null; + } + + const recordChipData = generateRecordChipData(recordValue); return ( - + ); }; diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/PhoneFieldDisplay.tsx b/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/PhoneFieldDisplay.tsx index 4fff5669bb..acfd141a32 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/PhoneFieldDisplay.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/PhoneFieldDisplay.tsx @@ -1,9 +1,8 @@ +import { usePhoneFieldDisplay } from '@/object-record/record-field/meta-types/hooks/usePhoneFieldDisplay'; import { PhoneDisplay } from '@/ui/field/display/components/PhoneDisplay'; -import { usePhoneField } from '../../hooks/usePhoneField'; - export const PhoneFieldDisplay = () => { - const { fieldValue } = usePhoneField(); + const { fieldValue } = usePhoneFieldDisplay(); return ; }; diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/RelationFromManyFieldDisplay.tsx b/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/RelationFromManyFieldDisplay.tsx index d498faaa29..808565a5a9 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/RelationFromManyFieldDisplay.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/RelationFromManyFieldDisplay.tsx @@ -23,8 +23,8 @@ export const RelationFromManyFieldDisplay = ({ {recordChipsData.map((record) => { return ( { - const setEntityFields = useSetRecoilState(recordStoreFamilyState('123')); - - useEffect(() => { - setEntityFields({ - id: 'henry', - name: { - firstName: 'Henry', - lastName: 'Cavill', - }, - __typename: 'Person', - }); - }, [setEntityFields]); - - return null; -}; - -const meta: Meta = { - title: 'UI/Data/Field/Display/ChipFieldDisplay', - decorators: [ - MemoryRouterDecorator, - (Story) => ( - - - - - ), - ComponentDecorator, - ], - component: ChipFieldDisplay, - argTypes: { value: { control: 'date' } }, - args: {}, -}; - -export default meta; - -type Story = StoryObj; - -export const Default: Story = {}; diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/__stories__/PhoneFieldDisplay.stories.tsx b/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/__stories__/PhoneFieldDisplay.stories.tsx deleted file mode 100644 index 0d4d07d71b..0000000000 --- a/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/__stories__/PhoneFieldDisplay.stories.tsx +++ /dev/null @@ -1,68 +0,0 @@ -import { useEffect } from 'react'; -import { Meta, StoryObj } from '@storybook/react'; -import { ComponentDecorator } from 'twenty-ui'; - -import { FieldContext } from '@/object-record/record-field/contexts/FieldContext'; -import { usePhoneField } from '@/object-record/record-field/meta-types/hooks/usePhoneField'; -import { FieldMetadataType } from '~/generated/graphql'; -import { MemoryRouterDecorator } from '~/testing/decorators/MemoryRouterDecorator'; - -import { PhoneFieldDisplay } from '../PhoneFieldDisplay'; - -const PhoneFieldValueSetterEffect = ({ value }: { value: string }) => { - const { setFieldValue } = usePhoneField(); - - useEffect(() => { - setFieldValue(value); - }, [setFieldValue, value]); - - return null; -}; - -const meta: Meta = { - title: 'UI/Data/Field/Display/PhoneFieldDisplay', - decorators: [ - MemoryRouterDecorator, - (Story, { args }) => ( - [() => undefined, {}], - }} - > - - - - ), - ComponentDecorator, - ], - component: PhoneFieldDisplay, - args: { - value: '362763872687362', - }, -}; - -export default meta; - -type Story = StoryObj; - -export const Default: Story = {}; - -export const Elipsis: Story = { - parameters: { - container: { width: 50 }, - }, -}; diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/__stories__/perf/ChipFieldDisplay.perf.stories.tsx b/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/__stories__/perf/ChipFieldDisplay.perf.stories.tsx new file mode 100644 index 0000000000..ad1235d241 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/__stories__/perf/ChipFieldDisplay.perf.stories.tsx @@ -0,0 +1,36 @@ +import { Meta, StoryObj } from '@storybook/react'; +import { ComponentDecorator } from 'twenty-ui'; + +import { ChipFieldDisplay } from '@/object-record/record-field/meta-types/display/components/ChipFieldDisplay'; +import { ChipGeneratorsDecorator } from '~/testing/decorators/ChipGeneratorsDecorator'; +import { getFieldDecorator } from '~/testing/decorators/getFieldDecorator'; +import { MemoryRouterDecorator } from '~/testing/decorators/MemoryRouterDecorator'; +import { getProfilingStory } from '~/testing/profiling/utils/getProfilingStory'; + +const meta: Meta = { + title: 'UI/Data/Field/Display/ChipFieldDisplay', + decorators: [ + MemoryRouterDecorator, + ChipGeneratorsDecorator, + getFieldDecorator('person', 'name'), + ComponentDecorator, + ], + component: ChipFieldDisplay, + args: {}, + parameters: { + chromatic: { disableSnapshot: true }, + }, +}; + +export default meta; + +type Story = StoryObj; + +export const Default: Story = {}; + +export const Performance = getProfilingStory({ + componentName: 'ChipFieldDisplay', + averageThresholdInMs: 0.2, + numberOfRuns: 20, + numberOfTestsPerRun: 100, +}); diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/__stories__/perf/PhoneFieldDisplay.perf.stories.tsx b/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/__stories__/perf/PhoneFieldDisplay.perf.stories.tsx new file mode 100644 index 0000000000..ccccf51695 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/__stories__/perf/PhoneFieldDisplay.perf.stories.tsx @@ -0,0 +1,47 @@ +import { Meta, StoryObj } from '@storybook/react'; +import { ComponentDecorator } from 'twenty-ui'; + +import { PhoneFieldDisplay } from '@/object-record/record-field/meta-types/display/components/PhoneFieldDisplay'; +import { getFieldDecorator } from '~/testing/decorators/getFieldDecorator'; +import { MemoryRouterDecorator } from '~/testing/decorators/MemoryRouterDecorator'; +import { getProfilingStory } from '~/testing/profiling/utils/getProfilingStory'; + +const meta: Meta = { + title: 'UI/Data/Field/Display/PhoneFieldDisplay', + decorators: [ + MemoryRouterDecorator, + getFieldDecorator('person', 'phone'), + ComponentDecorator, + ], + component: PhoneFieldDisplay, + args: {}, + parameters: { + chromatic: { disableSnapshot: true }, + }, +}; + +export default meta; + +type Story = StoryObj; + +export const Default: Story = {}; + +export const Elipsis: Story = { + parameters: { + container: { width: 50 }, + }, +}; + +export const WrongNumber: Story = { + parameters: { + container: { width: 50 }, + }, + decorators: [getFieldDecorator('person', 'phone', 'sdklaskdj')], +}; + +export const Performance = getProfilingStory({ + componentName: 'PhoneFieldDisplay', + averageThresholdInMs: 0.5, + numberOfRuns: 20, + numberOfTestsPerRun: 100, +}); diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/__stories__/perf/RelationFieldDisplay.perf.stories.tsx b/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/__stories__/perf/RelationFieldDisplay.perf.stories.tsx index f12a1716ee..6c985926d9 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/__stories__/perf/RelationFieldDisplay.perf.stories.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/__stories__/perf/RelationFieldDisplay.perf.stories.tsx @@ -1,74 +1,21 @@ -import { useEffect } from 'react'; import { Meta, StoryObj } from '@storybook/react'; -import { useSetRecoilState } from 'recoil'; import { ComponentDecorator } from 'twenty-ui'; -import { FieldContext } from '@/object-record/record-field/contexts/FieldContext'; import { RelationFieldDisplay } from '@/object-record/record-field/meta-types/display/components/RelationFieldDisplay'; -import { - RecordFieldValueSelectorContextProvider, - useSetRecordValue, -} from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext'; -import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; +import { ChipGeneratorsDecorator } from '~/testing/decorators/ChipGeneratorsDecorator'; +import { getFieldDecorator } from '~/testing/decorators/getFieldDecorator'; import { MemoryRouterDecorator } from '~/testing/decorators/MemoryRouterDecorator'; import { getProfilingStory } from '~/testing/profiling/utils/getProfilingStory'; -import { relationFieldDisplayMock } from './mock'; - -const RelationFieldValueSetterEffect = () => { - const setEntity = useSetRecoilState( - recordStoreFamilyState(relationFieldDisplayMock.entityId), - ); - - const setRelationEntity = useSetRecoilState( - recordStoreFamilyState(relationFieldDisplayMock.relationEntityId), - ); - - const setRecordValue = useSetRecordValue(); - - useEffect(() => { - setEntity(relationFieldDisplayMock.entityValue); - setRelationEntity(relationFieldDisplayMock.relationFieldValue); - - setRecordValue( - relationFieldDisplayMock.entityValue.id, - relationFieldDisplayMock.entityValue, - ); - setRecordValue( - relationFieldDisplayMock.relationFieldValue.id, - relationFieldDisplayMock.relationFieldValue, - ); - }, [setEntity, setRelationEntity, setRecordValue]); - - return null; -}; - const meta: Meta = { title: 'UI/Data/Field/Display/RelationFieldDisplay', decorators: [ MemoryRouterDecorator, - (Story) => ( - - - - - - - ), + ChipGeneratorsDecorator, + getFieldDecorator('person', 'company'), ComponentDecorator, ], component: RelationFieldDisplay, - argTypes: { value: { control: 'date' } }, args: {}, parameters: { chromatic: { disableSnapshot: true }, @@ -83,7 +30,7 @@ export const Default: Story = {}; export const Performance = getProfilingStory({ componentName: 'RelationFieldDisplay', - averageThresholdInMs: 0.4, + averageThresholdInMs: 0.2, numberOfRuns: 20, numberOfTestsPerRun: 100, }); diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/__stories__/perf/RelationFromManyFieldDisplay.perf.stories.tsx b/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/__stories__/perf/RelationFromManyFieldDisplay.perf.stories.tsx index 360abcf4c3..7c9ce09da8 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/__stories__/perf/RelationFromManyFieldDisplay.perf.stories.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/__stories__/perf/RelationFromManyFieldDisplay.perf.stories.tsx @@ -12,6 +12,7 @@ import { useSetRecordValue, } from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; +import { ChipGeneratorsDecorator } from '~/testing/decorators/ChipGeneratorsDecorator'; import { MemoryRouterDecorator } from '~/testing/decorators/MemoryRouterDecorator'; import { getProfilingStory } from '~/testing/profiling/utils/getProfilingStory'; @@ -52,6 +53,7 @@ const meta: Meta = { title: 'UI/Data/Field/Display/RelationFromManyFieldDisplay', decorators: [ MemoryRouterDecorator, + ChipGeneratorsDecorator, (Story) => ( { + const { entityId, fieldDefinition } = useContext(FieldContext); + + const { chipGeneratorPerObjectPerField } = useContext( + PreComputedChipGeneratorsContext, + ); + + if (!isDefined(chipGeneratorPerObjectPerField)) { + throw new Error('Chip generator per object per field is not defined'); + } + + const objectNameSingular = + isFieldText(fieldDefinition) || + isFieldFullName(fieldDefinition) || + isFieldNumber(fieldDefinition) + ? fieldDefinition.metadata.objectMetadataNameSingular + : undefined; + + const recordValue = useRecordValue(entityId); + + if (!isNonEmptyString(fieldDefinition.metadata.objectMetadataNameSingular)) { + throw new Error('Object metadata name singular is not a non-empty string'); + } + + const generateRecordChipData = + chipGeneratorPerObjectPerField[ + fieldDefinition.metadata.objectMetadataNameSingular + ][fieldDefinition.metadata.fieldName]; + + return { + objectNameSingular, + recordValue, + generateRecordChipData, + }; +}; diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/hooks/usePhoneFieldDisplay.ts b/packages/twenty-front/src/modules/object-record/record-field/meta-types/hooks/usePhoneFieldDisplay.ts new file mode 100644 index 0000000000..e96a81f3cf --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/hooks/usePhoneFieldDisplay.ts @@ -0,0 +1,19 @@ +import { useContext } from 'react'; + +import { useRecordFieldValue } from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext'; + +import { FieldContext } from '../../contexts/FieldContext'; + +export const usePhoneFieldDisplay = () => { + const { entityId, fieldDefinition, hotkeyScope } = useContext(FieldContext); + + const fieldName = fieldDefinition.metadata.fieldName; + + const fieldValue = useRecordFieldValue(entityId, fieldName); + + return { + fieldDefinition, + fieldValue, + hotkeyScope, + }; +}; diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/hooks/useRelationFieldDisplay.ts b/packages/twenty-front/src/modules/object-record/record-field/meta-types/hooks/useRelationFieldDisplay.ts index d51f7980bc..546a6ba43c 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/meta-types/hooks/useRelationFieldDisplay.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/hooks/useRelationFieldDisplay.ts @@ -1,9 +1,8 @@ import { useContext } from 'react'; +import { isNonEmptyString } from '@sniptt/guards'; -import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; -import { getObjectRecordIdentifier } from '@/object-metadata/utils/getObjectRecordIdentifier'; +import { PreComputedChipGeneratorsContext } from '@/object-metadata/context/PreComputedChipGeneratorsContext'; import { useRecordFieldValue } from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext'; -import { ObjectRecord } from '@/object-record/types/ObjectRecord'; import { FIELD_EDIT_BUTTON_WIDTH } from '@/ui/field/display/constants/FieldEditButtonWidth'; import { FieldMetadataType } from '~/generated-metadata/graphql'; import { isDefined } from '~/utils/isDefined'; @@ -15,6 +14,14 @@ import { isFieldRelation } from '../../types/guards/isFieldRelation'; export const useRelationFieldDisplay = () => { const { entityId, fieldDefinition, maxWidth } = useContext(FieldContext); + const { chipGeneratorPerObjectPerField } = useContext( + PreComputedChipGeneratorsContext, + ); + + if (!isDefined(chipGeneratorPerObjectPerField)) { + throw new Error('Chip generator per object per field is not defined'); + } + assertFieldMetadata( FieldMetadataType.Relation, isFieldRelation, @@ -32,18 +39,14 @@ export const useRelationFieldDisplay = () => { ? maxWidth - FIELD_EDIT_BUTTON_WIDTH : maxWidth; - const { objectMetadataItem: relationObjectMetadataItem } = - useObjectMetadataItem({ - objectNameSingular: - fieldDefinition.metadata.relationObjectMetadataNameSingular, - }); + if (!isNonEmptyString(fieldDefinition.metadata.objectMetadataNameSingular)) { + throw new Error('Object metadata name singular is not a non-empty string'); + } - const generateRecordChipData = (record: ObjectRecord) => { - return getObjectRecordIdentifier({ - objectMetadataItem: relationObjectMetadataItem, - record, - }); - }; + const generateRecordChipData = + chipGeneratorPerObjectPerField[ + fieldDefinition.metadata.objectMetadataNameSingular + ][fieldDefinition.metadata.fieldName]; return { fieldDefinition, diff --git a/packages/twenty-front/src/modules/object-record/record-field/types/RecordChipData.ts b/packages/twenty-front/src/modules/object-record/record-field/types/RecordChipData.ts index 77c80b6098..13eb99f84c 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/types/RecordChipData.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/types/RecordChipData.ts @@ -1,6 +1,7 @@ import { AvatarType } from 'twenty-ui'; export type RecordChipData = { + recordId: string; name: string | number; avatarType: AvatarType; avatarUrl: string; diff --git a/packages/twenty-front/src/modules/object-record/record-store/contexts/RecordFieldValueSelectorContext.tsx b/packages/twenty-front/src/modules/object-record/record-store/contexts/RecordFieldValueSelectorContext.tsx index d3d9b7a32d..3f7c074142 100644 --- a/packages/twenty-front/src/modules/object-record/record-store/contexts/RecordFieldValueSelectorContext.tsx +++ b/packages/twenty-front/src/modules/object-record/record-store/contexts/RecordFieldValueSelectorContext.tsx @@ -1,6 +1,8 @@ import { Dispatch, SetStateAction, useState } from 'react'; import { createContext, useContextSelector } from 'use-context-selector'; +import { ObjectRecord } from '@/object-record/types/ObjectRecord'; + export type RecordFieldValue = { [recordId: string]: { [fieldName: string]: any; @@ -31,7 +33,7 @@ export const useRecordValue = (recordId: string) => { (value) => value[0], ); - return tableValue?.[recordId]; + return tableValue?.[recordId] as ObjectRecord | undefined; }; export const useRecordFieldValue = (recordId: string, fieldName: string) => { diff --git a/packages/twenty-front/src/modules/object-record/record-table/components/__stories__/perf/RecordTableCell.perf.stories.tsx b/packages/twenty-front/src/modules/object-record/record-table/components/__stories__/perf/RecordTableCell.perf.stories.tsx index 9c0bf8b7ba..487465b609 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/components/__stories__/perf/RecordTableCell.perf.stories.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/components/__stories__/perf/RecordTableCell.perf.stories.tsx @@ -17,6 +17,7 @@ import { RecordTableCellContext } from '@/object-record/record-table/contexts/Re import { RecordTableContext } from '@/object-record/record-table/contexts/RecordTableContext'; import { RecordTableRowContext } from '@/object-record/record-table/contexts/RecordTableRowContext'; import { RecordTableScope } from '@/object-record/record-table/scopes/RecordTableScope'; +import { ChipGeneratorsDecorator } from '~/testing/decorators/ChipGeneratorsDecorator'; import { MemoryRouterDecorator } from '~/testing/decorators/MemoryRouterDecorator'; import { getProfilingStory } from '~/testing/profiling/utils/getProfilingStory'; @@ -57,6 +58,7 @@ const meta: Meta = { title: 'RecordIndex/Table/RecordTableCell', decorators: [ MemoryRouterDecorator, + ChipGeneratorsDecorator, (Story) => { return ( @@ -143,7 +145,7 @@ export const Default: Story = {}; export const Performance = getProfilingStory({ componentName: 'RecordTableCell', - averageThresholdInMs: 0.6, + averageThresholdInMs: 0.3, numberOfRuns: 50, numberOfTestsPerRun: 200, warmUpRounds: 20, diff --git a/packages/twenty-front/src/modules/object-record/record-table/hooks/useRecordChipDataGenerator.ts b/packages/twenty-front/src/modules/object-record/record-table/hooks/useRecordChipDataGenerator.ts deleted file mode 100644 index dd8cd1c58a..0000000000 --- a/packages/twenty-front/src/modules/object-record/record-table/hooks/useRecordChipDataGenerator.ts +++ /dev/null @@ -1,86 +0,0 @@ -import { useMemo } from 'react'; - -import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems'; -import { getAvatarType } from '@/object-metadata/utils/getAvatarType'; -import { getAvatarUrl } from '@/object-metadata/utils/getAvatarUrl'; -import { getLabelIdentifierFieldMetadataItem } from '@/object-metadata/utils/getLabelIdentifierFieldMetadataItem'; -import { getLabelIdentifierFieldValue } from '@/object-metadata/utils/getLabelIdentifierFieldValue'; -import { getLinkToShowPage } from '@/object-metadata/utils/getLinkToShowPage'; -import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata'; -import { isFieldRelation } from '@/object-record/record-field/types/guards/isFieldRelation'; -import { RecordChipData } from '@/object-record/record-field/types/RecordChipData'; -import { ColumnDefinition } from '@/object-record/record-table/types/ColumnDefinition'; -import { ObjectRecord } from '@/object-record/types/ObjectRecord'; -import { FieldMetadataType } from '~/generated-metadata/graphql'; -import { isDefined } from '~/utils/isDefined'; - -export const useRecordChipDataGenerator = ({ - objectNameSingular, - visibleTableColumns, -}: { - objectNameSingular: string; - visibleTableColumns: ColumnDefinition[]; -}) => { - const { objectMetadataItems } = useObjectMetadataItems(); - - return useMemo(() => { - return Object.fromEntries<(record: ObjectRecord) => RecordChipData>( - visibleTableColumns - .filter( - (tableColumn) => - tableColumn.isLabelIdentifier || - tableColumn.type === FieldMetadataType.Relation, - ) - .map((tableColumn) => { - const objectNameSingularToFind = tableColumn.isLabelIdentifier - ? objectNameSingular - : isFieldRelation(tableColumn) - ? tableColumn.metadata.relationObjectMetadataNameSingular - : undefined; - - const objectMetadataItem = objectMetadataItems.find( - (objectMetadataItem) => - objectMetadataItem.nameSingular === objectNameSingularToFind, - ); - - if ( - !isDefined(objectMetadataItem) || - !isDefined(objectNameSingularToFind) - ) { - return ['', () => ({}) as any]; - } - - const labelIdentifierFieldMetadataItem = - getLabelIdentifierFieldMetadataItem(objectMetadataItem); - - const imageIdentifierFieldMetadata = objectMetadataItem.fields.find( - (field) => - field.id === objectMetadataItem.imageIdentifierFieldMetadataId, - ); - - const avatarType = getAvatarType(objectNameSingularToFind); - - return [ - tableColumn.metadata.fieldName, - (record: ObjectRecord) => ({ - name: getLabelIdentifierFieldValue( - record, - labelIdentifierFieldMetadataItem, - objectMetadataItem.nameSingular, - ), - avatarUrl: getAvatarUrl( - objectMetadataItem.nameSingular, - record, - imageIdentifierFieldMetadata, - ), - avatarType, - linkToShowPage: getLinkToShowPage( - objectMetadataItem.nameSingular, - record, - ), - }), - ]; - }), - ); - }, [objectNameSingular, visibleTableColumns, objectMetadataItems]); -}; diff --git a/packages/twenty-front/src/modules/object-record/utils/getRecordChipGeneratorPerObjectPerField.ts b/packages/twenty-front/src/modules/object-record/utils/getRecordChipGeneratorPerObjectPerField.ts new file mode 100644 index 0000000000..f127e275ec --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/utils/getRecordChipGeneratorPerObjectPerField.ts @@ -0,0 +1,116 @@ +import { ChipGeneratorPerObjectPerField } from '@/object-metadata/context/PreComputedChipGeneratorsContext'; +import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem'; +import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; +import { getAvatarType } from '@/object-metadata/utils/getAvatarType'; +import { getAvatarUrl } from '@/object-metadata/utils/getAvatarUrl'; +import { getLabelIdentifierFieldMetadataItem } from '@/object-metadata/utils/getLabelIdentifierFieldMetadataItem'; +import { getLabelIdentifierFieldValue } from '@/object-metadata/utils/getLabelIdentifierFieldValue'; +import { getLinkToShowPage } from '@/object-metadata/utils/getLinkToShowPage'; +import { isLabelIdentifierField } from '@/object-metadata/utils/isLabelIdentifierField'; +import { isFieldFullName } from '@/object-record/record-field/types/guards/isFieldFullName'; +import { isFieldNumber } from '@/object-record/record-field/types/guards/isFieldNumber'; +import { isFieldRelation } from '@/object-record/record-field/types/guards/isFieldRelation'; +import { isFieldText } from '@/object-record/record-field/types/guards/isFieldText'; +import { RecordChipData } from '@/object-record/record-field/types/RecordChipData'; +import { ObjectRecord } from '@/object-record/types/ObjectRecord'; +import { FieldMetadataType } from '~/generated-metadata/graphql'; +import { isDefined } from '~/utils/isDefined'; + +export const isFieldChipDisplay = ( + field: Pick, + isLabelIdentifier: boolean, +) => + isLabelIdentifier && + (isFieldText(field) || isFieldFullName(field) || isFieldNumber(field)); + +export const getRecordChipGeneratorPerObjectPerField = ( + objectMetadataItems: ObjectMetadataItem[], +) => { + const recordChipGeneratorPerObjectPerField: ChipGeneratorPerObjectPerField = + {}; + + for (const objectMetadataItem of objectMetadataItems) { + const generatorPerField = Object.fromEntries< + (record: ObjectRecord) => RecordChipData + >( + objectMetadataItem.fields + .filter( + (fieldMetadataItem) => + isLabelIdentifierField({ + fieldMetadataItem: fieldMetadataItem, + objectMetadataItem, + }) || + fieldMetadataItem.type === FieldMetadataType.Relation || + isFieldChipDisplay( + fieldMetadataItem, + isLabelIdentifierField({ + fieldMetadataItem: fieldMetadataItem, + objectMetadataItem, + }), + ), + ) + .map((fieldMetadataItem) => { + const objectNameSingularToFind = isLabelIdentifierField({ + fieldMetadataItem: fieldMetadataItem, + objectMetadataItem: objectMetadataItem, + }) + ? objectMetadataItem.nameSingular + : isFieldRelation(fieldMetadataItem) + ? fieldMetadataItem.relationDefinition?.targetObjectMetadata + .nameSingular ?? undefined + : undefined; + + const objectMetadataItemToUse = objectMetadataItems.find( + (objectMetadataItem) => + objectMetadataItem.nameSingular === objectNameSingularToFind, + ); + + if ( + !isDefined(objectMetadataItemToUse) || + !isDefined(objectNameSingularToFind) + ) { + return ['', () => ({}) as any]; + } + + const labelIdentifierFieldMetadataItem = + getLabelIdentifierFieldMetadataItem(objectMetadataItemToUse); + + const imageIdentifierFieldMetadata = + objectMetadataItemToUse.fields.find( + (field) => + field.id === + objectMetadataItemToUse.imageIdentifierFieldMetadataId, + ); + + const avatarType = getAvatarType(objectNameSingularToFind); + + return [ + fieldMetadataItem.name, + (record: ObjectRecord) => ({ + recordId: record.id, + name: getLabelIdentifierFieldValue( + record, + labelIdentifierFieldMetadataItem, + objectMetadataItemToUse.nameSingular, + ), + avatarUrl: getAvatarUrl( + objectMetadataItemToUse.nameSingular, + record, + imageIdentifierFieldMetadata, + ), + avatarType, + linkToShowPage: getLinkToShowPage( + objectMetadataItemToUse.nameSingular, + record, + ), + }), + ]; + }), + ); + + recordChipGeneratorPerObjectPerField[objectMetadataItem.nameSingular] = + generatorPerField; + } + + return recordChipGeneratorPerObjectPerField; +}; diff --git a/packages/twenty-front/src/modules/people/types/Person.ts b/packages/twenty-front/src/modules/people/types/Person.ts index fd5b75ad84..eef68681e2 100644 --- a/packages/twenty-front/src/modules/people/types/Person.ts +++ b/packages/twenty-front/src/modules/people/types/Person.ts @@ -2,24 +2,39 @@ export type Person = { __typename: 'Person'; id: string; createdAt: string; - updatedAt: string; - deletedAt: string | null; + updatedAt?: string; + deletedAt?: string | null; name: { + __typename?: 'FullName'; firstName: string; lastName: string; }; - avatarUrl: string; + avatarUrl?: string; jobTitle: string; linkedinLink: { + __typename?: 'Link'; url: string; label: string; }; xLink: { + __typename?: 'Link'; url: string; label: string; }; city: string; email: string; phone: string; - companyId: string; + companyId?: string; + position?: number; + links?: { + __typename: 'Links'; + primaryLinkUrl: string; + primaryLinkLabel: ''; + secondaryLinks?: + | { + url: string; + label: string; + }[] + | null; + }; }; diff --git a/packages/twenty-front/src/modules/ui/field/display/components/EllipsisDisplay.tsx b/packages/twenty-front/src/modules/ui/field/display/components/EllipsisDisplay.tsx index 608019e93c..d5c336005f 100644 --- a/packages/twenty-front/src/modules/ui/field/display/components/EllipsisDisplay.tsx +++ b/packages/twenty-front/src/modules/ui/field/display/components/EllipsisDisplay.tsx @@ -1,4 +1,4 @@ -import styled from '@emotion/styled'; +import { styled } from '@linaria/react'; const StyledEllipsisDisplay = styled.div<{ maxWidth?: number }>` max-width: ${({ maxWidth }) => maxWidth ?? '100%'}; @@ -19,7 +19,7 @@ export const EllipsisDisplay = ({ maxWidth, className, }: EllipsisDisplayProps) => ( - + {children} ); diff --git a/packages/twenty-front/src/modules/ui/field/display/components/PhoneDisplay.tsx b/packages/twenty-front/src/modules/ui/field/display/components/PhoneDisplay.tsx index b9e73c45da..f4cdc8519d 100644 --- a/packages/twenty-front/src/modules/ui/field/display/components/PhoneDisplay.tsx +++ b/packages/twenty-front/src/modules/ui/field/display/components/PhoneDisplay.tsx @@ -1,27 +1,39 @@ import { MouseEvent } from 'react'; -import { isValidPhoneNumber, parsePhoneNumber } from 'libphonenumber-js'; +import { parsePhoneNumber, PhoneNumber } from 'libphonenumber-js'; import { ContactLink } from '@/ui/navigation/link/components/ContactLink'; - -import { EllipsisDisplay } from './EllipsisDisplay'; +import { isDefined } from '~/utils/isDefined'; type PhoneDisplayProps = { value: string | null; }; -export const PhoneDisplay = ({ value }: PhoneDisplayProps) => ( - - {value && isValidPhoneNumber(value) ? ( - ) => { - event.stopPropagation(); - }} - > - {parsePhoneNumber(value, 'FR')?.formatNational() || value} - - ) : ( - {value} - )} - -); +// TODO: see if we can find a faster way to format the phone number +export const PhoneDisplay = ({ value }: PhoneDisplayProps) => { + if (!isDefined(value)) { + return {value}; + } + + let parsedPhoneNumber: PhoneNumber | null = null; + + try { + // TODO: parse according to locale not hard coded FR + parsedPhoneNumber = parsePhoneNumber(value, 'FR'); + } catch (error) { + return {value}; + } + + const URI = parsedPhoneNumber.getURI(); + const formattedNational = parsedPhoneNumber?.formatNational(); + + return ( + ) => { + event.stopPropagation(); + }} + > + {formattedNational || value} + + ); +}; diff --git a/packages/twenty-front/src/modules/ui/field/display/components/__stories__/EllipsisDisplay.stories.tsx b/packages/twenty-front/src/modules/ui/field/display/components/__stories__/EllipsisDisplay.stories.tsx deleted file mode 100644 index d331c13145..0000000000 --- a/packages/twenty-front/src/modules/ui/field/display/components/__stories__/EllipsisDisplay.stories.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import { Meta, StoryObj } from '@storybook/react'; -import { ComponentDecorator } from 'twenty-ui'; - -import { EllipsisDisplay } from '@/ui/field/display/components/EllipsisDisplay'; - -const meta: Meta = { - title: 'UI/Input/EllipsisDisplay/EllipsisDisplay', - component: EllipsisDisplay, - decorators: [ComponentDecorator], - args: { - maxWidth: 100, - children: 'This is a long text that should be truncated', - }, -}; - -export default meta; - -type Story = StoryObj; - -export const Default: Story = {}; diff --git a/packages/twenty-front/src/modules/ui/field/display/components/__stories__/perf/EllipsisDisplay.perf.stories.tsx b/packages/twenty-front/src/modules/ui/field/display/components/__stories__/perf/EllipsisDisplay.perf.stories.tsx index 7bc88fff54..98d66dc2d2 100644 --- a/packages/twenty-front/src/modules/ui/field/display/components/__stories__/perf/EllipsisDisplay.perf.stories.tsx +++ b/packages/twenty-front/src/modules/ui/field/display/components/__stories__/perf/EllipsisDisplay.perf.stories.tsx @@ -1,4 +1,4 @@ -import { Meta } from '@storybook/react'; +import { Meta, StoryObj } from '@storybook/react'; import { ComponentDecorator } from 'twenty-ui'; import { EllipsisDisplay } from '@/ui/field/display/components/EllipsisDisplay'; @@ -19,6 +19,10 @@ const meta: Meta = { export default meta; +type Story = StoryObj; + +export const Default: Story = {}; + export const Performance = getProfilingStory({ componentName: 'EllipsisDisplay', averageThresholdInMs: 0.1, diff --git a/packages/twenty-front/src/modules/ui/navigation/link/components/ContactLink.tsx b/packages/twenty-front/src/modules/ui/navigation/link/components/ContactLink.tsx index 4afea7333b..6508c0dc56 100644 --- a/packages/twenty-front/src/modules/ui/navigation/link/components/ContactLink.tsx +++ b/packages/twenty-front/src/modules/ui/navigation/link/components/ContactLink.tsx @@ -1,43 +1,47 @@ import * as React from 'react'; -import { Link as ReactLink } from 'react-router-dom'; -import styled from '@emotion/styled'; +import { Theme, withTheme } from '@emotion/react'; +import { styled } from '@linaria/react'; + +const StyledClickableLink = withTheme(styled.a<{ + theme: Theme; + maxWidth?: number; +}>` + color: inherit; + overflow: hidden; + text-decoration: underline; + text-decoration-color: ${({ theme }) => theme.border.color.strong}; + text-overflow: ellipsis; + + text-overflow: ellipsis; + white-space: nowrap; + width: 100%; + + max-width: ${({ maxWidth }) => maxWidth ?? '100%'}; + + &:hover { + text-decoration-color: ${({ theme }) => theme.font.color.primary}; + } +`); type ContactLinkProps = { - className?: string; href: string; children?: React.ReactNode; onClick?: (event: React.MouseEvent) => void; + maxWidth?: number; }; -const StyledClickable = styled.div` - display: flex; - overflow: hidden; - white-space: nowrap; - - a { - color: inherit; - overflow: hidden; - text-decoration: underline; - text-decoration-color: ${({ theme }) => theme.border.color.strong}; - text-overflow: ellipsis; - - &:hover { - text-decoration-color: ${({ theme }) => theme.font.color.primary}; - } - } -`; - export const ContactLink = ({ - className, href, children, onClick, + maxWidth, }: ContactLinkProps) => ( -
- - - {children} - - -
+ + {children} + ); diff --git a/packages/twenty-front/src/modules/ui/navigation/link/components/__stories__/ContactLink.stories.tsx b/packages/twenty-front/src/modules/ui/navigation/link/components/__stories__/ContactLink.stories.tsx index c139f409fa..f4bcf867b5 100644 --- a/packages/twenty-front/src/modules/ui/navigation/link/components/__stories__/ContactLink.stories.tsx +++ b/packages/twenty-front/src/modules/ui/navigation/link/components/__stories__/ContactLink.stories.tsx @@ -10,7 +10,6 @@ const meta: Meta = { component: ContactLink, decorators: [ComponentWithRouterDecorator], args: { - className: 'ContactLink', href: '/test', children: 'Contact Link', }, diff --git a/packages/twenty-front/src/modules/workspace-member/types/WorkspaceMember.ts b/packages/twenty-front/src/modules/workspace-member/types/WorkspaceMember.ts index fffbc97e90..83f029206a 100644 --- a/packages/twenty-front/src/modules/workspace-member/types/WorkspaceMember.ts +++ b/packages/twenty-front/src/modules/workspace-member/types/WorkspaceMember.ts @@ -4,6 +4,7 @@ export type WorkspaceMember = { __typename: 'WorkspaceMember'; id: string; name: { + __typename?: 'FullName'; firstName: string; lastName: string; }; diff --git a/packages/twenty-front/src/testing/decorators/ChipGeneratorsDecorator.tsx b/packages/twenty-front/src/testing/decorators/ChipGeneratorsDecorator.tsx new file mode 100644 index 0000000000..6f9ac5d305 --- /dev/null +++ b/packages/twenty-front/src/testing/decorators/ChipGeneratorsDecorator.tsx @@ -0,0 +1,24 @@ +import { useMemo } from 'react'; +import { Decorator } from '@storybook/react'; + +import { PreComputedChipGeneratorsContext } from '@/object-metadata/context/PreComputedChipGeneratorsContext'; +import { getRecordChipGeneratorPerObjectPerField } from '@/object-record/utils/getRecordChipGeneratorPerObjectPerField'; +import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems'; + +export const ChipGeneratorsDecorator: Decorator = (Story) => { + const chipGeneratorPerObjectPerField = useMemo(() => { + return getRecordChipGeneratorPerObjectPerField( + generatedMockObjectMetadataItems, + ); + }, []); + + return ( + + + + ); +}; diff --git a/packages/twenty-front/src/testing/decorators/ObjectMetadataItemsDecorator.tsx b/packages/twenty-front/src/testing/decorators/ObjectMetadataItemsDecorator.tsx index c54ff5dd13..9c27a82e35 100644 --- a/packages/twenty-front/src/testing/decorators/ObjectMetadataItemsDecorator.tsx +++ b/packages/twenty-front/src/testing/decorators/ObjectMetadataItemsDecorator.tsx @@ -1,11 +1,13 @@ -import { useEffect } from 'react'; +import { useEffect, useMemo } from 'react'; import { Decorator } from '@storybook/react'; import { useRecoilValue, useSetRecoilState } from 'recoil'; import { currentUserState } from '@/auth/states/currentUserState'; import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState'; import { ObjectMetadataItemsLoadEffect } from '@/object-metadata/components/ObjectMetadataItemsLoadEffect'; +import { PreComputedChipGeneratorsContext } from '@/object-metadata/context/PreComputedChipGeneratorsContext'; import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; +import { getRecordChipGeneratorPerObjectPerField } from '@/object-record/utils/getRecordChipGeneratorPerObjectPerField'; import { mockedUsersData } from '~/testing/mock-data/users'; import { mockWorkspaceMembers } from '~/testing/mock-data/workspace-members'; @@ -21,10 +23,20 @@ export const ObjectMetadataItemsDecorator: Decorator = (Story) => { setCurrentUser(mockedUsersData[0]); }, [setCurrentUser, setCurrentWorkspaceMember]); + const chipGeneratorPerObjectPerField = useMemo(() => { + return getRecordChipGeneratorPerObjectPerField(objectMetadataItems); + }, [objectMetadataItems]); + return ( <> - {!!objectMetadataItems.length && } + + {!!objectMetadataItems.length && } + ); }; diff --git a/packages/twenty-front/src/testing/decorators/getFieldDecorator.tsx b/packages/twenty-front/src/testing/decorators/getFieldDecorator.tsx new file mode 100644 index 0000000000..b0de8bcefb --- /dev/null +++ b/packages/twenty-front/src/testing/decorators/getFieldDecorator.tsx @@ -0,0 +1,125 @@ +import { useEffect } from 'react'; +import { Decorator } from '@storybook/react'; +import { useRecoilCallback } from 'recoil'; + +import { Company } from '@/companies/types/Company'; +import { formatFieldMetadataItemAsColumnDefinition } from '@/object-metadata/utils/formatFieldMetadataItemAsColumnDefinition'; +import { isLabelIdentifierField } from '@/object-metadata/utils/isLabelIdentifierField'; +import { FieldContext } from '@/object-record/record-field/contexts/FieldContext'; +import { + RecordFieldValueSelectorContextProvider, + useSetRecordValue, +} from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext'; +import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; +import { ObjectRecord } from '@/object-record/types/ObjectRecord'; +import { Person } from '@/people/types/Person'; +import { mockedCompaniesDataV2 } from '~/testing/mock-data/companiesV2'; +import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems'; +import { mockPeopleDataV2 } from '~/testing/mock-data/peopleV2'; +import { isDefined } from '~/utils/isDefined'; + +const RecordMockSetterEffect = ({ + companies, + people, +}: { + companies: Company[]; + people: Person[]; +}) => { + const setRecordValue = useSetRecordValue(); + + const setRecordInBothStores = useRecoilCallback( + ({ set }) => + (record: ObjectRecord) => { + set(recordStoreFamilyState(record.id), record); + setRecordValue(record.id, record); + }, + [setRecordValue], + ); + + useEffect(() => { + for (const company of companies) { + setRecordInBothStores(company); + } + + for (const person of people) { + setRecordInBothStores(person); + } + }, [setRecordInBothStores, companies, people]); + + return null; +}; + +export const getFieldDecorator = + ( + objectNameSingular: 'company' | 'person', + fieldName: string, + fieldValue?: any, + ): Decorator => + (Story) => { + const companies = + objectNameSingular === 'company' && isDefined(fieldValue) + ? [ + { ...mockedCompaniesDataV2[0], [fieldName]: fieldValue }, + ...mockedCompaniesDataV2.slice(1), + ] + : mockedCompaniesDataV2; + + const people = + objectNameSingular === 'person' && isDefined(fieldValue) + ? [ + { ...mockPeopleDataV2[0], [fieldName]: fieldValue }, + ...mockPeopleDataV2.slice(1), + ] + : mockPeopleDataV2; + + const record = objectNameSingular === 'company' ? companies[0] : people[0]; + + if (isDefined(fieldValue)) { + (record as any)[fieldName] = fieldValue; + } + + const objectMetadataItem = generatedMockObjectMetadataItems.find( + (objectMetadataItem) => + objectMetadataItem.nameSingular === objectNameSingular, + ); + + const fieldMetadataItem = objectMetadataItem?.fields.find( + (field) => field.name === fieldName, + ); + + if (!isDefined(objectMetadataItem)) { + throw new Error(`Object ${objectNameSingular} not found`); + } + + if (!isDefined(fieldMetadataItem)) { + throw new Error( + `Field ${fieldName} not found in object ${objectNameSingular}`, + ); + } + + const isLabelIdentifier = isLabelIdentifierField({ + fieldMetadataItem, + objectMetadataItem, + }); + + return ( + + + + + + + ); + }; diff --git a/packages/twenty-front/src/testing/hooks/useMockFieldContext.tsx b/packages/twenty-front/src/testing/hooks/useMockFieldContext.tsx new file mode 100644 index 0000000000..278b5004f0 --- /dev/null +++ b/packages/twenty-front/src/testing/hooks/useMockFieldContext.tsx @@ -0,0 +1,78 @@ +import { ReactNode } from 'react'; + +import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; +import { formatFieldMetadataItemAsColumnDefinition } from '@/object-metadata/utils/formatFieldMetadataItemAsColumnDefinition'; +import { getBasePathToShowPage } from '@/object-metadata/utils/getBasePathToShowPage'; +import { + FieldContext, + RecordUpdateHook, +} from '@/object-record/record-field/contexts/FieldContext'; +import { InlineCellHotkeyScope } from '@/object-record/record-inline-cell/types/InlineCellHotkeyScope'; + +export const useMockFieldContext = ({ + clearable, + fieldMetadataName, + fieldPosition, + isLabelIdentifier = false, + objectNameSingular, + objectRecordId, + customHotkeyScope, +}: { + clearable?: boolean; + fieldMetadataName: string; + fieldPosition: number; + isLabelIdentifier?: boolean; + objectNameSingular: string; + objectRecordId: string; + customHotkeyScope?: string; +}) => { + const { objectMetadataItem } = useObjectMetadataItem({ + objectNameSingular, + }); + + const basePathToShowPage = getBasePathToShowPage({ + objectNameSingular, + }); + + const fieldMetadataItem = objectMetadataItem?.fields.find( + (field) => field.name === fieldMetadataName, + ); + + const useUpdateOneObjectMutation: RecordUpdateHook = () => { + const updateEntity = () => {}; + + return [updateEntity, { loading: false }]; + }; + + const FieldContextProvider = + fieldMetadataItem && objectMetadataItem + ? ({ children }: { children: ReactNode }) => ( + + {children} + + ) + : undefined; + + return { + FieldContextProvider, + }; +}; diff --git a/packages/twenty-front/src/testing/mock-data/companiesV2.ts b/packages/twenty-front/src/testing/mock-data/companiesV2.ts new file mode 100644 index 0000000000..ad19e3f4ea --- /dev/null +++ b/packages/twenty-front/src/testing/mock-data/companiesV2.ts @@ -0,0 +1,493 @@ +import { Company } from '@/companies/types/Company'; +import { Favorite } from '@/favorites/types/Favorite'; +import { WorkspaceMember } from '@/workspace-member/types/WorkspaceMember'; +import { mockedCompaniesData } from '~/testing/mock-data/companies'; + +type MockedCompanyV2 = Omit & { + accountOwner: WorkspaceMember | null; + Favorite?: Pick | null; +}; + +export const mockedCompaniesDataV2: Array = [ + { + __typename: 'Company', + domainName: 'paris.com', + name: 'Test', + employees: null, + address: 'Paris France', + createdAt: '2024-05-27T11:23:05.954Z', + id: 'd55c240e-e4e0-4248-b56d-8004d1218a9c', + position: 6.109375, + annualRecurringRevenue: { + __typename: 'Currency', + amountMicros: 1000000000, + currencyCode: 'USD', + }, + linkedinLink: { + __typename: 'Link', + label: '', + url: 'paris.com', + }, + accountOwner: { + __typename: 'WorkspaceMember', + createdAt: '2024-05-01T13:16:29.046Z', + id: '20202020-1553-45c6-a028-5a9064cce07f', + colorScheme: 'Light', + updatedAt: '2024-05-01T13:16:29.046Z', + locale: 'en', + avatarUrl: '', + userId: '20202020-7169-42cf-bc47-1cfef15264b8', + userEmail: 'phil.schiler@apple.dev', + name: { + __typename: 'FullName', + firstName: 'Phil', + lastName: 'Shiler', + }, + }, + }, + { + __typename: 'Company', + domainName: 'google.com', + name: 'Google', + employees: 10202, + address: 'Paris France', + createdAt: '2024-05-21T13:16:29.000Z', + id: '20202020-c21e-4ec2-873b-de4264d89025', + position: 7.5, + annualRecurringRevenue: { + __typename: 'Currency', + amountMicros: 1001000000, + currencyCode: 'USD', + }, + linkedinLink: { + __typename: 'Link', + label: '', + url: '', + }, + accountOwner: { + __typename: 'WorkspaceMember', + createdAt: '2024-05-01T13:16:29.046Z', + id: '20202020-0687-4c41-b707-ed1bfca972a7', + colorScheme: 'Light', + updatedAt: '2024-05-30T09:00:31.127Z', + locale: 'en', + avatarUrl: '', + userId: '20202020-9e3b-46d4-a556-88b9ddc2b034', + userEmail: 'tim@apple.dev', + name: { + __typename: 'FullName', + firstName: 'Tim', + lastName: 'Apple', + }, + }, + }, + { + __typename: 'Company', + domainName: 'hasura.io', + name: 'Hasura', + employees: 102938102938, + address: '', + createdAt: '2024-05-16T13:16:29.000Z', + id: '20202020-f86b-419f-b794-02319abe8637', + position: 10, + annualRecurringRevenue: { + __typename: 'Currency', + amountMicros: null, + currencyCode: '', + }, + linkedinLink: { + __typename: 'Link', + label: '', + url: '', + }, + accountOwner: { + __typename: 'WorkspaceMember', + createdAt: '2024-05-01T13:16:29.046Z', + id: '20202020-77d5-4cb6-b60a-f4a835a85d61', + colorScheme: 'Light', + updatedAt: '2024-05-01T13:16:29.046Z', + locale: 'en', + avatarUrl: '', + userId: '20202020-3957-4908-9c36-2929a23f8357', + userEmail: 'jony.ive@apple.dev', + name: { + __typename: 'FullName', + firstName: 'Jony', + lastName: 'Ive', + }, + }, + }, + { + __typename: 'Company', + domainName: 'netflix.com', + name: 'Netflix', + employees: null, + address: '', + createdAt: '2024-05-15T13:16:29.000Z', + id: '20202020-707e-44dc-a1d2-30030bf1a944', + position: 7, + annualRecurringRevenue: { + __typename: 'Currency', + amountMicros: 2000000000, + currencyCode: 'USD', + }, + linkedinLink: { + __typename: 'Link', + label: '', + url: '', + }, + accountOwner: { + __typename: 'WorkspaceMember', + createdAt: '2024-05-01T13:16:29.046Z', + id: '20202020-1553-45c6-a028-5a9064cce07f', + colorScheme: 'Light', + updatedAt: '2024-05-01T13:16:29.046Z', + locale: 'en', + avatarUrl: '', + userId: '20202020-7169-42cf-bc47-1cfef15264b8', + userEmail: 'phil.schiler@apple.dev', + name: { + __typename: 'FullName', + firstName: 'Phil', + lastName: 'Shiler', + }, + }, + }, + { + __typename: 'Company', + domainName: 'claap.io', + name: 'Claap', + employees: 2131920, + address: 'asdasd', + createdAt: '2024-05-10T13:16:29.000Z', + id: '20202020-cfbf-4156-a790-e39854dcd4eb', + position: 9, + annualRecurringRevenue: { + __typename: 'Currency', + amountMicros: null, + currencyCode: '', + }, + linkedinLink: { + __typename: 'Link', + label: '', + url: 'asmdlkasd', + }, + accountOwner: { + __typename: 'WorkspaceMember', + createdAt: '2024-05-01T13:16:29.046Z', + id: '20202020-0687-4c41-b707-ed1bfca972a7', + colorScheme: 'Light', + updatedAt: '2024-05-30T09:00:31.127Z', + locale: 'en', + avatarUrl: '', + userId: '20202020-9e3b-46d4-a556-88b9ddc2b034', + userEmail: 'tim@apple.dev', + name: { + __typename: 'FullName', + firstName: 'Tim', + lastName: 'Apple', + }, + }, + }, + { + __typename: 'Company', + domainName: 'libeo.io', + name: 'Libeo', + employees: 1239819238, + address: '', + createdAt: '2024-05-09T13:16:29.000Z', + id: '20202020-3f74-492d-a101-2a70f50a1645', + position: 8, + annualRecurringRevenue: { + __typename: 'Currency', + amountMicros: null, + currencyCode: '', + }, + linkedinLink: { + __typename: 'Link', + label: '', + url: '', + }, + accountOwner: { + __typename: 'WorkspaceMember', + createdAt: '2024-05-01T13:16:29.046Z', + id: '20202020-1553-45c6-a028-5a9064cce07f', + colorScheme: 'Light', + updatedAt: '2024-05-01T13:16:29.046Z', + locale: 'en', + avatarUrl: '', + userId: '20202020-7169-42cf-bc47-1cfef15264b8', + userEmail: 'phil.schiler@apple.dev', + name: { + __typename: 'FullName', + firstName: 'Phil', + lastName: 'Shiler', + }, + }, + }, + { + __typename: 'Company', + domainName: 'qonto.com', + name: 'Qonto', + employees: 123123123, + address: '', + createdAt: '2024-05-08T13:16:29.000Z', + id: '20202020-0713-40a5-8216-82802401d33e', + position: 9.5, + annualRecurringRevenue: { + __typename: 'Currency', + amountMicros: null, + currencyCode: '', + }, + linkedinLink: { + __typename: 'Link', + label: '', + url: '', + }, + accountOwner: { + __typename: 'WorkspaceMember', + createdAt: '2024-05-01T13:16:29.046Z', + id: '20202020-1553-45c6-a028-5a9064cce07f', + colorScheme: 'Light', + updatedAt: '2024-05-01T13:16:29.046Z', + locale: 'en', + avatarUrl: '', + userId: '20202020-7169-42cf-bc47-1cfef15264b8', + userEmail: 'phil.schiler@apple.dev', + name: { + __typename: 'FullName', + firstName: 'Phil', + lastName: 'Shiler', + }, + }, + }, + { + __typename: 'Company', + domainName: 'wework.com', + name: 'Wework', + employees: 123123123, + address: '', + createdAt: '2024-05-08T13:16:29.000Z', + id: '20202020-5518-4553-9433-42d8eb82834b', + position: 11, + annualRecurringRevenue: { + __typename: 'Currency', + amountMicros: null, + currencyCode: '', + }, + linkedinLink: { + __typename: 'Link', + label: '', + url: '', + }, + accountOwner: { + __typename: 'WorkspaceMember', + createdAt: '2024-05-01T13:16:29.046Z', + id: '20202020-0687-4c41-b707-ed1bfca972a7', + colorScheme: 'Light', + updatedAt: '2024-05-30T09:00:31.127Z', + locale: 'en', + avatarUrl: '', + userId: '20202020-9e3b-46d4-a556-88b9ddc2b034', + userEmail: 'tim@apple.dev', + name: { + __typename: 'FullName', + firstName: 'Tim', + lastName: 'Apple', + }, + }, + }, + { + __typename: 'Company', + domainName: 'linkedin.com', + name: 'Linkedin', + employees: 10102, + accountOwner: null, + address: '', + createdAt: '2024-05-01T13:16:29.046Z', + id: '20202020-3ec3-4fe3-8997-b76aa0bfa408', + position: 1, + annualRecurringRevenue: { + __typename: 'Currency', + amountMicros: null, + currencyCode: '', + }, + linkedinLink: { + __typename: 'Link', + label: 'adasd', + url: 'adasd', + }, + }, + { + __typename: 'Company', + domainName: 'airbnb.com', + name: 'Airbnb', + employees: 123333, + accountOwner: null, + address: '', + createdAt: '2024-05-01T13:16:29.046Z', + id: '20202020-171e-4bcc-9cf7-43448d6fb278', + position: 5, + annualRecurringRevenue: { + __typename: 'Currency', + amountMicros: null, + currencyCode: '', + }, + linkedinLink: { + __typename: 'Link', + label: '', + url: '', + }, + }, + { + __typename: 'Company', + domainName: 'samsung.com', + name: 'Samsung', + employees: 10000, + address: '', + createdAt: '2024-05-01T13:16:29.046Z', + id: '20202020-f79e-40dd-bd06-c36e6abb4678', + position: 12, + annualRecurringRevenue: { + __typename: 'Currency', + amountMicros: null, + currencyCode: '', + }, + linkedinLink: { + __typename: 'Link', + label: '', + url: '', + }, + accountOwner: { + __typename: 'WorkspaceMember', + createdAt: '2024-05-01T13:16:29.046Z', + id: '20202020-1553-45c6-a028-5a9064cce07f', + colorScheme: 'Light', + updatedAt: '2024-05-01T13:16:29.046Z', + locale: 'en', + avatarUrl: '', + userId: '20202020-7169-42cf-bc47-1cfef15264b8', + userEmail: 'phil.schiler@apple.dev', + name: { + __typename: 'FullName', + firstName: 'Phil', + lastName: 'Shiler', + }, + }, + }, + { + __typename: 'Company', + domainName: 'algolia.com', + name: 'Algolia', + employees: 10000, + address: '', + createdAt: '2024-05-01T13:16:29.046Z', + id: '20202020-1455-4c57-afaf-dd5dc086361d', + position: 13, + annualRecurringRevenue: { + __typename: 'Currency', + amountMicros: null, + currencyCode: '', + }, + linkedinLink: { + __typename: 'Link', + label: '', + url: '', + }, + accountOwner: { + __typename: 'WorkspaceMember', + createdAt: '2024-05-01T13:16:29.046Z', + id: '20202020-77d5-4cb6-b60a-f4a835a85d61', + colorScheme: 'Light', + updatedAt: '2024-05-01T13:16:29.046Z', + locale: 'en', + avatarUrl: '', + userId: '20202020-3957-4908-9c36-2929a23f8357', + userEmail: 'jony.ive@apple.dev', + name: { + __typename: 'FullName', + firstName: 'Jony', + lastName: 'Ive', + }, + }, + }, + { + __typename: 'Company', + domainName: 'facebook.com', + name: 'Facebook', + employees: 220323, + accountOwner: null, + address: '', + createdAt: '2024-05-01T13:16:29.046Z', + id: '20202020-5d81-46d6-bf83-f7fd33ea6102', + position: 6.0625, + annualRecurringRevenue: { + __typename: 'Currency', + amountMicros: null, + currencyCode: '', + }, + linkedinLink: { + __typename: 'Link', + label: '', + url: 'asdasd', + }, + }, + { + __typename: 'Company', + domainName: 'microsoft.com', + name: 'Microsoft', + employees: 10000, + address: '', + createdAt: '2024-05-01T13:16:29.046Z', + id: '20202020-ed89-413a-b31a-962986e67bb4', + position: 6.09375, + annualRecurringRevenue: { + __typename: 'Currency', + amountMicros: 10000000000, + currencyCode: 'USD', + }, + linkedinLink: { + __typename: 'Link', + label: '', + url: '', + }, + accountOwner: { + __typename: 'WorkspaceMember', + createdAt: '2024-05-01T13:16:29.046Z', + id: '20202020-0687-4c41-b707-ed1bfca972a7', + colorScheme: 'Light', + updatedAt: '2024-05-30T09:00:31.127Z', + locale: 'en', + avatarUrl: '', + userId: '20202020-9e3b-46d4-a556-88b9ddc2b034', + userEmail: 'tim@apple.dev', + name: { + __typename: 'FullName', + firstName: 'Tim', + lastName: 'Apple', + }, + }, + }, +]; + +export const mockedDuplicateCompanyData: MockedCompanyV2 = { + ...mockedCompaniesData[0], + id: '8b40856a-2ec9-4c03-8bc0-c032c89e1824', +}; + +export const mockedEmptyCompanyData = { + id: '9231e6ee-4cc2-4c7b-8c55-dff16f4d968a', + name: '', + domainName: '', + address: '', + accountOwner: null, + annualRecurringRevenue: null, + createdAt: null, + updatedAt: null, + employees: null, + idealCustomerProfile: null, + linkedinLink: null, + xLink: null, + _activityCount: null, + __typename: 'Company', +}; diff --git a/packages/twenty-front/src/testing/mock-data/generated/standard-metadata-query-result.ts b/packages/twenty-front/src/testing/mock-data/generated/standard-metadata-query-result.ts index 85c091ded4..7adbd67f30 100644 --- a/packages/twenty-front/src/testing/mock-data/generated/standard-metadata-query-result.ts +++ b/packages/twenty-front/src/testing/mock-data/generated/standard-metadata-query-result.ts @@ -13249,3 +13249,4 @@ export const mockedStandardObjectMetadataQueryResult: ObjectMetadataItemsQuery = ] as ObjectEdge[], }, } as ObjectMetadataItemsQuery; + diff --git a/packages/twenty-front/src/testing/mock-data/objectMetadataItems.ts b/packages/twenty-front/src/testing/mock-data/objectMetadataItems.ts index b0de8f389d..e49af452c5 100644 --- a/packages/twenty-front/src/testing/mock-data/objectMetadataItems.ts +++ b/packages/twenty-front/src/testing/mock-data/objectMetadataItems.ts @@ -3,6 +3,13 @@ import { FieldMetadataType, RelationMetadataType, } from '~/generated-metadata/graphql'; +import { mockedStandardObjectMetadataQueryResult } from '~/testing/mock-data/generated/standard-metadata-query-result'; + +export const generatedMockObjectMetadataItems: ObjectMetadataItem[] = + mockedStandardObjectMetadataQueryResult.objects.edges.map((edge) => ({ + ...edge.node, + fields: edge.node.fields.edges.map((edge) => edge.node), + })); export const mockObjectMetadataItem: ObjectMetadataItem = { __typename: 'object', diff --git a/packages/twenty-front/src/testing/mock-data/people.ts b/packages/twenty-front/src/testing/mock-data/people.ts index 9db0b32ead..1baec770db 100644 --- a/packages/twenty-front/src/testing/mock-data/people.ts +++ b/packages/twenty-front/src/testing/mock-data/people.ts @@ -1,11 +1,11 @@ import { Company } from '@/companies/types/Company'; import { Person } from '@/people/types/Person'; -type RequiredAndNotNull = { +export type RequiredAndNotNull = { [P in keyof T]-?: Exclude; }; -type MockedPerson = RequiredAndNotNull< +export type MockedPerson = RequiredAndNotNull< Pick< Person, | '__typename' diff --git a/packages/twenty-front/src/testing/mock-data/peopleV2.ts b/packages/twenty-front/src/testing/mock-data/peopleV2.ts new file mode 100644 index 0000000000..066910f635 --- /dev/null +++ b/packages/twenty-front/src/testing/mock-data/peopleV2.ts @@ -0,0 +1,533 @@ +import { Company } from '@/companies/types/Company'; +import { Person } from '@/people/types/Person'; + +export type MockedPersonV2 = Pick< + Person, + | '__typename' + | 'id' + | 'name' + | 'linkedinLink' + | 'xLink' + | 'links' + | 'jobTitle' + | 'email' + | 'phone' + | 'city' + | 'avatarUrl' + | 'createdAt' + | 'updatedAt' + | 'companyId' + | 'position' +> & { + company?: Company; +}; + +export const mockPeopleDataV2: MockedPersonV2[] = [ + { + __typename: 'Person', + city: 'Seattle', + jobTitle: '', + createdAt: '2024-05-01T13:16:29.046Z', + id: '20202020-1c0e-494c-a1b6-85b1c6fefaa5', + email: 'christoph.calisto@linkedin.com', + phone: '+33789012345', + position: 1, + name: { + __typename: 'FullName', + firstName: 'Christoph', + lastName: 'Callisto', + }, + linkedinLink: { __typename: 'Link', label: '', url: 'asd' }, + xLink: { __typename: 'Link', label: '', url: 'asd' }, + company: { + __typename: 'Company', + domainName: 'linkedin.com', + name: 'Linkedin', + employees: 10102, + accountOwnerId: null, + address: '', + idealCustomerProfile: false, + createdAt: '2024-05-01T13:16:29.046Z', + id: '20202020-3ec3-4fe3-8997-b76aa0bfa408', + position: 1, + updatedAt: '2024-05-23T13:21:41.159Z', + xLink: { __typename: 'Link', label: '', url: '' }, + annualRecurringRevenue: { + __typename: 'Currency', + amountMicros: null, + currencyCode: '', + }, + linkedinLink: { __typename: 'Link', label: 'adasd', url: 'adasd' }, + }, + }, + { + __typename: 'Person', + city: 'Los Angeles', + jobTitle: '@', + createdAt: '2024-05-01T13:16:29.046Z', + id: '20202020-ac73-4797-824e-87a1f5aea9e0', + email: 'sylvie.palmer@linkedin.com', + phone: '+33780123456', + position: 2, + name: { __typename: 'FullName', firstName: 'Sylvie', lastName: 'Palmer' }, + linkedinLink: { __typename: 'Link', label: '', url: '' }, + xLink: { __typename: 'Link', label: '', url: '' }, + company: { + __typename: 'Company', + domainName: 'algolia.com', + name: 'Algolia', + employees: 10000, + accountOwnerId: '20202020-77d5-4cb6-b60a-f4a835a85d61', + address: '', + idealCustomerProfile: false, + createdAt: '2024-05-01T13:16:29.046Z', + id: '20202020-1455-4c57-afaf-dd5dc086361d', + position: 13, + updatedAt: '2024-05-28T15:52:31.839Z', + xLink: { __typename: 'Link', label: '', url: '' }, + annualRecurringRevenue: { + __typename: 'Currency', + amountMicros: null, + currencyCode: '', + }, + linkedinLink: { __typename: 'Link', label: '', url: '' }, + }, + }, + { + __typename: 'Person', + city: 'Seattle', + jobTitle: '', + createdAt: '2024-05-01T13:16:29.046Z', + id: '20202020-f517-42fd-80ae-14173b3b70ae', + email: 'christopher.gonzalez@qonto.com', + phone: '+33789012345', + position: 3, + name: { + __typename: 'FullName', + firstName: 'Christopher', + lastName: 'Gonzalez', + }, + linkedinLink: { __typename: 'Link', label: '', url: '' }, + xLink: { __typename: 'Link', label: '', url: '' }, + company: { + __typename: 'Company', + domainName: 'qonto.com', + name: 'Qonto', + employees: 123123123, + accountOwnerId: '20202020-1553-45c6-a028-5a9064cce07f', + address: '', + idealCustomerProfile: false, + createdAt: '2024-05-08T13:16:29.000Z', + id: '20202020-0713-40a5-8216-82802401d33e', + position: 9.5, + updatedAt: '2024-05-28T15:52:46.961Z', + xLink: { __typename: 'Link', label: '', url: '' }, + annualRecurringRevenue: { + __typename: 'Currency', + amountMicros: null, + currencyCode: '', + }, + linkedinLink: { __typename: 'Link', label: '', url: '' }, + }, + }, + { + __typename: 'Person', + city: 'Los Angeles', + jobTitle: '', + createdAt: '2024-05-01T13:16:29.046Z', + id: '20202020-eee1-4690-ad2c-8619e5b56a2e', + email: 'ashley.parker@qonto.com', + phone: '+33780123456', + position: 4, + name: { __typename: 'FullName', firstName: 'Ashley', lastName: 'Parker' }, + linkedinLink: { __typename: 'Link', label: '', url: '' }, + xLink: { __typename: 'Link', label: '', url: '' }, + company: { + __typename: 'Company', + domainName: 'qonto.com', + name: 'Qonto', + employees: 123123123, + accountOwnerId: '20202020-1553-45c6-a028-5a9064cce07f', + address: '', + idealCustomerProfile: false, + createdAt: '2024-05-08T13:16:29.000Z', + id: '20202020-0713-40a5-8216-82802401d33e', + position: 9.5, + updatedAt: '2024-05-28T15:52:46.961Z', + xLink: { __typename: 'Link', label: '', url: '' }, + annualRecurringRevenue: { + __typename: 'Currency', + amountMicros: null, + currencyCode: '', + }, + linkedinLink: { __typename: 'Link', label: '', url: '' }, + }, + }, + { + __typename: 'Person', + city: 'Seattle', + jobTitle: '', + createdAt: '2024-05-01T13:16:29.046Z', + id: '20202020-6784-4449-afdf-dc62cb8702f2', + email: 'nicholas.wright@microsoft.com', + phone: '+33781234567', + position: 5, + name: { __typename: 'FullName', firstName: 'Nicholas', lastName: 'Wright' }, + linkedinLink: { __typename: 'Link', label: '', url: '' }, + xLink: { __typename: 'Link', label: '', url: '' }, + company: { + __typename: 'Company', + domainName: 'microsoft.com', + name: 'Microsoft', + employees: 10000, + accountOwnerId: '20202020-0687-4c41-b707-ed1bfca972a7', + address: '', + idealCustomerProfile: false, + createdAt: '2024-05-01T13:16:29.046Z', + id: '20202020-ed89-413a-b31a-962986e67bb4', + position: 6.09375, + updatedAt: '2024-05-28T15:52:35.621Z', + xLink: { __typename: 'Link', label: '', url: '' }, + annualRecurringRevenue: { + __typename: 'Currency', + amountMicros: 10000000000, + currencyCode: 'USD', + }, + linkedinLink: { __typename: 'Link', label: '', url: '' }, + }, + }, + { + __typename: 'Person', + city: 'New York', + jobTitle: '', + createdAt: '2024-05-01T13:16:29.046Z', + id: '20202020-490f-4466-8391-733cfd66a0c8', + email: 'isabella.scott@microsoft.com', + phone: '+33782345678', + position: 6, + name: { __typename: 'FullName', firstName: 'Isabella', lastName: 'Scott' }, + linkedinLink: { __typename: 'Link', label: '', url: '' }, + xLink: { __typename: 'Link', label: '', url: '' }, + company: { + __typename: 'Company', + domainName: 'microsoft.com', + name: 'Microsoft', + employees: 10000, + accountOwnerId: '20202020-0687-4c41-b707-ed1bfca972a7', + address: '', + idealCustomerProfile: false, + createdAt: '2024-05-01T13:16:29.046Z', + id: '20202020-ed89-413a-b31a-962986e67bb4', + position: 6.09375, + updatedAt: '2024-05-28T15:52:35.621Z', + xLink: { __typename: 'Link', label: '', url: '' }, + annualRecurringRevenue: { + __typename: 'Currency', + amountMicros: 10000000000, + currencyCode: 'USD', + }, + linkedinLink: { __typename: 'Link', label: '', url: '' }, + }, + }, + { + __typename: 'Person', + city: 'Seattle', + jobTitle: '', + createdAt: '2024-05-01T13:16:29.046Z', + id: '20202020-80f1-4dff-b570-a74942528de3', + email: 'matthew.green@microsoft.com', + phone: '+33783456789', + position: 7, + name: { __typename: 'FullName', firstName: 'Matthew', lastName: 'Green' }, + linkedinLink: { __typename: 'Link', label: '', url: '' }, + xLink: { __typename: 'Link', label: '', url: '' }, + company: { + __typename: 'Company', + domainName: 'microsoft.com', + name: 'Microsoft', + employees: 10000, + accountOwnerId: '20202020-0687-4c41-b707-ed1bfca972a7', + address: '', + idealCustomerProfile: false, + createdAt: '2024-05-01T13:16:29.046Z', + id: '20202020-ed89-413a-b31a-962986e67bb4', + position: 6.09375, + updatedAt: '2024-05-28T15:52:35.621Z', + xLink: { __typename: 'Link', label: '', url: '' }, + annualRecurringRevenue: { + __typename: 'Currency', + amountMicros: 10000000000, + currencyCode: 'USD', + }, + linkedinLink: { __typename: 'Link', label: '', url: '' }, + }, + }, + { + __typename: 'Person', + city: 'New York', + jobTitle: '', + createdAt: '2024-05-01T13:16:29.046Z', + id: '20202020-338b-46df-8811-fa08c7d19d35', + email: 'elizabeth.baker@airbnb.com', + phone: '+33784567890', + position: 8, + name: { __typename: 'FullName', firstName: 'Elizabeth', lastName: 'Baker' }, + linkedinLink: { __typename: 'Link', label: '', url: '' }, + xLink: { __typename: 'Link', label: '', url: '' }, + company: { + __typename: 'Company', + domainName: 'airbnb.com', + name: 'Airbnb', + employees: 123333, + accountOwnerId: null, + address: '', + idealCustomerProfile: false, + createdAt: '2024-05-01T13:16:29.046Z', + id: '20202020-171e-4bcc-9cf7-43448d6fb278', + position: 5, + updatedAt: '2024-05-28T15:52:27.902Z', + xLink: { __typename: 'Link', label: '', url: '' }, + annualRecurringRevenue: { + __typename: 'Currency', + amountMicros: null, + currencyCode: '', + }, + linkedinLink: { __typename: 'Link', label: '', url: '' }, + }, + }, + { + __typename: 'Person', + city: 'San Francisco', + jobTitle: '', + createdAt: '2024-05-01T13:16:29.046Z', + id: '20202020-64ad-4b0e-bbfd-e9fd795b7016', + email: 'christopher.nelson@airbnb.com', + phone: '+33785678901', + position: 9, + name: { + __typename: 'FullName', + firstName: 'Christopher', + lastName: 'Nelson', + }, + linkedinLink: { __typename: 'Link', label: '', url: '' }, + xLink: { __typename: 'Link', label: '', url: '' }, + company: { + __typename: 'Company', + domainName: 'airbnb.com', + name: 'Airbnb', + employees: 123333, + accountOwnerId: null, + address: '', + idealCustomerProfile: false, + createdAt: '2024-05-01T13:16:29.046Z', + id: '20202020-171e-4bcc-9cf7-43448d6fb278', + position: 5, + updatedAt: '2024-05-28T15:52:27.902Z', + xLink: { __typename: 'Link', label: '', url: '' }, + annualRecurringRevenue: { + __typename: 'Currency', + amountMicros: null, + currencyCode: '', + }, + linkedinLink: { __typename: 'Link', label: '', url: '' }, + }, + }, + { + __typename: 'Person', + city: 'New York', + jobTitle: '', + createdAt: '2024-05-01T13:16:29.046Z', + id: '20202020-5d54-41b7-ba36-f0d20e1417ae', + email: 'avery.carter@airbnb.com', + phone: '+33786789012', + position: 10, + name: { __typename: 'FullName', firstName: 'Avery', lastName: 'Carter' }, + linkedinLink: { __typename: 'Link', label: '', url: '' }, + xLink: { __typename: 'Link', label: '', url: '' }, + company: { + __typename: 'Company', + domainName: 'airbnb.com', + name: 'Airbnb', + employees: 123333, + accountOwnerId: null, + address: '', + idealCustomerProfile: false, + createdAt: '2024-05-01T13:16:29.046Z', + id: '20202020-171e-4bcc-9cf7-43448d6fb278', + position: 5, + updatedAt: '2024-05-28T15:52:27.902Z', + xLink: { __typename: 'Link', label: '', url: '' }, + annualRecurringRevenue: { + __typename: 'Currency', + amountMicros: null, + currencyCode: '', + }, + linkedinLink: { __typename: 'Link', label: '', url: '' }, + }, + }, + { + __typename: 'Person', + city: 'Los Angeles', + jobTitle: '', + createdAt: '2024-05-01T13:16:29.046Z', + id: '20202020-623d-41fe-92e7-dd45b7c568e1', + email: 'ethan.mitchell@google.com', + phone: '+33787890123', + position: 11, + name: { __typename: 'FullName', firstName: 'Ethan', lastName: 'Mitchell' }, + linkedinLink: { __typename: 'Link', label: '', url: '' }, + xLink: { __typename: 'Link', label: '', url: '' }, + company: { + __typename: 'Company', + domainName: 'google.com', + name: 'Google', + employees: 10202, + accountOwnerId: '20202020-0687-4c41-b707-ed1bfca972a7', + address: 'Paris France', + idealCustomerProfile: false, + createdAt: '2024-05-21T13:16:29.000Z', + id: '20202020-c21e-4ec2-873b-de4264d89025', + position: 7.5, + updatedAt: '2024-05-28T15:53:28.838Z', + xLink: { __typename: 'Link', label: '', url: '' }, + annualRecurringRevenue: { + __typename: 'Currency', + amountMicros: 1001000000, + currencyCode: 'USD', + }, + linkedinLink: { __typename: 'Link', label: '', url: '' }, + }, + }, + { + __typename: 'Person', + city: 'Seattle', + jobTitle: '', + createdAt: '2024-05-01T13:16:29.046Z', + id: '20202020-2d40-4e49-8df4-9c6a049190ef', + email: 'madison.perez@google.com', + phone: '+33788901234', + position: 12, + name: { __typename: 'FullName', firstName: 'Madison', lastName: 'Perez' }, + linkedinLink: { __typename: 'Link', label: '', url: '' }, + xLink: { __typename: 'Link', label: '', url: '' }, + company: { + __typename: 'Company', + domainName: 'google.com', + name: 'Google', + employees: 10202, + accountOwnerId: '20202020-0687-4c41-b707-ed1bfca972a7', + address: 'Paris France', + idealCustomerProfile: false, + createdAt: '2024-05-21T13:16:29.000Z', + id: '20202020-c21e-4ec2-873b-de4264d89025', + position: 7.5, + updatedAt: '2024-05-28T15:53:28.838Z', + xLink: { __typename: 'Link', label: '', url: '' }, + annualRecurringRevenue: { + __typename: 'Currency', + amountMicros: 1001000000, + currencyCode: 'USD', + }, + linkedinLink: { __typename: 'Link', label: '', url: '' }, + }, + }, + { + __typename: 'Person', + city: 'Seattle', + jobTitle: '', + createdAt: '2024-05-01T13:16:29.046Z', + id: '20202020-2d40-4e49-8df4-9c6a049190df', + email: 'bertrand.voulzy@google.com', + phone: '+33788901234', + position: 13, + name: { __typename: 'FullName', firstName: 'Bertrand', lastName: 'Voulzy' }, + linkedinLink: { __typename: 'Link', label: '', url: '' }, + xLink: { __typename: 'Link', label: '', url: '' }, + company: { + __typename: 'Company', + domainName: 'google.com', + name: 'Google', + employees: 10202, + accountOwnerId: '20202020-0687-4c41-b707-ed1bfca972a7', + address: 'Paris France', + idealCustomerProfile: false, + createdAt: '2024-05-21T13:16:29.000Z', + id: '20202020-c21e-4ec2-873b-de4264d89025', + position: 7.5, + updatedAt: '2024-05-28T15:53:28.838Z', + xLink: { __typename: 'Link', label: '', url: '' }, + annualRecurringRevenue: { + __typename: 'Currency', + amountMicros: 1001000000, + currencyCode: 'USD', + }, + linkedinLink: { __typename: 'Link', label: '', url: '' }, + }, + }, + { + __typename: 'Person', + city: 'Seattle', + jobTitle: '', + createdAt: '2024-05-01T13:16:29.046Z', + id: '20202020-2d40-4e49-8df4-9c6a049191de', + email: 'louis.duss@google.com', + phone: '+33788901234', + position: 14, + name: { __typename: 'FullName', firstName: 'Louis', lastName: 'Duss' }, + linkedinLink: { __typename: 'Link', label: '', url: '' }, + xLink: { __typename: 'Link', label: '', url: '' }, + company: { + __typename: 'Company', + domainName: 'google.com', + name: 'Google', + employees: 10202, + accountOwnerId: '20202020-0687-4c41-b707-ed1bfca972a7', + address: 'Paris France', + idealCustomerProfile: false, + createdAt: '2024-05-21T13:16:29.000Z', + id: '20202020-c21e-4ec2-873b-de4264d89025', + position: 7.5, + updatedAt: '2024-05-28T15:53:28.838Z', + xLink: { __typename: 'Link', label: '', url: '' }, + annualRecurringRevenue: { + __typename: 'Currency', + amountMicros: 1001000000, + currencyCode: 'USD', + }, + linkedinLink: { __typename: 'Link', label: '', url: '' }, + }, + }, + { + __typename: 'Person', + city: 'Seattle', + jobTitle: '', + createdAt: '2024-05-01T13:16:29.046Z', + id: '20202020-2d40-4e49-8df4-9c6a049191df', + email: 'lorie.vladim@google.com', + phone: '+33788901235', + position: 15, + name: { __typename: 'FullName', firstName: 'Lorie', lastName: 'Vladim' }, + linkedinLink: { __typename: 'Link', label: '', url: '' }, + xLink: { __typename: 'Link', label: '', url: '' }, + company: { + __typename: 'Company', + domainName: 'google.com', + name: 'Google', + employees: 10202, + accountOwnerId: '20202020-0687-4c41-b707-ed1bfca972a7', + address: 'Paris France', + idealCustomerProfile: false, + createdAt: '2024-05-21T13:16:29.000Z', + id: '20202020-c21e-4ec2-873b-de4264d89025', + position: 7.5, + updatedAt: '2024-05-28T15:53:28.838Z', + xLink: { __typename: 'Link', label: '', url: '' }, + annualRecurringRevenue: { + __typename: 'Currency', + amountMicros: 1001000000, + currencyCode: 'USD', + }, + linkedinLink: { __typename: 'Link', label: '', url: '' }, + }, + }, +]; diff --git a/packages/twenty-front/vite.config.ts b/packages/twenty-front/vite.config.ts index 67dd65707a..b38c80ebcb 100644 --- a/packages/twenty-front/vite.config.ts +++ b/packages/twenty-front/vite.config.ts @@ -1,4 +1,5 @@ import react from '@vitejs/plugin-react-swc'; +import wyw from '@wyw-in-js/vite'; import path from 'path'; import { defineConfig, loadEnv } from 'vite'; import checker from 'vite-plugin-checker'; @@ -48,6 +49,12 @@ export default defineConfig(({ command, mode }) => { }), svgr(), checker(checkers), + wyw({ + include: ['**/EllipsisDisplay.tsx', '**/ContactLink.tsx'], + babelOptions: { + presets: ['@babel/preset-typescript', '@babel/preset-react'], + }, + }), ], build: { diff --git a/yarn.lock b/yarn.lock index 36d34c38e6..a95b93a370 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1516,6 +1516,16 @@ __metadata: languageName: node linkType: hard +"@babel/code-frame@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/code-frame@npm:7.24.6" + dependencies: + "@babel/highlight": "npm:^7.24.6" + picocolors: "npm:^1.0.0" + checksum: c93c6d1763530f415218c31d07359364397f19b70026abdff766164c21ed352a931cf07f3102c5fb9e04792de319e332d68bcb1f7debef601a02197f90f9ba24 + languageName: node + linkType: hard + "@babel/compat-data@npm:^7.20.5, @babel/compat-data@npm:^7.22.6, @babel/compat-data@npm:^7.23.3, @babel/compat-data@npm:^7.23.5": version: 7.23.5 resolution: "@babel/compat-data@npm:7.23.5" @@ -1648,6 +1658,15 @@ __metadata: languageName: node linkType: hard +"@babel/helper-annotate-as-pure@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/helper-annotate-as-pure@npm:7.24.6" + dependencies: + "@babel/types": "npm:^7.24.6" + checksum: 3fe446e3bd37e5e32152279c84ace4e83815e5b88b9e09a82a83974a0bb22e941d89db26b23aaab4c9eb0f9713772c2f6163feffc1bcb055c4cdb6b67e5dc82f + languageName: node + linkType: hard + "@babel/helper-builder-binary-assignment-operator-visitor@npm:^7.22.15": version: 7.22.15 resolution: "@babel/helper-builder-binary-assignment-operator-visitor@npm:7.22.15" @@ -1708,6 +1727,25 @@ __metadata: languageName: node linkType: hard +"@babel/helper-create-class-features-plugin@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/helper-create-class-features-plugin@npm:7.24.6" + dependencies: + "@babel/helper-annotate-as-pure": "npm:^7.24.6" + "@babel/helper-environment-visitor": "npm:^7.24.6" + "@babel/helper-function-name": "npm:^7.24.6" + "@babel/helper-member-expression-to-functions": "npm:^7.24.6" + "@babel/helper-optimise-call-expression": "npm:^7.24.6" + "@babel/helper-replace-supers": "npm:^7.24.6" + "@babel/helper-skip-transparent-expression-wrappers": "npm:^7.24.6" + "@babel/helper-split-export-declaration": "npm:^7.24.6" + semver: "npm:^6.3.1" + peerDependencies: + "@babel/core": ^7.0.0 + checksum: e6734671bc6a5f3cca4ec46e4cc70238e5a2fa063e51225c2be572f157119002af419b33ea0f846dbb1307370fe9f3aa92d199449abbea5e88e0262513c8a821 + languageName: node + linkType: hard + "@babel/helper-create-regexp-features-plugin@npm:^7.18.6, @babel/helper-create-regexp-features-plugin@npm:^7.22.15, @babel/helper-create-regexp-features-plugin@npm:^7.22.5": version: 7.22.15 resolution: "@babel/helper-create-regexp-features-plugin@npm:7.22.15" @@ -1773,6 +1811,13 @@ __metadata: languageName: node linkType: hard +"@babel/helper-environment-visitor@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/helper-environment-visitor@npm:7.24.6" + checksum: fdcd18ac505ed71f40c05cc992b648a4495b0aa5310a774492a0f74d8dcf3579691102f516561a651d3de6c3a44fe64bfb3049d11c14c5857634ef1823ea409a + languageName: node + linkType: hard + "@babel/helper-function-name@npm:^7.22.5, @babel/helper-function-name@npm:^7.23.0": version: 7.23.0 resolution: "@babel/helper-function-name@npm:7.23.0" @@ -1783,6 +1828,16 @@ __metadata: languageName: node linkType: hard +"@babel/helper-function-name@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/helper-function-name@npm:7.24.6" + dependencies: + "@babel/template": "npm:^7.24.6" + "@babel/types": "npm:^7.24.6" + checksum: 5ba2f8db789b3f5a2b2239300a217aa212e303cd7bfad9c8b90563807f49215e8c679e8f8f177b6aaca2038038e29bc702b83839e1f7b4896d79c44a75cac97a + languageName: node + linkType: hard + "@babel/helper-hoist-variables@npm:^7.22.5": version: 7.22.5 resolution: "@babel/helper-hoist-variables@npm:7.22.5" @@ -1801,6 +1856,15 @@ __metadata: languageName: node linkType: hard +"@babel/helper-member-expression-to-functions@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/helper-member-expression-to-functions@npm:7.24.6" + dependencies: + "@babel/types": "npm:^7.24.6" + checksum: 7595f62978f55921b24de6ed5252fcedbffacfb8271f71e092f38724179ba554cb3a24a4764a1a3890b8a53504c2bee9c99eab81f1f365582739f566c8e28eaa + languageName: node + linkType: hard + "@babel/helper-module-imports@npm:^7.16.7, @babel/helper-module-imports@npm:^7.22.15": version: 7.22.15 resolution: "@babel/helper-module-imports@npm:7.22.15" @@ -1810,6 +1874,15 @@ __metadata: languageName: node linkType: hard +"@babel/helper-module-imports@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/helper-module-imports@npm:7.24.6" + dependencies: + "@babel/types": "npm:^7.24.6" + checksum: e0db3fbfcd963d138f0792ff626f940a576fcf212d02b8fe6478dccf3421bd1c2a76f8e69c7450c049985e7b63b30be309a24eeeb6ad7c2137a31b676a095a84 + languageName: node + linkType: hard + "@babel/helper-module-transforms@npm:^7.23.3": version: 7.23.3 resolution: "@babel/helper-module-transforms@npm:7.23.3" @@ -1825,6 +1898,21 @@ __metadata: languageName: node linkType: hard +"@babel/helper-module-transforms@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/helper-module-transforms@npm:7.24.6" + dependencies: + "@babel/helper-environment-visitor": "npm:^7.24.6" + "@babel/helper-module-imports": "npm:^7.24.6" + "@babel/helper-simple-access": "npm:^7.24.6" + "@babel/helper-split-export-declaration": "npm:^7.24.6" + "@babel/helper-validator-identifier": "npm:^7.24.6" + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 9e2e3d0ddb397b36b9e8c7d94e175a36be8cb888ef370cefef2cdfd53ae1f87d567b268bd90ed9a6c706485a8de3da19cac577657613e9cd17210b91cbdfb00b + languageName: node + linkType: hard + "@babel/helper-optimise-call-expression@npm:^7.22.5": version: 7.22.5 resolution: "@babel/helper-optimise-call-expression@npm:7.22.5" @@ -1834,6 +1922,15 @@ __metadata: languageName: node linkType: hard +"@babel/helper-optimise-call-expression@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/helper-optimise-call-expression@npm:7.24.6" + dependencies: + "@babel/types": "npm:^7.24.6" + checksum: 7fce2c4ce22c4ba3c2178d1ce85f34fc9bbe286af5ec153b4b6ea9bf2212390359c4a1e8a54551c4daa4688022d619668bdb8c8060cb185c0c9ad02c5247efc9 + languageName: node + linkType: hard + "@babel/helper-plugin-utils@npm:^7.0.0, @babel/helper-plugin-utils@npm:^7.10.4, @babel/helper-plugin-utils@npm:^7.12.13, @babel/helper-plugin-utils@npm:^7.14.5, @babel/helper-plugin-utils@npm:^7.18.6, @babel/helper-plugin-utils@npm:^7.20.2, @babel/helper-plugin-utils@npm:^7.22.5, @babel/helper-plugin-utils@npm:^7.8.0, @babel/helper-plugin-utils@npm:^7.8.3": version: 7.22.5 resolution: "@babel/helper-plugin-utils@npm:7.22.5" @@ -1848,6 +1945,13 @@ __metadata: languageName: node linkType: hard +"@babel/helper-plugin-utils@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/helper-plugin-utils@npm:7.24.6" + checksum: 636d3ce8cabc0621c1f78187e1d95f1087209921fa452f76aad06224ef5dffb3d934946f5183109920f32a4b94dd75ac91c63bc52813fee639d10cd54d49ba1f + languageName: node + linkType: hard + "@babel/helper-remap-async-to-generator@npm:^7.22.20": version: 7.22.20 resolution: "@babel/helper-remap-async-to-generator@npm:7.22.20" @@ -1874,6 +1978,19 @@ __metadata: languageName: node linkType: hard +"@babel/helper-replace-supers@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/helper-replace-supers@npm:7.24.6" + dependencies: + "@babel/helper-environment-visitor": "npm:^7.24.6" + "@babel/helper-member-expression-to-functions": "npm:^7.24.6" + "@babel/helper-optimise-call-expression": "npm:^7.24.6" + peerDependencies: + "@babel/core": ^7.0.0 + checksum: aaf2dfaf25360da1525ecea5979d5afed201b96f0feeed2e15f90883a97776132a720b25039e67fee10a5c537363aea5cc2a46c0f1d13fdb86d0e920244f2da7 + languageName: node + linkType: hard + "@babel/helper-simple-access@npm:^7.22.5": version: 7.22.5 resolution: "@babel/helper-simple-access@npm:7.22.5" @@ -1883,6 +2000,15 @@ __metadata: languageName: node linkType: hard +"@babel/helper-simple-access@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/helper-simple-access@npm:7.24.6" + dependencies: + "@babel/types": "npm:^7.24.6" + checksum: b17e404dd6c9787fc7d558aea5222471a77e29596705f0d10b4c2a58b9d71ff7eae915094204848cc1af99b771553caa69337a768b9abdd82b54a0050ba83eb9 + languageName: node + linkType: hard + "@babel/helper-skip-transparent-expression-wrappers@npm:^7.20.0, @babel/helper-skip-transparent-expression-wrappers@npm:^7.22.5": version: 7.22.5 resolution: "@babel/helper-skip-transparent-expression-wrappers@npm:7.22.5" @@ -1892,6 +2018,15 @@ __metadata: languageName: node linkType: hard +"@babel/helper-skip-transparent-expression-wrappers@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/helper-skip-transparent-expression-wrappers@npm:7.24.6" + dependencies: + "@babel/types": "npm:^7.24.6" + checksum: 6928f698362d6082a67ee2bc73991ef6b0cc6b5f2854177389bc8f3c09296580f0ee20134dd1a29dfcb1906ad9e346fa0f7c6fcd7589ab3ff176d4f09504577f + languageName: node + linkType: hard + "@babel/helper-split-export-declaration@npm:^7.22.6": version: 7.22.6 resolution: "@babel/helper-split-export-declaration@npm:7.22.6" @@ -1901,6 +2036,15 @@ __metadata: languageName: node linkType: hard +"@babel/helper-split-export-declaration@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/helper-split-export-declaration@npm:7.24.6" + dependencies: + "@babel/types": "npm:^7.24.6" + checksum: 53a5dd8691fdffc89cc7fcf5aed0ad1d8bc39796a5782a3d170dcbf249eb5c15cc8a290e8d09615711d18798ad04a7d0694ab5195d35fa651abbc1b9c885d6a8 + languageName: node + linkType: hard + "@babel/helper-string-parser@npm:^7.23.4": version: 7.23.4 resolution: "@babel/helper-string-parser@npm:7.23.4" @@ -1908,6 +2052,13 @@ __metadata: languageName: node linkType: hard +"@babel/helper-string-parser@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/helper-string-parser@npm:7.24.6" + checksum: 95115bf676e92c4e99166395649108d97447e6cabef1fabaec8cdbc53a43f27b5df2268ff6534439d405bc1bd06685b163eb3b470455bd49f69159dada414145 + languageName: node + linkType: hard + "@babel/helper-validator-identifier@npm:^7.22.20": version: 7.22.20 resolution: "@babel/helper-validator-identifier@npm:7.22.20" @@ -1915,6 +2066,13 @@ __metadata: languageName: node linkType: hard +"@babel/helper-validator-identifier@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/helper-validator-identifier@npm:7.24.6" + checksum: d29d2e3fca66c31867a009014169b93f7bc21c8fc1dd7d0b9d85d7a4000670526ff2222d966febb75a6e12f9859a31d1e75b558984e28ecb69651314dd0a6fd1 + languageName: node + linkType: hard + "@babel/helper-validator-option@npm:^7.22.15, @babel/helper-validator-option@npm:^7.23.5": version: 7.23.5 resolution: "@babel/helper-validator-option@npm:7.23.5" @@ -1922,6 +2080,13 @@ __metadata: languageName: node linkType: hard +"@babel/helper-validator-option@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/helper-validator-option@npm:7.24.6" + checksum: 787268dff5cf77f3b704454b96ab7b58aa4f43b2808247e51859a103a1c28a9c252100f830433f4b37a73f4a61ba745bbeef4cdccbab48c1e9adf037f4ca3491 + languageName: node + linkType: hard + "@babel/helper-wrap-function@npm:^7.22.20": version: 7.22.20 resolution: "@babel/helper-wrap-function@npm:7.22.20" @@ -1988,6 +2153,18 @@ __metadata: languageName: node linkType: hard +"@babel/highlight@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/highlight@npm:7.24.6" + dependencies: + "@babel/helper-validator-identifier": "npm:^7.24.6" + chalk: "npm:^2.4.2" + js-tokens: "npm:^4.0.0" + picocolors: "npm:^1.0.0" + checksum: 5bbc31695e5d44e97feb267f7aaf4c52908560d184ffeb2e2e57aae058d40125592931883889413e19def3326895ddb41ff45e090fa90b459d8c294b4ffc238c + languageName: node + linkType: hard + "@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.14.0, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.16.8, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.22.15, @babel/parser@npm:^7.22.7, @babel/parser@npm:^7.23.0, @babel/parser@npm:^7.23.5": version: 7.23.5 resolution: "@babel/parser@npm:7.23.5" @@ -2015,6 +2192,15 @@ __metadata: languageName: node linkType: hard +"@babel/parser@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/parser@npm:7.24.6" + bin: + parser: ./bin/babel-parser.js + checksum: cbef70923078a20fe163b03f4a6482be65ed99d409a57f3091a23ce3a575ee75716c30e7ea9f40b692ac5660f34055f4cbeb66a354fad15a6cf1fca35c3496c5 + languageName: node + linkType: hard + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@npm:^7.23.3": version: 7.23.3 resolution: "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@npm:7.23.3" @@ -2268,6 +2454,17 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-syntax-jsx@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/plugin-syntax-jsx@npm:7.24.6" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.24.6" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: f00d783a9e2d52f0a8797823a3cbdbe2d0dc09c7235fe8c88e6dce3a02f234f52fb5e976a001cc30b0e2b330590b5680f54436e56d67f9ab05d1e4bdeb3992cd + languageName: node + linkType: hard + "@babel/plugin-syntax-logical-assignment-operators@npm:^7.10.4, @babel/plugin-syntax-logical-assignment-operators@npm:^7.8.3": version: 7.10.4 resolution: "@babel/plugin-syntax-logical-assignment-operators@npm:7.10.4" @@ -2367,6 +2564,17 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-syntax-typescript@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/plugin-syntax-typescript@npm:7.24.6" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.24.6" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: b1eeabf8bebfa78cea559c0a0d55e480fe2ebd799472d1f6bd5afbd2759d02b362d29ad30009c81d5b112797beb987e58a3000d2331adaa4bf03862e1ed18cef + languageName: node + linkType: hard + "@babel/plugin-syntax-unicode-sets-regex@npm:^7.18.6": version: 7.18.6 resolution: "@babel/plugin-syntax-unicode-sets-regex@npm:7.18.6" @@ -2691,6 +2899,19 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-modules-commonjs@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/plugin-transform-modules-commonjs@npm:7.24.6" + dependencies: + "@babel/helper-module-transforms": "npm:^7.24.6" + "@babel/helper-plugin-utils": "npm:^7.24.6" + "@babel/helper-simple-access": "npm:^7.24.6" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 4fc790136d066105fa773ffc7e249d88c6f0d0126984ede36fedd51ac2b622b46c08565bcdd1ab62ac10195eeedeaba0d26e7e4c676ed50906cbed16540a4e22 + languageName: node + linkType: hard + "@babel/plugin-transform-modules-systemjs@npm:^7.23.3": version: 7.23.3 resolution: "@babel/plugin-transform-modules-systemjs@npm:7.23.3" @@ -3071,6 +3292,20 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-typescript@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/plugin-transform-typescript@npm:7.24.6" + dependencies: + "@babel/helper-annotate-as-pure": "npm:^7.24.6" + "@babel/helper-create-class-features-plugin": "npm:^7.24.6" + "@babel/helper-plugin-utils": "npm:^7.24.6" + "@babel/plugin-syntax-typescript": "npm:^7.24.6" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 46b054e4d4253187403e392ef30f4dd624d8486a1992703f5ff1b415d4e8d00f474e35fb77bc7a3a16a17330873cadcd5af4a8493c61b16da2dde212b2788ccd + languageName: node + linkType: hard + "@babel/plugin-transform-unicode-escapes@npm:^7.23.3": version: 7.23.3 resolution: "@babel/plugin-transform-unicode-escapes@npm:7.23.3" @@ -3355,6 +3590,21 @@ __metadata: languageName: node linkType: hard +"@babel/preset-typescript@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/preset-typescript@npm:7.24.6" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.24.6" + "@babel/helper-validator-option": "npm:^7.24.6" + "@babel/plugin-syntax-jsx": "npm:^7.24.6" + "@babel/plugin-transform-modules-commonjs": "npm:^7.24.6" + "@babel/plugin-transform-typescript": "npm:^7.24.6" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: bfcef91ed80d67301301e17a799814457b57bfd0d85d9897dce6df6ed0b0af155c0f5b2af7a1a122a3f36faaaa1de87ccf9954ce06d2f440898ffdfaf18aab86 + languageName: node + linkType: hard + "@babel/register@npm:^7.13.16, @babel/register@npm:^7.22.15": version: 7.23.7 resolution: "@babel/register@npm:7.23.7" @@ -3446,6 +3696,17 @@ __metadata: languageName: node linkType: hard +"@babel/template@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/template@npm:7.24.6" + dependencies: + "@babel/code-frame": "npm:^7.24.6" + "@babel/parser": "npm:^7.24.6" + "@babel/types": "npm:^7.24.6" + checksum: a4d5805770de908b445f7cdcebfcb6eaa07b1ec9c7b78fd3f375a911b1522c249bddae6b96bc4aac24247cc603e3e6cffcf2fe50b4c929dfeb22de289b517525 + languageName: node + linkType: hard + "@babel/traverse@npm:^7.14.0, @babel/traverse@npm:^7.16.8, @babel/traverse@npm:^7.18.9, @babel/traverse@npm:^7.22.8, @babel/traverse@npm:^7.23.2, @babel/traverse@npm:^7.23.5": version: 7.23.5 resolution: "@babel/traverse@npm:7.23.5" @@ -3551,6 +3812,17 @@ __metadata: languageName: node linkType: hard +"@babel/types@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/types@npm:7.24.6" + dependencies: + "@babel/helper-string-parser": "npm:^7.24.6" + "@babel/helper-validator-identifier": "npm:^7.24.6" + to-fast-properties: "npm:^2.0.0" + checksum: 1d94d92d97ef49030ad7f9e14cfccfeb70b1706dabcaa69037e659ec9d2c3178fb005d2088cce40d88dfc1306153d9157fe038a79ea2be92e5e6b99a59ef80cc + languageName: node + linkType: hard + "@base2/pretty-print-object@npm:1.0.1": version: 1.0.1 resolution: "@base2/pretty-print-object@npm:1.0.1" @@ -4760,6 +5032,15 @@ __metadata: languageName: node linkType: hard +"@emotion/is-prop-valid@npm:^1.2.0": + version: 1.2.2 + resolution: "@emotion/is-prop-valid@npm:1.2.2" + dependencies: + "@emotion/memoize": "npm:^0.8.1" + checksum: bb1530dcb4e0e5a4fabb219279f2d0bc35796baf66f6241f98b0d03db1985c890a8cafbea268e0edefd5eeda143dbd5c09a54b5fba74cee8c69b98b13194af50 + languageName: node + linkType: hard + "@emotion/is-prop-valid@npm:^1.2.1": version: 1.2.1 resolution: "@emotion/is-prop-valid@npm:1.2.1" @@ -7479,6 +7760,33 @@ __metadata: languageName: node linkType: hard +"@linaria/core@npm:^6.2.0": + version: 6.2.0 + resolution: "@linaria/core@npm:6.2.0" + dependencies: + "@wyw-in-js/processor-utils": "npm:^0.5.3" + checksum: 4eb6083c0988f19aa3721e34bf14093dab8a0c6a784237ae4276a0b4e68bb82e91c594d7dd1d12173aaa2b38400a6bf5e0bd8b961a9ae05cdba854e2c566a134 + languageName: node + linkType: hard + +"@linaria/react@npm:^6.2.1": + version: 6.2.1 + resolution: "@linaria/react@npm:6.2.1" + dependencies: + "@emotion/is-prop-valid": "npm:^1.2.0" + "@linaria/core": "npm:^6.2.0" + "@wyw-in-js/processor-utils": "npm:^0.5.3" + "@wyw-in-js/shared": "npm:^0.5.3" + minimatch: "npm:^9.0.3" + react-html-attributes: "npm:^1.4.6" + resolve: "npm:^1.22.8" + ts-invariant: "npm:^0.10.3" + peerDependencies: + react: ">=16" + checksum: 102480195bc6e5f41cf3da4c7181640cf617256fcdd48847238cdc7def30536f132f29f35530bd261cbf5580a87981f5a6f7717e791b73cc309552141a10d256 + languageName: node + linkType: hard + "@ljharb/through@npm:^2.3.9": version: 2.3.12 resolution: "@ljharb/through@npm:2.3.12" @@ -18685,6 +18993,62 @@ __metadata: languageName: node linkType: hard +"@wyw-in-js/processor-utils@npm:0.5.3, @wyw-in-js/processor-utils@npm:^0.5.3": + version: 0.5.3 + resolution: "@wyw-in-js/processor-utils@npm:0.5.3" + dependencies: + "@babel/generator": "npm:^7.23.5" + "@wyw-in-js/shared": "npm:0.5.3" + checksum: d9d12fe96a423551876b00cd715c61945a11770b448cb9363d435f1cd3506f7f57c068558ea8cb87eb78d39ff7cdb255ed055af540ee289f8b4e4798f12dd66d + languageName: node + linkType: hard + +"@wyw-in-js/shared@npm:0.5.3, @wyw-in-js/shared@npm:^0.5.3": + version: 0.5.3 + resolution: "@wyw-in-js/shared@npm:0.5.3" + dependencies: + debug: "npm:^4.3.4" + find-up: "npm:^5.0.0" + minimatch: "npm:^9.0.3" + checksum: 0e02195f113793231953f8a2b0a65e8641f851d2627d961949fa925c60a72ce35a20dd477b12f5ac3f0cfedc30c8507a4540d0f5acf7983fd5c636acba50d293 + languageName: node + linkType: hard + +"@wyw-in-js/transform@npm:0.5.3": + version: 0.5.3 + resolution: "@wyw-in-js/transform@npm:0.5.3" + dependencies: + "@babel/core": "npm:^7.23.5" + "@babel/generator": "npm:^7.23.5" + "@babel/helper-module-imports": "npm:^7.22.15" + "@babel/plugin-transform-modules-commonjs": "npm:^7.23.3" + "@babel/template": "npm:^7.22.15" + "@babel/traverse": "npm:^7.23.5" + "@babel/types": "npm:^7.23.5" + "@wyw-in-js/processor-utils": "npm:0.5.3" + "@wyw-in-js/shared": "npm:0.5.3" + babel-merge: "npm:^3.0.0" + cosmiconfig: "npm:^8.0.0" + happy-dom: "npm:^12.5.0" + source-map: "npm:^0.7.4" + stylis: "npm:^4.3.0" + ts-invariant: "npm:^0.10.3" + checksum: 947633c7ed6fbbd2546a88db7ba5e70e558eb460eb60a479031f5edae07234f4e7eda5bc960aabee755e154d7cf6e3f191cd291666f3c5735b65d469896e8574 + languageName: node + linkType: hard + +"@wyw-in-js/vite@npm:^0.5.3": + version: 0.5.3 + resolution: "@wyw-in-js/vite@npm:0.5.3" + dependencies: + "@wyw-in-js/shared": "npm:0.5.3" + "@wyw-in-js/transform": "npm:0.5.3" + peerDependencies: + vite: ">=3.2.7" + checksum: 0fbbdfe2fde2061b160052c7607d15f4fc3254058888b03f4affe42f4fd5bc059784732e1d372e79dcd8b40e9fa4f92c98805c018d5912d4227236328c32ea30 + languageName: node + linkType: hard + "@xobotyi/scrollbar-width@npm:^1.9.5": version: 1.9.5 resolution: "@xobotyi/scrollbar-width@npm:1.9.5" @@ -20244,6 +20608,18 @@ __metadata: languageName: node linkType: hard +"babel-merge@npm:^3.0.0": + version: 3.0.0 + resolution: "babel-merge@npm:3.0.0" + dependencies: + deepmerge: "npm:^2.2.1" + object.omit: "npm:^3.0.0" + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 8337358ba69553305ba0ee6ddfdeb79b58d37012d5c99953d87e608eb22299a565501a854e451c2daa8f7b2310d1a52c66ed92f17e18a9858153e9fd9f3090e5 + languageName: node + linkType: hard + "babel-messages@npm:^6.23.0": version: 6.23.0 resolution: "babel-messages@npm:6.23.0" @@ -23714,7 +24090,7 @@ __metadata: languageName: node linkType: hard -"cosmiconfig@npm:8.3.6, cosmiconfig@npm:^8.1.3, cosmiconfig@npm:^8.2.0, cosmiconfig@npm:^8.3.5": +"cosmiconfig@npm:8.3.6, cosmiconfig@npm:^8.0.0, cosmiconfig@npm:^8.1.3, cosmiconfig@npm:^8.2.0, cosmiconfig@npm:^8.3.5": version: 8.3.6 resolution: "cosmiconfig@npm:8.3.6" dependencies: @@ -24836,6 +25212,13 @@ __metadata: languageName: node linkType: hard +"deepmerge@npm:^2.2.1": + version: 2.2.1 + resolution: "deepmerge@npm:2.2.1" + checksum: 4379288cabd817587cee92a095ea65d18317b45e48010a2e0d87982b5f432239a144f9c8ebd4ab090cc21f0cb47e51ebfe32921f329b3b3084a2711d5d63e450 + languageName: node + linkType: hard + "deepmerge@npm:^4.2.2, deepmerge@npm:^4.3.1": version: 4.3.1 resolution: "deepmerge@npm:4.3.1" @@ -29608,6 +29991,20 @@ __metadata: languageName: node linkType: hard +"happy-dom@npm:^12.5.0": + version: 12.10.3 + resolution: "happy-dom@npm:12.10.3" + dependencies: + css.escape: "npm:^1.5.1" + entities: "npm:^4.5.0" + iconv-lite: "npm:^0.6.3" + webidl-conversions: "npm:^7.0.0" + whatwg-encoding: "npm:^2.0.0" + whatwg-mimetype: "npm:^3.0.0" + checksum: fbf8647e17c4af5c166d7c4b6963f4bbc9d1c279e94a4c77234b1fecca98c59989b894c7b186f5107e1062d40ffd84f12350b757f51330a5fc1c5228eb199517 + languageName: node + linkType: hard + "har-schema@npm:^2.0.0": version: 2.0.0 resolution: "har-schema@npm:2.0.0" @@ -30391,6 +30788,13 @@ __metadata: languageName: node linkType: hard +"html-element-attributes@npm:^1.0.0": + version: 1.3.1 + resolution: "html-element-attributes@npm:1.3.1" + checksum: caf9704577854275bfe4b6f5a77c9b5f2d988b6bc86f48aa1ee043421950c314c43d8f2915178f5cb7a00409e1f2690c1ddb0f4758f9d63b875172cbaa32bc9f + languageName: node + linkType: hard + "html-encoding-sniffer@npm:^3.0.0": version: 3.0.0 resolution: "html-encoding-sniffer@npm:3.0.0" @@ -30857,7 +31261,7 @@ __metadata: languageName: node linkType: hard -"iconv-lite@npm:0.6.3, iconv-lite@npm:^0.6.2": +"iconv-lite@npm:0.6.3, iconv-lite@npm:^0.6.2, iconv-lite@npm:^0.6.3": version: 0.6.3 resolution: "iconv-lite@npm:0.6.3" dependencies: @@ -41673,6 +42077,15 @@ __metadata: languageName: node linkType: hard +"react-html-attributes@npm:^1.4.6": + version: 1.4.6 + resolution: "react-html-attributes@npm:1.4.6" + dependencies: + html-element-attributes: "npm:^1.0.0" + checksum: f2ef5b80c6254a0bc4cc802d7412bee0bd5008a1ac1a96eb52cdfde9b7e5017e9373ee613361d6c83df3faa8743c71fb42d1fb238bb797ece481d97848c02be2 + languageName: node + linkType: hard + "react-icons@npm:^4.12.0, react-icons@npm:^4.3.1": version: 4.12.0 resolution: "react-icons@npm:4.12.0" @@ -43180,7 +43593,7 @@ __metadata: languageName: node linkType: hard -"resolve@npm:^1.1.4, resolve@npm:^1.1.6, resolve@npm:^1.10.0, resolve@npm:^1.12.0, resolve@npm:^1.14.2, resolve@npm:^1.17.0, resolve@npm:^1.19.0, resolve@npm:^1.20.0, resolve@npm:^1.22.1, resolve@npm:^1.22.4, resolve@npm:^1.4.0, resolve@npm:~1.22.1": +"resolve@npm:^1.1.4, resolve@npm:^1.1.6, resolve@npm:^1.10.0, resolve@npm:^1.12.0, resolve@npm:^1.14.2, resolve@npm:^1.17.0, resolve@npm:^1.19.0, resolve@npm:^1.20.0, resolve@npm:^1.22.1, resolve@npm:^1.22.4, resolve@npm:^1.22.8, resolve@npm:^1.4.0, resolve@npm:~1.22.1": version: 1.22.8 resolution: "resolve@npm:1.22.8" dependencies: @@ -43216,7 +43629,7 @@ __metadata: languageName: node linkType: hard -"resolve@patch:resolve@npm%3A^1.1.4#optional!builtin, resolve@patch:resolve@npm%3A^1.1.6#optional!builtin, resolve@patch:resolve@npm%3A^1.10.0#optional!builtin, resolve@patch:resolve@npm%3A^1.12.0#optional!builtin, resolve@patch:resolve@npm%3A^1.14.2#optional!builtin, resolve@patch:resolve@npm%3A^1.17.0#optional!builtin, resolve@patch:resolve@npm%3A^1.19.0#optional!builtin, resolve@patch:resolve@npm%3A^1.20.0#optional!builtin, resolve@patch:resolve@npm%3A^1.22.1#optional!builtin, resolve@patch:resolve@npm%3A^1.22.4#optional!builtin, resolve@patch:resolve@npm%3A^1.4.0#optional!builtin, resolve@patch:resolve@npm%3A~1.22.1#optional!builtin": +"resolve@patch:resolve@npm%3A^1.1.4#optional!builtin, resolve@patch:resolve@npm%3A^1.1.6#optional!builtin, resolve@patch:resolve@npm%3A^1.10.0#optional!builtin, resolve@patch:resolve@npm%3A^1.12.0#optional!builtin, resolve@patch:resolve@npm%3A^1.14.2#optional!builtin, resolve@patch:resolve@npm%3A^1.17.0#optional!builtin, resolve@patch:resolve@npm%3A^1.19.0#optional!builtin, resolve@patch:resolve@npm%3A^1.20.0#optional!builtin, resolve@patch:resolve@npm%3A^1.22.1#optional!builtin, resolve@patch:resolve@npm%3A^1.22.4#optional!builtin, resolve@patch:resolve@npm%3A^1.22.8#optional!builtin, resolve@patch:resolve@npm%3A^1.4.0#optional!builtin, resolve@patch:resolve@npm%3A~1.22.1#optional!builtin": version: 1.22.8 resolution: "resolve@patch:resolve@npm%3A1.22.8#optional!builtin::version=1.22.8&hash=c3c19d" dependencies: @@ -46796,6 +47209,7 @@ __metadata: "@aws-sdk/credential-providers": "npm:^3.363.0" "@babel/core": "npm:^7.14.5" "@babel/preset-react": "npm:^7.14.5" + "@babel/preset-typescript": "npm:^7.24.6" "@blocknote/core": "npm:^0.12.1" "@blocknote/react": "npm:^0.12.2" "@chakra-ui/accordion": "npm:^2.3.0" @@ -46822,6 +47236,8 @@ __metadata: "@hello-pangea/dnd": "npm:^16.2.0" "@hookform/resolvers": "npm:^3.1.1" "@jsdevtools/rehype-toc": "npm:^3.0.2" + "@linaria/core": "npm:^6.2.0" + "@linaria/react": "npm:^6.2.1" "@mdx-js/react": "npm:^3.0.0" "@nestjs/apollo": "npm:^11.0.5" "@nestjs/axios": "npm:^3.0.1" @@ -46934,6 +47350,7 @@ __metadata: "@typescript-eslint/utils": "npm:6.21.0" "@vitejs/plugin-react-swc": "npm:^3.5.0" "@vitest/ui": "npm:1.4.0" + "@wyw-in-js/vite": "npm:^0.5.3" add: "npm:^2.0.6" addressparser: "npm:^1.0.1" afterframe: "npm:^1.0.2"