Feature: Add Empty State Display for Tables (#2841)

* Added empty state display for when object table is empty

* Added functionality to add button for empty state

* Fixed positioning of empty state

* Renamed style containers for empty state

* Added empty state display for when object table is empty

* Added functionality to add button for empty state

* Fixed positioning of empty state

* Renamed style containers for empty state

* Addressed PR comments by using createRecord prop and numberOfTableRowsState
This commit is contained in:
Tenzin Mahabir
2023-12-08 04:59:42 -05:00
committed by GitHub
parent cf334ada0e
commit 921366f5b3

View File

@ -1,20 +1,54 @@
import { useRef } from 'react'; import { useRef } from 'react';
import styled from '@emotion/styled'; import styled from '@emotion/styled';
import { useRecoilCallback } from 'recoil'; import { useRecoilCallback, useRecoilValue } from 'recoil';
import { RecordTableBodyEffect } from '@/object-record/record-table/components/RecordTableBodyEffect'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
import { RecordTableHeader } from '@/object-record/record-table/components/RecordTableHeader'; import { useObjectNameSingularFromPlural } from '@/object-metadata/hooks/useObjectNameSingularFromPlural';
import { RecordTableInternalEffect } from '@/object-record/record-table/components/RecordTableInternalEffect'; import { IconPlus } from '@/ui/display/icon';
import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable'; import { Button } from '@/ui/input/button/components/Button';
import { RecordTableScope } from '@/object-record/record-table/scopes/RecordTableScope';
import { DragSelect } from '@/ui/utilities/drag-select/components/DragSelect'; import { DragSelect } from '@/ui/utilities/drag-select/components/DragSelect';
import { ScrollWrapper } from '@/ui/utilities/scroll/components/ScrollWrapper'; import { ScrollWrapper } from '@/ui/utilities/scroll/components/ScrollWrapper';
import { useViewFields } from '@/views/hooks/internal/useViewFields'; import { useViewFields } from '@/views/hooks/internal/useViewFields';
import { mapColumnDefinitionsToViewFields } from '@/views/utils/mapColumnDefinitionToViewField'; import { mapColumnDefinitionsToViewFields } from '@/views/utils/mapColumnDefinitionToViewField';
import { EntityUpdateMutationContext } from '../contexts/EntityUpdateMutationHookContext'; import { EntityUpdateMutationContext } from '../contexts/EntityUpdateMutationHookContext';
import { useRecordTable } from '../hooks/useRecordTable';
import { RecordTableScope } from '../scopes/RecordTableScope';
import { numberOfTableRowsState } from '../states/numberOfTableRowsState';
import { RecordTableBody } from './RecordTableBody'; import { RecordTableBody } from './RecordTableBody';
import { RecordTableBodyEffect } from './RecordTableBodyEffect';
import { RecordTableHeader } from './RecordTableHeader';
import { RecordTableInternalEffect } from './RecordTableInternalEffect';
const StyledObjectEmptyContainer = styled.div`
align-items: center;
align-self: stretch;
display: flex;
flex: 1 0 0;
flex-direction: column;
gap: ${({ theme }) => theme.spacing(2)};
justify-content: center;
padding-bottom: ${({ theme }) => theme.spacing(16)};
padding-left: ${({ theme }) => theme.spacing(4)};
padding-right: ${({ theme }) => theme.spacing(4)};
padding-top: ${({ theme }) => theme.spacing(3)};
`;
const StyledEmptyObjectTitle = styled.div`
color: ${({ theme }) => theme.font.color.secondary};
font-size: ${({ theme }) => theme.font.size.xxl};
font-weight: ${({ theme }) => theme.font.weight.semiBold};
line-height: ${({ theme }) => theme.text.lineHeight.md};
`;
const StyledEmptyObjectSubTitle = styled.div`
color: ${({ theme }) => theme.font.color.extraLight};
font-size: ${({ theme }) => theme.font.size.xxl};
font-weight: ${({ theme }) => theme.font.weight.semiBold};
line-height: ${({ theme }) => theme.text.lineHeight.md};
margin-bottom: ${({ theme }) => theme.spacing(2)};
`;
const StyledTable = styled.table` const StyledTable = styled.table`
border-collapse: collapse; border-collapse: collapse;
@ -90,9 +124,26 @@ export const RecordTable = ({
}: RecordTableProps) => { }: RecordTableProps) => {
const tableBodyRef = useRef<HTMLDivElement>(null); const tableBodyRef = useRef<HTMLDivElement>(null);
const { resetTableRowSelection, setRowSelectedState } = useRecordTable({ const numberOfTableRows = useRecoilValue(numberOfTableRowsState);
const {
scopeId: objectNamePlural,
resetTableRowSelection,
setRowSelectedState,
} = useRecordTable({
recordTableScopeId: recordTableId, recordTableScopeId: recordTableId,
}); });
const { objectNameSingular } = useObjectNameSingularFromPlural({
objectNamePlural,
});
const { objectMetadataItem: foundObjectMetadataItem } = useObjectMetadataItem(
{
objectNameSingular,
},
);
const { persistViewFields } = useViewFields(viewBarId); const { persistViewFields } = useViewFields(viewBarId);
return ( return (
@ -119,6 +170,22 @@ export const RecordTable = ({
/> />
</div> </div>
<RecordTableInternalEffect tableBodyRef={tableBodyRef} /> <RecordTableInternalEffect tableBodyRef={tableBodyRef} />
{numberOfTableRows === 0 && (
<StyledObjectEmptyContainer>
<StyledEmptyObjectTitle>
No {foundObjectMetadataItem?.namePlural}
</StyledEmptyObjectTitle>
<StyledEmptyObjectSubTitle>
Create one:
</StyledEmptyObjectSubTitle>
<Button
Icon={IconPlus}
title={`Add a ${foundObjectMetadataItem?.nameSingular}`}
variant={'secondary'}
onClick={createRecord}
/>
</StyledObjectEmptyContainer>
)}
</StyledTableContainer> </StyledTableContainer>
</StyledTableWithHeader> </StyledTableWithHeader>
</EntityUpdateMutationContext.Provider> </EntityUpdateMutationContext.Provider>