From 5f886e3804ce87f07bdb54671ef882af9f9c8156 Mon Sep 17 00:00:00 2001 From: Thomas Trompette Date: Wed, 29 May 2024 16:35:02 +0200 Subject: [PATCH] Build empty state for remote tables --- .../hooks/useLoadRecordIndexTable.ts | 21 +++++-- .../hooks/useRecordTableRecordGqlFields.ts | 4 +- .../record-table/components/RecordTable.tsx | 18 +++++- .../components/RecordTableBody.tsx | 41 +++++------- .../components/RecordTableEmptyState.tsx | 63 +++++++++++++++++++ 5 files changed, 115 insertions(+), 32 deletions(-) create mode 100644 packages/twenty-front/src/modules/object-record/record-table/components/RecordTableEmptyState.tsx diff --git a/packages/twenty-front/src/modules/object-record/record-index/hooks/useLoadRecordIndexTable.ts b/packages/twenty-front/src/modules/object-record/record-index/hooks/useLoadRecordIndexTable.ts index 50320fd1304bf..0623e87078506 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/hooks/useLoadRecordIndexTable.ts +++ b/packages/twenty-front/src/modules/object-record/record-index/hooks/useLoadRecordIndexTable.ts @@ -34,19 +34,28 @@ export const useFindManyParams = ( return { objectNameSingular, filter, orderBy }; }; -export const useLoadRecordIndexTable = (objectNameSingular: string) => { +export const useLoadRecordIndexTable = ( + objectNameSingular: string, + recordTableId?: string, +) => { const { objectMetadataItem } = useObjectMetadataItem({ objectNameSingular, }); - const { setRecordTableData, setIsRecordTableInitialLoading } = - useRecordTable(); - const { tableLastRowVisibleState } = useRecordTableStates(); + const { setRecordTableData, setIsRecordTableInitialLoading } = useRecordTable( + { + recordTableId, + }, + ); + const { tableLastRowVisibleState } = useRecordTableStates(recordTableId); const setLastRowVisible = useSetRecoilState(tableLastRowVisibleState); const currentWorkspace = useRecoilValue(currentWorkspaceState); - const params = useFindManyParams(objectNameSingular); + const params = useFindManyParams(objectNameSingular, recordTableId); - const recordGqlFields = useRecordTableRecordGqlFields({ objectMetadataItem }); + const recordGqlFields = useRecordTableRecordGqlFields({ + objectMetadataItem, + recordTableId, + }); const { records, diff --git a/packages/twenty-front/src/modules/object-record/record-index/hooks/useRecordTableRecordGqlFields.ts b/packages/twenty-front/src/modules/object-record/record-index/hooks/useRecordTableRecordGqlFields.ts index fc8929564b12c..f125220e896da 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/hooks/useRecordTableRecordGqlFields.ts +++ b/packages/twenty-front/src/modules/object-record/record-index/hooks/useRecordTableRecordGqlFields.ts @@ -7,10 +7,12 @@ import { isDefined } from '~/utils/isDefined'; export const useRecordTableRecordGqlFields = ({ objectMetadataItem, + recordTableId, }: { objectMetadataItem: ObjectMetadataItem; + recordTableId?: string; }) => { - const { visibleTableColumnsSelector } = useRecordTableStates(); + const { visibleTableColumnsSelector } = useRecordTableStates(recordTableId); const { imageIdentifierFieldMetadataItem, labelIdentifierFieldMetadataItem } = getObjectMetadataIdentifierFields({ objectMetadataItem }); 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 92280dfd1f6b8..22a9c36b46467 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 @@ -4,8 +4,10 @@ import { useRecoilValue } from 'recoil'; import { MOBILE_VIEWPORT, RGBA } from 'twenty-ui'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; +import { useLoadRecordIndexTable } from '@/object-record/record-index/hooks/useLoadRecordIndexTable'; import { RecordTableBody } from '@/object-record/record-table/components/RecordTableBody'; import { RecordTableBodyEffect } from '@/object-record/record-table/components/RecordTableBodyEffect'; +import { RecordTableEmptyState } from '@/object-record/record-table/components/RecordTableEmptyState'; import { RecordTableHeader } from '@/object-record/record-table/components/RecordTableHeader'; import { RecordTableContext } from '@/object-record/record-table/contexts/RecordTableContext'; import { useHandleContainerMouseEnter } from '@/object-record/record-table/hooks/internal/useHandleContainerMouseEnter'; @@ -207,6 +209,14 @@ export const RecordTable = ({ const visibleTableColumns = useRecoilValue(visibleTableColumnsSelector()); + const { tableRowIdsState } = useRecordTableStates(recordTableId); + const tableRowIds = useRecoilValue(tableRowIdsState); + + const { loading } = useLoadRecordIndexTable( + objectNameSingular, + recordTableId, + ); + return ( - + + {!loading && tableRowIds.length === 0 && ( + + )} )} diff --git a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableBody.tsx b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableBody.tsx index 3947067f48062..bce4743858e91 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableBody.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableBody.tsx @@ -1,34 +1,27 @@ -import { useRecoilValue } from 'recoil'; - import { RecordTableBodyFetchMoreLoader } from '@/object-record/record-table/components/RecordTableBodyFetchMoreLoader'; import { RecordTablePendingRow } from '@/object-record/record-table/components/RecordTablePendingRow'; import { RecordTableRow } from '@/object-record/record-table/components/RecordTableRow'; -import { useRecordTableStates } from '@/object-record/record-table/hooks/internal/useRecordTableStates'; type RecordTableBodyProps = { objectNameSingular: string; + tableRowIds: string[]; }; export const RecordTableBody = ({ objectNameSingular, -}: RecordTableBodyProps) => { - const { tableRowIdsState } = useRecordTableStates(); - - const tableRowIds = useRecoilValue(tableRowIdsState); - - return ( - <> - - - {tableRowIds.map((recordId, rowIndex) => ( - - ))} - - - - ); -}; + tableRowIds, +}: RecordTableBodyProps) => ( + <> + + + {tableRowIds.map((recordId, rowIndex) => ( + + ))} + + + +); diff --git a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableEmptyState.tsx b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableEmptyState.tsx new file mode 100644 index 0000000000000..3d8ef3795ed63 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableEmptyState.tsx @@ -0,0 +1,63 @@ +import { useNavigate } from 'react-router-dom'; +import { ThemeProvider, useTheme } from '@emotion/react'; +import styled from '@emotion/styled'; +import isEmpty from 'lodash.isempty'; +import { IconSettings, THEME_LIGHT } from 'twenty-ui'; + +import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; +import { Button } from '@/ui/input/button/components/Button'; +import AnimatedPlaceholder from '@/ui/layout/animated-placeholder/components/AnimatedPlaceholder'; +import { + AnimatedPlaceholderEmptyContainer, + AnimatedPlaceholderEmptySubTitle, + AnimatedPlaceholderEmptyTextContainer, + AnimatedPlaceholderEmptyTitle, +} from '@/ui/layout/animated-placeholder/components/EmptyPlaceholderStyled'; + +const StyledEmptyStateContainer = styled.div` + display: flex; + justify-content: center; + height: 100%; + width: 100%; + margin-top: ${({ theme }) => theme.spacing(8)}; +`; + +type RecordTableEmptyStateProps = { + objectMetadataItem: ObjectMetadataItem; +}; + +export const RecordTableEmptyState = ({ + objectMetadataItem, +}: RecordTableEmptyStateProps) => { + const theme = useTheme(); + const navigate = useNavigate(); + + // If the object is not remote, we do not show an empty state yet + if (!objectMetadataItem.isRemote) { + return <>; + } + + return ( + + + + + + + No Data Available for Remote Table + + + If this is unexpected, please verify your settings. + + +