Show Header in RecordTable on empty state and show groups in Group By views (#11416)
Closes #11298 --------- Co-authored-by: Félix Malfait <felix@twenty.com>
This commit is contained in:
committed by
GitHub
parent
07b25a2aad
commit
6bc18960c9
@ -1,36 +1,17 @@
|
||||
import styled from '@emotion/styled';
|
||||
import { isNonEmptyString } from '@sniptt/guards';
|
||||
import { useRef } from 'react';
|
||||
|
||||
import { hasRecordGroupsComponentSelector } from '@/object-record/record-group/states/selectors/hasRecordGroupsComponentSelector';
|
||||
import { recordIndexAllRecordIdsComponentSelector } from '@/object-record/record-index/states/selectors/recordIndexAllRecordIdsComponentSelector';
|
||||
import { RecordTableStickyBottomEffect } from '@/object-record/record-table/components/RecordTableStickyBottomEffect';
|
||||
import { RecordTableStickyEffect } from '@/object-record/record-table/components/RecordTableStickyEffect';
|
||||
import { RecordTableBodyEffectsWrapper } from '@/object-record/record-table/components/RecordTableBodyEffectsWrapper';
|
||||
import { RecordTableContent } from '@/object-record/record-table/components/RecordTableContent';
|
||||
import { RecordTableEmpty } from '@/object-record/record-table/components/RecordTableEmpty';
|
||||
import { RECORD_TABLE_CLICK_OUTSIDE_LISTENER_ID } from '@/object-record/record-table/constants/RecordTableClickOutsideListenerId';
|
||||
import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext';
|
||||
import { RecordTableEmptyState } from '@/object-record/record-table/empty-state/components/RecordTableEmptyState';
|
||||
import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable';
|
||||
import { RecordTableBodyUnselectEffect } from '@/object-record/record-table/record-table-body/components/RecordTableBodyUnselectEffect';
|
||||
import { RecordTableNoRecordGroupBody } from '@/object-record/record-table/record-table-body/components/RecordTableNoRecordGroupBody';
|
||||
import { RecordTableNoRecordGroupBodyEffect } from '@/object-record/record-table/record-table-body/components/RecordTableNoRecordGroupBodyEffect';
|
||||
import { RecordTableRecordGroupBodyEffects } from '@/object-record/record-table/record-table-body/components/RecordTableRecordGroupBodyEffects';
|
||||
import { RecordTableRecordGroupsBody } from '@/object-record/record-table/record-table-body/components/RecordTableRecordGroupsBody';
|
||||
import { RecordTableHeader } from '@/object-record/record-table/record-table-header/components/RecordTableHeader';
|
||||
import { isRecordTableInitialLoadingComponentState } from '@/object-record/record-table/states/isRecordTableInitialLoadingComponentState';
|
||||
import { DragSelect } from '@/ui/utilities/drag-select/components/DragSelect';
|
||||
import { useClickOutsideListener } from '@/ui/utilities/pointer-event/hooks/useClickOutsideListener';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { useRef } from 'react';
|
||||
|
||||
const StyledTable = styled.table`
|
||||
border-radius: ${({ theme }) => theme.border.radius.sm};
|
||||
border-spacing: 0;
|
||||
table-layout: fixed;
|
||||
width: 100%;
|
||||
|
||||
.footer-sticky tr:nth-last-of-type(2) td {
|
||||
border-bottom-color: ${({ theme }) => theme.background.transparent};
|
||||
}
|
||||
`;
|
||||
|
||||
export const RecordTable = () => {
|
||||
const { recordTableId, objectNameSingular } = useRecordTableContextOrThrow();
|
||||
@ -56,51 +37,46 @@ export const RecordTable = () => {
|
||||
recordTableId,
|
||||
);
|
||||
|
||||
const recordTableIsEmpty =
|
||||
!isRecordTableInitialLoading && allRecordIds.length === 0;
|
||||
|
||||
const { resetTableRowSelection, setRowSelected } = useRecordTable({
|
||||
recordTableId,
|
||||
});
|
||||
|
||||
const recordTableIsEmpty =
|
||||
!isRecordTableInitialLoading && allRecordIds.length === 0;
|
||||
|
||||
if (!isNonEmptyString(objectNameSingular)) {
|
||||
return <></>;
|
||||
}
|
||||
|
||||
const handleDragSelectionStart = () => {
|
||||
resetTableRowSelection();
|
||||
toggleClickOutsideListener(false);
|
||||
};
|
||||
|
||||
const handleDragSelectionEnd = () => {
|
||||
toggleClickOutsideListener(true);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
{!hasRecordGroups ? (
|
||||
<RecordTableNoRecordGroupBodyEffect />
|
||||
) : (
|
||||
<RecordTableRecordGroupBodyEffects />
|
||||
)}
|
||||
<RecordTableBodyUnselectEffect tableBodyRef={tableBodyRef} />
|
||||
<RecordTableBodyEffectsWrapper
|
||||
hasRecordGroups={hasRecordGroups}
|
||||
tableBodyRef={tableBodyRef}
|
||||
/>
|
||||
|
||||
{recordTableIsEmpty ? (
|
||||
<RecordTableEmptyState />
|
||||
<RecordTableEmpty
|
||||
tableBodyRef={tableBodyRef}
|
||||
hasRecordGroups={hasRecordGroups}
|
||||
/>
|
||||
) : (
|
||||
<>
|
||||
<StyledTable ref={tableBodyRef}>
|
||||
<RecordTableHeader />
|
||||
{!hasRecordGroups ? (
|
||||
<RecordTableNoRecordGroupBody />
|
||||
) : (
|
||||
<RecordTableRecordGroupsBody />
|
||||
)}
|
||||
<RecordTableStickyEffect />
|
||||
<RecordTableStickyBottomEffect />
|
||||
</StyledTable>
|
||||
<DragSelect
|
||||
dragSelectable={tableBodyRef}
|
||||
onDragSelectionStart={() => {
|
||||
resetTableRowSelection();
|
||||
toggleClickOutsideListener(false);
|
||||
}}
|
||||
onDragSelectionChange={setRowSelected}
|
||||
onDragSelectionEnd={() => {
|
||||
toggleClickOutsideListener(true);
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
<RecordTableContent
|
||||
tableBodyRef={tableBodyRef}
|
||||
handleDragSelectionStart={handleDragSelectionStart}
|
||||
handleDragSelectionEnd={handleDragSelectionEnd}
|
||||
setRowSelected={setRowSelected}
|
||||
hasRecordGroups={hasRecordGroups}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
|
||||
@ -0,0 +1,22 @@
|
||||
import { RecordTableBodyUnselectEffect } from '@/object-record/record-table/record-table-body/components/RecordTableBodyUnselectEffect';
|
||||
import { RecordTableNoRecordGroupBodyEffect } from '@/object-record/record-table/record-table-body/components/RecordTableNoRecordGroupBodyEffect';
|
||||
import { RecordTableRecordGroupBodyEffects } from '@/object-record/record-table/record-table-body/components/RecordTableRecordGroupBodyEffects';
|
||||
|
||||
export interface RecordTableBodyEffectsWrapperProps {
|
||||
hasRecordGroups: boolean;
|
||||
tableBodyRef: React.RefObject<HTMLTableElement>;
|
||||
}
|
||||
|
||||
export const RecordTableBodyEffectsWrapper = ({
|
||||
hasRecordGroups,
|
||||
tableBodyRef,
|
||||
}: RecordTableBodyEffectsWrapperProps) => (
|
||||
<>
|
||||
{hasRecordGroups ? (
|
||||
<RecordTableRecordGroupBodyEffects />
|
||||
) : (
|
||||
<RecordTableNoRecordGroupBodyEffect />
|
||||
)}
|
||||
<RecordTableBodyUnselectEffect tableBodyRef={tableBodyRef} />
|
||||
</>
|
||||
);
|
||||
@ -0,0 +1,42 @@
|
||||
import { RecordTableStickyBottomEffect } from '@/object-record/record-table/components/RecordTableStickyBottomEffect';
|
||||
import { RecordTableStickyEffect } from '@/object-record/record-table/components/RecordTableStickyEffect';
|
||||
import { StyledTable } from '@/object-record/record-table/components/RecordTableStyles';
|
||||
import { RecordTableNoRecordGroupBody } from '@/object-record/record-table/record-table-body/components/RecordTableNoRecordGroupBody';
|
||||
import { RecordTableRecordGroupsBody } from '@/object-record/record-table/record-table-body/components/RecordTableRecordGroupsBody';
|
||||
import { RecordTableHeader } from '@/object-record/record-table/record-table-header/components/RecordTableHeader';
|
||||
import { DragSelect } from '@/ui/utilities/drag-select/components/DragSelect';
|
||||
|
||||
export interface RecordTableContentProps {
|
||||
tableBodyRef: React.RefObject<HTMLTableElement>;
|
||||
handleDragSelectionStart: () => void;
|
||||
handleDragSelectionEnd: () => void;
|
||||
setRowSelected: (rowId: string, selected: boolean) => void;
|
||||
hasRecordGroups: boolean;
|
||||
}
|
||||
|
||||
export const RecordTableContent = ({
|
||||
tableBodyRef,
|
||||
handleDragSelectionStart,
|
||||
handleDragSelectionEnd,
|
||||
setRowSelected,
|
||||
hasRecordGroups,
|
||||
}: RecordTableContentProps) => (
|
||||
<>
|
||||
<StyledTable ref={tableBodyRef}>
|
||||
<RecordTableHeader />
|
||||
{hasRecordGroups ? (
|
||||
<RecordTableRecordGroupsBody />
|
||||
) : (
|
||||
<RecordTableNoRecordGroupBody />
|
||||
)}
|
||||
<RecordTableStickyEffect />
|
||||
<RecordTableStickyBottomEffect />
|
||||
</StyledTable>
|
||||
<DragSelect
|
||||
dragSelectable={tableBodyRef}
|
||||
onDragSelectionStart={handleDragSelectionStart}
|
||||
onDragSelectionChange={setRowSelected}
|
||||
onDragSelectionEnd={handleDragSelectionEnd}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
@ -0,0 +1,25 @@
|
||||
import { StyledTable } from '@/object-record/record-table/components/RecordTableStyles';
|
||||
import { RecordTableEmptyState } from '@/object-record/record-table/empty-state/components/RecordTableEmptyState';
|
||||
import { RecordTableRecordGroupsBody } from '@/object-record/record-table/record-table-body/components/RecordTableRecordGroupsBody';
|
||||
import { RecordTableHeader } from '@/object-record/record-table/record-table-header/components/RecordTableHeader';
|
||||
|
||||
export interface RecordTableEmptyProps {
|
||||
tableBodyRef: React.RefObject<HTMLTableElement>;
|
||||
hasRecordGroups: boolean;
|
||||
}
|
||||
|
||||
export const RecordTableEmpty = ({
|
||||
tableBodyRef,
|
||||
hasRecordGroups,
|
||||
}: RecordTableEmptyProps) => (
|
||||
<>
|
||||
<StyledTable ref={tableBodyRef}>
|
||||
<RecordTableHeader />
|
||||
</StyledTable>
|
||||
{hasRecordGroups ? (
|
||||
<RecordTableRecordGroupsBody />
|
||||
) : (
|
||||
<RecordTableEmptyState />
|
||||
)}
|
||||
</>
|
||||
);
|
||||
@ -0,0 +1,12 @@
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
export const StyledTable = styled.table`
|
||||
border-radius: ${({ theme }) => theme.border.radius.sm};
|
||||
border-spacing: 0;
|
||||
table-layout: fixed;
|
||||
width: 100%;
|
||||
|
||||
.footer-sticky tr:nth-last-of-type(2) td {
|
||||
border-bottom-color: ${({ theme }) => theme.background.transparent};
|
||||
}
|
||||
`;
|
||||
@ -1,6 +1,9 @@
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import { recordIndexAllRecordIdsComponentSelector } from '@/object-record/record-index/states/selectors/recordIndexAllRecordIdsComponentSelector';
|
||||
import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext';
|
||||
import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable';
|
||||
import { isRecordTableInitialLoadingComponentState } from '@/object-record/record-table/states/isRecordTableInitialLoadingComponentState';
|
||||
import { allRowsSelectedStatusComponentSelector } from '@/object-record/record-table/states/selectors/allRowsSelectedStatusComponentSelector';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { Checkbox } from 'twenty-ui/input';
|
||||
@ -30,6 +33,21 @@ export const RecordTableHeaderCheckboxColumn = () => {
|
||||
allRowsSelectedStatus === 'all' || allRowsSelectedStatus === 'some';
|
||||
const indeterminate = allRowsSelectedStatus === 'some';
|
||||
|
||||
const { recordTableId } = useRecordTableContextOrThrow();
|
||||
|
||||
const isRecordTableInitialLoading = useRecoilComponentValueV2(
|
||||
isRecordTableInitialLoadingComponentState,
|
||||
recordTableId,
|
||||
);
|
||||
|
||||
const allRecordIds = useRecoilComponentValueV2(
|
||||
recordIndexAllRecordIdsComponentSelector,
|
||||
recordTableId,
|
||||
);
|
||||
|
||||
const recordTableIsEmpty =
|
||||
!isRecordTableInitialLoading && allRecordIds.length === 0;
|
||||
|
||||
const onChange = () => {
|
||||
if (checked) {
|
||||
setHasUserSelectedAllRows(false);
|
||||
@ -48,6 +66,7 @@ export const RecordTableHeaderCheckboxColumn = () => {
|
||||
checked={checked}
|
||||
onChange={onChange}
|
||||
indeterminate={indeterminate}
|
||||
disabled={recordTableIsEmpty}
|
||||
/>
|
||||
</StyledContainer>
|
||||
</StyledColumnHeaderCell>
|
||||
|
||||
Reference in New Issue
Block a user