From 56874bf84b634f214d01a4355f6f6bd8a256e045 Mon Sep 17 00:00:00 2001 From: Charles Bochet Date: Thu, 17 Apr 2025 15:29:20 +0200 Subject: [PATCH] Fix aggregate bar (#11620) Closes https://github.com/twentyhq/twenty/issues/10943 Also adds stories: image --- .../hooks/useLoadRecordIndexStates.ts | 2 +- .../__stories__/RecordTable.stories.tsx | 117 +++++++++++++++ .../record-table/components/RecordTable.tsx | 2 +- .../components/RecordTableEmpty.tsx | 12 +- ...EmptyStateNoGroupNoRecordAtAll.stories.tsx | 33 +++-- ...ptyStateNoRecordFoundForFilter.stories.tsx | 33 +++-- .../RecordTableEmptyStateRemote.stories.tsx | 33 +++-- ...ecordTableEmptyStateSoftDelete.stories.tsx | 38 ++--- .../components/RecordTableBody.tsx | 6 +- .../components/RecordTableHeader.tsx | 8 +- .../decorators/RecordTableDecorator.tsx | 134 +++++++++++++++--- .../components/AnimatedPlaceholder.tsx | 1 + .../src/testing/ComponentStorybookLayout.tsx | 17 ++- .../testing/decorators/ComponentDecorator.tsx | 1 + 14 files changed, 339 insertions(+), 98 deletions(-) create mode 100644 packages/twenty-front/src/modules/object-record/record-table/__stories__/RecordTable.stories.tsx diff --git a/packages/twenty-front/src/modules/object-record/record-index/hooks/useLoadRecordIndexStates.ts b/packages/twenty-front/src/modules/object-record/record-index/hooks/useLoadRecordIndexStates.ts index 44f8c5487..1b415f3fb 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/hooks/useLoadRecordIndexStates.ts +++ b/packages/twenty-front/src/modules/object-record/record-index/hooks/useLoadRecordIndexStates.ts @@ -23,8 +23,8 @@ import { ViewField } from '@/views/types/ViewField'; import { mapViewFieldsToColumnDefinitions } from '@/views/utils/mapViewFieldsToColumnDefinitions'; import { mapViewFiltersToFilters } from '@/views/utils/mapViewFiltersToFilters'; import { useRecoilCallback, useSetRecoilState } from 'recoil'; -import { isDeeplyEqual } from '~/utils/isDeeplyEqual'; import { isDefined } from 'twenty-shared/utils'; +import { isDeeplyEqual } from '~/utils/isDeeplyEqual'; export const useLoadRecordIndexStates = () => { const setContextStoreTargetedRecordsRuleComponentState = diff --git a/packages/twenty-front/src/modules/object-record/record-table/__stories__/RecordTable.stories.tsx b/packages/twenty-front/src/modules/object-record/record-table/__stories__/RecordTable.stories.tsx new file mode 100644 index 000000000..016f10afc --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-table/__stories__/RecordTable.stories.tsx @@ -0,0 +1,117 @@ +import { Meta, StoryObj } from '@storybook/react'; + +import { RecordTableWithWrappers } from '@/object-record/record-table/components/RecordTableWithWrappers'; +import { RecordTableEmptyStateNoGroupNoRecordAtAll } from '@/object-record/record-table/empty-state/components/RecordTableEmptyStateNoGroupNoRecordAtAll'; +import { fireEvent, userEvent, within } from '@storybook/test'; +import { ComponentDecorator } from 'twenty-ui/testing'; +import { ContextStoreDecorator } from '~/testing/decorators/ContextStoreDecorator'; +import { I18nFrontDecorator } from '~/testing/decorators/I18nFrontDecorator'; +import { MemoryRouterDecorator } from '~/testing/decorators/MemoryRouterDecorator'; +import { ObjectMetadataItemsDecorator } from '~/testing/decorators/ObjectMetadataItemsDecorator'; +import { RecordTableDecorator } from '~/testing/decorators/RecordTableDecorator'; +import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator'; +import { graphqlMocks } from '~/testing/graphqlMocks'; +import { mockedViewsData } from '~/testing/mock-data/views'; +import { sleep } from '~/utils/sleep'; + +const meta: Meta = { + title: 'Modules/ObjectRecord/RecordTable/RecordTable', + component: RecordTableWithWrappers, + decorators: [ + ComponentDecorator, + MemoryRouterDecorator, + RecordTableDecorator, + ContextStoreDecorator, + SnackBarDecorator, + ObjectMetadataItemsDecorator, + I18nFrontDecorator, + ], + args: { + recordTableId: `companies-${mockedViewsData[0].id}`, + viewBarId: 'view-bar', + objectNameSingular: 'company', + }, + parameters: { + recordTableObjectNameSingular: 'company', + msw: graphqlMocks, + }, +}; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + play: async ({ canvasElement }) => { + const canvas = within(canvasElement); + + await canvas.findByText('Linkedin'); + }, +}; + +export const HeaderMenuOpen: Story = { + play: async () => { + const canvas = within(document.body); + await canvas.findByText('Linkedin'); + + const headerMenuButton = await canvas.findByText('Domain Name'); + + await userEvent.click(headerMenuButton); + + await canvas.findByText('Move right'); + }, +}; + +export const ScrolledLeft: Story = { + play: async () => { + const canvas = within(document.body); + await canvas.findByText('Linkedin'); + + const scrollWrapper = document.body.querySelector( + '.scroll-wrapper-x-enabled', + ); + + if (!scrollWrapper) { + throw new Error('Scroll wrapper not found'); + } + + await sleep(1000); + + fireEvent.scroll(scrollWrapper, { + target: { + scrollLeft: 100, + }, + }); + + await canvas.findByText('Facebook'); + }, +}; + +export const ScrolledBottom: Story = { + parameters: { + container: { + height: 300, + }, + }, + play: async () => { + const canvas = within(document.body); + await canvas.findByText('Linkedin'); + + const scrollWrapper = document.body.querySelector( + '.scroll-wrapper-y-enabled', + ); + + if (!scrollWrapper) { + throw new Error('Scroll wrapper not found'); + } + + await sleep(1000); + + fireEvent.scroll(scrollWrapper, { + target: { + scrollTop: 80, + }, + }); + + await canvas.findByText('Facebook'); + }, +}; diff --git a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTable.tsx b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTable.tsx index 3e792cc2b..8f5627ac6 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTable.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTable.tsx @@ -64,7 +64,7 @@ export const RecordTable = () => { tableBodyRef={tableBodyRef} /> - {recordTableIsEmpty ? ( + {recordTableIsEmpty && !hasRecordGroups ? ( ( +export const RecordTableEmpty = ({ tableBodyRef }: RecordTableEmptyProps) => ( <> - {hasRecordGroups ? ( - - ) : ( - - )} + ); diff --git a/packages/twenty-front/src/modules/object-record/record-table/empty-state/components/__stories__/RecordTableEmptyStateNoGroupNoRecordAtAll.stories.tsx b/packages/twenty-front/src/modules/object-record/record-table/empty-state/components/__stories__/RecordTableEmptyStateNoGroupNoRecordAtAll.stories.tsx index b85c30533..4bb49b7d6 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/empty-state/components/__stories__/RecordTableEmptyStateNoGroupNoRecordAtAll.stories.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/empty-state/components/__stories__/RecordTableEmptyStateNoGroupNoRecordAtAll.stories.tsx @@ -1,35 +1,40 @@ import { Meta, StoryObj } from '@storybook/react'; -import { RecordTableComponentInstance } from '@/object-record/record-table/components/RecordTableComponentInstance'; +import { RecordTableContextProvider } from '@/object-record/record-table/components/RecordTableContextProvider'; import { RecordTableEmptyStateNoGroupNoRecordAtAll } from '@/object-record/record-table/empty-state/components/RecordTableEmptyStateNoGroupNoRecordAtAll'; -import { SnackBarProviderScope } from '@/ui/feedback/snack-bar-manager/scopes/SnackBarProviderScope'; +import { ComponentDecorator } from 'twenty-ui/testing'; +import { ContextStoreDecorator } from '~/testing/decorators/ContextStoreDecorator'; +import { I18nFrontDecorator } from '~/testing/decorators/I18nFrontDecorator'; import { MemoryRouterDecorator } from '~/testing/decorators/MemoryRouterDecorator'; import { ObjectMetadataItemsDecorator } from '~/testing/decorators/ObjectMetadataItemsDecorator'; import { RecordTableDecorator } from '~/testing/decorators/RecordTableDecorator'; +import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator'; import { graphqlMocks } from '~/testing/graphqlMocks'; -import { ComponentDecorator } from 'twenty-ui/testing'; const meta: Meta = { title: 'Modules/ObjectRecord/RecordTable/RecordTableEmptyStateNoGroupNoRecordAtAll', component: RecordTableEmptyStateNoGroupNoRecordAtAll, decorators: [ + (Story) => ( + + + + ), ComponentDecorator, MemoryRouterDecorator, - ObjectMetadataItemsDecorator, RecordTableDecorator, - (Story) => ( - - {}} - > - - - - ), + ContextStoreDecorator, + SnackBarDecorator, + ObjectMetadataItemsDecorator, + I18nFrontDecorator, ], parameters: { + recordTableObjectNameSingular: 'person', msw: graphqlMocks, }, }; diff --git a/packages/twenty-front/src/modules/object-record/record-table/empty-state/components/__stories__/RecordTableEmptyStateNoRecordFoundForFilter.stories.tsx b/packages/twenty-front/src/modules/object-record/record-table/empty-state/components/__stories__/RecordTableEmptyStateNoRecordFoundForFilter.stories.tsx index 60896f838..25caa8738 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/empty-state/components/__stories__/RecordTableEmptyStateNoRecordFoundForFilter.stories.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/empty-state/components/__stories__/RecordTableEmptyStateNoRecordFoundForFilter.stories.tsx @@ -1,35 +1,40 @@ import { Meta, StoryObj } from '@storybook/react'; -import { RecordTableComponentInstance } from '@/object-record/record-table/components/RecordTableComponentInstance'; +import { RecordTableContextProvider } from '@/object-record/record-table/components/RecordTableContextProvider'; import { RecordTableEmptyStateNoRecordFoundForFilter } from '@/object-record/record-table/empty-state/components/RecordTableEmptyStateNoRecordFoundForFilter'; -import { SnackBarProviderScope } from '@/ui/feedback/snack-bar-manager/scopes/SnackBarProviderScope'; +import { ComponentDecorator } from 'twenty-ui/testing'; +import { ContextStoreDecorator } from '~/testing/decorators/ContextStoreDecorator'; +import { I18nFrontDecorator } from '~/testing/decorators/I18nFrontDecorator'; import { MemoryRouterDecorator } from '~/testing/decorators/MemoryRouterDecorator'; import { ObjectMetadataItemsDecorator } from '~/testing/decorators/ObjectMetadataItemsDecorator'; import { RecordTableDecorator } from '~/testing/decorators/RecordTableDecorator'; +import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator'; import { graphqlMocks } from '~/testing/graphqlMocks'; -import { ComponentDecorator } from 'twenty-ui/testing'; const meta: Meta = { title: 'Modules/ObjectRecord/RecordTable/RecordTableEmptyStateNoRecordFoundForFilter', component: RecordTableEmptyStateNoRecordFoundForFilter, decorators: [ + (Story) => ( + + + + ), ComponentDecorator, MemoryRouterDecorator, - ObjectMetadataItemsDecorator, RecordTableDecorator, - (Story) => ( - - {}} - > - - - - ), + ContextStoreDecorator, + SnackBarDecorator, + ObjectMetadataItemsDecorator, + I18nFrontDecorator, ], parameters: { + recordTableObjectNameSingular: 'person', msw: graphqlMocks, }, }; diff --git a/packages/twenty-front/src/modules/object-record/record-table/empty-state/components/__stories__/RecordTableEmptyStateRemote.stories.tsx b/packages/twenty-front/src/modules/object-record/record-table/empty-state/components/__stories__/RecordTableEmptyStateRemote.stories.tsx index 5092f7e27..b9d89296f 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/empty-state/components/__stories__/RecordTableEmptyStateRemote.stories.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/empty-state/components/__stories__/RecordTableEmptyStateRemote.stories.tsx @@ -1,34 +1,39 @@ import { Meta, StoryObj } from '@storybook/react'; -import { RecordTableComponentInstance } from '@/object-record/record-table/components/RecordTableComponentInstance'; +import { RecordTableContextProvider } from '@/object-record/record-table/components/RecordTableContextProvider'; import { RecordTableEmptyStateRemote } from '@/object-record/record-table/empty-state/components/RecordTableEmptyStateRemote'; -import { SnackBarProviderScope } from '@/ui/feedback/snack-bar-manager/scopes/SnackBarProviderScope'; +import { ComponentDecorator } from 'twenty-ui/testing'; +import { ContextStoreDecorator } from '~/testing/decorators/ContextStoreDecorator'; +import { I18nFrontDecorator } from '~/testing/decorators/I18nFrontDecorator'; import { MemoryRouterDecorator } from '~/testing/decorators/MemoryRouterDecorator'; import { ObjectMetadataItemsDecorator } from '~/testing/decorators/ObjectMetadataItemsDecorator'; import { RecordTableDecorator } from '~/testing/decorators/RecordTableDecorator'; +import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator'; import { graphqlMocks } from '~/testing/graphqlMocks'; -import { ComponentDecorator } from 'twenty-ui/testing'; const meta: Meta = { title: 'Modules/ObjectRecord/RecordTable/RecordTableEmptyStateRemote', component: RecordTableEmptyStateRemote, decorators: [ + (Story) => ( + + + + ), ComponentDecorator, MemoryRouterDecorator, - ObjectMetadataItemsDecorator, RecordTableDecorator, - (Story) => ( - - {}} - > - - - - ), + ContextStoreDecorator, + SnackBarDecorator, + ObjectMetadataItemsDecorator, + I18nFrontDecorator, ], parameters: { + recordTableObjectNameSingular: 'person', msw: graphqlMocks, }, }; diff --git a/packages/twenty-front/src/modules/object-record/record-table/empty-state/components/__stories__/RecordTableEmptyStateSoftDelete.stories.tsx b/packages/twenty-front/src/modules/object-record/record-table/empty-state/components/__stories__/RecordTableEmptyStateSoftDelete.stories.tsx index 9fff5e04a..cc35af801 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/empty-state/components/__stories__/RecordTableEmptyStateSoftDelete.stories.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/empty-state/components/__stories__/RecordTableEmptyStateSoftDelete.stories.tsx @@ -1,39 +1,39 @@ import { Meta, StoryObj } from '@storybook/react'; -import { RecordFiltersComponentInstanceContext } from '@/object-record/record-filter/states/context/RecordFiltersComponentInstanceContext'; -import { RecordTableComponentInstance } from '@/object-record/record-table/components/RecordTableComponentInstance'; +import { RecordTableContextProvider } from '@/object-record/record-table/components/RecordTableContextProvider'; import { RecordTableEmptyStateSoftDelete } from '@/object-record/record-table/empty-state/components/RecordTableEmptyStateSoftDelete'; -import { SnackBarProviderScope } from '@/ui/feedback/snack-bar-manager/scopes/SnackBarProviderScope'; +import { ComponentDecorator } from 'twenty-ui/testing'; +import { ContextStoreDecorator } from '~/testing/decorators/ContextStoreDecorator'; +import { I18nFrontDecorator } from '~/testing/decorators/I18nFrontDecorator'; import { MemoryRouterDecorator } from '~/testing/decorators/MemoryRouterDecorator'; import { ObjectMetadataItemsDecorator } from '~/testing/decorators/ObjectMetadataItemsDecorator'; import { RecordTableDecorator } from '~/testing/decorators/RecordTableDecorator'; +import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator'; import { graphqlMocks } from '~/testing/graphqlMocks'; -import { ComponentDecorator } from 'twenty-ui/testing'; const meta: Meta = { title: 'Modules/ObjectRecord/RecordTable/RecordTableEmptyStateSoftDelete', component: RecordTableEmptyStateSoftDelete, decorators: [ + (Story) => ( + + + + ), ComponentDecorator, MemoryRouterDecorator, - ObjectMetadataItemsDecorator, RecordTableDecorator, - (Story) => ( - - - {}} - > - - - - - ), + ContextStoreDecorator, + SnackBarDecorator, + ObjectMetadataItemsDecorator, + I18nFrontDecorator, ], parameters: { + recordTableObjectNameSingular: 'person', msw: graphqlMocks, }, }; diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableBody.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableBody.tsx index 8022cce69..e1a1f6f03 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableBody.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableBody.tsx @@ -5,20 +5,20 @@ const StyledTbody = styled.tbody` td:nth-of-type(1) { position: sticky; left: 0; - z-index: 5; + z-index: 6; transition: 0.3s ease; } td:nth-of-type(2) { position: sticky; left: 11px; - z-index: 5; + z-index: 6; transition: 0.3s ease; } tr:not(:last-child) td:nth-of-type(3) { // Last row is aggregate footer position: sticky; left: 43px; - z-index: 5; + z-index: 6; transition: 0.3s ease; &:not(.disable-shadow)::after { diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeader.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeader.tsx index 56421f3f2..f255231c9 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeader.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeader.tsx @@ -26,21 +26,21 @@ const StyledTableHead = styled.thead` th:nth-of-type(1) { position: sticky; left: 0; - z-index: 5; + z-index: 6; transition: 0.3s ease; } th:nth-of-type(2) { position: sticky; left: 11px; - z-index: 5; + z-index: 6; transition: 0.3s ease; } th:nth-of-type(3) { position: sticky; left: 43px; - z-index: 5; + z-index: 6; transition: 0.3s ease; &::after { @@ -65,7 +65,7 @@ const StyledTableHead = styled.thead` th { position: sticky; top: 0; - z-index: 5; + z-index: 6; } } diff --git a/packages/twenty-front/src/testing/decorators/RecordTableDecorator.tsx b/packages/twenty-front/src/testing/decorators/RecordTableDecorator.tsx index 289cd0a71..93315ff85 100644 --- a/packages/twenty-front/src/testing/decorators/RecordTableDecorator.tsx +++ b/packages/twenty-front/src/testing/decorators/RecordTableDecorator.tsx @@ -1,41 +1,81 @@ import { Decorator } from '@storybook/react'; import { useRecoilValue } from 'recoil'; +import { ActionMenuComponentInstanceContext } from '@/action-menu/states/contexts/ActionMenuComponentInstanceContext'; +import { getActionMenuIdFromRecordIndexId } from '@/action-menu/utils/getActionMenuIdFromRecordIndexId'; import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; +import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; +import { RecordFilterGroupsComponentInstanceContext } from '@/object-record/record-filter-group/states/context/RecordFilterGroupsComponentInstanceContext'; +import { RecordFiltersComponentInstanceContext } from '@/object-record/record-filter/states/context/RecordFiltersComponentInstanceContext'; import { RecordIndexContextProvider } from '@/object-record/record-index/contexts/RecordIndexContext'; +import { useLoadRecordIndexStates } from '@/object-record/record-index/hooks/useLoadRecordIndexStates'; +import { RecordSortsComponentInstanceContext } from '@/object-record/record-sort/states/context/RecordSortsComponentInstanceContext'; +import { RecordFieldValueSelectorContextProvider } from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext'; import { RecordTableBodyContextProvider } from '@/object-record/record-table/contexts/RecordTableBodyContext'; import { RecordTableContextProvider } from '@/object-record/record-table/contexts/RecordTableContext'; +import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext'; +import { visibleTableColumnsComponentSelector } from '@/object-record/record-table/states/selectors/visibleTableColumnsComponentSelector'; +import { getRecordIndexIdFromObjectNamePluralAndViewId } from '@/object-record/utils/getRecordIndexIdFromObjectNamePluralAndViewId'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; +import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext'; +import { View } from '@/views/types/View'; +import { useEffect, useMemo } from 'react'; import { isDefined } from 'twenty-shared/utils'; +import { mockedViewFieldsData } from '~/testing/mock-data/view-fields'; +import { mockedViewsData } from '~/testing/mock-data/views'; -export const RecordTableDecorator: Decorator = (Story) => { - const objectMetadataItems = useRecoilValue(objectMetadataItemsState); +const InternalTableStateLoaderEffect = ({ + objectMetadataItem, +}: { + objectMetadataItem: ObjectMetadataItem; +}) => { + const { loadRecordIndexStates } = useLoadRecordIndexStates(); - const personObjectMetadataItem = objectMetadataItems.find( - (objectMetadataItem) => objectMetadataItem.nameSingular === 'person', + const view = useMemo(() => { + return { + ...mockedViewsData[0], + viewFields: mockedViewFieldsData.filter( + (viewField) => viewField.viewId === mockedViewsData[0].id, + ), + } as unknown as View; + }, []); + + useEffect(() => { + loadRecordIndexStates(view, objectMetadataItem); + }, [loadRecordIndexStates, objectMetadataItem, view]); + + return null; +}; + +const InternalTableContextProviders = ({ + children, + objectMetadataItem, +}: { + children: React.ReactNode; + objectMetadataItem: ObjectMetadataItem; +}) => { + const visibleTableColumns = useRecoilComponentValueV2( + visibleTableColumnsComponentSelector, ); - if (!isDefined(personObjectMetadataItem)) { - return ; - } - return ( '', onIndexRecordsLoaded: () => {}, - objectNamePlural: personObjectMetadataItem.namePlural, - objectNameSingular: personObjectMetadataItem.nameSingular, - objectMetadataItem: personObjectMetadataItem, + objectNamePlural: objectMetadataItem.namePlural, + objectNameSingular: objectMetadataItem.nameSingular, + objectMetadataItem: objectMetadataItem, recordIndexId: 'record-index', }} > { onMoveSoftFocusToCurrentCell: () => {}, }} > - + {children} ); }; + +export const RecordTableDecorator: Decorator = (Story, context) => { + const { recordTableObjectNameSingular: objectNameSingular } = + context.parameters; + + const objectMetadataItems = useRecoilValue(objectMetadataItemsState); + + const objectMetadataItem = objectMetadataItems.find( + (objectMetadataItem) => + objectMetadataItem.nameSingular === objectNameSingular, + ); + + if (!isDefined(objectMetadataItem)) { + throw new Error( + 'Object metadata item not found while loading RecordTableDecorator', + ); + } + + const recordIndexId = getRecordIndexIdFromObjectNamePluralAndViewId( + objectMetadataItem.namePlural, + mockedViewsData[0].id, + ); + + return ( + + {} }} + > + + + + + + + + + + + + + + + + + ); +}; diff --git a/packages/twenty-ui/src/layout/animated-placeholder/components/AnimatedPlaceholder.tsx b/packages/twenty-ui/src/layout/animated-placeholder/components/AnimatedPlaceholder.tsx index 10b7e366d..12408aeef 100644 --- a/packages/twenty-ui/src/layout/animated-placeholder/components/AnimatedPlaceholder.tsx +++ b/packages/twenty-ui/src/layout/animated-placeholder/components/AnimatedPlaceholder.tsx @@ -12,6 +12,7 @@ const StyledContainer = styled.div` align-items: center; justify-content: center; position: relative; + min-height: 100px; `; interface StyledImageProps { diff --git a/packages/twenty-ui/src/testing/ComponentStorybookLayout.tsx b/packages/twenty-ui/src/testing/ComponentStorybookLayout.tsx index fdb381866..f4f22b46a 100644 --- a/packages/twenty-ui/src/testing/ComponentStorybookLayout.tsx +++ b/packages/twenty-ui/src/testing/ComponentStorybookLayout.tsx @@ -1,8 +1,10 @@ import styled from '@emotion/styled'; +import { isDefined } from 'twenty-shared/utils'; const StyledLayout = styled.div<{ width?: number; backgroundColor?: string | undefined; + height: number | 'fit-content'; }>` background: ${({ theme, backgroundColor }) => backgroundColor ?? theme.background.primary}; @@ -12,7 +14,12 @@ const StyledLayout = styled.div<{ display: flex; flex-direction: row; - height: fit-content; + height: ${({ height }) => + height === 'fit-content' + ? 'fit-content' + : ` + ${height}px + `}; max-width: calc(100% - 40px); min-width: ${({ width }) => (width ? 'unset' : '300px')}; padding: 20px; @@ -22,15 +29,21 @@ const StyledLayout = styled.div<{ type ComponentStorybookLayoutProps = { width?: number; backgroundColor?: string | undefined; + height?: number; children: JSX.Element; }; export const ComponentStorybookLayout = ({ width, backgroundColor, + height, children, }: ComponentStorybookLayoutProps) => ( - + {children} ); diff --git a/packages/twenty-ui/src/testing/decorators/ComponentDecorator.tsx b/packages/twenty-ui/src/testing/decorators/ComponentDecorator.tsx index 8e4fd8664..f5dc25023 100644 --- a/packages/twenty-ui/src/testing/decorators/ComponentDecorator.tsx +++ b/packages/twenty-ui/src/testing/decorators/ComponentDecorator.tsx @@ -28,6 +28,7 @@ export const ComponentDecorator: Decorator = (Story, context) => { return (