mirror of
https://github.com/twentyhq/twenty.git
synced 2024-12-22 19:41:53 +03:00
fix: can't properly drag and drop in empty record group (#9039)
Fix #8968 Fix issue with drag and drop when record group are empty. Happy to discuss the implementation, as it's limited to the `@hello-pangea/dnd` api. --------- Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
parent
d56c815897
commit
07aaf0801c
@ -1,14 +1,6 @@
|
||||
import React, { Ref, RefCallback } from 'react';
|
||||
import { isFunction } from '@sniptt/guards';
|
||||
import { Ref, RefCallback } from 'react';
|
||||
import { combineRefs } from '~/utils/combineRefs';
|
||||
|
||||
export const useCombinedRefs =
|
||||
<T>(...refs: (Ref<T> | undefined)[]): RefCallback<T> =>
|
||||
(node: T) => {
|
||||
for (const ref of refs) {
|
||||
if (isFunction(ref)) {
|
||||
ref(node);
|
||||
} else if (ref !== null && ref !== undefined) {
|
||||
(ref as React.MutableRefObject<T | null>).current = node;
|
||||
}
|
||||
}
|
||||
};
|
||||
export const useCombinedRefs = <T>(
|
||||
...refs: (Ref<T> | undefined)[]
|
||||
): RefCallback<T> => combineRefs<T>(...refs);
|
||||
|
@ -14,13 +14,14 @@ import {
|
||||
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
|
||||
import { RecordTableComponentInstance } from '@/object-record/record-table/components/RecordTableComponentInstance';
|
||||
import { RecordTableCellContext } from '@/object-record/record-table/contexts/RecordTableCellContext';
|
||||
import { RecordTableRowContext } from '@/object-record/record-table/contexts/RecordTableRowContext';
|
||||
import { ChipGeneratorsDecorator } from '~/testing/decorators/ChipGeneratorsDecorator';
|
||||
import { MemoryRouterDecorator } from '~/testing/decorators/MemoryRouterDecorator';
|
||||
import { getProfilingStory } from '~/testing/profiling/utils/getProfilingStory';
|
||||
|
||||
import { RecordTableBodyContextProvider } from '@/object-record/record-table/contexts/RecordTableBodyContext';
|
||||
import { RecordTableContextProvider } from '@/object-record/record-table/contexts/RecordTableContext';
|
||||
import { RecordTableRowContextProvider } from '@/object-record/record-table/contexts/RecordTableRowContext';
|
||||
import { RecordTableRowDraggableContextProvider } from '@/object-record/record-table/contexts/RecordTableRowDraggableContext';
|
||||
import { RecordTableCellFieldContextWrapper } from '@/object-record/record-table/record-table-cell/components/RecordTableCellFieldContextWrapper';
|
||||
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
|
||||
import { mockPerformance } from './mock';
|
||||
@ -87,7 +88,7 @@ const meta: Meta = {
|
||||
onCellMouseEnter: () => {},
|
||||
}}
|
||||
>
|
||||
<RecordTableRowContext.Provider
|
||||
<RecordTableRowContextProvider
|
||||
value={{
|
||||
objectNameSingular:
|
||||
mockPerformance.entityValue.__typename.toLocaleLowerCase(),
|
||||
@ -99,43 +100,48 @@ const meta: Meta = {
|
||||
mockPerformance.entityValue.__typename.toLocaleLowerCase(),
|
||||
}) + mockPerformance.recordId,
|
||||
isSelected: false,
|
||||
isDragging: false,
|
||||
dragHandleProps: null,
|
||||
inView: true,
|
||||
isPendingRow: false,
|
||||
inView: true,
|
||||
}}
|
||||
>
|
||||
<RecordTableCellContext.Provider
|
||||
<RecordTableRowDraggableContextProvider
|
||||
value={{
|
||||
columnDefinition: mockPerformance.fieldDefinition,
|
||||
columnIndex: 0,
|
||||
cellPosition: { row: 0, column: 0 },
|
||||
hasSoftFocus: false,
|
||||
isInEditMode: false,
|
||||
isDragging: false,
|
||||
dragHandleProps: null,
|
||||
}}
|
||||
>
|
||||
<FieldContext.Provider
|
||||
<RecordTableCellContext.Provider
|
||||
value={{
|
||||
recordId: mockPerformance.recordId,
|
||||
basePathToShowPage: '/object-record/',
|
||||
isLabelIdentifier: false,
|
||||
fieldDefinition: {
|
||||
...mockPerformance.fieldDefinition,
|
||||
},
|
||||
hotkeyScope: 'hotkey-scope',
|
||||
columnDefinition: mockPerformance.fieldDefinition,
|
||||
columnIndex: 0,
|
||||
cellPosition: { row: 0, column: 0 },
|
||||
hasSoftFocus: false,
|
||||
isInEditMode: false,
|
||||
}}
|
||||
>
|
||||
<RelationFieldValueSetterEffect />
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<Story />
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</FieldContext.Provider>
|
||||
</RecordTableCellContext.Provider>
|
||||
</RecordTableRowContext.Provider>
|
||||
<FieldContext.Provider
|
||||
value={{
|
||||
recordId: mockPerformance.recordId,
|
||||
basePathToShowPage: '/object-record/',
|
||||
isLabelIdentifier: false,
|
||||
fieldDefinition: {
|
||||
...mockPerformance.fieldDefinition,
|
||||
},
|
||||
hotkeyScope: 'hotkey-scope',
|
||||
}}
|
||||
>
|
||||
<RelationFieldValueSetterEffect />
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<Story />
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</FieldContext.Provider>
|
||||
</RecordTableCellContext.Provider>
|
||||
</RecordTableRowDraggableContextProvider>
|
||||
</RecordTableRowContextProvider>
|
||||
</RecordTableBodyContextProvider>
|
||||
</RecordTableComponentInstance>
|
||||
</RecordTableContextProvider>
|
||||
|
@ -4,7 +4,7 @@ import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata'
|
||||
import { ColumnDefinition } from '@/object-record/record-table/types/ColumnDefinition';
|
||||
import { TableCellPosition } from '@/object-record/record-table/types/TableCellPosition';
|
||||
|
||||
export type RecordTableCellContextProps = {
|
||||
export type RecordTableCellContextValue = {
|
||||
columnDefinition: ColumnDefinition<FieldMetadata>;
|
||||
columnIndex: number;
|
||||
isInEditMode: boolean;
|
||||
@ -13,4 +13,4 @@ export type RecordTableCellContextProps = {
|
||||
};
|
||||
|
||||
export const RecordTableCellContext =
|
||||
createContext<RecordTableCellContextProps>({} as RecordTableCellContextProps);
|
||||
createContext<RecordTableCellContextValue>({} as RecordTableCellContextValue);
|
||||
|
@ -1,19 +1,14 @@
|
||||
import { DraggableProvidedDragHandleProps } from '@hello-pangea/dnd';
|
||||
import { createContext } from 'react';
|
||||
import { createRequiredContext } from '~/utils/createRequiredContext';
|
||||
|
||||
export type RecordTableRowContextProps = {
|
||||
export type RecordTableRowContextValue = {
|
||||
pathToShowPage: string;
|
||||
objectNameSingular: string;
|
||||
recordId: string;
|
||||
rowIndex: number;
|
||||
isSelected: boolean;
|
||||
inView: boolean;
|
||||
isPendingRow?: boolean;
|
||||
isDragging: boolean;
|
||||
dragHandleProps: DraggableProvidedDragHandleProps | null;
|
||||
inView?: boolean;
|
||||
isDragDisabled?: boolean;
|
||||
};
|
||||
|
||||
export const RecordTableRowContext = createContext<RecordTableRowContextProps>(
|
||||
{} as RecordTableRowContextProps,
|
||||
);
|
||||
export const [RecordTableRowContextProvider, useRecordTableRowContextOrThrow] =
|
||||
createRequiredContext<RecordTableRowContextValue>('RecordTableRowContext');
|
||||
|
@ -0,0 +1,14 @@
|
||||
import { DraggableProvidedDragHandleProps } from '@hello-pangea/dnd';
|
||||
import { createRequiredContext } from '~/utils/createRequiredContext';
|
||||
|
||||
export type RecordTableRowDraggableContextValue = {
|
||||
isDragging: boolean;
|
||||
dragHandleProps: DraggableProvidedDragHandleProps | null;
|
||||
};
|
||||
|
||||
export const [
|
||||
RecordTableRowDraggableContextProvider,
|
||||
useRecordTableRowDraggableContextOrThrow,
|
||||
] = createRequiredContext<RecordTableRowDraggableContextValue>(
|
||||
'RecordTableRowDraggableContext',
|
||||
);
|
@ -1,3 +1,5 @@
|
||||
import { RecordTableRowContextProvider } from '@/object-record/record-table/contexts/RecordTableRowContext';
|
||||
import { RecordTableRowDraggableContextProvider } from '@/object-record/record-table/contexts/RecordTableRowDraggableContext';
|
||||
import { RecordTableCellCheckbox } from '@/object-record/record-table/record-table-cell/components/RecordTableCellCheckbox';
|
||||
import { RecordTableCellGrip } from '@/object-record/record-table/record-table-cell/components/RecordTableCellGrip';
|
||||
import { RecordTableCellLoading } from '@/object-record/record-table/record-table-cell/components/RecordTableCellLoading';
|
||||
@ -13,18 +15,36 @@ export const RecordTableBodyLoading = () => {
|
||||
return (
|
||||
<tbody>
|
||||
{Array.from({ length: 8 }).map((_, rowIndex) => (
|
||||
<RecordTableTr
|
||||
isDragging={false}
|
||||
data-testid={`row-id-${rowIndex}`}
|
||||
data-selectable-id={`row-id-${rowIndex}`}
|
||||
<RecordTableRowContextProvider
|
||||
key={rowIndex}
|
||||
value={{
|
||||
pathToShowPage: '',
|
||||
objectNameSingular: '',
|
||||
recordId: `${rowIndex}`,
|
||||
rowIndex,
|
||||
isSelected: false,
|
||||
inView: true,
|
||||
}}
|
||||
>
|
||||
<RecordTableCellGrip />
|
||||
<RecordTableCellCheckbox />
|
||||
{visibleTableColumns.map((column) => (
|
||||
<RecordTableCellLoading key={column.fieldMetadataId} />
|
||||
))}
|
||||
</RecordTableTr>
|
||||
<RecordTableRowDraggableContextProvider
|
||||
value={{
|
||||
dragHandleProps: {} as any,
|
||||
isDragging: false,
|
||||
}}
|
||||
>
|
||||
<RecordTableTr
|
||||
isDragging={false}
|
||||
data-testid={`row-id-${rowIndex}`}
|
||||
data-selectable-id={`row-id-${rowIndex}`}
|
||||
>
|
||||
<RecordTableCellGrip />
|
||||
<RecordTableCellCheckbox />
|
||||
{visibleTableColumns.map((column) => (
|
||||
<RecordTableCellLoading key={column.fieldMetadataId} />
|
||||
))}
|
||||
</RecordTableTr>
|
||||
</RecordTableRowDraggableContextProvider>
|
||||
</RecordTableRowContextProvider>
|
||||
))}
|
||||
</tbody>
|
||||
);
|
||||
|
@ -35,9 +35,9 @@ export const RecordTableRecordGroupsBody = () => {
|
||||
key={recordGroupId}
|
||||
recordGroupId={recordGroupId}
|
||||
>
|
||||
{index > 0 && <RecordTableRecordGroupEmptyRow />}
|
||||
<RecordGroupContext.Provider value={{ recordGroupId }}>
|
||||
<RecordTableBodyDroppable recordGroupId={recordGroupId}>
|
||||
{index > 0 && <RecordTableRecordGroupEmptyRow />}
|
||||
<RecordTableRecordGroupSection />
|
||||
<RecordTableRecordGroupRows />
|
||||
</RecordTableBodyDroppable>
|
||||
|
@ -1,7 +1,7 @@
|
||||
import styled from '@emotion/styled';
|
||||
import { useCallback, useContext } from 'react';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import { RecordTableRowContext } from '@/object-record/record-table/contexts/RecordTableRowContext';
|
||||
import { useRecordTableRowContextOrThrow } from '@/object-record/record-table/contexts/RecordTableRowContext';
|
||||
import { RecordTableTd } from '@/object-record/record-table/record-table-cell/components/RecordTableTd';
|
||||
import { useSetCurrentRowSelected } from '@/object-record/record-table/record-table-row/hooks/useSetCurrentRowSelected';
|
||||
import { Checkbox } from 'twenty-ui';
|
||||
@ -16,7 +16,7 @@ const StyledContainer = styled.div`
|
||||
`;
|
||||
|
||||
export const RecordTableCellCheckbox = () => {
|
||||
const { isSelected } = useContext(RecordTableRowContext);
|
||||
const { isSelected } = useRecordTableRowContextOrThrow();
|
||||
|
||||
const { setCurrentRowSelected } = useSetCurrentRowSelected();
|
||||
|
||||
|
@ -7,7 +7,7 @@ import { isFieldSelect } from '@/object-record/record-field/types/guards/isField
|
||||
import { RecordUpdateContext } from '@/object-record/record-table/contexts/EntityUpdateMutationHookContext';
|
||||
import { RecordTableCellContext } from '@/object-record/record-table/contexts/RecordTableCellContext';
|
||||
import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext';
|
||||
import { RecordTableRowContext } from '@/object-record/record-table/contexts/RecordTableRowContext';
|
||||
import { useRecordTableRowContextOrThrow } from '@/object-record/record-table/contexts/RecordTableRowContext';
|
||||
import { TableHotkeyScope } from '@/object-record/record-table/types/TableHotkeyScope';
|
||||
import { RelationPickerHotkeyScope } from '@/object-record/relation-picker/types/RelationPickerHotkeyScope';
|
||||
import { SelectFieldHotkeyScope } from '@/object-record/select/types/SelectFieldHotkeyScope';
|
||||
@ -22,7 +22,7 @@ export const RecordTableCellFieldContextWrapper = ({
|
||||
|
||||
const { columnDefinition } = useContext(RecordTableCellContext);
|
||||
|
||||
const { recordId, pathToShowPage } = useContext(RecordTableRowContext);
|
||||
const { recordId, pathToShowPage } = useRecordTableRowContextOrThrow();
|
||||
|
||||
const updateRecord = useContext(RecordUpdateContext);
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
import styled from '@emotion/styled';
|
||||
import { useContext } from 'react';
|
||||
|
||||
import { RecordTableRowContext } from '@/object-record/record-table/contexts/RecordTableRowContext';
|
||||
import { useRecordTableRowContextOrThrow } from '@/object-record/record-table/contexts/RecordTableRowContext';
|
||||
import { useRecordTableRowDraggableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableRowDraggableContext';
|
||||
import { RecordTableTd } from '@/object-record/record-table/record-table-cell/components/RecordTableTd';
|
||||
import { css } from '@emotion/react';
|
||||
import { IconListViewGrip } from 'twenty-ui';
|
||||
@ -30,9 +30,10 @@ const StyledIconWrapper = styled.div<{ isDragging: boolean }>`
|
||||
`;
|
||||
|
||||
export const RecordTableCellGrip = () => {
|
||||
const { dragHandleProps, isDragging, isPendingRow } = useContext(
|
||||
RecordTableRowContext,
|
||||
);
|
||||
const { isPendingRow } = useRecordTableRowContextOrThrow();
|
||||
|
||||
const { dragHandleProps, isDragging } =
|
||||
useRecordTableRowDraggableContextOrThrow();
|
||||
|
||||
return (
|
||||
<RecordTableTd
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { useContext, useMemo } from 'react';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata';
|
||||
import { RecordTableCellContext } from '@/object-record/record-table/contexts/RecordTableCellContext';
|
||||
import { RecordTableRowContext } from '@/object-record/record-table/contexts/RecordTableRowContext';
|
||||
import { useRecordTableRowContextOrThrow } from '@/object-record/record-table/contexts/RecordTableRowContext';
|
||||
import { RecordTableCellFieldContextWrapper } from '@/object-record/record-table/record-table-cell/components/RecordTableCellFieldContextWrapper';
|
||||
import { isSoftFocusOnTableCellComponentFamilyState } from '@/object-record/record-table/states/isSoftFocusOnTableCellComponentFamilyState';
|
||||
import { isTableCellInEditModeComponentFamilyState } from '@/object-record/record-table/states/isTableCellInEditModeComponentFamilyState';
|
||||
@ -19,7 +19,7 @@ export const RecordTableCellWrapper = ({
|
||||
columnIndex: number;
|
||||
children: React.ReactNode;
|
||||
}) => {
|
||||
const { rowIndex } = useContext(RecordTableRowContext);
|
||||
const { rowIndex } = useRecordTableRowContextOrThrow();
|
||||
|
||||
const currentTableCellPosition: TableCellPosition = useMemo(
|
||||
() => ({
|
||||
|
@ -1,10 +1,8 @@
|
||||
import { useContext } from 'react';
|
||||
|
||||
import { RecordTableRowContext } from '@/object-record/record-table/contexts/RecordTableRowContext';
|
||||
import { useRecordTableRowContextOrThrow } from '@/object-record/record-table/contexts/RecordTableRowContext';
|
||||
import { RecordTableTd } from '@/object-record/record-table/record-table-cell/components/RecordTableTd';
|
||||
|
||||
export const RecordTableLastEmptyCell = () => {
|
||||
const { isSelected } = useContext(RecordTableRowContext);
|
||||
const { isSelected } = useRecordTableRowContextOrThrow();
|
||||
|
||||
return (
|
||||
<>
|
||||
|
@ -1,20 +1,24 @@
|
||||
import { RecordTableCellContextProps } from '@/object-record/record-table/contexts/RecordTableCellContext';
|
||||
import { RecordTableRowContextProps } from '@/object-record/record-table/contexts/RecordTableRowContext';
|
||||
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
||||
import { RecordTableCellContextValue } from '@/object-record/record-table/contexts/RecordTableCellContext';
|
||||
import { RecordTableRowContextValue } from '@/object-record/record-table/contexts/RecordTableRowContext';
|
||||
import { RecordTableRowDraggableContextValue } from '@/object-record/record-table/contexts/RecordTableRowDraggableContext';
|
||||
import { FieldMetadataType } from '~/generated/graphql';
|
||||
|
||||
export const recordTableRow: RecordTableRowContextProps = {
|
||||
export const recordTableRowContextValue: RecordTableRowContextValue = {
|
||||
rowIndex: 2,
|
||||
isSelected: false,
|
||||
recordId: 'recordId',
|
||||
pathToShowPage: '/',
|
||||
objectNameSingular: 'objectNameSingular',
|
||||
dragHandleProps: {} as any,
|
||||
isDragging: false,
|
||||
inView: true,
|
||||
isPendingRow: false,
|
||||
inView: true,
|
||||
};
|
||||
|
||||
export const recordTableCell: RecordTableCellContextProps = {
|
||||
export const recordTableRowDraggableContextValue: RecordTableRowDraggableContextValue = {
|
||||
dragHandleProps: {} as any,
|
||||
isDragging: false,
|
||||
};
|
||||
|
||||
export const recordTableCellContextValue: RecordTableCellContextValue = {
|
||||
columnIndex: 3,
|
||||
columnDefinition: {
|
||||
size: 1,
|
||||
|
@ -1,19 +1,28 @@
|
||||
import { renderHook } from '@testing-library/react';
|
||||
|
||||
import { RecordTableCellContext } from '@/object-record/record-table/contexts/RecordTableCellContext';
|
||||
import { RecordTableRowContext } from '@/object-record/record-table/contexts/RecordTableRowContext';
|
||||
import { RecordTableRowContextProvider } from '@/object-record/record-table/contexts/RecordTableRowContext';
|
||||
|
||||
import { recordTableCell, recordTableRow } from '../__mocks__/cell';
|
||||
import { RecordTableRowDraggableContextProvider } from '@/object-record/record-table/contexts/RecordTableRowDraggableContext';
|
||||
import {
|
||||
recordTableCellContextValue,
|
||||
recordTableRowContextValue,
|
||||
recordTableRowDraggableContextValue,
|
||||
} from '@/object-record/record-table/record-table-cell/hooks/__mocks__/cell';
|
||||
import { useCurrentTableCellPosition } from '../useCurrentCellPosition';
|
||||
|
||||
describe('useCurrentTableCellPosition', () => {
|
||||
it('should return the current table cell position', () => {
|
||||
const wrapper = ({ children }: { children: React.ReactNode }) => (
|
||||
<RecordTableRowContext.Provider value={recordTableRow}>
|
||||
<RecordTableCellContext.Provider value={recordTableCell}>
|
||||
{children}
|
||||
</RecordTableCellContext.Provider>
|
||||
</RecordTableRowContext.Provider>
|
||||
<RecordTableRowContextProvider value={recordTableRowContextValue}>
|
||||
<RecordTableRowDraggableContextProvider
|
||||
value={recordTableRowDraggableContextValue}
|
||||
>
|
||||
<RecordTableCellContext.Provider value={recordTableCellContextValue}>
|
||||
{children}
|
||||
</RecordTableCellContext.Provider>
|
||||
</RecordTableRowDraggableContextProvider>
|
||||
</RecordTableRowContextProvider>
|
||||
);
|
||||
|
||||
const { result } = renderHook(() => useCurrentTableCellPosition(), {
|
||||
|
@ -3,10 +3,12 @@ import { RecoilRoot } from 'recoil';
|
||||
|
||||
import { RecordTableComponentInstance } from '@/object-record/record-table/components/RecordTableComponentInstance';
|
||||
import { RecordTableCellContext } from '@/object-record/record-table/contexts/RecordTableCellContext';
|
||||
import { RecordTableRowContext } from '@/object-record/record-table/contexts/RecordTableRowContext';
|
||||
import { RecordTableRowContextProvider } from '@/object-record/record-table/contexts/RecordTableRowContext';
|
||||
import { RecordTableRowDraggableContextProvider } from '@/object-record/record-table/contexts/RecordTableRowDraggableContext';
|
||||
import {
|
||||
recordTableCell,
|
||||
recordTableRow,
|
||||
recordTableCellContextValue,
|
||||
recordTableRowContextValue,
|
||||
recordTableRowDraggableContextValue,
|
||||
} from '@/object-record/record-table/record-table-cell/hooks/__mocks__/cell';
|
||||
import { useIsSoftFocusOnCurrentTableCell } from '@/object-record/record-table/record-table-cell/hooks/useIsSoftFocusOnCurrentTableCell';
|
||||
|
||||
@ -16,11 +18,15 @@ const Wrapper = ({ children }: { children: React.ReactNode }) => (
|
||||
recordTableId="scopeId"
|
||||
onColumnsChange={jest.fn()}
|
||||
>
|
||||
<RecordTableRowContext.Provider value={recordTableRow}>
|
||||
<RecordTableCellContext.Provider value={recordTableCell}>
|
||||
{children}
|
||||
</RecordTableCellContext.Provider>
|
||||
</RecordTableRowContext.Provider>
|
||||
<RecordTableRowContextProvider value={recordTableRowContextValue}>
|
||||
<RecordTableRowDraggableContextProvider
|
||||
value={recordTableRowDraggableContextValue}
|
||||
>
|
||||
<RecordTableCellContext.Provider value={recordTableCellContextValue}>
|
||||
{children}
|
||||
</RecordTableCellContext.Provider>
|
||||
</RecordTableRowDraggableContextProvider>
|
||||
</RecordTableRowContextProvider>
|
||||
</RecordTableComponentInstance>
|
||||
</RecoilRoot>
|
||||
);
|
||||
|
@ -3,10 +3,12 @@ import { CallbackInterface, RecoilRoot } from 'recoil';
|
||||
|
||||
import { RecordTableComponentInstance } from '@/object-record/record-table/components/RecordTableComponentInstance';
|
||||
import { RecordTableCellContext } from '@/object-record/record-table/contexts/RecordTableCellContext';
|
||||
import { RecordTableRowContext } from '@/object-record/record-table/contexts/RecordTableRowContext';
|
||||
import { RecordTableRowContextProvider } from '@/object-record/record-table/contexts/RecordTableRowContext';
|
||||
import { RecordTableRowDraggableContextProvider } from '@/object-record/record-table/contexts/RecordTableRowDraggableContext';
|
||||
import {
|
||||
recordTableCell,
|
||||
recordTableRow,
|
||||
recordTableCellContextValue,
|
||||
recordTableRowContextValue,
|
||||
recordTableRowDraggableContextValue,
|
||||
} from '@/object-record/record-table/record-table-cell/hooks/__mocks__/cell';
|
||||
import { useMoveSoftFocusToCurrentCellOnHover } from '@/object-record/record-table/record-table-cell/hooks/useMoveSoftFocusToCurrentCellOnHover';
|
||||
import { TableCellPosition } from '@/object-record/record-table/types/TableCellPosition';
|
||||
@ -80,11 +82,15 @@ const Wrapper = ({ children }: { children: React.ReactNode }) => (
|
||||
recordTableId="scopeId"
|
||||
onColumnsChange={jest.fn()}
|
||||
>
|
||||
<RecordTableRowContext.Provider value={recordTableRow}>
|
||||
<RecordTableCellContext.Provider value={recordTableCell}>
|
||||
{children}
|
||||
</RecordTableCellContext.Provider>
|
||||
</RecordTableRowContext.Provider>
|
||||
<RecordTableRowContextProvider value={recordTableRowContextValue}>
|
||||
<RecordTableRowDraggableContextProvider
|
||||
value={recordTableRowDraggableContextValue}
|
||||
>
|
||||
<RecordTableCellContext.Provider value={recordTableCellContextValue}>
|
||||
{children}
|
||||
</RecordTableCellContext.Provider>
|
||||
</RecordTableRowDraggableContextProvider>
|
||||
</RecordTableRowContextProvider>
|
||||
</RecordTableComponentInstance>
|
||||
</RecoilRoot>
|
||||
);
|
||||
|
@ -8,10 +8,12 @@ import { FieldContext } from '@/object-record/record-field/contexts/FieldContext
|
||||
import { RecordTableComponentInstance } from '@/object-record/record-table/components/RecordTableComponentInstance';
|
||||
import { RecordTableContextProvider } from '@/object-record/record-table/components/RecordTableContextProvider';
|
||||
import { RecordTableCellContext } from '@/object-record/record-table/contexts/RecordTableCellContext';
|
||||
import { RecordTableRowContext } from '@/object-record/record-table/contexts/RecordTableRowContext';
|
||||
import { RecordTableRowContextProvider } from '@/object-record/record-table/contexts/RecordTableRowContext';
|
||||
import { RecordTableRowDraggableContextProvider } from '@/object-record/record-table/contexts/RecordTableRowDraggableContext';
|
||||
import {
|
||||
recordTableCell,
|
||||
recordTableRow,
|
||||
recordTableCellContextValue,
|
||||
recordTableRowContextValue,
|
||||
recordTableRowDraggableContextValue,
|
||||
} from '@/object-record/record-table/record-table-cell/hooks/__mocks__/cell';
|
||||
import { useCloseRecordTableCellInGroup } from '@/object-record/record-table/record-table-cell/hooks/internal/useCloseRecordTableCellInGroup';
|
||||
import { currentTableCellInEditModePositionComponentState } from '@/object-record/record-table/states/currentTableCellInEditModePositionComponentState';
|
||||
@ -55,13 +57,17 @@ const Wrapper = ({ children }: { children: React.ReactNode }) => (
|
||||
isLabelIdentifier: false,
|
||||
}}
|
||||
>
|
||||
<RecordTableRowContext.Provider value={recordTableRow}>
|
||||
<RecordTableCellContext.Provider
|
||||
value={{ ...recordTableCell, columnIndex: 0 }}
|
||||
<RecordTableRowContextProvider value={recordTableRowContextValue}>
|
||||
<RecordTableRowDraggableContextProvider
|
||||
value={recordTableRowDraggableContextValue}
|
||||
>
|
||||
{children}
|
||||
</RecordTableCellContext.Provider>
|
||||
</RecordTableRowContext.Provider>
|
||||
<RecordTableCellContext.Provider
|
||||
value={{ ...recordTableCellContextValue, columnIndex: 0 }}
|
||||
>
|
||||
{children}
|
||||
</RecordTableCellContext.Provider>
|
||||
</RecordTableRowDraggableContextProvider>
|
||||
</RecordTableRowContextProvider>
|
||||
</FieldContext.Provider>
|
||||
</RecordTableContextProvider>
|
||||
</RecordTableComponentInstance>
|
||||
|
@ -8,10 +8,12 @@ import { FieldContext } from '@/object-record/record-field/contexts/FieldContext
|
||||
import { RecordTableComponentInstance } from '@/object-record/record-table/components/RecordTableComponentInstance';
|
||||
import { RecordTableContextProvider } from '@/object-record/record-table/components/RecordTableContextProvider';
|
||||
import { RecordTableCellContext } from '@/object-record/record-table/contexts/RecordTableCellContext';
|
||||
import { RecordTableRowContext } from '@/object-record/record-table/contexts/RecordTableRowContext';
|
||||
import { RecordTableRowContextProvider } from '@/object-record/record-table/contexts/RecordTableRowContext';
|
||||
import { RecordTableRowDraggableContextProvider } from '@/object-record/record-table/contexts/RecordTableRowDraggableContext';
|
||||
import {
|
||||
recordTableCell,
|
||||
recordTableRow,
|
||||
recordTableCellContextValue,
|
||||
recordTableRowContextValue,
|
||||
recordTableRowDraggableContextValue,
|
||||
} from '@/object-record/record-table/record-table-cell/hooks/__mocks__/cell';
|
||||
import { useCloseRecordTableCellNoGroup } from '@/object-record/record-table/record-table-cell/hooks/internal/useCloseRecordTableCellNoGroup';
|
||||
import { currentTableCellInEditModePositionComponentState } from '@/object-record/record-table/states/currentTableCellInEditModePositionComponentState';
|
||||
@ -54,13 +56,17 @@ const Wrapper = ({ children }: { children: React.ReactNode }) => (
|
||||
isLabelIdentifier: false,
|
||||
}}
|
||||
>
|
||||
<RecordTableRowContext.Provider value={recordTableRow}>
|
||||
<RecordTableCellContext.Provider
|
||||
value={{ ...recordTableCell, columnIndex: 0 }}
|
||||
<RecordTableRowContextProvider value={recordTableRowContextValue}>
|
||||
<RecordTableRowDraggableContextProvider
|
||||
value={recordTableRowDraggableContextValue}
|
||||
>
|
||||
{children}
|
||||
</RecordTableCellContext.Provider>
|
||||
</RecordTableRowContext.Provider>
|
||||
<RecordTableCellContext.Provider
|
||||
value={{ ...recordTableCellContextValue, columnIndex: 0 }}
|
||||
>
|
||||
{children}
|
||||
</RecordTableCellContext.Provider>
|
||||
</RecordTableRowDraggableContextProvider>
|
||||
</RecordTableRowContextProvider>
|
||||
</FieldContext.Provider>
|
||||
</RecordTableContextProvider>
|
||||
</RecordTableComponentInstance>
|
||||
|
@ -5,7 +5,7 @@ import { useIsFieldValueReadOnly } from '@/object-record/record-field/hooks/useI
|
||||
import { FieldDefinition } from '@/object-record/record-field/types/FieldDefinition';
|
||||
import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata';
|
||||
import { CellHotkeyScopeContext } from '@/object-record/record-table/contexts/CellHotkeyScopeContext';
|
||||
import { RecordTableRowContext } from '@/object-record/record-table/contexts/RecordTableRowContext';
|
||||
import { useRecordTableRowContextOrThrow } from '@/object-record/record-table/contexts/RecordTableRowContext';
|
||||
import { useCurrentTableCellPosition } from '@/object-record/record-table/record-table-cell/hooks/useCurrentCellPosition';
|
||||
import { TableCellPosition } from '@/object-record/record-table/types/TableCellPosition';
|
||||
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
|
||||
@ -30,9 +30,9 @@ export type OpenTableCellArgs = {
|
||||
export const useOpenRecordTableCellFromCell = () => {
|
||||
const customCellHotkeyScope = useContext(CellHotkeyScopeContext);
|
||||
const { recordId, fieldDefinition } = useContext(FieldContext);
|
||||
const { pathToShowPage, objectNameSingular } = useContext(
|
||||
RecordTableRowContext,
|
||||
);
|
||||
|
||||
const { pathToShowPage, objectNameSingular } =
|
||||
useRecordTableRowContextOrThrow();
|
||||
|
||||
const { onOpenTableCell } = useRecordTableBodyContextOrThrow();
|
||||
|
||||
|
@ -1,12 +1,12 @@
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext';
|
||||
import { RecordTableTd } from '@/object-record/record-table/record-table-cell/components/RecordTableTd';
|
||||
import { visibleTableColumnsComponentSelector } from '@/object-record/record-table/states/selectors/visibleTableColumnsComponentSelector';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { RecordTableDraggableTr } from '@/object-record/record-table/record-table-row/components/RecordTableDraggableTr';
|
||||
import { useTheme } from '@emotion/react';
|
||||
import { IconComponent } from 'twenty-ui';
|
||||
|
||||
const StyledTrContainer = styled.tr`
|
||||
const StyledRecordTableDraggableTr = styled(RecordTableDraggableTr)`
|
||||
cursor: pointer;
|
||||
`;
|
||||
|
||||
@ -36,33 +36,40 @@ const StyledEmptyTd = styled.td`
|
||||
`;
|
||||
|
||||
type RecordTableActionRowProps = {
|
||||
draggableId: string;
|
||||
draggableIndex: number;
|
||||
LeftIcon: IconComponent;
|
||||
text: string;
|
||||
onClick?: (event?: React.MouseEvent<HTMLTableRowElement>) => void;
|
||||
};
|
||||
|
||||
export const RecordTableActionRow = ({
|
||||
draggableId,
|
||||
draggableIndex,
|
||||
LeftIcon,
|
||||
text,
|
||||
onClick,
|
||||
}: RecordTableActionRowProps) => {
|
||||
const theme = useTheme();
|
||||
|
||||
const visibleColumns = useRecoilComponentValueV2(
|
||||
visibleTableColumnsComponentSelector,
|
||||
);
|
||||
const { visibleTableColumns } = useRecordTableContextOrThrow();
|
||||
|
||||
return (
|
||||
<StyledTrContainer onClick={onClick}>
|
||||
<StyledRecordTableDraggableTr
|
||||
draggableId={draggableId}
|
||||
draggableIndex={draggableIndex}
|
||||
onClick={onClick}
|
||||
isDragDisabled
|
||||
>
|
||||
<td aria-hidden />
|
||||
<StyledIconContainer>
|
||||
<LeftIcon size={theme.icon.size.sm} color={theme.font.color.tertiary} />
|
||||
</StyledIconContainer>
|
||||
<StyledRecordTableTdTextContainer colSpan={visibleColumns.length}>
|
||||
<StyledRecordTableTdTextContainer colSpan={visibleTableColumns.length}>
|
||||
<StyledText>{text}</StyledText>
|
||||
</StyledRecordTableTdTextContainer>
|
||||
<StyledEmptyTd />
|
||||
<StyledEmptyTd />
|
||||
</StyledTrContainer>
|
||||
</StyledRecordTableDraggableTr>
|
||||
);
|
||||
};
|
||||
|
@ -1,11 +1,12 @@
|
||||
import { useContext } from 'react';
|
||||
|
||||
import { RecordTableRowContext } from '@/object-record/record-table/contexts/RecordTableRowContext';
|
||||
import { useRecordTableRowContextOrThrow } from '@/object-record/record-table/contexts/RecordTableRowContext';
|
||||
import { useRecordTableRowDraggableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableRowDraggableContext';
|
||||
import { RecordTableCellsEmpty } from '@/object-record/record-table/record-table-row/components/RecordTableCellsEmpty';
|
||||
import { RecordTableCellsVisible } from '@/object-record/record-table/record-table-row/components/RecordTableCellsVisible';
|
||||
|
||||
export const RecordTableCells = () => {
|
||||
const { inView, isDragging } = useContext(RecordTableRowContext);
|
||||
const { inView } = useRecordTableRowContextOrThrow();
|
||||
|
||||
const { isDragging } = useRecordTableRowDraggableContextOrThrow();
|
||||
|
||||
const areCellsVisible = inView || isDragging;
|
||||
|
||||
|
@ -1,11 +1,10 @@
|
||||
import { RecordTableRowContext } from '@/object-record/record-table/contexts/RecordTableRowContext';
|
||||
import { useRecordTableRowContextOrThrow } from '@/object-record/record-table/contexts/RecordTableRowContext';
|
||||
import { RecordTableTd } from '@/object-record/record-table/record-table-cell/components/RecordTableTd';
|
||||
import { visibleTableColumnsComponentSelector } from '@/object-record/record-table/states/selectors/visibleTableColumnsComponentSelector';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { useContext } from 'react';
|
||||
|
||||
export const RecordTableCellsEmpty = () => {
|
||||
const { isSelected } = useContext(RecordTableRowContext);
|
||||
const { isSelected } = useRecordTableRowContextOrThrow();
|
||||
|
||||
const visibleTableColumns = useRecoilComponentValueV2(
|
||||
visibleTableColumnsComponentSelector,
|
||||
|
@ -1,20 +1,15 @@
|
||||
import { useContext } from 'react';
|
||||
|
||||
import { RecordTableRowContext } from '@/object-record/record-table/contexts/RecordTableRowContext';
|
||||
import { useRecordTableRowContextOrThrow } from '@/object-record/record-table/contexts/RecordTableRowContext';
|
||||
import { useRecordTableRowDraggableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableRowDraggableContext';
|
||||
import { RecordTableCell } from '@/object-record/record-table/record-table-cell/components/RecordTableCell';
|
||||
import { RecordTableCellWrapper } from '@/object-record/record-table/record-table-cell/components/RecordTableCellWrapper';
|
||||
import { RecordTableTd } from '@/object-record/record-table/record-table-cell/components/RecordTableTd';
|
||||
import { visibleTableColumnsComponentSelector } from '@/object-record/record-table/states/selectors/visibleTableColumnsComponentSelector';
|
||||
import { tableCellWidthsComponentState } from '@/object-record/record-table/states/tableCellWidthsComponentState';
|
||||
import { useRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentStateV2';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
|
||||
export const RecordTableCellsVisible = () => {
|
||||
const { isSelected, isDragging } = useContext(RecordTableRowContext);
|
||||
const { isSelected } = useRecordTableRowContextOrThrow();
|
||||
|
||||
const [tableCellWidths] = useRecoilComponentStateV2(
|
||||
tableCellWidthsComponentState,
|
||||
);
|
||||
const { isDragging } = useRecordTableRowDraggableContextOrThrow();
|
||||
|
||||
const visibleTableColumns = useRecoilComponentValueV2(
|
||||
visibleTableColumnsComponentSelector,
|
||||
@ -28,7 +23,7 @@ export const RecordTableCellsVisible = () => {
|
||||
<RecordTableTd
|
||||
isSelected={isSelected}
|
||||
isDragging={isDragging}
|
||||
width={tableCellWidths[2]}
|
||||
width={visibleTableColumns[0].size}
|
||||
>
|
||||
<RecordTableCell />
|
||||
</RecordTableTd>
|
||||
@ -42,7 +37,7 @@ export const RecordTableCellsVisible = () => {
|
||||
<RecordTableTd
|
||||
isSelected={isSelected}
|
||||
isDragging={isDragging}
|
||||
width={tableCellWidths[columnIndex + 3]}
|
||||
width={column.size}
|
||||
>
|
||||
<RecordTableCell />
|
||||
</RecordTableTd>
|
||||
|
@ -0,0 +1,63 @@
|
||||
import { useTheme } from '@emotion/react';
|
||||
import { Draggable, DraggableId } from '@hello-pangea/dnd';
|
||||
import { forwardRef, ReactNode } from 'react';
|
||||
|
||||
import { RecordTableRowDraggableContextProvider } from '@/object-record/record-table/contexts/RecordTableRowDraggableContext';
|
||||
import { RecordTableTr } from '@/object-record/record-table/record-table-row/components/RecordTableTr';
|
||||
import { combineRefs } from '~/utils/combineRefs';
|
||||
|
||||
type RecordTableDraggableTrProps = {
|
||||
draggableId: DraggableId;
|
||||
draggableIndex: number;
|
||||
isDragDisabled?: boolean;
|
||||
onClick?: (event: React.MouseEvent<HTMLTableRowElement>) => void;
|
||||
children: ReactNode;
|
||||
};
|
||||
|
||||
export const RecordTableDraggableTr = forwardRef<
|
||||
HTMLTableRowElement,
|
||||
RecordTableDraggableTrProps
|
||||
>(({ draggableId, draggableIndex, isDragDisabled, onClick, children }, ref) => {
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<Draggable
|
||||
draggableId={draggableId}
|
||||
index={draggableIndex}
|
||||
isDragDisabled={isDragDisabled}
|
||||
>
|
||||
{(draggableProvided, draggableSnapshot) => (
|
||||
<RecordTableTr
|
||||
ref={combineRefs<HTMLTableRowElement>(
|
||||
ref,
|
||||
draggableProvided.innerRef,
|
||||
)}
|
||||
// eslint-disable-next-line react/jsx-props-no-spreading
|
||||
{...draggableProvided.draggableProps}
|
||||
style={{
|
||||
...draggableProvided.draggableProps.style,
|
||||
background: draggableSnapshot.isDragging
|
||||
? theme.background.transparent.light
|
||||
: 'none',
|
||||
borderColor: draggableSnapshot.isDragging
|
||||
? `${theme.border.color.medium}`
|
||||
: 'transparent',
|
||||
}}
|
||||
isDragging={draggableSnapshot.isDragging}
|
||||
data-testid={`row-id-${draggableId}`}
|
||||
data-selectable-id={draggableId}
|
||||
onClick={onClick}
|
||||
>
|
||||
<RecordTableRowDraggableContextProvider
|
||||
value={{
|
||||
isDragging: draggableSnapshot.isDragging,
|
||||
dragHandleProps: draggableProvided.dragHandleProps,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</RecordTableRowDraggableContextProvider>
|
||||
</RecordTableTr>
|
||||
)}
|
||||
</Draggable>
|
||||
);
|
||||
});
|
@ -1,18 +1,14 @@
|
||||
import { useTheme } from '@emotion/react';
|
||||
import { Draggable } from '@hello-pangea/dnd';
|
||||
import { ReactNode, useContext, useEffect, useRef } from 'react';
|
||||
import { useInView } from 'react-intersection-observer';
|
||||
import { ReactNode, useContext, useEffect } from 'react';
|
||||
|
||||
import { getBasePathToShowPage } from '@/object-metadata/utils/getBasePathToShowPage';
|
||||
import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext';
|
||||
import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext';
|
||||
import { RecordTableRowContext } from '@/object-record/record-table/contexts/RecordTableRowContext';
|
||||
import { RecordTableTr } from '@/object-record/record-table/record-table-row/components/RecordTableTr';
|
||||
import { RecordTableRowContextProvider } from '@/object-record/record-table/contexts/RecordTableRowContext';
|
||||
import { RecordTableDraggableTr } from '@/object-record/record-table/record-table-row/components/RecordTableDraggableTr';
|
||||
import { isRowSelectedComponentFamilyState } from '@/object-record/record-table/record-table-row/states/isRowSelectedComponentFamilyState';
|
||||
import { tableCellWidthsComponentState } from '@/object-record/record-table/states/tableCellWidthsComponentState';
|
||||
import { RecordTableWithWrappersScrollWrapperContext } from '@/ui/utilities/scroll/contexts/ScrollWrapperContexts';
|
||||
import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValueV2';
|
||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||
import { useInView } from 'react-intersection-observer';
|
||||
|
||||
type RecordTableRowWrapperProps = {
|
||||
recordId: string;
|
||||
@ -29,18 +25,15 @@ export const RecordTableRowWrapper = ({
|
||||
isPendingRow,
|
||||
children,
|
||||
}: RecordTableRowWrapperProps) => {
|
||||
const trRef = useRef<HTMLTableRowElement>(null);
|
||||
|
||||
const { objectMetadataItem } = useRecordTableContextOrThrow();
|
||||
const { onIndexRecordsLoaded } = useRecordIndexContextOrThrow();
|
||||
|
||||
const theme = useTheme();
|
||||
|
||||
const currentRowSelected = useRecoilComponentFamilyValueV2(
|
||||
isRowSelectedComponentFamilyState,
|
||||
recordId,
|
||||
);
|
||||
|
||||
const { onIndexRecordsLoaded } = useRecordIndexContextOrThrow();
|
||||
|
||||
const scrollWrapperRef = useContext(
|
||||
RecordTableWithWrappersScrollWrapperContext,
|
||||
);
|
||||
@ -52,24 +45,6 @@ export const RecordTableRowWrapper = ({
|
||||
rootMargin: '1000px',
|
||||
});
|
||||
|
||||
const setTableCellWidths = useSetRecoilComponentStateV2(
|
||||
tableCellWidthsComponentState,
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (rowIndexForFocus === 0) {
|
||||
const tdArray = Array.from(
|
||||
trRef.current?.getElementsByTagName('td') ?? [],
|
||||
);
|
||||
|
||||
const tdWidths = tdArray.map((td) => {
|
||||
return td.getBoundingClientRect().width;
|
||||
});
|
||||
|
||||
setTableCellWidths(tdWidths);
|
||||
}
|
||||
}, [trRef, rowIndexForFocus, setTableCellWidths]);
|
||||
|
||||
// TODO: find a better way to emit this event
|
||||
useEffect(() => {
|
||||
if (inView) {
|
||||
@ -78,55 +53,29 @@ export const RecordTableRowWrapper = ({
|
||||
}, [inView, onIndexRecordsLoaded]);
|
||||
|
||||
return (
|
||||
<Draggable
|
||||
<RecordTableDraggableTr
|
||||
ref={elementRef}
|
||||
key={recordId}
|
||||
draggableId={recordId}
|
||||
index={rowIndexForDrag}
|
||||
draggableIndex={rowIndexForDrag}
|
||||
isDragDisabled={isPendingRow}
|
||||
>
|
||||
{(draggableProvided, draggableSnapshot) => (
|
||||
<RecordTableTr
|
||||
ref={(node) => {
|
||||
// @ts-expect-error - TS doesn't know that node.current is assignable
|
||||
trRef.current = node;
|
||||
elementRef(node);
|
||||
draggableProvided.innerRef(node);
|
||||
}}
|
||||
// eslint-disable-next-line react/jsx-props-no-spreading
|
||||
{...draggableProvided.draggableProps}
|
||||
style={{
|
||||
...draggableProvided.draggableProps.style,
|
||||
background: draggableSnapshot.isDragging
|
||||
? theme.background.transparent.light
|
||||
: 'none',
|
||||
borderColor: draggableSnapshot.isDragging
|
||||
? `${theme.border.color.medium}`
|
||||
: 'transparent',
|
||||
}}
|
||||
isDragging={draggableSnapshot.isDragging}
|
||||
data-testid={`row-id-${recordId}`}
|
||||
data-selectable-id={recordId}
|
||||
>
|
||||
<RecordTableRowContext.Provider
|
||||
value={{
|
||||
recordId,
|
||||
rowIndex: rowIndexForFocus,
|
||||
pathToShowPage:
|
||||
getBasePathToShowPage({
|
||||
objectNameSingular: objectMetadataItem.nameSingular,
|
||||
}) + recordId,
|
||||
<RecordTableRowContextProvider
|
||||
value={{
|
||||
recordId,
|
||||
rowIndex: rowIndexForFocus,
|
||||
pathToShowPage:
|
||||
getBasePathToShowPage({
|
||||
objectNameSingular: objectMetadataItem.nameSingular,
|
||||
isSelected: currentRowSelected,
|
||||
isPendingRow,
|
||||
isDragging: draggableSnapshot.isDragging,
|
||||
dragHandleProps: draggableProvided.dragHandleProps,
|
||||
inView,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</RecordTableRowContext.Provider>
|
||||
</RecordTableTr>
|
||||
)}
|
||||
</Draggable>
|
||||
}) + recordId,
|
||||
objectNameSingular: objectMetadataItem.nameSingular,
|
||||
isSelected: currentRowSelected,
|
||||
isPendingRow,
|
||||
inView,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</RecordTableRowContextProvider>
|
||||
</RecordTableDraggableTr>
|
||||
);
|
||||
};
|
||||
|
@ -1,13 +1,12 @@
|
||||
import { useContext } from 'react';
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
|
||||
import { RecordTableRowContext } from '@/object-record/record-table/contexts/RecordTableRowContext';
|
||||
import { useRecordTableRowContextOrThrow } from '@/object-record/record-table/contexts/RecordTableRowContext';
|
||||
import { isRowSelectedComponentFamilyState } from '@/object-record/record-table/record-table-row/states/isRowSelectedComponentFamilyState';
|
||||
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
|
||||
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
||||
|
||||
export const useSetCurrentRowSelected = () => {
|
||||
const { recordId } = useContext(RecordTableRowContext);
|
||||
const { recordId } = useRecordTableRowContextOrThrow();
|
||||
|
||||
const isRowSelectedFamilyState = useRecoilComponentCallbackStateV2(
|
||||
isRowSelectedComponentFamilyState,
|
||||
|
@ -1,9 +1,11 @@
|
||||
import { useCurrentRecordGroupId } from '@/object-record/record-group/hooks/useCurrentRecordGroupId';
|
||||
import { recordIndexAllRecordIdsComponentSelector } from '@/object-record/record-index/states/selectors/recordIndexAllRecordIdsComponentSelector';
|
||||
import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext';
|
||||
import { useCreateNewTableRecord } from '@/object-record/record-table/hooks/useCreateNewTableRecords';
|
||||
import { RecordTableActionRow } from '@/object-record/record-table/record-table-row/components/RecordTableActionRow';
|
||||
import { recordTablePendingRecordIdByGroupComponentFamilyState } from '@/object-record/record-table/states/recordTablePendingRecordIdByGroupComponentFamilyState';
|
||||
import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValueV2';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { IconPlus } from 'twenty-ui';
|
||||
import { isDefined } from '~/utils/isDefined';
|
||||
|
||||
@ -17,6 +19,10 @@ export const RecordTableRecordGroupSectionAddNew = () => {
|
||||
currentRecordGroupId,
|
||||
);
|
||||
|
||||
const recordIds = useRecoilComponentValueV2(
|
||||
recordIndexAllRecordIdsComponentSelector,
|
||||
);
|
||||
|
||||
const { createNewTableRecordInGroup } =
|
||||
useCreateNewTableRecord(recordTableId);
|
||||
|
||||
@ -28,6 +34,8 @@ export const RecordTableRecordGroupSectionAddNew = () => {
|
||||
|
||||
return (
|
||||
<RecordTableActionRow
|
||||
draggableId={`add-new-record-${currentRecordGroupId}`}
|
||||
draggableIndex={recordIds.length + 2}
|
||||
LeftIcon={IconPlus}
|
||||
text="Add new"
|
||||
onClick={handleAddNewRecord}
|
||||
|
@ -1,9 +1,11 @@
|
||||
import { useCurrentRecordGroupId } from '@/object-record/record-group/hooks/useCurrentRecordGroupId';
|
||||
import { useLazyLoadRecordIndexTable } from '@/object-record/record-index/hooks/useLazyLoadRecordIndexTable';
|
||||
import { recordIndexHasFetchedAllRecordsByGroupComponentState } from '@/object-record/record-index/states/recordIndexHasFetchedAllRecordsByGroupComponentState';
|
||||
import { recordIndexAllRecordIdsComponentSelector } from '@/object-record/record-index/states/selectors/recordIndexAllRecordIdsComponentSelector';
|
||||
import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext';
|
||||
import { RecordTableActionRow } from '@/object-record/record-table/record-table-row/components/RecordTableActionRow';
|
||||
import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValueV2';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { IconArrowDown } from 'twenty-ui';
|
||||
|
||||
export const RecordTableRecordGroupSectionLoadMore = () => {
|
||||
@ -18,6 +20,10 @@ export const RecordTableRecordGroupSectionLoadMore = () => {
|
||||
currentRecordGroupId,
|
||||
);
|
||||
|
||||
const recordIds = useRecoilComponentValueV2(
|
||||
recordIndexAllRecordIdsComponentSelector,
|
||||
);
|
||||
|
||||
const handleLoadMore = () => {
|
||||
fetchMoreRecords();
|
||||
};
|
||||
@ -28,6 +34,8 @@ export const RecordTableRecordGroupSectionLoadMore = () => {
|
||||
|
||||
return (
|
||||
<RecordTableActionRow
|
||||
draggableId={`load-more-records-${currentRecordGroupId}`}
|
||||
draggableIndex={recordIds.length + 1}
|
||||
LeftIcon={IconArrowDown}
|
||||
text="Load more"
|
||||
onClick={handleLoadMore}
|
||||
|
15
packages/twenty-front/src/utils/combineRefs.ts
Normal file
15
packages/twenty-front/src/utils/combineRefs.ts
Normal file
@ -0,0 +1,15 @@
|
||||
import { isFunction } from '@sniptt/guards';
|
||||
import { MutableRefObject, Ref } from 'react';
|
||||
import { isDefined } from '~/utils/isDefined';
|
||||
|
||||
export const combineRefs = <T>(...refs: (Ref<T> | undefined)[]) => {
|
||||
return (node: T) => {
|
||||
for (const ref of refs) {
|
||||
if (isFunction(ref)) {
|
||||
ref(node);
|
||||
} else if (isDefined(ref) && 'current' in ref) {
|
||||
(ref as MutableRefObject<T | null>).current = node;
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
Loading…
Reference in New Issue
Block a user