mirror of
https://github.com/twentyhq/twenty.git
synced 2024-11-27 11:03:40 +03:00
first column of objects table fixed (#3147)
* ui:first column of objects table fixed * refactor shadow style logic * Minor renaming fixes --------- Co-authored-by: Lucas Bordeau <bordeau.lucas@gmail.com>
This commit is contained in:
parent
858c294f14
commit
2204345300
@ -6,7 +6,7 @@ import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadata
|
|||||||
import { useObjectNameSingularFromPlural } from '@/object-metadata/hooks/useObjectNameSingularFromPlural';
|
import { useObjectNameSingularFromPlural } from '@/object-metadata/hooks/useObjectNameSingularFromPlural';
|
||||||
import { RecordUpdateHookParams } from '@/object-record/field/contexts/FieldContext';
|
import { RecordUpdateHookParams } from '@/object-record/field/contexts/FieldContext';
|
||||||
import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord';
|
import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord';
|
||||||
import { RecordTable } from '@/object-record/record-table/components/RecordTable';
|
import { RecordTableWithWrappers } from '@/object-record/record-table/components/RecordTableWithWrappers';
|
||||||
import { TableOptionsDropdownId } from '@/object-record/record-table/constants/TableOptionsDropdownId';
|
import { TableOptionsDropdownId } from '@/object-record/record-table/constants/TableOptionsDropdownId';
|
||||||
import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable';
|
import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable';
|
||||||
import { TableOptionsDropdown } from '@/object-record/record-table/options/components/TableOptionsDropdown';
|
import { TableOptionsDropdown } from '@/object-record/record-table/options/components/TableOptionsDropdown';
|
||||||
@ -24,6 +24,7 @@ const StyledContainer = styled.div`
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
|
padding-left: ${({ theme }) => theme.table.horizontalCellPadding};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const RecordTableContainer = ({
|
export const RecordTableContainer = ({
|
||||||
@ -103,7 +104,7 @@ export const RecordTableContainer = ({
|
|||||||
/>
|
/>
|
||||||
</SpreadsheetImportProvider>
|
</SpreadsheetImportProvider>
|
||||||
<RecordTableEffect recordTableId={recordTableId} viewBarId={viewBarId} />
|
<RecordTableEffect recordTableId={recordTableId} viewBarId={viewBarId} />
|
||||||
<RecordTable
|
<RecordTableWithWrappers
|
||||||
recordTableId={recordTableId}
|
recordTableId={recordTableId}
|
||||||
viewBarId={viewBarId}
|
viewBarId={viewBarId}
|
||||||
updateRecordMutation={updateEntity}
|
updateRecordMutation={updateEntity}
|
||||||
|
@ -1,70 +1,22 @@
|
|||||||
import { useRef } from 'react';
|
import { useContext } from 'react';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import { useRecoilCallback, useRecoilValue } from 'recoil';
|
|
||||||
|
|
||||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
import { RecordTableBody } from '@/object-record/record-table/components/RecordTableBody';
|
||||||
import { useObjectNameSingularFromPlural } from '@/object-metadata/hooks/useObjectNameSingularFromPlural';
|
import { RecordTableBodyEffect } from '@/object-record/record-table/components/RecordTableBodyEffect';
|
||||||
import { isRecordTableInitialLoadingState } from '@/object-record/record-table/states/isRecordTableInitialLoadingState';
|
import { RecordTableHeader } from '@/object-record/record-table/components/RecordTableHeader';
|
||||||
import { IconPlus } from '@/ui/display/icon';
|
import { RecordTableRefContext } from '@/object-record/record-table/contexts/RecordTableRefContext';
|
||||||
import { Button } from '@/ui/input/button/components/Button';
|
import { rgba } from '@/ui/theme/constants/colors';
|
||||||
import { DragSelect } from '@/ui/utilities/drag-select/components/DragSelect';
|
|
||||||
import { ScrollWrapper } from '@/ui/utilities/scroll/components/ScrollWrapper';
|
|
||||||
import { useViewFields } from '@/views/hooks/internal/useViewFields';
|
|
||||||
import { mapColumnDefinitionsToViewFields } from '@/views/utils/mapColumnDefinitionToViewField';
|
|
||||||
|
|
||||||
import { RecordUpdateContext } from '../contexts/EntityUpdateMutationHookContext';
|
|
||||||
import { useRecordTable } from '../hooks/useRecordTable';
|
|
||||||
import { RecordTableScope } from '../scopes/RecordTableScope';
|
|
||||||
import { numberOfTableRowsState } from '../states/numberOfTableRowsState';
|
|
||||||
|
|
||||||
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-radius: ${({ theme }) => theme.border.radius.sm};
|
border-radius: ${({ theme }) => theme.border.radius.sm};
|
||||||
border-spacing: 0;
|
border-spacing: 0;
|
||||||
margin-left: ${({ theme }) => theme.table.horizontalCellMargin};
|
|
||||||
margin-right: ${({ theme }) => theme.table.horizontalCellMargin};
|
margin-right: ${({ theme }) => theme.table.horizontalCellMargin};
|
||||||
table-layout: fixed;
|
table-layout: fixed;
|
||||||
|
|
||||||
width: calc(100% - ${({ theme }) => theme.table.horizontalCellMargin} * 2);
|
width: calc(100% - ${({ theme }) => theme.table.horizontalCellMargin} * 2);
|
||||||
|
|
||||||
th {
|
th {
|
||||||
border: 1px solid ${({ theme }) => theme.border.color.light};
|
border-block: 1px solid ${({ theme }) => theme.border.color.light};
|
||||||
border-collapse: collapse;
|
|
||||||
color: ${({ theme }) => theme.font.color.tertiary};
|
color: ${({ theme }) => theme.font.color.tertiary};
|
||||||
padding: 0;
|
padding: 0;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
@ -79,8 +31,7 @@ const StyledTable = styled.table`
|
|||||||
}
|
}
|
||||||
|
|
||||||
td {
|
td {
|
||||||
border: 1px solid ${({ theme }) => theme.border.color.light};
|
border-bottom: 1px solid ${({ theme }) => theme.border.color.light};
|
||||||
border-collapse: collapse;
|
|
||||||
color: ${({ theme }) => theme.font.color.primary};
|
color: ${({ theme }) => theme.font.color.primary};
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
|
||||||
@ -94,107 +45,67 @@ const StyledTable = styled.table`
|
|||||||
border-right-color: transparent;
|
border-right-color: transparent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
|
||||||
|
|
||||||
const StyledTableWithHeader = styled.div`
|
th,
|
||||||
display: flex;
|
td {
|
||||||
flex: 1;
|
background-color: ${({ theme }) => theme.background.primary};
|
||||||
flex-direction: column;
|
border-right: 1px solid ${({ theme }) => theme.border.color.light};
|
||||||
width: 100%;
|
}
|
||||||
`;
|
|
||||||
|
|
||||||
const StyledTableContainer = styled.div`
|
thead th:nth-of-type(-n + 2),
|
||||||
display: flex;
|
tbody td:nth-of-type(-n + 2) {
|
||||||
flex-direction: column;
|
position: sticky;
|
||||||
height: 100%;
|
z-index: 2;
|
||||||
position: relative;
|
border-right: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
thead th:nth-of-type(1),
|
||||||
|
tbody td:nth-of-type(1) {
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
thead th:nth-of-type(2),
|
||||||
|
tbody td:nth-of-type(2) {
|
||||||
|
left: calc(${({ theme }) => theme.table.checkboxColumnWidth} - 2px);
|
||||||
|
}
|
||||||
|
|
||||||
|
tbody td:nth-of-type(2)::after,
|
||||||
|
thead th:nth-of-type(2)::after {
|
||||||
|
content: '';
|
||||||
|
height: calc(100% + 1px);
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
width: 4px;
|
||||||
|
right: -4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.freeze-first-columns-shadow thead th:nth-of-type(2)::after,
|
||||||
|
&.freeze-first-columns-shadow tbody td:nth-of-type(2)::after {
|
||||||
|
box-shadow: ${({ theme }) =>
|
||||||
|
`4px 0px 4px -4px ${
|
||||||
|
theme.name === 'dark'
|
||||||
|
? rgba(theme.grayScale.gray50, 0.8)
|
||||||
|
: rgba(theme.grayScale.gray100, 0.25)
|
||||||
|
} inset`};
|
||||||
|
}
|
||||||
|
|
||||||
|
thead th:nth-of-type(3),
|
||||||
|
tbody td:nth-of-type(3) {
|
||||||
|
border-left: 1px solid ${({ theme }) => theme.border.color.light};
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
type RecordTableProps = {
|
type RecordTableProps = {
|
||||||
recordTableId: string;
|
|
||||||
viewBarId: string;
|
|
||||||
updateRecordMutation: (params: any) => void;
|
|
||||||
createRecord: () => void;
|
createRecord: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const RecordTable = ({
|
export const RecordTable = ({ createRecord }: RecordTableProps) => {
|
||||||
updateRecordMutation,
|
const recordTableRef = useContext(RecordTableRefContext);
|
||||||
createRecord,
|
|
||||||
recordTableId,
|
|
||||||
viewBarId,
|
|
||||||
}: RecordTableProps) => {
|
|
||||||
const tableBodyRef = useRef<HTMLDivElement>(null);
|
|
||||||
|
|
||||||
const numberOfTableRows = useRecoilValue(numberOfTableRowsState);
|
|
||||||
|
|
||||||
const isRecordTableInitialLoading = useRecoilValue(
|
|
||||||
isRecordTableInitialLoadingState,
|
|
||||||
);
|
|
||||||
|
|
||||||
const {
|
|
||||||
scopeId: objectNamePlural,
|
|
||||||
resetTableRowSelection,
|
|
||||||
setRowSelectedState,
|
|
||||||
} = useRecordTable({
|
|
||||||
recordTableScopeId: recordTableId,
|
|
||||||
});
|
|
||||||
|
|
||||||
const { objectNameSingular } = useObjectNameSingularFromPlural({
|
|
||||||
objectNamePlural,
|
|
||||||
});
|
|
||||||
|
|
||||||
const { objectMetadataItem: foundObjectMetadataItem } = useObjectMetadataItem(
|
|
||||||
{
|
|
||||||
objectNameSingular,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
const { persistViewFields } = useViewFields(viewBarId);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<RecordTableScope
|
<StyledTable ref={recordTableRef} className="entity-table-cell">
|
||||||
recordTableScopeId={recordTableId}
|
|
||||||
onColumnsChange={useRecoilCallback(() => (columns) => {
|
|
||||||
persistViewFields(mapColumnDefinitionsToViewFields(columns));
|
|
||||||
})}
|
|
||||||
>
|
|
||||||
<ScrollWrapper>
|
|
||||||
<RecordUpdateContext.Provider value={updateRecordMutation}>
|
|
||||||
<StyledTableWithHeader>
|
|
||||||
<StyledTableContainer>
|
|
||||||
<div ref={tableBodyRef}>
|
|
||||||
<StyledTable className="entity-table-cell">
|
|
||||||
<RecordTableHeader createRecord={createRecord} />
|
<RecordTableHeader createRecord={createRecord} />
|
||||||
<RecordTableBodyEffect />
|
<RecordTableBodyEffect />
|
||||||
<RecordTableBody />
|
<RecordTableBody />
|
||||||
</StyledTable>
|
</StyledTable>
|
||||||
<DragSelect
|
|
||||||
dragSelectable={tableBodyRef}
|
|
||||||
onDragSelectionStart={resetTableRowSelection}
|
|
||||||
onDragSelectionChange={setRowSelectedState}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<RecordTableInternalEffect tableBodyRef={tableBodyRef} />
|
|
||||||
{!isRecordTableInitialLoading && 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>
|
|
||||||
</StyledTableWithHeader>
|
|
||||||
</RecordUpdateContext.Provider>
|
|
||||||
</ScrollWrapper>
|
|
||||||
</RecordTableScope>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -0,0 +1,22 @@
|
|||||||
|
import { useContext } from 'react';
|
||||||
|
import { useInView } from 'react-intersection-observer';
|
||||||
|
|
||||||
|
import { RecordTableRefContext } from '@/object-record/record-table/contexts/RecordTableRefContext';
|
||||||
|
import { ScrollWrapperContext } from '@/ui/utilities/scroll/components/ScrollWrapper';
|
||||||
|
|
||||||
|
export const RecordTableFirstColumnScrollObserver = () => {
|
||||||
|
const scrollWrapperRef = useContext(ScrollWrapperContext);
|
||||||
|
const recordTableRef = useContext(RecordTableRefContext);
|
||||||
|
|
||||||
|
const { ref: elementRef } = useInView({
|
||||||
|
root: scrollWrapperRef.current,
|
||||||
|
onChange: (inView) => {
|
||||||
|
recordTableRef.current?.classList.toggle(
|
||||||
|
'freeze-first-columns-shadow',
|
||||||
|
!inView,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return <div ref={elementRef}></div>;
|
||||||
|
};
|
@ -28,7 +28,7 @@ const StyledColumnHeaderCell = styled.th<{
|
|||||||
${({ theme }) => {
|
${({ theme }) => {
|
||||||
return `
|
return `
|
||||||
&:hover {
|
&:hover {
|
||||||
background: ${theme.background.transparent.light};
|
background: ${theme.background.quaternary};
|
||||||
};
|
};
|
||||||
`;
|
`;
|
||||||
}};
|
}};
|
||||||
|
@ -0,0 +1,19 @@
|
|||||||
|
import { useRef } from 'react';
|
||||||
|
|
||||||
|
import { RecordTableRefContext } from '@/object-record/record-table/contexts/RecordTableRefContext';
|
||||||
|
|
||||||
|
export type RecordTableRefContextWrapperProps = {
|
||||||
|
children: React.ReactNode;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const RecordTableRefContextWrapper = ({
|
||||||
|
children,
|
||||||
|
}: RecordTableRefContextWrapperProps) => {
|
||||||
|
const tableRef = useRef<HTMLTableElement>(null);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<RecordTableRefContext.Provider value={tableRef}>
|
||||||
|
{children}
|
||||||
|
</RecordTableRefContext.Provider>
|
||||||
|
);
|
||||||
|
};
|
@ -0,0 +1,154 @@
|
|||||||
|
import { useRef } from 'react';
|
||||||
|
import styled from '@emotion/styled';
|
||||||
|
import { useRecoilCallback, useRecoilValue } from 'recoil';
|
||||||
|
|
||||||
|
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||||
|
import { useObjectNameSingularFromPlural } from '@/object-metadata/hooks/useObjectNameSingularFromPlural';
|
||||||
|
import { RecordTable } from '@/object-record/record-table/components/RecordTable';
|
||||||
|
import { RecordTableFirstColumnScrollObserver } from '@/object-record/record-table/components/RecordTableFirstColumnScrollObserver';
|
||||||
|
import { RecordTableRefContextWrapper } from '@/object-record/record-table/components/RecordTableRefContext';
|
||||||
|
import { isRecordTableInitialLoadingState } from '@/object-record/record-table/states/isRecordTableInitialLoadingState';
|
||||||
|
import { IconPlus } from '@/ui/display/icon';
|
||||||
|
import { Button } from '@/ui/input/button/components/Button';
|
||||||
|
import { DragSelect } from '@/ui/utilities/drag-select/components/DragSelect';
|
||||||
|
import { ScrollWrapper } from '@/ui/utilities/scroll/components/ScrollWrapper';
|
||||||
|
import { useViewFields } from '@/views/hooks/internal/useViewFields';
|
||||||
|
import { mapColumnDefinitionsToViewFields } from '@/views/utils/mapColumnDefinitionToViewField';
|
||||||
|
|
||||||
|
import { RecordUpdateContext } from '../contexts/EntityUpdateMutationHookContext';
|
||||||
|
import { useRecordTable } from '../hooks/useRecordTable';
|
||||||
|
import { RecordTableScope } from '../scopes/RecordTableScope';
|
||||||
|
import { numberOfTableRowsState } from '../states/numberOfTableRowsState';
|
||||||
|
|
||||||
|
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 StyledTableWithHeader = styled.div`
|
||||||
|
display: flex;
|
||||||
|
flex: 1;
|
||||||
|
flex-direction: column;
|
||||||
|
width: 100%;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const StyledTableContainer = styled.div`
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100%;
|
||||||
|
position: relative;
|
||||||
|
`;
|
||||||
|
|
||||||
|
type RecordTableWithWrappersProps = {
|
||||||
|
recordTableId: string;
|
||||||
|
viewBarId: string;
|
||||||
|
updateRecordMutation: (params: any) => void;
|
||||||
|
createRecord: () => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const RecordTableWithWrappers = ({
|
||||||
|
updateRecordMutation,
|
||||||
|
createRecord,
|
||||||
|
recordTableId,
|
||||||
|
viewBarId,
|
||||||
|
}: RecordTableWithWrappersProps) => {
|
||||||
|
const tableBodyRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
|
const numberOfTableRows = useRecoilValue(numberOfTableRowsState);
|
||||||
|
|
||||||
|
const isRecordTableInitialLoading = useRecoilValue(
|
||||||
|
isRecordTableInitialLoadingState,
|
||||||
|
);
|
||||||
|
|
||||||
|
const {
|
||||||
|
scopeId: objectNamePlural,
|
||||||
|
resetTableRowSelection,
|
||||||
|
setRowSelectedState,
|
||||||
|
} = useRecordTable({
|
||||||
|
recordTableScopeId: recordTableId,
|
||||||
|
});
|
||||||
|
|
||||||
|
const { objectNameSingular } = useObjectNameSingularFromPlural({
|
||||||
|
objectNamePlural,
|
||||||
|
});
|
||||||
|
|
||||||
|
const { objectMetadataItem: foundObjectMetadataItem } = useObjectMetadataItem(
|
||||||
|
{
|
||||||
|
objectNameSingular,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
const { persistViewFields } = useViewFields(viewBarId);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<RecordTableScope
|
||||||
|
recordTableScopeId={recordTableId}
|
||||||
|
onColumnsChange={useRecoilCallback(() => (columns) => {
|
||||||
|
persistViewFields(mapColumnDefinitionsToViewFields(columns));
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<ScrollWrapper>
|
||||||
|
<RecordTableRefContextWrapper>
|
||||||
|
<RecordTableFirstColumnScrollObserver />
|
||||||
|
<RecordUpdateContext.Provider value={updateRecordMutation}>
|
||||||
|
<StyledTableWithHeader>
|
||||||
|
<StyledTableContainer>
|
||||||
|
<div ref={tableBodyRef}>
|
||||||
|
<RecordTable createRecord={createRecord} />
|
||||||
|
<DragSelect
|
||||||
|
dragSelectable={tableBodyRef}
|
||||||
|
onDragSelectionStart={resetTableRowSelection}
|
||||||
|
onDragSelectionChange={setRowSelectedState}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<RecordTableInternalEffect tableBodyRef={tableBodyRef} />
|
||||||
|
{!isRecordTableInitialLoading && 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>
|
||||||
|
</StyledTableWithHeader>
|
||||||
|
</RecordUpdateContext.Provider>
|
||||||
|
</RecordTableRefContextWrapper>
|
||||||
|
</ScrollWrapper>
|
||||||
|
</RecordTableScope>
|
||||||
|
);
|
||||||
|
};
|
@ -0,0 +1,7 @@
|
|||||||
|
import { createContext, RefObject } from 'react';
|
||||||
|
|
||||||
|
export const RecordTableRefContext = createContext<RefObject<HTMLTableElement>>(
|
||||||
|
{
|
||||||
|
current: null,
|
||||||
|
},
|
||||||
|
);
|
@ -1,6 +1,6 @@
|
|||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
|
|
||||||
import { RecordTable } from '@/object-record/record-table/components/RecordTable';
|
import { RecordTableWithWrappers } from '@/object-record/record-table/components/RecordTableWithWrappers';
|
||||||
import { TableOptionsDropdownId } from '@/object-record/record-table/constants/TableOptionsDropdownId';
|
import { TableOptionsDropdownId } from '@/object-record/record-table/constants/TableOptionsDropdownId';
|
||||||
import { TableOptionsDropdown } from '@/object-record/record-table/options/components/TableOptionsDropdown';
|
import { TableOptionsDropdown } from '@/object-record/record-table/options/components/TableOptionsDropdown';
|
||||||
import { SignInBackgroundMockContainerEffect } from '@/sign-in-background-mock/components/SignInBackgroundMockContainerEffect';
|
import { SignInBackgroundMockContainerEffect } from '@/sign-in-background-mock/components/SignInBackgroundMockContainerEffect';
|
||||||
@ -30,7 +30,7 @@ export const SignInBackgroundMockContainer = () => {
|
|||||||
recordTableId={recordTableId}
|
recordTableId={recordTableId}
|
||||||
viewId={viewBarId}
|
viewId={viewBarId}
|
||||||
/>
|
/>
|
||||||
<RecordTable
|
<RecordTableWithWrappers
|
||||||
recordTableId={recordTableId}
|
recordTableId={recordTableId}
|
||||||
viewBarId={viewBarId}
|
viewBarId={viewBarId}
|
||||||
createRecord={() => {}}
|
createRecord={() => {}}
|
||||||
|
@ -41,6 +41,7 @@ const common = {
|
|||||||
table: {
|
table: {
|
||||||
horizontalCellMargin: '8px',
|
horizontalCellMargin: '8px',
|
||||||
checkboxColumnWidth: '32px',
|
checkboxColumnWidth: '32px',
|
||||||
|
horizontalCellPadding: '8px',
|
||||||
},
|
},
|
||||||
rightDrawerWidth: '500px',
|
rightDrawerWidth: '500px',
|
||||||
clickableElementBackgroundTransition: 'background 0.1s ease',
|
clickableElementBackgroundTransition: 'background 0.1s ease',
|
||||||
|
Loading…
Reference in New Issue
Block a user