feat: table record group (#8781)

Fix #8401 #8402

This PR is only taking care or displaying properly the record group on
the table.
Record-reorder within group has also been prepared.
Start of collapsible animation has been done, but not working for now.

<img width="1381" alt="Screenshot 2024-11-28 at 2 52 07 PM"
src="https://github.com/user-attachments/assets/514bb3e6-3475-4c47-a91c-64f7d20bbe73">
This commit is contained in:
Jérémy M 2024-11-29 13:04:27 +01:00 committed by GitHub
parent 05149feb00
commit a2d55a8694
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
41 changed files with 671 additions and 392 deletions

View File

@ -3,15 +3,18 @@ import {
IconChevronLeft, IconChevronLeft,
IconSettings, IconSettings,
MenuItem, MenuItem,
MenuItemSelect,
UndecoratedLink, UndecoratedLink,
useIcons, useIcons,
} from 'twenty-ui'; } from 'twenty-ui';
import { useObjectNamePluralFromSingular } from '@/object-metadata/hooks/useObjectNamePluralFromSingular'; import { useObjectNamePluralFromSingular } from '@/object-metadata/hooks/useObjectNamePluralFromSingular';
import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
import { StyledInput } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterSelect'; import { StyledInput } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterSelect';
import { useOptionsDropdown } from '@/object-record/object-options-dropdown/hooks/useOptionsDropdown'; import { useOptionsDropdown } from '@/object-record/object-options-dropdown/hooks/useOptionsDropdown';
import { useSearchRecordGroupField } from '@/object-record/object-options-dropdown/hooks/useSearchRecordGroupField'; import { useSearchRecordGroupField } from '@/object-record/object-options-dropdown/hooks/useSearchRecordGroupField';
import { recordGroupFieldMetadataComponentState } from '@/object-record/record-group/states/recordGroupFieldMetadataComponentState';
import { hiddenRecordGroupIdsComponentSelector } from '@/object-record/record-group/states/selectors/hiddenRecordGroupIdsComponentSelector'; import { hiddenRecordGroupIdsComponentSelector } from '@/object-record/record-group/states/selectors/hiddenRecordGroupIdsComponentSelector';
import { useHandleRecordGroupField } from '@/object-record/record-index/hooks/useHandleRecordGroupField'; import { useHandleRecordGroupField } from '@/object-record/record-index/hooks/useHandleRecordGroupField';
import { getSettingsPagePath } from '@/settings/utils/getSettingsPagePath'; import { getSettingsPagePath } from '@/settings/utils/getSettingsPagePath';
@ -23,6 +26,7 @@ import { navigationMemorizedUrlState } from '@/ui/navigation/states/navigationMe
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
import { useLocation } from 'react-router-dom'; import { useLocation } from 'react-router-dom';
import { useSetRecoilState } from 'recoil'; import { useSetRecoilState } from 'recoil';
import { isDefined } from '~/utils/isDefined';
export const ObjectOptionsDropdownRecordGroupFieldsContent = () => { export const ObjectOptionsDropdownRecordGroupFieldsContent = () => {
const { getIcon } = useIcons(); const { getIcon } = useIcons();
@ -43,14 +47,20 @@ export const ObjectOptionsDropdownRecordGroupFieldsContent = () => {
hiddenRecordGroupIdsComponentSelector, hiddenRecordGroupIdsComponentSelector,
); );
const recordGroupFieldMetadataItem = useRecoilComponentValueV2(
recordGroupFieldMetadataComponentState,
);
const { const {
recordGroupFieldSearchInput, recordGroupFieldSearchInput,
setRecordGroupFieldSearchInput, setRecordGroupFieldSearchInput,
filteredRecordGroupFieldMetadataItems, filteredRecordGroupFieldMetadataItems,
} = useSearchRecordGroupField(); } = useSearchRecordGroupField();
const { handleRecordGroupFieldChange, resetRecordGroupField } = const {
useHandleRecordGroupField({ handleRecordGroupFieldChange: setRecordGroupField,
resetRecordGroupField,
} = useHandleRecordGroupField({
viewBarComponentId: recordIndexId, viewBarComponentId: recordIndexId,
}); });
@ -66,6 +76,18 @@ export const ObjectOptionsDropdownRecordGroupFieldsContent = () => {
navigationMemorizedUrlState, navigationMemorizedUrlState,
); );
const handleResetRecordGroupField = () => {
resetRecordGroupField();
closeDropdown();
};
const handleRecordGroupFieldChange = (
fieldMetadataItem: FieldMetadataItem,
) => {
setRecordGroupField(fieldMetadataItem);
closeDropdown();
};
useEffect(() => { useEffect(() => {
if ( if (
currentContentId === 'hiddenRecordGroups' && currentContentId === 'hiddenRecordGroups' &&
@ -90,13 +112,16 @@ export const ObjectOptionsDropdownRecordGroupFieldsContent = () => {
onChange={(event) => setRecordGroupFieldSearchInput(event.target.value)} onChange={(event) => setRecordGroupFieldSearchInput(event.target.value)}
/> />
<DropdownMenuItemsContainer> <DropdownMenuItemsContainer>
<MenuItem text="None" onClick={resetRecordGroupField} /> <MenuItemSelect
text="None"
selected={!isDefined(recordGroupFieldMetadataItem)}
onClick={handleResetRecordGroupField}
/>
{filteredRecordGroupFieldMetadataItems.map((fieldMetadataItem) => ( {filteredRecordGroupFieldMetadataItems.map((fieldMetadataItem) => (
<MenuItem <MenuItemSelect
key={fieldMetadataItem.id} key={fieldMetadataItem.id}
onClick={() => { selected={fieldMetadataItem.id === recordGroupFieldMetadataItem?.id}
handleRecordGroupFieldChange(fieldMetadataItem); onClick={() => handleRecordGroupFieldChange(fieldMetadataItem)}
}}
LeftIcon={getIcon(fieldMetadataItem.icon)} LeftIcon={getIcon(fieldMetadataItem.icon)}
text={fieldMetadataItem.label} text={fieldMetadataItem.label}
/> />

View File

@ -16,8 +16,8 @@ import { RecordBoardComponentInstanceContext } from '@/object-record/record-boar
import { getDraggedRecordPosition } from '@/object-record/record-board/utils/getDraggedRecordPosition'; import { getDraggedRecordPosition } from '@/object-record/record-board/utils/getDraggedRecordPosition';
import { recordGroupDefinitionFamilyState } from '@/object-record/record-group/states/recordGroupDefinitionFamilyState'; import { recordGroupDefinitionFamilyState } from '@/object-record/record-group/states/recordGroupDefinitionFamilyState';
import { visibleRecordGroupIdsComponentSelector } from '@/object-record/record-group/states/selectors/visibleRecordGroupIdsComponentSelector'; import { visibleRecordGroupIdsComponentSelector } from '@/object-record/record-group/states/selectors/visibleRecordGroupIdsComponentSelector';
import { recordIndexAllRowIdsComponentState } from '@/object-record/record-index/states/recordIndexAllRowIdsComponentState'; import { recordIndexRecordIdsByGroupComponentFamilyState } from '@/object-record/record-index/states/recordIndexRecordIdsByGroupComponentFamilyState';
import { recordIndexRowIdsByGroupComponentFamilyState } from '@/object-record/record-index/states/recordIndexRowIdsByGroupComponentFamilyState'; import { recordIndexAllRecordIdsComponentSelector } from '@/object-record/record-index/states/selectors/recordIndexAllRecordIdsComponentSelector';
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
import { TableHotkeyScope } from '@/object-record/record-table/types/TableHotkeyScope'; import { TableHotkeyScope } from '@/object-record/record-table/types/TableHotkeyScope';
import { DragSelect } from '@/ui/utilities/drag-select/components/DragSelect'; import { DragSelect } from '@/ui/utilities/drag-select/components/DragSelect';
@ -69,12 +69,13 @@ export const RecordBoard = () => {
visibleRecordGroupIdsComponentSelector, visibleRecordGroupIdsComponentSelector,
); );
const recordIndexRowIdsByGroupFamilyState = useRecoilComponentCallbackStateV2( const recordIndexRecordIdsByGroupFamilyState =
recordIndexRowIdsByGroupComponentFamilyState, useRecoilComponentCallbackStateV2(
recordIndexRecordIdsByGroupComponentFamilyState,
); );
const recordIndexAllRowIdsState = useRecoilComponentCallbackStateV2( const recordIndexAllRecordIdsState = useRecoilComponentCallbackStateV2(
recordIndexAllRowIdsComponentState, recordIndexAllRecordIdsComponentSelector,
); );
const { resetRecordSelection, setRecordAsSelected } = const { resetRecordSelection, setRecordAsSelected } =
@ -97,14 +98,14 @@ export const RecordBoard = () => {
() => { () => {
const allRecordIds = getSnapshotValue( const allRecordIds = getSnapshotValue(
snapshot, snapshot,
recordIndexAllRowIdsState, recordIndexAllRecordIdsState,
); );
for (const recordId of allRecordIds) { for (const recordId of allRecordIds) {
setRecordAsSelected(recordId, true); setRecordAsSelected(recordId, true);
} }
}, },
[recordIndexAllRowIdsState, setRecordAsSelected], [recordIndexAllRecordIdsState, setRecordAsSelected],
); );
useScopedHotkeys('ctrl+a,meta+a', selectAll, TableHotkeyScope.Table); useScopedHotkeys('ctrl+a,meta+a', selectAll, TableHotkeyScope.Table);
@ -137,7 +138,7 @@ export const RecordBoard = () => {
const destinationRecordByGroupIds = getSnapshotValue( const destinationRecordByGroupIds = getSnapshotValue(
snapshot, snapshot,
recordIndexRowIdsByGroupFamilyState(destinationRecordGroupId), recordIndexRecordIdsByGroupFamilyState(destinationRecordGroupId),
); );
const otherRecordIdsInDestinationColumn = const otherRecordIdsInDestinationColumn =
sourceRecordGroupId === destinationRecordGroupId sourceRecordGroupId === destinationRecordGroupId
@ -172,7 +173,7 @@ export const RecordBoard = () => {
}); });
}, },
[ [
recordIndexRowIdsByGroupFamilyState, recordIndexRecordIdsByGroupFamilyState,
selectFieldMetadataItem, selectFieldMetadataItem,
updateOneRecord, updateOneRecord,
], ],

View File

@ -3,8 +3,7 @@ import { useRecoilCallback } from 'recoil';
import { recordGroupDefinitionFamilyState } from '@/object-record/record-group/states/recordGroupDefinitionFamilyState'; import { recordGroupDefinitionFamilyState } from '@/object-record/record-group/states/recordGroupDefinitionFamilyState';
import { recordGroupFieldMetadataComponentState } from '@/object-record/record-group/states/recordGroupFieldMetadataComponentState'; import { recordGroupFieldMetadataComponentState } from '@/object-record/record-group/states/recordGroupFieldMetadataComponentState';
import { visibleRecordGroupIdsComponentSelector } from '@/object-record/record-group/states/selectors/visibleRecordGroupIdsComponentSelector'; import { visibleRecordGroupIdsComponentSelector } from '@/object-record/record-group/states/selectors/visibleRecordGroupIdsComponentSelector';
import { recordIndexAllRowIdsComponentState } from '@/object-record/record-index/states/recordIndexAllRowIdsComponentState'; import { recordIndexRecordIdsByGroupComponentFamilyState } from '@/object-record/record-index/states/recordIndexRecordIdsByGroupComponentFamilyState';
import { recordIndexRowIdsByGroupComponentFamilyState } from '@/object-record/record-index/states/recordIndexRowIdsByGroupComponentFamilyState';
import { ObjectRecord } from '@/object-record/types/ObjectRecord'; import { ObjectRecord } from '@/object-record/types/ObjectRecord';
import { sortRecordsByPosition } from '@/object-record/utils/sortRecordsByPosition'; import { sortRecordsByPosition } from '@/object-record/utils/sortRecordsByPosition';
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2'; import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
@ -22,24 +21,15 @@ export const useSetRecordBoardRecordIds = (recordBoardId?: string) => {
recordBoardId, recordBoardId,
); );
const recordIndexAllRowIdsState = useRecoilComponentCallbackStateV2( const recordIndexRecordIdsByGroupFamilyState =
recordIndexAllRowIdsComponentState, useRecoilComponentCallbackStateV2(
recordBoardId, recordIndexRecordIdsByGroupComponentFamilyState,
);
const recordIndexRowIdsByGroupFamilyState = useRecoilComponentCallbackStateV2(
recordIndexRowIdsByGroupComponentFamilyState,
recordBoardId, recordBoardId,
); );
const setRecordIds = useRecoilCallback( const setRecordIds = useRecoilCallback(
({ set, snapshot }) => ({ set, snapshot }) =>
(records: ObjectRecord[]) => { (records: ObjectRecord[]) => {
const existingAllRowIds = getSnapshotValue(
snapshot,
recordIndexAllRowIdsState,
);
const recordGroupIds = getSnapshotValue( const recordGroupIds = getSnapshotValue(
snapshot, snapshot,
visibleRecordGroupIdsSelector, visibleRecordGroupIdsSelector,
@ -53,7 +43,7 @@ export const useSetRecordBoardRecordIds = (recordBoardId?: string) => {
const existingRecordGroupRowIds = getSnapshotValue( const existingRecordGroupRowIds = getSnapshotValue(
snapshot, snapshot,
recordIndexRowIdsByGroupFamilyState(recordGroupId), recordIndexRecordIdsByGroupFamilyState(recordGroupId),
); );
const recordGroupFieldMetadata = getSnapshotValue( const recordGroupFieldMetadata = getSnapshotValue(
@ -75,32 +65,16 @@ export const useSetRecordBoardRecordIds = (recordBoardId?: string) => {
if (!isDeeplyEqual(existingRecordGroupRowIds, recordGroupRowIds)) { if (!isDeeplyEqual(existingRecordGroupRowIds, recordGroupRowIds)) {
set( set(
recordIndexRowIdsByGroupFamilyState(recordGroupId), recordIndexRecordIdsByGroupFamilyState(recordGroupId),
recordGroupRowIds, recordGroupRowIds,
); );
} }
} }
const allRowIds: string[] = [];
for (const recordGroupId of recordGroupIds) {
const tableRowIdsByGroup = getSnapshotValue(
snapshot,
recordIndexRowIdsByGroupFamilyState(recordGroupId),
);
allRowIds.push(...tableRowIdsByGroup);
}
if (!isDeeplyEqual(existingAllRowIds, allRowIds)) {
set(recordIndexAllRowIdsState, allRowIds);
}
}, },
[ [
visibleRecordGroupIdsSelector, visibleRecordGroupIdsSelector,
recordIndexRowIdsByGroupFamilyState, recordIndexRecordIdsByGroupFamilyState,
recordGroupFieldMetadataState, recordGroupFieldMetadataState,
recordIndexAllRowIdsState,
], ],
); );

View File

@ -2,9 +2,7 @@ import { useRecoilCallback } from 'recoil';
import { recordGroupDefinitionFamilyState } from '@/object-record/record-group/states/recordGroupDefinitionFamilyState'; import { recordGroupDefinitionFamilyState } from '@/object-record/record-group/states/recordGroupDefinitionFamilyState';
import { recordGroupFieldMetadataComponentState } from '@/object-record/record-group/states/recordGroupFieldMetadataComponentState'; import { recordGroupFieldMetadataComponentState } from '@/object-record/record-group/states/recordGroupFieldMetadataComponentState';
import { recordGroupIdsComponentState } from '@/object-record/record-group/states/recordGroupIdsComponentState'; import { recordIndexRecordIdsByGroupComponentFamilyState } from '@/object-record/record-index/states/recordIndexRecordIdsByGroupComponentFamilyState';
import { recordIndexAllRowIdsComponentState } from '@/object-record/record-index/states/recordIndexAllRowIdsComponentState';
import { recordIndexRowIdsByGroupComponentFamilyState } from '@/object-record/record-index/states/recordIndexRowIdsByGroupComponentFamilyState';
import { ObjectRecord } from '@/object-record/types/ObjectRecord'; import { ObjectRecord } from '@/object-record/types/ObjectRecord';
import { sortRecordsByPosition } from '@/object-record/utils/sortRecordsByPosition'; import { sortRecordsByPosition } from '@/object-record/utils/sortRecordsByPosition';
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2'; import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
@ -13,36 +11,20 @@ import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
import { isDefined } from '~/utils/isDefined'; import { isDefined } from '~/utils/isDefined';
export const useSetRecordIdsForColumn = (recordBoardId?: string) => { export const useSetRecordIdsForColumn = (recordBoardId?: string) => {
const recordGroupIdsState = useRecoilComponentCallbackStateV2(
recordGroupIdsComponentState,
recordBoardId,
);
const recordGroupFieldMetadataState = useRecoilComponentCallbackStateV2( const recordGroupFieldMetadataState = useRecoilComponentCallbackStateV2(
recordGroupFieldMetadataComponentState, recordGroupFieldMetadataComponentState,
recordBoardId, recordBoardId,
); );
const recordIndexAllRowIdsState = useRecoilComponentCallbackStateV2( const recordIndexRecordIdsByGroupFamilyState =
recordIndexAllRowIdsComponentState, useRecoilComponentCallbackStateV2(
recordBoardId, recordIndexRecordIdsByGroupComponentFamilyState,
);
const recordIndexRowIdsByGroupFamilyState = useRecoilComponentCallbackStateV2(
recordIndexRowIdsByGroupComponentFamilyState,
recordBoardId, recordBoardId,
); );
const setRecordIdsForColumn = useRecoilCallback( const setRecordIdsForColumn = useRecoilCallback(
({ set, snapshot }) => ({ set, snapshot }) =>
(currentRecordGroupId: string, records: ObjectRecord[]) => { (currentRecordGroupId: string, records: ObjectRecord[]) => {
const existingAllRowIds = getSnapshotValue(
snapshot,
recordIndexAllRowIdsState,
);
const recordGroupIds = getSnapshotValue(snapshot, recordGroupIdsState);
const recordGroup = getSnapshotValue( const recordGroup = getSnapshotValue(
snapshot, snapshot,
recordGroupDefinitionFamilyState(currentRecordGroupId), recordGroupDefinitionFamilyState(currentRecordGroupId),
@ -50,7 +32,7 @@ export const useSetRecordIdsForColumn = (recordBoardId?: string) => {
const existingRecordGroupRowIds = getSnapshotValue( const existingRecordGroupRowIds = getSnapshotValue(
snapshot, snapshot,
recordIndexRowIdsByGroupFamilyState(currentRecordGroupId), recordIndexRecordIdsByGroupFamilyState(currentRecordGroupId),
); );
const recordGroupFieldMetadata = getSnapshotValue( const recordGroupFieldMetadata = getSnapshotValue(
@ -72,35 +54,12 @@ export const useSetRecordIdsForColumn = (recordBoardId?: string) => {
if (!isDeeplyEqual(existingRecordGroupRowIds, recordGroupRowIds)) { if (!isDeeplyEqual(existingRecordGroupRowIds, recordGroupRowIds)) {
set( set(
recordIndexRowIdsByGroupFamilyState(currentRecordGroupId), recordIndexRecordIdsByGroupFamilyState(currentRecordGroupId),
recordGroupRowIds, recordGroupRowIds,
); );
} }
const allRowIds: string[] = [];
for (const recordGroupId of recordGroupIds) {
const tableRowIdsByGroup =
recordGroupId !== currentRecordGroupId
? getSnapshotValue(
snapshot,
recordIndexRowIdsByGroupFamilyState(recordGroupId),
)
: recordGroupRowIds;
allRowIds.push(...tableRowIdsByGroup);
}
if (!isDeeplyEqual(existingAllRowIds, allRowIds)) {
set(recordIndexAllRowIdsState, allRowIds);
}
}, },
[ [recordIndexRecordIdsByGroupFamilyState, recordGroupFieldMetadataState],
recordGroupIdsState,
recordIndexRowIdsByGroupFamilyState,
recordGroupFieldMetadataState,
recordIndexAllRowIdsState,
],
); );
return { return {

View File

@ -4,7 +4,7 @@ import { Droppable } from '@hello-pangea/dnd';
import { RecordBoardColumnCardsContainer } from '@/object-record/record-board/record-board-column/components/RecordBoardColumnCardsContainer'; import { RecordBoardColumnCardsContainer } from '@/object-record/record-board/record-board-column/components/RecordBoardColumnCardsContainer';
import { RecordBoardColumnContext } from '@/object-record/record-board/record-board-column/contexts/RecordBoardColumnContext'; import { RecordBoardColumnContext } from '@/object-record/record-board/record-board-column/contexts/RecordBoardColumnContext';
import { recordGroupDefinitionFamilyState } from '@/object-record/record-group/states/recordGroupDefinitionFamilyState'; import { recordGroupDefinitionFamilyState } from '@/object-record/record-group/states/recordGroupDefinitionFamilyState';
import { recordIndexRowIdsByGroupComponentFamilyState } from '@/object-record/record-index/states/recordIndexRowIdsByGroupComponentFamilyState'; import { recordIndexRecordIdsByGroupComponentFamilyState } from '@/object-record/record-index/states/recordIndexRecordIdsByGroupComponentFamilyState';
import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValueV2'; import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValueV2';
import { useRecoilValue } from 'recoil'; import { useRecoilValue } from 'recoil';
@ -31,8 +31,8 @@ export const RecordBoardColumn = ({
recordGroupDefinitionFamilyState(recordBoardColumnId), recordGroupDefinitionFamilyState(recordBoardColumnId),
); );
const recordRowIdsByGroup = useRecoilComponentFamilyValueV2( const recordIdsByGroup = useRecoilComponentFamilyValueV2(
recordIndexRowIdsByGroupComponentFamilyState, recordIndexRecordIdsByGroupComponentFamilyState,
recordBoardColumnId, recordBoardColumnId,
); );
@ -44,9 +44,9 @@ export const RecordBoardColumn = ({
<RecordBoardColumnContext.Provider <RecordBoardColumnContext.Provider
value={{ value={{
columnDefinition: recordGroupDefinition, columnDefinition: recordGroupDefinition,
recordCount: recordRowIdsByGroup.length, recordCount: recordIdsByGroup.length,
columnId: recordBoardColumnId, columnId: recordBoardColumnId,
recordIds: recordRowIdsByGroup, recordIds: recordIdsByGroup,
}} }}
> >
<Droppable droppableId={recordBoardColumnId}> <Droppable droppableId={recordBoardColumnId}>
@ -54,7 +54,7 @@ export const RecordBoardColumn = ({
<StyledColumn> <StyledColumn>
<RecordBoardColumnCardsContainer <RecordBoardColumnCardsContainer
droppableProvided={droppableProvided} droppableProvided={droppableProvided}
recordIds={recordRowIdsByGroup} recordIds={recordIdsByGroup}
/> />
</StyledColumn> </StyledColumn>
)} )}

View File

@ -3,7 +3,7 @@ import { isDefined } from 'twenty-ui';
import { RecordBoardColumnHeader } from '@/object-record/record-board/record-board-column/components/RecordBoardColumnHeader'; import { RecordBoardColumnHeader } from '@/object-record/record-board/record-board-column/components/RecordBoardColumnHeader';
import { RecordBoardColumnContext } from '@/object-record/record-board/record-board-column/contexts/RecordBoardColumnContext'; import { RecordBoardColumnContext } from '@/object-record/record-board/record-board-column/contexts/RecordBoardColumnContext';
import { recordGroupDefinitionFamilyState } from '@/object-record/record-group/states/recordGroupDefinitionFamilyState'; import { recordGroupDefinitionFamilyState } from '@/object-record/record-group/states/recordGroupDefinitionFamilyState';
import { recordIndexRowIdsByGroupComponentFamilyState } from '@/object-record/record-index/states/recordIndexRowIdsByGroupComponentFamilyState'; import { recordIndexRecordIdsByGroupComponentFamilyState } from '@/object-record/record-index/states/recordIndexRecordIdsByGroupComponentFamilyState';
import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValueV2'; import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValueV2';
import { useRecoilValue } from 'recoil'; import { useRecoilValue } from 'recoil';
@ -18,8 +18,8 @@ export const RecordBoardColumnHeaderWrapper = ({
recordGroupDefinitionFamilyState(columnId), recordGroupDefinitionFamilyState(columnId),
); );
const recordRowIdsByGroup = useRecoilComponentFamilyValueV2( const recordIdsByGroup = useRecoilComponentFamilyValueV2(
recordIndexRowIdsByGroupComponentFamilyState, recordIndexRecordIdsByGroupComponentFamilyState,
columnId, columnId,
); );
@ -32,8 +32,8 @@ export const RecordBoardColumnHeaderWrapper = ({
value={{ value={{
columnId, columnId,
columnDefinition: recordGroupDefinition, columnDefinition: recordGroupDefinition,
recordCount: recordRowIdsByGroup.length, recordCount: recordIdsByGroup.length,
recordIds: recordRowIdsByGroup, recordIds: recordIdsByGroup,
}} }}
> >
<RecordBoardColumnHeader /> <RecordBoardColumnHeader />

View File

@ -1,6 +1,6 @@
import { RecordBoardComponentInstanceContext } from '@/object-record/record-board/states/contexts/RecordBoardComponentInstanceContext'; import { RecordBoardComponentInstanceContext } from '@/object-record/record-board/states/contexts/RecordBoardComponentInstanceContext';
import { isRecordBoardCardSelectedComponentFamilyState } from '@/object-record/record-board/states/isRecordBoardCardSelectedComponentFamilyState'; import { isRecordBoardCardSelectedComponentFamilyState } from '@/object-record/record-board/states/isRecordBoardCardSelectedComponentFamilyState';
import { recordIndexAllRowIdsComponentState } from '@/object-record/record-index/states/recordIndexAllRowIdsComponentState'; import { recordIndexAllRecordIdsComponentSelector } from '@/object-record/record-index/states/selectors/recordIndexAllRecordIdsComponentSelector';
import { createComponentSelectorV2 } from '@/ui/utilities/state/component-state/utils/createComponentSelectorV2'; import { createComponentSelectorV2 } from '@/ui/utilities/state/component-state/utils/createComponentSelectorV2';
export const recordBoardSelectedRecordIdsComponentSelector = export const recordBoardSelectedRecordIdsComponentSelector =
@ -10,11 +10,15 @@ export const recordBoardSelectedRecordIdsComponentSelector =
get: get:
({ instanceId }) => ({ instanceId }) =>
({ get }) => { ({ get }) => {
const allRowIds = get( const allRecordIds = get(
recordIndexAllRowIdsComponentState.atomFamily({ instanceId }), // TODO: This selector use a context different from the one used in the snippet
// its working for now as the instanceId is the same but we should change this
recordIndexAllRecordIdsComponentSelector.selectorFamily({
instanceId,
}),
); );
return allRowIds.filter( return allRecordIds.filter(
(recordId) => (recordId) =>
get( get(
isRecordBoardCardSelectedComponentFamilyState.atomFamily({ isRecordBoardCardSelectedComponentFamilyState.atomFamily({

View File

@ -2,7 +2,7 @@ import { recordGroupDefinitionFamilyState } from '@/object-record/record-group/s
import { recordGroupIdsComponentState } from '@/object-record/record-group/states/recordGroupIdsComponentState'; import { recordGroupIdsComponentState } from '@/object-record/record-group/states/recordGroupIdsComponentState';
import { RecordGroupDefinition } from '@/object-record/record-group/types/RecordGroupDefinition'; import { RecordGroupDefinition } from '@/object-record/record-group/types/RecordGroupDefinition';
import { recordIndexRecordGroupHideComponentState } from '@/object-record/record-index/states/recordIndexRecordGroupHideComponentState'; import { recordIndexRecordGroupHideComponentState } from '@/object-record/record-index/states/recordIndexRecordGroupHideComponentState';
import { recordIndexRowIdsByGroupComponentFamilyState } from '@/object-record/record-index/states/recordIndexRowIdsByGroupComponentFamilyState'; import { recordIndexRecordIdsByGroupComponentFamilyState } from '@/object-record/record-index/states/recordIndexRecordIdsByGroupComponentFamilyState';
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2'; import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue'; import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue';
import { useSaveCurrentViewGroups } from '@/views/hooks/useSaveCurrentViewGroups'; import { useSaveCurrentViewGroups } from '@/views/hooks/useSaveCurrentViewGroups';
@ -22,8 +22,9 @@ export const useRecordGroupVisibility = ({
recordGroupIdsComponentState, recordGroupIdsComponentState,
); );
const recordIndexRowIdsByGroupFamilyState = useRecoilComponentCallbackStateV2( const recordIndexRecordIdsByGroupFamilyState =
recordIndexRowIdsByGroupComponentFamilyState, useRecoilComponentCallbackStateV2(
recordIndexRecordIdsByGroupComponentFamilyState,
viewBarId, viewBarId,
); );
@ -79,7 +80,7 @@ export const useRecordGroupVisibility = ({
const recordGroupRowIds = getSnapshotValue( const recordGroupRowIds = getSnapshotValue(
snapshot, snapshot,
recordIndexRowIdsByGroupFamilyState(recordGroupId), recordIndexRecordIdsByGroupFamilyState(recordGroupId),
); );
if (recordGroupRowIds.length > 0) { if (recordGroupRowIds.length > 0) {
@ -107,7 +108,7 @@ export const useRecordGroupVisibility = ({
recordIndexRecordGroupIdsState, recordIndexRecordGroupIdsState,
objectOptionsDropdownRecordGroupHideState, objectOptionsDropdownRecordGroupHideState,
saveViewGroups, saveViewGroups,
recordIndexRowIdsByGroupFamilyState, recordIndexRecordIdsByGroupFamilyState,
], ],
); );

View File

@ -8,7 +8,6 @@ import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue';
import { useContext } from 'react'; import { useContext } from 'react';
import { useRecoilCallback } from 'recoil'; import { useRecoilCallback } from 'recoil';
import { isDeeplyEqual } from '~/utils/isDeeplyEqual'; import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
import { isDefined } from '~/utils/isDefined';
export const useSetRecordGroup = (viewId?: string) => { export const useSetRecordGroup = (viewId?: string) => {
const { objectMetadataItem } = useContext(RecordIndexRootPropsContext); const { objectMetadataItem } = useContext(RecordIndexRootPropsContext);
@ -26,28 +25,23 @@ export const useSetRecordGroup = (viewId?: string) => {
return useRecoilCallback( return useRecoilCallback(
({ snapshot, set }) => ({ snapshot, set }) =>
(recordGroups: RecordGroupDefinition[]) => { (recordGroups: RecordGroupDefinition[]) => {
if (recordGroups.length === 0) {
return;
}
const currentRecordGroupId = getSnapshotValue( const currentRecordGroupId = getSnapshotValue(
snapshot, snapshot,
recordIndexRecordGroupIdsState, recordIndexRecordGroupIdsState,
); );
const fieldMetadataId = recordGroups[0].fieldMetadataId; const fieldMetadataId = recordGroups?.[0]?.fieldMetadataId;
const fieldMetadata = objectMetadataItem.fields.find( const fieldMetadata = fieldMetadataId
? objectMetadataItem.fields.find(
(field) => field.id === fieldMetadataId, (field) => field.id === fieldMetadataId,
); )
: undefined;
const currentFieldMetadata = getSnapshotValue( const currentFieldMetadata = getSnapshotValue(
snapshot, snapshot,
recordGroupFieldMetadataState, recordGroupFieldMetadataState,
); );
// Set the field metadata linked to the record groups // Set the field metadata linked to the record groups
if ( if (!isDeeplyEqual(fieldMetadata, currentFieldMetadata)) {
isDefined(fieldMetadata) &&
!isDeeplyEqual(fieldMetadata, currentFieldMetadata)
) {
set(recordGroupFieldMetadataState, fieldMetadata); set(recordGroupFieldMetadataState, fieldMetadata);
} }
@ -67,6 +61,16 @@ export const useSetRecordGroup = (viewId?: string) => {
const recordGroupIds = recordGroups.map(({ id }) => id); const recordGroupIds = recordGroups.map(({ id }) => id);
// Get ids that has been removed between the current and new record groups
const removedRecordGroupIds = currentRecordGroupId.filter(
(id) => !recordGroupIds.includes(id),
);
// Remove the record groups that has been removed
removedRecordGroupIds.forEach((id) => {
set(recordGroupDefinitionFamilyState(id), undefined);
});
if (isDeeplyEqual(currentRecordGroupId, recordGroupIds)) { if (isDeeplyEqual(currentRecordGroupId, recordGroupIds)) {
return; return;
} }

View File

@ -1,12 +1,13 @@
import { recordGroupDefinitionFamilyState } from '@/object-record/record-group/states/recordGroupDefinitionFamilyState'; import { recordGroupDefinitionFamilyState } from '@/object-record/record-group/states/recordGroupDefinitionFamilyState';
import { recordGroupIdsComponentState } from '@/object-record/record-group/states/recordGroupIdsComponentState'; import { recordGroupIdsComponentState } from '@/object-record/record-group/states/recordGroupIdsComponentState';
import { RecordGroupDefinition } from '@/object-record/record-group/types/RecordGroupDefinition';
import { createComponentSelectorV2 } from '@/ui/utilities/state/component-state/utils/createComponentSelectorV2'; import { createComponentSelectorV2 } from '@/ui/utilities/state/component-state/utils/createComponentSelectorV2';
import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext'; import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext';
import { isDefined } from '~/utils/isDefined'; import { isDefined } from '~/utils/isDefined';
export const hiddenRecordGroupIdsComponentSelector = createComponentSelectorV2< export const hiddenRecordGroupIdsComponentSelector = createComponentSelectorV2<
string[] RecordGroupDefinition['id'][]
>({ >({
key: 'hiddenRecordGroupIdsComponentSelector', key: 'hiddenRecordGroupIdsComponentSelector',
componentInstanceContext: ViewComponentInstanceContext, componentInstanceContext: ViewComponentInstanceContext,

View File

@ -10,7 +10,7 @@ import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewCompon
import { isDefined } from '~/utils/isDefined'; import { isDefined } from '~/utils/isDefined';
export const visibleRecordGroupIdsComponentSelector = createComponentSelectorV2< export const visibleRecordGroupIdsComponentSelector = createComponentSelectorV2<
string[] RecordGroupDefinition['id'][]
>({ >({
key: 'visibleRecordGroupIdsComponentSelector', key: 'visibleRecordGroupIdsComponentSelector',
componentInstanceContext: ViewComponentInstanceContext, componentInstanceContext: ViewComponentInstanceContext,

View File

@ -6,7 +6,7 @@ export const sortRecordGroupDefinitions = (
recordGroupSort: RecordGroupSort, recordGroupSort: RecordGroupSort,
) => { ) => {
const visibleRecordGroups = recordGroupDefinitions.filter( const visibleRecordGroups = recordGroupDefinitions.filter(
(boardGroup) => boardGroup.isVisible, (recordGroup) => recordGroup.isVisible,
); );
const compareAlphabetical = (a: string, b: string, reverse = false) => { const compareAlphabetical = (a: string, b: string, reverse = false) => {

View File

@ -61,6 +61,10 @@ export const useFindManyParams = (
); );
} }
if (!isDefined(currentRecordGroupDefinition.value)) {
return { [fieldMetadataItem.name]: { is: 'NULL' } };
}
return { return {
[fieldMetadataItem.name]: { [fieldMetadataItem.name]: {
eq: currentRecordGroupDefinition.value, eq: currentRecordGroupDefinition.value,
@ -68,8 +72,6 @@ export const useFindManyParams = (
}; };
} }
// TODO: Handle case when value is nullable
return {}; return {};
}, [objectMetadataItem.fields, currentRecordGroupDefinition]); }, [objectMetadataItem.fields, currentRecordGroupDefinition]);

View File

@ -1,10 +0,0 @@
import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2';
import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext';
export const recordIndexAllRowIdsComponentState = createComponentStateV2<
string[]
>({
key: 'recordIndexAllRowIdsComponentState',
defaultValue: [],
componentInstanceContext: ViewComponentInstanceContext,
});

View File

@ -2,9 +2,9 @@ import { RecordGroupDefinition } from '@/object-record/record-group/types/Record
import { createComponentFamilyStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentFamilyStateV2'; import { createComponentFamilyStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentFamilyStateV2';
import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext'; import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext';
export const recordIndexRowIdsByGroupComponentFamilyState = export const recordIndexRecordIdsByGroupComponentFamilyState =
createComponentFamilyStateV2<string[], RecordGroupDefinition['id']>({ createComponentFamilyStateV2<string[], RecordGroupDefinition['id']>({
key: 'recordIndexRowIdsByGroupComponentFamilyState', key: 'recordIndexRecordIdsByGroupComponentFamilyState',
defaultValue: [], defaultValue: [],
componentInstanceContext: ViewComponentInstanceContext, componentInstanceContext: ViewComponentInstanceContext,
}); });

View File

@ -0,0 +1,59 @@
import { recordGroupIdsComponentState } from '@/object-record/record-group/states/recordGroupIdsComponentState';
import { recordIndexRecordIdsByGroupComponentFamilyState } from '@/object-record/record-index/states/recordIndexRecordIdsByGroupComponentFamilyState';
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
import { createComponentSelectorV2 } from '@/ui/utilities/state/component-state/utils/createComponentSelectorV2';
import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext';
/**
* Do not use this key outside of this file.
* This is a temporary key to store the record ids for the default record group.
*/
const defaultFamilyKey = 'record-group-default-id';
export const recordIndexAllRecordIdsComponentSelector =
createComponentSelectorV2<ObjectRecord['id'][]>({
key: 'recordIndexAllRecordIdsComponentSelector',
componentInstanceContext: ViewComponentInstanceContext,
get:
({ instanceId }) =>
({ get }) => {
const recordGroupIds = get(
recordGroupIdsComponentState.atomFamily({
instanceId,
}),
);
if (recordGroupIds.length === 0) {
return get(
recordIndexRecordIdsByGroupComponentFamilyState.atomFamily({
instanceId,
familyKey: defaultFamilyKey,
}),
);
}
return recordGroupIds.reduce<ObjectRecord['id'][]>(
(acc, recordGroupId) => {
const rowIds = get(
recordIndexRecordIdsByGroupComponentFamilyState.atomFamily({
instanceId,
familyKey: recordGroupId,
}),
);
return [...acc, ...rowIds];
},
[],
);
},
set:
({ instanceId }) =>
({ set }, recordIds) =>
set(
recordIndexRecordIdsByGroupComponentFamilyState.atomFamily({
instanceId,
familyKey: defaultFamilyKey,
}),
recordIds,
),
});

View File

@ -4,7 +4,7 @@ import { createComponentSelectorV2 } from '@/ui/utilities/state/component-state/
import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext'; import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext';
export const recordIndexRecordGroupIsDraggableSortComponentSelector = export const recordIndexRecordGroupIsDraggableSortComponentSelector =
createComponentSelectorV2({ createComponentSelectorV2<boolean>({
key: 'recordIndexRecordGroupIsDraggableSortComponentSelector', key: 'recordIndexRecordGroupIsDraggableSortComponentSelector',
componentInstanceContext: ViewComponentInstanceContext, componentInstanceContext: ViewComponentInstanceContext,
get: get:

View File

@ -2,7 +2,7 @@ import styled from '@emotion/styled';
import { isNonEmptyString, isNull } from '@sniptt/guards'; import { isNonEmptyString, isNull } from '@sniptt/guards';
import { hasRecordGroupsComponentSelector } from '@/object-record/record-group/states/selectors/hasRecordGroupsComponentSelector'; import { hasRecordGroupsComponentSelector } from '@/object-record/record-group/states/selectors/hasRecordGroupsComponentSelector';
import { recordIndexAllRowIdsComponentState } from '@/object-record/record-index/states/recordIndexAllRowIdsComponentState'; import { recordIndexAllRecordIdsComponentSelector } from '@/object-record/record-index/states/selectors/recordIndexAllRecordIdsComponentSelector';
import { RecordTableComponentInstance } from '@/object-record/record-table/components/RecordTableComponentInstance'; import { RecordTableComponentInstance } from '@/object-record/record-table/components/RecordTableComponentInstance';
import { RecordTableContextProvider } from '@/object-record/record-table/components/RecordTableContextProvider'; import { RecordTableContextProvider } from '@/object-record/record-table/components/RecordTableContextProvider';
import { RecordTableStickyEffect } from '@/object-record/record-table/components/RecordTableStickyEffect'; import { RecordTableStickyEffect } from '@/object-record/record-table/components/RecordTableStickyEffect';
@ -53,8 +53,8 @@ export const RecordTable = ({
recordTableId, recordTableId,
); );
const allRowIds = useRecoilComponentValueV2( const allRecordIds = useRecoilComponentValueV2(
recordIndexAllRowIdsComponentState, recordIndexAllRecordIdsComponentSelector,
recordTableId, recordTableId,
); );
@ -70,7 +70,7 @@ export const RecordTable = ({
const recordTableIsEmpty = const recordTableIsEmpty =
!isRecordTableInitialLoading && !isRecordTableInitialLoading &&
allRowIds.length === 0 && allRecordIds.length === 0 &&
isNull(pendingRecordId); isNull(pendingRecordId);
const { resetTableRowSelection, setRowSelected } = useRecordTable({ const { resetTableRowSelection, setRowSelected } = useRecordTable({

View File

@ -1,16 +1,16 @@
import { recordIndexAllRowIdsComponentState } from '@/object-record/record-index/states/recordIndexAllRowIdsComponentState'; import { recordIndexAllRecordIdsComponentSelector } from '@/object-record/record-index/states/selectors/recordIndexAllRecordIdsComponentSelector';
import { RecordTableBodyFetchMoreLoader } from '@/object-record/record-table/record-table-body/components/RecordTableBodyFetchMoreLoader'; import { RecordTableBodyFetchMoreLoader } from '@/object-record/record-table/record-table-body/components/RecordTableBodyFetchMoreLoader';
import { RecordTableRow } from '@/object-record/record-table/record-table-row/components/RecordTableRow'; import { RecordTableRow } from '@/object-record/record-table/record-table-row/components/RecordTableRow';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
export const RecordTableNoRecordGroupRows = () => { export const RecordTableNoRecordGroupRows = () => {
const allRowIds = useRecoilComponentValueV2( const allRecordIds = useRecoilComponentValueV2(
recordIndexAllRowIdsComponentState, recordIndexAllRecordIdsComponentSelector,
); );
return ( return (
<> <>
{allRowIds.map((recordId, rowIndex) => { {allRecordIds.map((recordId, rowIndex) => {
return ( return (
<RecordTableRow <RecordTableRow
key={recordId} key={recordId}

View File

@ -1,37 +1,52 @@
import { useCurrentRecordGroupId } from '@/object-record/record-group/hooks/useCurrentRecordGroupId'; import { useCurrentRecordGroupId } from '@/object-record/record-group/hooks/useCurrentRecordGroupId';
import { recordIndexAllRowIdsComponentState } from '@/object-record/record-index/states/recordIndexAllRowIdsComponentState'; import { recordIndexRecordIdsByGroupComponentFamilyState } from '@/object-record/record-index/states/recordIndexRecordIdsByGroupComponentFamilyState';
import { recordIndexRowIdsByGroupComponentFamilyState } from '@/object-record/record-index/states/recordIndexRowIdsByGroupComponentFamilyState'; import { recordIndexAllRecordIdsComponentSelector } from '@/object-record/record-index/states/selectors/recordIndexAllRecordIdsComponentSelector';
import { RecordTableRow } from '@/object-record/record-table/record-table-row/components/RecordTableRow'; import { RecordTableRow } from '@/object-record/record-table/record-table-row/components/RecordTableRow';
import { isRecordGroupTableSectionToggledComponentState } from '@/object-record/record-table/record-table-section/states/isRecordGroupTableSectionToggledComponentState';
import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValueV2'; import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValueV2';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
import { useMemo } from 'react'; import { useMemo } from 'react';
import { isDefined } from '~/utils/isDefined';
export const RecordTableRecordGroupRows = () => { export const RecordTableRecordGroupRows = () => {
const recordGroupId = useCurrentRecordGroupId(); const currentRecordGroupId = useCurrentRecordGroupId();
const allRowIds = useRecoilComponentValueV2( const allRecordIds = useRecoilComponentValueV2(
recordIndexAllRowIdsComponentState, recordIndexAllRecordIdsComponentSelector,
); );
const recordGroupRowIds = useRecoilComponentFamilyValueV2( const recordIdsByGroup = useRecoilComponentFamilyValueV2(
recordIndexRowIdsByGroupComponentFamilyState, recordIndexRecordIdsByGroupComponentFamilyState,
recordGroupId, currentRecordGroupId,
);
const isRecordGroupTableSectionToggled = useRecoilComponentFamilyValueV2(
isRecordGroupTableSectionToggledComponentState,
currentRecordGroupId,
); );
const rowIndexMap = useMemo( const rowIndexMap = useMemo(
() => new Map(allRowIds.map((id, index) => [id, index])), () => new Map(allRecordIds.map((recordId, index) => [recordId, index])),
[allRowIds], [allRecordIds],
); );
return recordGroupRowIds.map((recordId) => { return (
isRecordGroupTableSectionToggled &&
recordIdsByGroup.map((recordId) => {
const rowIndex = rowIndexMap.get(recordId); const rowIndex = rowIndexMap.get(recordId);
if (!rowIndex) { if (!isDefined(rowIndex)) {
throw new Error(`Row index for record id ${recordId} not found`); return null;
} }
return ( return (
<RecordTableRow key={recordId} recordId={recordId} rowIndex={rowIndex} /> <RecordTableRow
key={recordId}
recordId={recordId}
rowIndex={rowIndex}
isPendingRow={!isRecordGroupTableSectionToggled}
/>
);
})
); );
});
}; };

View File

@ -1,6 +1,6 @@
import { isNull } from '@sniptt/guards'; import { isNull } from '@sniptt/guards';
import { recordIndexAllRowIdsComponentState } from '@/object-record/record-index/states/recordIndexAllRowIdsComponentState'; import { recordIndexAllRecordIdsComponentSelector } from '@/object-record/record-index/states/selectors/recordIndexAllRecordIdsComponentSelector';
import { RecordTableEmptyState } from '@/object-record/record-table/empty-state/components/RecordTableEmptyState'; import { RecordTableEmptyState } from '@/object-record/record-table/empty-state/components/RecordTableEmptyState';
import { isRecordTableInitialLoadingComponentState } from '@/object-record/record-table/states/isRecordTableInitialLoadingComponentState'; import { isRecordTableInitialLoadingComponentState } from '@/object-record/record-table/states/isRecordTableInitialLoadingComponentState';
import { recordTablePendingRecordIdComponentState } from '@/object-record/record-table/states/recordTablePendingRecordIdComponentState'; import { recordTablePendingRecordIdComponentState } from '@/object-record/record-table/states/recordTablePendingRecordIdComponentState';
@ -20,8 +20,8 @@ export const RecordTableEmptyHandler = ({
recordTableId, recordTableId,
); );
const allRowIds = useRecoilComponentValueV2( const allRecordIds = useRecoilComponentValueV2(
recordIndexAllRowIdsComponentState, recordIndexAllRecordIdsComponentSelector,
recordTableId, recordTableId,
); );
@ -32,7 +32,7 @@ export const RecordTableEmptyHandler = ({
const recordTableIsEmpty = const recordTableIsEmpty =
!isRecordTableInitialLoading && !isRecordTableInitialLoading &&
allRowIds.length === 0 && allRecordIds.length === 0 &&
isNull(pendingRecordId); isNull(pendingRecordId);
if (recordTableIsEmpty) { if (recordTableIsEmpty) {

View File

@ -2,7 +2,7 @@ import { useRecoilCallback } from 'recoil';
import { getActionMenuDropdownIdFromActionMenuId } from '@/action-menu/utils/getActionMenuDropdownIdFromActionMenuId'; import { getActionMenuDropdownIdFromActionMenuId } from '@/action-menu/utils/getActionMenuDropdownIdFromActionMenuId';
import { getActionMenuIdFromRecordIndexId } from '@/action-menu/utils/getActionMenuIdFromRecordIndexId'; import { getActionMenuIdFromRecordIndexId } from '@/action-menu/utils/getActionMenuIdFromRecordIndexId';
import { recordIndexAllRowIdsComponentState } from '@/object-record/record-index/states/recordIndexAllRowIdsComponentState'; import { recordIndexAllRecordIdsComponentSelector } from '@/object-record/record-index/states/selectors/recordIndexAllRecordIdsComponentSelector';
import { hasUserSelectedAllRowsComponentState } from '@/object-record/record-table/record-table-row/states/hasUserSelectedAllRowsFamilyState'; import { hasUserSelectedAllRowsComponentState } from '@/object-record/record-table/record-table-row/states/hasUserSelectedAllRowsFamilyState';
import { isRowSelectedComponentFamilyState } from '@/object-record/record-table/record-table-row/states/isRowSelectedComponentFamilyState'; import { isRowSelectedComponentFamilyState } from '@/object-record/record-table/record-table-row/states/isRowSelectedComponentFamilyState';
import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext'; import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext';
@ -18,8 +18,8 @@ export const useResetTableRowSelection = (recordTableId?: string) => {
recordTableId, recordTableId,
); );
const recordIndexAllRowIdsState = useRecoilComponentCallbackStateV2( const recordIndexAllRecordIdsSelector = useRecoilComponentCallbackStateV2(
recordIndexAllRowIdsComponentState, recordIndexAllRecordIdsComponentSelector,
recordTableIdFromContext, recordTableIdFromContext,
); );
@ -43,10 +43,13 @@ export const useResetTableRowSelection = (recordTableId?: string) => {
return useRecoilCallback( return useRecoilCallback(
({ set, snapshot }) => ({ set, snapshot }) =>
() => { () => {
const allRowIds = getSnapshotValue(snapshot, recordIndexAllRowIdsState); const allRecordIds = getSnapshotValue(
snapshot,
recordIndexAllRecordIdsSelector,
);
for (const rowId of allRowIds) { for (const recordId of allRecordIds) {
set(isRowSelectedFamilyState(rowId), false); set(isRowSelectedFamilyState(recordId), false);
} }
set(hasUserSelectedAllRowsState, false); set(hasUserSelectedAllRowsState, false);
@ -54,7 +57,7 @@ export const useResetTableRowSelection = (recordTableId?: string) => {
set(isActionMenuDropdownOpenState, false); set(isActionMenuDropdownOpenState, false);
}, },
[ [
recordIndexAllRowIdsState, recordIndexAllRecordIdsSelector,
hasUserSelectedAllRowsState, hasUserSelectedAllRowsState,
isActionMenuDropdownOpenState, isActionMenuDropdownOpenState,
isRowSelectedFamilyState, isRowSelectedFamilyState,

View File

@ -1,6 +1,6 @@
import { useRecoilCallback } from 'recoil'; import { useRecoilCallback } from 'recoil';
import { recordIndexAllRowIdsComponentState } from '@/object-record/record-index/states/recordIndexAllRowIdsComponentState'; import { recordIndexAllRecordIdsComponentSelector } from '@/object-record/record-index/states/selectors/recordIndexAllRecordIdsComponentSelector';
import { isRowSelectedComponentFamilyState } from '@/object-record/record-table/record-table-row/states/isRowSelectedComponentFamilyState'; import { isRowSelectedComponentFamilyState } from '@/object-record/record-table/record-table-row/states/isRowSelectedComponentFamilyState';
import { allRowsSelectedStatusComponentSelector } from '@/object-record/record-table/states/selectors/allRowsSelectedStatusComponentSelector'; import { allRowsSelectedStatusComponentSelector } from '@/object-record/record-table/states/selectors/allRowsSelectedStatusComponentSelector';
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue'; import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
@ -15,8 +15,8 @@ export const useSelectAllRows = (recordTableId?: string) => {
isRowSelectedComponentFamilyState, isRowSelectedComponentFamilyState,
recordTableId, recordTableId,
); );
const recordIndexAllRowIdsState = useRecoilComponentCallbackStateV2( const recordIndexAllRecordIdsSelector = useRecoilComponentCallbackStateV2(
recordIndexAllRowIdsComponentState, recordIndexAllRecordIdsComponentSelector,
recordTableId, recordTableId,
); );
@ -28,24 +28,22 @@ export const useSelectAllRows = (recordTableId?: string) => {
allRowsSelectedStatusSelector, allRowsSelectedStatusSelector,
); );
const allRowIds = getSnapshotValue(snapshot, recordIndexAllRowIdsState); const allRecordIds = getSnapshotValue(
snapshot,
recordIndexAllRecordIdsSelector,
);
if ( for (const recordId of allRecordIds) {
const isSelected =
allRowsSelectedStatus === 'none' || allRowsSelectedStatus === 'none' ||
allRowsSelectedStatus === 'some' allRowsSelectedStatus === 'some';
) {
for (const rowId of allRowIds) { set(isRowSelectedFamilyState(recordId), isSelected);
set(isRowSelectedFamilyState(rowId), true);
}
} else {
for (const rowId of allRowIds) {
set(isRowSelectedFamilyState(rowId), false);
}
} }
}, },
[ [
allRowsSelectedStatusSelector, allRowsSelectedStatusSelector,
recordIndexAllRowIdsState, recordIndexAllRecordIdsSelector,
isRowSelectedFamilyState, isRowSelectedFamilyState,
], ],
); );

View File

@ -1,8 +1,7 @@
import { useRecoilCallback } from 'recoil'; import { useRecoilCallback } from 'recoil';
import { recordGroupIdsComponentState } from '@/object-record/record-group/states/recordGroupIdsComponentState'; import { recordIndexRecordIdsByGroupComponentFamilyState } from '@/object-record/record-index/states/recordIndexRecordIdsByGroupComponentFamilyState';
import { recordIndexAllRowIdsComponentState } from '@/object-record/record-index/states/recordIndexAllRowIdsComponentState'; import { recordIndexAllRecordIdsComponentSelector } from '@/object-record/record-index/states/selectors/recordIndexAllRecordIdsComponentSelector';
import { recordIndexRowIdsByGroupComponentFamilyState } from '@/object-record/record-index/states/recordIndexRowIdsByGroupComponentFamilyState';
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
import { hasUserSelectedAllRowsComponentState } from '@/object-record/record-table/record-table-row/states/hasUserSelectedAllRowsFamilyState'; import { hasUserSelectedAllRowsComponentState } from '@/object-record/record-table/record-table-row/states/hasUserSelectedAllRowsFamilyState';
import { isRowSelectedComponentFamilyState } from '@/object-record/record-table/record-table-row/states/isRowSelectedComponentFamilyState'; import { isRowSelectedComponentFamilyState } from '@/object-record/record-table/record-table-row/states/isRowSelectedComponentFamilyState';
@ -21,26 +20,26 @@ export const useSetRecordTableData = ({
recordTableId, recordTableId,
onEntityCountChange, onEntityCountChange,
}: useSetRecordTableDataProps) => { }: useSetRecordTableDataProps) => {
const recordIndexRowIdsByGroupFamilyState = useRecoilComponentCallbackStateV2( const recordIndexRecordIdsByGroupFamilyState =
recordIndexRowIdsByGroupComponentFamilyState, useRecoilComponentCallbackStateV2(
recordIndexRecordIdsByGroupComponentFamilyState,
recordTableId, recordTableId,
); );
const recordIndexAllRowIdsState = useRecoilComponentCallbackStateV2(
recordIndexAllRowIdsComponentState, const recordIndexAllRecordIdsSelector = useRecoilComponentCallbackStateV2(
recordIndexAllRecordIdsComponentSelector,
recordTableId, recordTableId,
); );
const isRowSelectedFamilyState = useRecoilComponentCallbackStateV2( const isRowSelectedFamilyState = useRecoilComponentCallbackStateV2(
isRowSelectedComponentFamilyState, isRowSelectedComponentFamilyState,
recordTableId, recordTableId,
); );
const hasUserSelectedAllRowsState = useRecoilComponentCallbackStateV2( const hasUserSelectedAllRowsState = useRecoilComponentCallbackStateV2(
hasUserSelectedAllRowsComponentState, hasUserSelectedAllRowsComponentState,
recordTableId, recordTableId,
); );
const recordIndexRecordGroupIdsState = useRecoilComponentCallbackStateV2(
recordGroupIdsComponentState,
recordTableId,
);
return useRecoilCallback( return useRecoilCallback(
({ set, snapshot }) => ({ set, snapshot }) =>
@ -67,8 +66,8 @@ export const useSetRecordTableData = ({
const currentRowIds = getSnapshotValue( const currentRowIds = getSnapshotValue(
snapshot, snapshot,
currentRecordGroupId currentRecordGroupId
? recordIndexRowIdsByGroupFamilyState(currentRecordGroupId) ? recordIndexRecordIdsByGroupFamilyState(currentRecordGroupId)
: recordIndexAllRowIdsState, : recordIndexAllRecordIdsSelector,
); );
const hasUserSelectedAllRows = getSnapshotValue( const hasUserSelectedAllRows = getSnapshotValue(
@ -76,11 +75,6 @@ export const useSetRecordTableData = ({
hasUserSelectedAllRowsState, hasUserSelectedAllRowsState,
); );
const recordGroupIds = getSnapshotValue(
snapshot,
recordIndexRecordGroupIdsState,
);
const recordIds = records.map((record) => record.id); const recordIds = records.map((record) => record.id);
if (!isDeeplyEqual(currentRowIds, recordIds)) { if (!isDeeplyEqual(currentRowIds, recordIds)) {
@ -91,39 +85,21 @@ export const useSetRecordTableData = ({
} }
if (isDefined(currentRecordGroupId)) { if (isDefined(currentRecordGroupId)) {
// TODO: Hack to store all ids in the same order as the record group definitions
// Should be replaced by something more efficient
const allRowIds: string[] = [];
set( set(
recordIndexRowIdsByGroupFamilyState(currentRecordGroupId), recordIndexRecordIdsByGroupFamilyState(currentRecordGroupId),
recordIds, recordIds,
); );
for (const recordGroupId of recordGroupIds) {
const tableRowIdsByGroup =
recordGroupId !== currentRecordGroupId
? getSnapshotValue(
snapshot,
recordIndexRowIdsByGroupFamilyState(recordGroupId),
)
: recordIds;
allRowIds.push(...tableRowIdsByGroup);
}
set(recordIndexAllRowIdsState, allRowIds);
} else { } else {
set(recordIndexAllRowIdsState, recordIds); set(recordIndexAllRecordIdsSelector, recordIds);
} }
onEntityCountChange(totalCount); onEntityCountChange(totalCount);
} }
}, },
[ [
recordIndexRowIdsByGroupFamilyState, recordIndexRecordIdsByGroupFamilyState,
recordIndexAllRowIdsState, recordIndexAllRecordIdsSelector,
hasUserSelectedAllRowsState, hasUserSelectedAllRowsState,
recordIndexRecordGroupIdsState,
onEntityCountChange, onEntityCountChange,
isRowSelectedFamilyState, isRowSelectedFamilyState,
], ],

View File

@ -3,7 +3,7 @@ import { useRecoilCallback } from 'recoil';
import { MoveFocusDirection } from '@/object-record/record-table/types/MoveFocusDirection'; import { MoveFocusDirection } from '@/object-record/record-table/types/MoveFocusDirection';
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue'; import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
import { recordIndexAllRowIdsComponentState } from '@/object-record/record-index/states/recordIndexAllRowIdsComponentState'; import { recordIndexAllRecordIdsComponentSelector } from '@/object-record/record-index/states/selectors/recordIndexAllRecordIdsComponentSelector';
import { numberOfTableColumnsComponentSelector } from '@/object-record/record-table/states/selectors/numberOfTableColumnsComponentSelector'; import { numberOfTableColumnsComponentSelector } from '@/object-record/record-table/states/selectors/numberOfTableColumnsComponentSelector';
import { softFocusPositionComponentState } from '@/object-record/record-table/states/softFocusPositionComponentState'; import { softFocusPositionComponentState } from '@/object-record/record-table/states/softFocusPositionComponentState';
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2'; import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
@ -17,8 +17,8 @@ export const useRecordTableMoveFocus = (recordTableId?: string) => {
recordTableId, recordTableId,
); );
const recordIndexAllRowIdsState = useRecoilComponentCallbackStateV2( const recordIndexAllRecordIdsSelector = useRecoilComponentCallbackStateV2(
recordIndexAllRowIdsComponentState, recordIndexAllRecordIdsComponentSelector,
recordTableId, recordTableId,
); );
@ -47,7 +47,10 @@ export const useRecordTableMoveFocus = (recordTableId?: string) => {
const moveDown = useRecoilCallback( const moveDown = useRecoilCallback(
({ snapshot }) => ({ snapshot }) =>
() => { () => {
const allRowIds = getSnapshotValue(snapshot, recordIndexAllRowIdsState); const allRecordIds = getSnapshotValue(
snapshot,
recordIndexAllRecordIdsSelector,
);
const softFocusPosition = getSnapshotValue( const softFocusPosition = getSnapshotValue(
snapshot, snapshot,
softFocusPositionState, softFocusPositionState,
@ -55,8 +58,8 @@ export const useRecordTableMoveFocus = (recordTableId?: string) => {
let newRowIndex = softFocusPosition.row + 1; let newRowIndex = softFocusPosition.row + 1;
if (newRowIndex >= allRowIds.length) { if (newRowIndex >= allRecordIds.length) {
newRowIndex = allRowIds.length - 1; newRowIndex = allRecordIds.length - 1;
} }
setSoftFocusPosition({ setSoftFocusPosition({
@ -64,7 +67,11 @@ export const useRecordTableMoveFocus = (recordTableId?: string) => {
row: newRowIndex, row: newRowIndex,
}); });
}, },
[recordIndexAllRowIdsState, setSoftFocusPosition, softFocusPositionState], [
recordIndexAllRecordIdsSelector,
setSoftFocusPosition,
softFocusPositionState,
],
); );
const numberOfTableColumnsSelector = useRecoilComponentCallbackStateV2( const numberOfTableColumnsSelector = useRecoilComponentCallbackStateV2(
@ -75,7 +82,10 @@ export const useRecordTableMoveFocus = (recordTableId?: string) => {
const moveRight = useRecoilCallback( const moveRight = useRecoilCallback(
({ snapshot }) => ({ snapshot }) =>
() => { () => {
const allRowIds = getSnapshotValue(snapshot, recordIndexAllRowIdsState); const allRecordIds = getSnapshotValue(
snapshot,
recordIndexAllRecordIdsSelector,
);
const softFocusPosition = getSnapshotValue( const softFocusPosition = getSnapshotValue(
snapshot, snapshot,
softFocusPositionState, softFocusPositionState,
@ -91,11 +101,11 @@ export const useRecordTableMoveFocus = (recordTableId?: string) => {
const isLastRowAndLastColumn = const isLastRowAndLastColumn =
currentColumnIndex === numberOfTableColumns - 1 && currentColumnIndex === numberOfTableColumns - 1 &&
currentRowIndex === allRowIds.length - 1; currentRowIndex === allRecordIds.length - 1;
const isLastColumnButNotLastRow = const isLastColumnButNotLastRow =
currentColumnIndex === numberOfTableColumns - 1 && currentColumnIndex === numberOfTableColumns - 1 &&
currentRowIndex !== allRowIds.length - 1; currentRowIndex !== allRecordIds.length - 1;
const isNotLastColumn = currentColumnIndex !== numberOfTableColumns - 1; const isNotLastColumn = currentColumnIndex !== numberOfTableColumns - 1;
@ -116,7 +126,7 @@ export const useRecordTableMoveFocus = (recordTableId?: string) => {
} }
}, },
[ [
recordIndexAllRowIdsState, recordIndexAllRecordIdsSelector,
softFocusPositionState, softFocusPositionState,
numberOfTableColumnsSelector, numberOfTableColumnsSelector,
setSoftFocusPosition, setSoftFocusPosition,

View File

@ -0,0 +1,50 @@
import styled from '@emotion/styled';
import { MOBILE_VIEWPORT } from 'twenty-ui';
const StyledTbody = styled.tbody`
&.first-columns-sticky {
td:nth-of-type(1) {
position: sticky;
left: 0;
z-index: 5;
transition: 0.3s ease;
}
td:nth-of-type(2) {
position: sticky;
left: 11px;
z-index: 5;
transition: 0.3s ease;
}
td:nth-of-type(3) {
position: sticky;
left: 43px;
z-index: 5;
transition: 0.3s ease;
@media (max-width: ${MOBILE_VIEWPORT}px) {
& [data-testid='editable-cell-display-mode'] {
[data-testid='tooltip'] {
display: none;
}
[data-testid='chip'] {
gap: 0;
}
}
}
&::after {
content: '';
position: absolute;
top: -1px;
height: calc(100% + 2px);
width: 4px;
right: 0px;
box-shadow: ${({ theme }) => theme.boxShadow.light};
clip-path: inset(0px -4px 0px 0px);
}
}
}
`;
export const RecordTableBody = StyledTbody;

View File

@ -3,7 +3,7 @@ import { ReactNode, useContext } from 'react';
import { useSetRecoilState } from 'recoil'; import { useSetRecoilState } from 'recoil';
import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord'; import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord';
import { recordIndexAllRowIdsComponentState } from '@/object-record/record-index/states/recordIndexAllRowIdsComponentState'; import { recordIndexAllRecordIdsComponentSelector } from '@/object-record/record-index/states/selectors/recordIndexAllRecordIdsComponentSelector';
import { RecordTableContext } from '@/object-record/record-table/contexts/RecordTableContext'; import { RecordTableContext } from '@/object-record/record-table/contexts/RecordTableContext';
import { useComputeNewRowPosition } from '@/object-record/record-table/hooks/useComputeNewRowPosition'; import { useComputeNewRowPosition } from '@/object-record/record-table/hooks/useComputeNewRowPosition';
import { isRemoveSortingModalOpenState } from '@/object-record/record-table/states/isRemoveSortingModalOpenState'; import { isRemoveSortingModalOpenState } from '@/object-record/record-table/states/isRemoveSortingModalOpenState';
@ -11,7 +11,7 @@ import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/
import { useGetCurrentView } from '@/views/hooks/useGetCurrentView'; import { useGetCurrentView } from '@/views/hooks/useGetCurrentView';
import { isDefined } from '~/utils/isDefined'; import { isDefined } from '~/utils/isDefined';
export const RecordTableBodyDragDropContext = ({ export const RecordTableBodyDragDropContextProvider = ({
children, children,
}: { }: {
children: ReactNode; children: ReactNode;
@ -22,8 +22,8 @@ export const RecordTableBodyDragDropContext = ({
objectNameSingular, objectNameSingular,
}); });
const allRowIds = useRecoilComponentValueV2( const allRecordIds = useRecoilComponentValueV2(
recordIndexAllRowIdsComponentState, recordIndexAllRecordIdsComponentSelector,
); );
const { currentViewWithCombinedFiltersAndSorts } = const { currentViewWithCombinedFiltersAndSorts } =
@ -43,7 +43,7 @@ export const RecordTableBodyDragDropContext = ({
return; return;
} }
const computeResult = computeNewRowPosition(result, allRowIds); const computeResult = computeNewRowPosition(result, allRecordIds);
if (!isDefined(computeResult)) { if (!isDefined(computeResult)) {
return; return;

View File

@ -1,80 +1,36 @@
import { Theme } from '@emotion/react'; import { RecordTableBody } from '@/object-record/record-table/record-table-body/components/RecordTableBody';
import { Droppable } from '@hello-pangea/dnd'; import { Droppable } from '@hello-pangea/dnd';
import { styled } from '@linaria/react'; import { ReactNode, useState } from 'react';
import { ReactNode, useContext, useState } from 'react';
import { MOBILE_VIEWPORT, ThemeContext } from 'twenty-ui';
import { v4 } from 'uuid'; import { v4 } from 'uuid';
const StyledTbody = styled.tbody<{ type RecordTableBodyDroppableProps = {
theme: Theme; children: ReactNode;
}>` recordGroupId?: string;
&.first-columns-sticky { isDropDisabled?: boolean;
td:nth-of-type(1) { };
position: sticky;
left: 0;
z-index: 5;
transition: 0.3s ease;
}
td:nth-of-type(2) {
position: sticky;
left: 11px;
z-index: 5;
transition: 0.3s ease;
}
td:nth-of-type(3) {
position: sticky;
left: 43px;
z-index: 5;
transition: 0.3s ease;
@media (max-width: ${MOBILE_VIEWPORT}px) {
& [data-testid='editable-cell-display-mode'] {
[data-testid='tooltip'] {
display: none;
}
[data-testid='chip'] {
gap: 0;
}
}
}
&::after {
content: '';
position: absolute;
top: -1px;
height: calc(100% + 2px);
width: 4px;
right: 0px;
box-shadow: ${({ theme }) => theme.boxShadow.light};
clip-path: inset(0px -4px 0px 0px);
}
}
}
`;
export const RecordTableBodyDroppable = ({ export const RecordTableBodyDroppable = ({
children, children,
}: { recordGroupId,
children: ReactNode; isDropDisabled,
}) => { }: RecordTableBodyDroppableProps) => {
const [v4Persistable] = useState(v4()); const [v4Persistable] = useState(v4());
const { theme } = useContext(ThemeContext);
return ( return (
<Droppable droppableId={v4Persistable}> <Droppable
droppableId={recordGroupId ?? v4Persistable}
isDropDisabled={isDropDisabled}
>
{(provided) => ( {(provided) => (
<StyledTbody <RecordTableBody
id="record-table-body" id={`record-table-body${recordGroupId ? `-${recordGroupId}` : ''}`}
theme={theme}
ref={provided.innerRef} ref={provided.innerRef}
// eslint-disable-next-line react/jsx-props-no-spreading // eslint-disable-next-line react/jsx-props-no-spreading
{...provided.droppableProps} {...provided.droppableProps}
> >
{children} {children}
{provided.placeholder} {provided.placeholder}
</StyledTbody> </RecordTableBody>
)} )}
</Droppable> </Droppable>
); );

View File

@ -0,0 +1,106 @@
import { DragDropContext, DropResult } from '@hello-pangea/dnd';
import { ReactNode, useContext } from 'react';
import { useRecoilCallback, useSetRecoilState } from 'recoil';
import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord';
import { recordGroupDefinitionFamilyState } from '@/object-record/record-group/states/recordGroupDefinitionFamilyState';
import { recordIndexAllRecordIdsComponentSelector } from '@/object-record/record-index/states/selectors/recordIndexAllRecordIdsComponentSelector';
import { RecordTableContext } from '@/object-record/record-table/contexts/RecordTableContext';
import { useComputeNewRowPosition } from '@/object-record/record-table/hooks/useComputeNewRowPosition';
import { isRemoveSortingModalOpenState } from '@/object-record/record-table/states/isRemoveSortingModalOpenState';
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue';
import { useGetCurrentView } from '@/views/hooks/useGetCurrentView';
import { isDefined } from '~/utils/isDefined';
export const RecordTableBodyRecordGroupDragDropContextProvider = ({
children,
}: {
children: ReactNode;
}) => {
const { objectNameSingular, recordTableId, objectMetadataItem } =
useContext(RecordTableContext);
const { updateOneRecord: updateOneRow } = useUpdateOneRecord({
objectNameSingular,
});
const recordIndexAllRecordIdsSelector = useRecoilComponentCallbackStateV2(
recordIndexAllRecordIdsComponentSelector,
);
const { currentViewWithCombinedFiltersAndSorts } =
useGetCurrentView(recordTableId);
const viewSorts = currentViewWithCombinedFiltersAndSorts?.viewSorts || [];
const setIsRemoveSortingModalOpenState = useSetRecoilState(
isRemoveSortingModalOpenState,
);
const computeNewRowPosition = useComputeNewRowPosition();
const handleDragEnd = useRecoilCallback(
({ snapshot }) =>
(result: DropResult) => {
const tableAllRecordIds = getSnapshotValue(
snapshot,
recordIndexAllRecordIdsSelector,
);
const recordGroupId = result.destination?.droppableId;
if (!isDefined(recordGroupId)) {
throw new Error('Record group id is not defined');
}
const recordGroup = getSnapshotValue(
snapshot,
recordGroupDefinitionFamilyState(recordGroupId),
);
if (!isDefined(recordGroup)) {
throw new Error('Record group is not defined');
}
const fieldMetadata = objectMetadataItem.fields.find(
(field) => field.id === recordGroup.fieldMetadataId,
);
if (!isDefined(fieldMetadata)) {
throw new Error('Field metadata is not defined');
}
if (viewSorts.length > 0) {
setIsRemoveSortingModalOpenState(true);
return;
}
const computeResult = computeNewRowPosition(result, tableAllRecordIds);
if (!isDefined(computeResult)) {
return;
}
updateOneRow({
idToUpdate: computeResult.draggedRecordId,
updateOneRecordInput: {
position: computeResult.newPosition,
[fieldMetadata.name]: recordGroup.value,
},
});
},
[
recordIndexAllRecordIdsSelector,
objectMetadataItem.fields,
viewSorts.length,
computeNewRowPosition,
updateOneRow,
setIsRemoveSortingModalOpenState,
],
);
return (
<DragDropContext onDragEnd={handleDragEnd}>{children}</DragDropContext>
);
};

View File

@ -1,6 +1,6 @@
import { recordIndexAllRowIdsComponentState } from '@/object-record/record-index/states/recordIndexAllRowIdsComponentState'; import { recordIndexAllRecordIdsComponentSelector } from '@/object-record/record-index/states/selectors/recordIndexAllRecordIdsComponentSelector';
import { RecordTableNoRecordGroupRows } from '@/object-record/record-table/components/RecordTableNoRecordGroupRows'; import { RecordTableNoRecordGroupRows } from '@/object-record/record-table/components/RecordTableNoRecordGroupRows';
import { RecordTableBodyDragDropContext } from '@/object-record/record-table/record-table-body/components/RecordTableBodyDragDropContext'; import { RecordTableBodyDragDropContextProvider } from '@/object-record/record-table/record-table-body/components/RecordTableBodyDragDropContextProvider';
import { RecordTableBodyDroppable } from '@/object-record/record-table/record-table-body/components/RecordTableBodyDroppable'; import { RecordTableBodyDroppable } from '@/object-record/record-table/record-table-body/components/RecordTableBodyDroppable';
import { RecordTableBodyLoading } from '@/object-record/record-table/record-table-body/components/RecordTableBodyLoading'; import { RecordTableBodyLoading } from '@/object-record/record-table/record-table-body/components/RecordTableBodyLoading';
import { RecordTablePendingRow } from '@/object-record/record-table/record-table-row/components/RecordTablePendingRow'; import { RecordTablePendingRow } from '@/object-record/record-table/record-table-row/components/RecordTablePendingRow';
@ -8,24 +8,24 @@ import { isRecordTableInitialLoadingComponentState } from '@/object-record/recor
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
export const RecordTableNoRecordGroupBody = () => { export const RecordTableNoRecordGroupBody = () => {
const allRowIds = useRecoilComponentValueV2( const allRecordIds = useRecoilComponentValueV2(
recordIndexAllRowIdsComponentState, recordIndexAllRecordIdsComponentSelector,
); );
const isRecordTableInitialLoading = useRecoilComponentValueV2( const isRecordTableInitialLoading = useRecoilComponentValueV2(
isRecordTableInitialLoadingComponentState, isRecordTableInitialLoadingComponentState,
); );
if (isRecordTableInitialLoading && allRowIds.length === 0) { if (isRecordTableInitialLoading && allRecordIds.length === 0) {
return <RecordTableBodyLoading />; return <RecordTableBodyLoading />;
} }
return ( return (
<RecordTableBodyDragDropContext> <RecordTableBodyDragDropContextProvider>
<RecordTableBodyDroppable> <RecordTableBodyDroppable>
<RecordTablePendingRow /> <RecordTablePendingRow />
<RecordTableNoRecordGroupRows /> <RecordTableNoRecordGroupRows />
</RecordTableBodyDroppable> </RecordTableBodyDroppable>
</RecordTableBodyDragDropContext> </RecordTableBodyDragDropContextProvider>
); );
}; };

View File

@ -1,17 +1,18 @@
import { RecordGroupContext } from '@/object-record/record-group/states/context/RecordGroupContext'; import { RecordGroupContext } from '@/object-record/record-group/states/context/RecordGroupContext';
import { visibleRecordGroupIdsComponentSelector } from '@/object-record/record-group/states/selectors/visibleRecordGroupIdsComponentSelector'; import { visibleRecordGroupIdsComponentSelector } from '@/object-record/record-group/states/selectors/visibleRecordGroupIdsComponentSelector';
import { recordIndexAllRowIdsComponentState } from '@/object-record/record-index/states/recordIndexAllRowIdsComponentState'; import { recordIndexAllRecordIdsComponentSelector } from '@/object-record/record-index/states/selectors/recordIndexAllRecordIdsComponentSelector';
import { RecordTableRecordGroupRows } from '@/object-record/record-table/components/RecordTableRecordGroupRows'; import { RecordTableRecordGroupRows } from '@/object-record/record-table/components/RecordTableRecordGroupRows';
import { RecordTableBodyDragDropContext } from '@/object-record/record-table/record-table-body/components/RecordTableBodyDragDropContext';
import { RecordTableBodyDroppable } from '@/object-record/record-table/record-table-body/components/RecordTableBodyDroppable'; import { RecordTableBodyDroppable } from '@/object-record/record-table/record-table-body/components/RecordTableBodyDroppable';
import { RecordTableBodyLoading } from '@/object-record/record-table/record-table-body/components/RecordTableBodyLoading'; import { RecordTableBodyLoading } from '@/object-record/record-table/record-table-body/components/RecordTableBodyLoading';
import { RecordTableBodyRecordGroupDragDropContextProvider } from '@/object-record/record-table/record-table-body/components/RecordTableBodyRecordGroupDragDropContextProvider';
import { RecordTablePendingRow } from '@/object-record/record-table/record-table-row/components/RecordTablePendingRow'; import { RecordTablePendingRow } from '@/object-record/record-table/record-table-row/components/RecordTablePendingRow';
import { RecordTableRecordGroupSection } from '@/object-record/record-table/record-table-section/components/RecordTableRecordGroupSection';
import { isRecordTableInitialLoadingComponentState } from '@/object-record/record-table/states/isRecordTableInitialLoadingComponentState'; import { isRecordTableInitialLoadingComponentState } from '@/object-record/record-table/states/isRecordTableInitialLoadingComponentState';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
export const RecordTableRecordGroupsBody = () => { export const RecordTableRecordGroupsBody = () => {
const allRowIds = useRecoilComponentValueV2( const allRecordIds = useRecoilComponentValueV2(
recordIndexAllRowIdsComponentState, recordIndexAllRecordIdsComponentSelector,
); );
const isRecordTableInitialLoading = useRecoilComponentValueV2( const isRecordTableInitialLoading = useRecoilComponentValueV2(
@ -22,23 +23,26 @@ export const RecordTableRecordGroupsBody = () => {
visibleRecordGroupIdsComponentSelector, visibleRecordGroupIdsComponentSelector,
); );
if (isRecordTableInitialLoading && allRowIds.length === 0) { if (isRecordTableInitialLoading && allRecordIds.length === 0) {
return <RecordTableBodyLoading />; return <RecordTableBodyLoading />;
} }
return ( return (
<RecordTableBodyDragDropContext> <RecordTableBodyRecordGroupDragDropContextProvider>
<RecordTableBodyDroppable> <RecordTableBodyDroppable isDropDisabled>
<RecordTablePendingRow /> <RecordTablePendingRow />
</RecordTableBodyDroppable>
{visibleRecordGroupIds.map((recordGroupId) => ( {visibleRecordGroupIds.map((recordGroupId) => (
<RecordGroupContext.Provider <RecordGroupContext.Provider
key={recordGroupId} key={recordGroupId}
value={{ recordGroupId }} value={{ recordGroupId }}
> >
<RecordTableBodyDroppable recordGroupId={recordGroupId}>
<RecordTableRecordGroupSection />
<RecordTableRecordGroupRows /> <RecordTableRecordGroupRows />
</RecordTableBodyDroppable>
</RecordGroupContext.Provider> </RecordGroupContext.Provider>
))} ))}
</RecordTableBodyDroppable> </RecordTableBodyRecordGroupDragDropContextProvider>
</RecordTableBodyDragDropContext>
); );
}; };

View File

@ -4,12 +4,14 @@ import { RecoilRoot } from 'recoil';
import { createState } from 'twenty-ui'; import { createState } from 'twenty-ui';
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
import { CoreObjectNamePlural } from '@/object-metadata/types/CoreObjectNamePlural';
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
import { useCreateOneRecord } from '@/object-record/hooks/useCreateOneRecord'; import { useCreateOneRecord } from '@/object-record/hooks/useCreateOneRecord';
import { textfieldDefinition } from '@/object-record/record-field/__mocks__/fieldDefinitions'; import { textfieldDefinition } from '@/object-record/record-field/__mocks__/fieldDefinitions';
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext'; import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
import { useUpsertRecord } from '@/object-record/record-table/record-table-cell/hooks/useUpsertRecord'; import { useUpsertRecord } from '@/object-record/record-table/record-table-cell/hooks/useUpsertRecord';
import { TableHotkeyScope } from '@/object-record/record-table/types/TableHotkeyScope'; import { TableHotkeyScope } from '@/object-record/record-table/types/TableHotkeyScope';
import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext';
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems'; import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
const draftValue = 'updated Name'; const draftValue = 'updated Name';
@ -61,6 +63,9 @@ const Wrapper = ({
snapshot.set(pendingRecordIdState, pendingRecordIdMockedValue); snapshot.set(pendingRecordIdState, pendingRecordIdMockedValue);
snapshot.set(draftValueState, draftValueMockedValue); snapshot.set(draftValueState, draftValueMockedValue);
}} }}
>
<ViewComponentInstanceContext.Provider
value={{ instanceId: CoreObjectNamePlural.Person }}
> >
<FieldContext.Provider <FieldContext.Provider
value={{ value={{
@ -78,6 +83,7 @@ const Wrapper = ({
> >
{children} {children}
</FieldContext.Provider> </FieldContext.Provider>
</ViewComponentInstanceContext.Provider>
</RecoilRoot> </RecoilRoot>
); );

View File

@ -4,10 +4,12 @@ import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadat
import { getLabelIdentifierFieldMetadataItem } from '@/object-metadata/utils/getLabelIdentifierFieldMetadataItem'; import { getLabelIdentifierFieldMetadataItem } from '@/object-metadata/utils/getLabelIdentifierFieldMetadataItem';
import { useCreateOneRecord } from '@/object-record/hooks/useCreateOneRecord'; import { useCreateOneRecord } from '@/object-record/hooks/useCreateOneRecord';
import { recordFieldInputDraftValueComponentSelector } from '@/object-record/record-field/states/selectors/recordFieldInputDraftValueComponentSelector'; import { recordFieldInputDraftValueComponentSelector } from '@/object-record/record-field/states/selectors/recordFieldInputDraftValueComponentSelector';
import { hasRecordGroupsComponentSelector } from '@/object-record/record-group/states/selectors/hasRecordGroupsComponentSelector';
import { recordTablePendingRecordIdComponentState } from '@/object-record/record-table/states/recordTablePendingRecordIdComponentState'; import { recordTablePendingRecordIdComponentState } from '@/object-record/record-table/states/recordTablePendingRecordIdComponentState';
import { getScopeIdFromComponentId } from '@/ui/utilities/recoil-scope/utils/getScopeIdFromComponentId'; import { getScopeIdFromComponentId } from '@/ui/utilities/recoil-scope/utils/getScopeIdFromComponentId';
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue'; import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2'; import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
import { extractComponentSelector } from '@/ui/utilities/state/component-state/utils/extractComponentSelector'; import { extractComponentSelector } from '@/ui/utilities/state/component-state/utils/extractComponentSelector';
import { isDefined } from '~/utils/isDefined'; import { isDefined } from '~/utils/isDefined';
@ -18,8 +20,13 @@ export const useUpsertRecord = ({
objectNameSingular: string; objectNameSingular: string;
recordTableId: string; recordTableId: string;
}) => { }) => {
const hasRecordGroups = useRecoilComponentValueV2(
hasRecordGroupsComponentSelector,
);
const { createOneRecord } = useCreateOneRecord({ const { createOneRecord } = useCreateOneRecord({
objectNameSingular, objectNameSingular,
shouldMatchRootQueryFilter: hasRecordGroups,
}); });
const recordTablePendingRecordIdState = useRecoilComponentCallbackStateV2( const recordTablePendingRecordIdState = useRecoilComponentCallbackStateV2(

View File

@ -14,17 +14,19 @@ import { RecordTableWithWrappersScrollWrapperContext } from '@/ui/utilities/scro
import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValueV2'; import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValueV2';
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2'; import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
type RecordTableRowWrapperProps = {
recordId: string;
rowIndex: number;
isPendingRow?: boolean;
children: ReactNode;
};
export const RecordTableRowWrapper = ({ export const RecordTableRowWrapper = ({
recordId, recordId,
rowIndex, rowIndex,
isPendingRow, isPendingRow,
children, children,
}: { }: RecordTableRowWrapperProps) => {
recordId: string;
rowIndex: number;
isPendingRow?: boolean;
children: ReactNode;
}) => {
const trRef = useRef<HTMLTableRowElement>(null); const trRef = useRef<HTMLTableRowElement>(null);
const { objectMetadataItem } = useContext(RecordTableContext); const { objectMetadataItem } = useContext(RecordTableContext);

View File

@ -0,0 +1,115 @@
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import { motion } from 'framer-motion';
import { useCallback } from 'react';
import { IconChevronUp, isDefined, Tag } from 'twenty-ui';
import { useCurrentRecordGroupId } from '@/object-record/record-group/hooks/useCurrentRecordGroupId';
import { recordGroupDefinitionFamilyState } from '@/object-record/record-group/states/recordGroupDefinitionFamilyState';
import { RecordGroupDefinitionType } from '@/object-record/record-group/types/RecordGroupDefinition';
import { recordIndexRecordIdsByGroupComponentFamilyState } from '@/object-record/record-index/states/recordIndexRecordIdsByGroupComponentFamilyState';
import { isRecordGroupTableSectionToggledComponentState } from '@/object-record/record-table/record-table-section/states/isRecordGroupTableSectionToggledComponentState';
import { visibleTableColumnsComponentSelector } from '@/object-record/record-table/states/selectors/visibleTableColumnsComponentSelector';
import { useRecoilComponentFamilyStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyStateV2';
import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValueV2';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
import { useRecoilValue } from 'recoil';
const StyledTrContainer = styled.tr`
cursor: pointer;
`;
const StyledChevronContainer = styled.td`
border-bottom: 1px solid ${({ theme }) => theme.border.color.light};
color: ${({ theme }) => theme.font.color.secondary};
text-align: center;
vertical-align: middle;
`;
const StyledTotalRow = styled.span`
color: ${({ theme }) => theme.font.color.tertiary};
margin-left: ${({ theme }) => theme.spacing(2)};
text-align: center;
vertical-align: middle;
`;
const StyledRecordGroupSection = styled.td`
border-bottom: 1px solid ${({ theme }) => theme.border.color.light};
padding-bottom: 6px;
padding-top: 6px;
`;
const StyledEmptyTd = styled.td`
border-bottom: 1px solid ${({ theme }) => theme.border.color.light};
`;
export const RecordTableRecordGroupSection = () => {
const theme = useTheme();
const currentRecordGroupId = useCurrentRecordGroupId();
const visibleColumns = useRecoilComponentValueV2(
visibleTableColumnsComponentSelector,
);
const recordIdsByGroup = useRecoilComponentFamilyValueV2(
recordIndexRecordIdsByGroupComponentFamilyState,
currentRecordGroupId,
);
const [
isRecordGroupTableSectionToggled,
setIsRecordGroupTableSectionToggled,
] = useRecoilComponentFamilyStateV2(
isRecordGroupTableSectionToggledComponentState,
currentRecordGroupId,
);
const recordGroup = useRecoilValue(
recordGroupDefinitionFamilyState(currentRecordGroupId),
);
const handleDropdownToggle = useCallback(() => {
setIsRecordGroupTableSectionToggled((prevState) => !prevState);
}, [setIsRecordGroupTableSectionToggled]);
if (!isDefined(recordGroup)) {
return null;
}
return (
<StyledTrContainer onClick={handleDropdownToggle}>
<td aria-hidden></td>
<StyledChevronContainer>
<motion.span
animate={{ rotate: isRecordGroupTableSectionToggled ? 180 : 0 }}
transition={{ duration: theme.animation.duration.normal }}
style={{
display: 'inline-block',
}}
>
<IconChevronUp size={theme.icon.size.md} />
</motion.span>
</StyledChevronContainer>
<StyledRecordGroupSection colSpan={visibleColumns.length}>
<Tag
variant={
recordGroup.type !== RecordGroupDefinitionType.NoValue
? 'solid'
: 'outline'
}
color={
recordGroup.type !== RecordGroupDefinitionType.NoValue
? recordGroup.color
: 'transparent'
}
text={recordGroup.title}
weight="medium"
/>
<StyledTotalRow>{recordIdsByGroup.length}</StyledTotalRow>
</StyledRecordGroupSection>
<StyledEmptyTd></StyledEmptyTd>
<StyledEmptyTd></StyledEmptyTd>
</StyledTrContainer>
);
};

View File

@ -0,0 +1,10 @@
import { RecordGroupDefinition } from '@/object-record/record-group/types/RecordGroupDefinition';
import { createComponentFamilyStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentFamilyStateV2';
import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext';
export const isRecordGroupTableSectionToggledComponentState =
createComponentFamilyStateV2<boolean, RecordGroupDefinition['id']>({
key: 'isRecordGroupTableSectionToggledComponentState',
defaultValue: true,
componentInstanceContext: ViewComponentInstanceContext,
});

View File

@ -1,6 +1,6 @@
import { selectedRowIdsComponentSelector } from '@/object-record/record-table/states/selectors/selectedRowIdsComponentSelector'; import { selectedRowIdsComponentSelector } from '@/object-record/record-table/states/selectors/selectedRowIdsComponentSelector';
import { recordIndexAllRowIdsComponentState } from '@/object-record/record-index/states/recordIndexAllRowIdsComponentState'; import { recordIndexAllRecordIdsComponentSelector } from '@/object-record/record-index/states/selectors/recordIndexAllRecordIdsComponentSelector';
import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext'; import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext';
import { createComponentSelectorV2 } from '@/ui/utilities/state/component-state/utils/createComponentSelectorV2'; import { createComponentSelectorV2 } from '@/ui/utilities/state/component-state/utils/createComponentSelectorV2';
import { AllRowsSelectedStatus } from '../../types/AllRowSelectedStatus'; import { AllRowsSelectedStatus } from '../../types/AllRowSelectedStatus';
@ -12,9 +12,9 @@ export const allRowsSelectedStatusComponentSelector =
get: get:
({ instanceId }) => ({ instanceId }) =>
({ get }) => { ({ get }) => {
const allRowIds = get( const allRecordIds = get(
// TODO: Working because instanceId is the same, but we're not in the same context, should be changed ! // TODO: Working because instanceId is the same, but we're not in the same context, should be changed !
recordIndexAllRowIdsComponentState.atomFamily({ recordIndexAllRecordIdsComponentSelector.selectorFamily({
instanceId, instanceId,
}), }),
); );
@ -30,7 +30,7 @@ export const allRowsSelectedStatusComponentSelector =
const allRowsSelectedStatus = const allRowsSelectedStatus =
numberOfSelectedRows === 0 numberOfSelectedRows === 0
? 'none' ? 'none'
: selectedRowIds.length === allRowIds.length : selectedRowIds.length === allRecordIds.length
? 'all' ? 'all'
: 'some'; : 'some';

View File

@ -1,4 +1,4 @@
import { recordIndexAllRowIdsComponentState } from '@/object-record/record-index/states/recordIndexAllRowIdsComponentState'; import { recordIndexAllRecordIdsComponentSelector } from '@/object-record/record-index/states/selectors/recordIndexAllRecordIdsComponentSelector';
import { isRowSelectedComponentFamilyState } from '@/object-record/record-table/record-table-row/states/isRowSelectedComponentFamilyState'; import { isRowSelectedComponentFamilyState } from '@/object-record/record-table/record-table-row/states/isRowSelectedComponentFamilyState';
import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext'; import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext';
import { createComponentSelectorV2 } from '@/ui/utilities/state/component-state/utils/createComponentSelectorV2'; import { createComponentSelectorV2 } from '@/ui/utilities/state/component-state/utils/createComponentSelectorV2';
@ -11,19 +11,19 @@ export const selectedRowIdsComponentSelector = createComponentSelectorV2<
get: get:
({ instanceId }) => ({ instanceId }) =>
({ get }) => { ({ get }) => {
const allRowIds = get( const allRecordIds = get(
// TODO: Working because instanceId is the same, but we're not in the same context, should be changed ! // TODO: Working because instanceId is the same, but we're not in the same context, should be changed !
recordIndexAllRowIdsComponentState.atomFamily({ recordIndexAllRecordIdsComponentSelector.selectorFamily({
instanceId, instanceId,
}), }),
); );
return allRowIds.filter( return allRecordIds.filter(
(rowId) => (recordId) =>
get( get(
isRowSelectedComponentFamilyState.atomFamily({ isRowSelectedComponentFamilyState.atomFamily({
instanceId, instanceId,
familyKey: rowId, familyKey: recordId,
}), }),
) === true, ) === true,
); );

View File

@ -1,4 +1,4 @@
import { recordIndexAllRowIdsComponentState } from '@/object-record/record-index/states/recordIndexAllRowIdsComponentState'; import { recordIndexAllRecordIdsComponentSelector } from '@/object-record/record-index/states/selectors/recordIndexAllRecordIdsComponentSelector';
import { isRowSelectedComponentFamilyState } from '@/object-record/record-table/record-table-row/states/isRowSelectedComponentFamilyState'; import { isRowSelectedComponentFamilyState } from '@/object-record/record-table/record-table-row/states/isRowSelectedComponentFamilyState';
import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext'; import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext';
import { createComponentSelectorV2 } from '@/ui/utilities/state/component-state/utils/createComponentSelectorV2'; import { createComponentSelectorV2 } from '@/ui/utilities/state/component-state/utils/createComponentSelectorV2';
@ -11,19 +11,19 @@ export const unselectedRowIdsComponentSelector = createComponentSelectorV2<
get: get:
({ instanceId }) => ({ instanceId }) =>
({ get }) => { ({ get }) => {
const rowIds = get( const allRecordIds = get(
// TODO: Working because instanceId is the same, but we're not in the same context, should be changed ! // TODO: Working because instanceId is the same, but we're not in the same context, should be changed !
recordIndexAllRowIdsComponentState.atomFamily({ recordIndexAllRecordIdsComponentSelector.selectorFamily({
instanceId, instanceId,
}), }),
); );
return rowIds.filter( return allRecordIds.filter(
(rowId) => (recordId) =>
get( get(
isRowSelectedComponentFamilyState.atomFamily({ isRowSelectedComponentFamilyState.atomFamily({
instanceId, instanceId,
familyKey: rowId, familyKey: recordId,
}), }),
) === false, ) === false,
); );

View File

@ -14,6 +14,7 @@ import { isDefined } from 'twenty-ui';
export function createComponentSelectorV2<ValueType>(options: { export function createComponentSelectorV2<ValueType>(options: {
key: string; key: string;
get: SelectorGetter<ValueType, ComponentStateKeyV2>; get: SelectorGetter<ValueType, ComponentStateKeyV2>;
set?: never;
componentInstanceContext: ComponentInstanceStateContext<any> | null; componentInstanceContext: ComponentInstanceStateContext<any> | null;
}): ComponentReadOnlySelectorV2<ValueType>; }): ComponentReadOnlySelectorV2<ValueType>;

View File

@ -38,7 +38,7 @@ export const StyledMenuItemSelect = styled(StyledMenuItemBase)<{
`; `;
type MenuItemSelectProps = { type MenuItemSelectProps = {
LeftIcon: IconComponent | null | undefined; LeftIcon?: IconComponent | null | undefined;
selected: boolean; selected: boolean;
text: string; text: string;
className?: string; className?: string;