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,
IconSettings,
MenuItem,
MenuItemSelect,
UndecoratedLink,
useIcons,
} from 'twenty-ui';
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 { useOptionsDropdown } from '@/object-record/object-options-dropdown/hooks/useOptionsDropdown';
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 { useHandleRecordGroupField } from '@/object-record/record-index/hooks/useHandleRecordGroupField';
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 { useLocation } from 'react-router-dom';
import { useSetRecoilState } from 'recoil';
import { isDefined } from '~/utils/isDefined';
export const ObjectOptionsDropdownRecordGroupFieldsContent = () => {
const { getIcon } = useIcons();
@ -43,14 +47,20 @@ export const ObjectOptionsDropdownRecordGroupFieldsContent = () => {
hiddenRecordGroupIdsComponentSelector,
);
const recordGroupFieldMetadataItem = useRecoilComponentValueV2(
recordGroupFieldMetadataComponentState,
);
const {
recordGroupFieldSearchInput,
setRecordGroupFieldSearchInput,
filteredRecordGroupFieldMetadataItems,
} = useSearchRecordGroupField();
const { handleRecordGroupFieldChange, resetRecordGroupField } =
useHandleRecordGroupField({
const {
handleRecordGroupFieldChange: setRecordGroupField,
resetRecordGroupField,
} = useHandleRecordGroupField({
viewBarComponentId: recordIndexId,
});
@ -66,6 +76,18 @@ export const ObjectOptionsDropdownRecordGroupFieldsContent = () => {
navigationMemorizedUrlState,
);
const handleResetRecordGroupField = () => {
resetRecordGroupField();
closeDropdown();
};
const handleRecordGroupFieldChange = (
fieldMetadataItem: FieldMetadataItem,
) => {
setRecordGroupField(fieldMetadataItem);
closeDropdown();
};
useEffect(() => {
if (
currentContentId === 'hiddenRecordGroups' &&
@ -90,13 +112,16 @@ export const ObjectOptionsDropdownRecordGroupFieldsContent = () => {
onChange={(event) => setRecordGroupFieldSearchInput(event.target.value)}
/>
<DropdownMenuItemsContainer>
<MenuItem text="None" onClick={resetRecordGroupField} />
<MenuItemSelect
text="None"
selected={!isDefined(recordGroupFieldMetadataItem)}
onClick={handleResetRecordGroupField}
/>
{filteredRecordGroupFieldMetadataItems.map((fieldMetadataItem) => (
<MenuItem
<MenuItemSelect
key={fieldMetadataItem.id}
onClick={() => {
handleRecordGroupFieldChange(fieldMetadataItem);
}}
selected={fieldMetadataItem.id === recordGroupFieldMetadataItem?.id}
onClick={() => handleRecordGroupFieldChange(fieldMetadataItem)}
LeftIcon={getIcon(fieldMetadataItem.icon)}
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 { recordGroupDefinitionFamilyState } from '@/object-record/record-group/states/recordGroupDefinitionFamilyState';
import { visibleRecordGroupIdsComponentSelector } from '@/object-record/record-group/states/selectors/visibleRecordGroupIdsComponentSelector';
import { recordIndexAllRowIdsComponentState } from '@/object-record/record-index/states/recordIndexAllRowIdsComponentState';
import { recordIndexRowIdsByGroupComponentFamilyState } from '@/object-record/record-index/states/recordIndexRowIdsByGroupComponentFamilyState';
import { recordIndexRecordIdsByGroupComponentFamilyState } from '@/object-record/record-index/states/recordIndexRecordIdsByGroupComponentFamilyState';
import { recordIndexAllRecordIdsComponentSelector } from '@/object-record/record-index/states/selectors/recordIndexAllRecordIdsComponentSelector';
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
import { TableHotkeyScope } from '@/object-record/record-table/types/TableHotkeyScope';
import { DragSelect } from '@/ui/utilities/drag-select/components/DragSelect';
@ -69,12 +69,13 @@ export const RecordBoard = () => {
visibleRecordGroupIdsComponentSelector,
);
const recordIndexRowIdsByGroupFamilyState = useRecoilComponentCallbackStateV2(
recordIndexRowIdsByGroupComponentFamilyState,
const recordIndexRecordIdsByGroupFamilyState =
useRecoilComponentCallbackStateV2(
recordIndexRecordIdsByGroupComponentFamilyState,
);
const recordIndexAllRowIdsState = useRecoilComponentCallbackStateV2(
recordIndexAllRowIdsComponentState,
const recordIndexAllRecordIdsState = useRecoilComponentCallbackStateV2(
recordIndexAllRecordIdsComponentSelector,
);
const { resetRecordSelection, setRecordAsSelected } =
@ -97,14 +98,14 @@ export const RecordBoard = () => {
() => {
const allRecordIds = getSnapshotValue(
snapshot,
recordIndexAllRowIdsState,
recordIndexAllRecordIdsState,
);
for (const recordId of allRecordIds) {
setRecordAsSelected(recordId, true);
}
},
[recordIndexAllRowIdsState, setRecordAsSelected],
[recordIndexAllRecordIdsState, setRecordAsSelected],
);
useScopedHotkeys('ctrl+a,meta+a', selectAll, TableHotkeyScope.Table);
@ -137,7 +138,7 @@ export const RecordBoard = () => {
const destinationRecordByGroupIds = getSnapshotValue(
snapshot,
recordIndexRowIdsByGroupFamilyState(destinationRecordGroupId),
recordIndexRecordIdsByGroupFamilyState(destinationRecordGroupId),
);
const otherRecordIdsInDestinationColumn =
sourceRecordGroupId === destinationRecordGroupId
@ -172,7 +173,7 @@ export const RecordBoard = () => {
});
},
[
recordIndexRowIdsByGroupFamilyState,
recordIndexRecordIdsByGroupFamilyState,
selectFieldMetadataItem,
updateOneRecord,
],

View File

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

View File

@ -2,9 +2,7 @@ import { useRecoilCallback } from 'recoil';
import { recordGroupDefinitionFamilyState } from '@/object-record/record-group/states/recordGroupDefinitionFamilyState';
import { recordGroupFieldMetadataComponentState } from '@/object-record/record-group/states/recordGroupFieldMetadataComponentState';
import { recordGroupIdsComponentState } from '@/object-record/record-group/states/recordGroupIdsComponentState';
import { recordIndexAllRowIdsComponentState } from '@/object-record/record-index/states/recordIndexAllRowIdsComponentState';
import { recordIndexRowIdsByGroupComponentFamilyState } from '@/object-record/record-index/states/recordIndexRowIdsByGroupComponentFamilyState';
import { recordIndexRecordIdsByGroupComponentFamilyState } from '@/object-record/record-index/states/recordIndexRecordIdsByGroupComponentFamilyState';
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
import { sortRecordsByPosition } from '@/object-record/utils/sortRecordsByPosition';
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
@ -13,36 +11,20 @@ import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
import { isDefined } from '~/utils/isDefined';
export const useSetRecordIdsForColumn = (recordBoardId?: string) => {
const recordGroupIdsState = useRecoilComponentCallbackStateV2(
recordGroupIdsComponentState,
recordBoardId,
);
const recordGroupFieldMetadataState = useRecoilComponentCallbackStateV2(
recordGroupFieldMetadataComponentState,
recordBoardId,
);
const recordIndexAllRowIdsState = useRecoilComponentCallbackStateV2(
recordIndexAllRowIdsComponentState,
recordBoardId,
);
const recordIndexRowIdsByGroupFamilyState = useRecoilComponentCallbackStateV2(
recordIndexRowIdsByGroupComponentFamilyState,
const recordIndexRecordIdsByGroupFamilyState =
useRecoilComponentCallbackStateV2(
recordIndexRecordIdsByGroupComponentFamilyState,
recordBoardId,
);
const setRecordIdsForColumn = useRecoilCallback(
({ set, snapshot }) =>
(currentRecordGroupId: string, records: ObjectRecord[]) => {
const existingAllRowIds = getSnapshotValue(
snapshot,
recordIndexAllRowIdsState,
);
const recordGroupIds = getSnapshotValue(snapshot, recordGroupIdsState);
const recordGroup = getSnapshotValue(
snapshot,
recordGroupDefinitionFamilyState(currentRecordGroupId),
@ -50,7 +32,7 @@ export const useSetRecordIdsForColumn = (recordBoardId?: string) => {
const existingRecordGroupRowIds = getSnapshotValue(
snapshot,
recordIndexRowIdsByGroupFamilyState(currentRecordGroupId),
recordIndexRecordIdsByGroupFamilyState(currentRecordGroupId),
);
const recordGroupFieldMetadata = getSnapshotValue(
@ -72,35 +54,12 @@ export const useSetRecordIdsForColumn = (recordBoardId?: string) => {
if (!isDeeplyEqual(existingRecordGroupRowIds, recordGroupRowIds)) {
set(
recordIndexRowIdsByGroupFamilyState(currentRecordGroupId),
recordIndexRecordIdsByGroupFamilyState(currentRecordGroupId),
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);
}
},
[
recordGroupIdsState,
recordIndexRowIdsByGroupFamilyState,
recordGroupFieldMetadataState,
recordIndexAllRowIdsState,
],
[recordIndexRecordIdsByGroupFamilyState, recordGroupFieldMetadataState],
);
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 { RecordBoardColumnContext } from '@/object-record/record-board/record-board-column/contexts/RecordBoardColumnContext';
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 { useRecoilValue } from 'recoil';
@ -31,8 +31,8 @@ export const RecordBoardColumn = ({
recordGroupDefinitionFamilyState(recordBoardColumnId),
);
const recordRowIdsByGroup = useRecoilComponentFamilyValueV2(
recordIndexRowIdsByGroupComponentFamilyState,
const recordIdsByGroup = useRecoilComponentFamilyValueV2(
recordIndexRecordIdsByGroupComponentFamilyState,
recordBoardColumnId,
);
@ -44,9 +44,9 @@ export const RecordBoardColumn = ({
<RecordBoardColumnContext.Provider
value={{
columnDefinition: recordGroupDefinition,
recordCount: recordRowIdsByGroup.length,
recordCount: recordIdsByGroup.length,
columnId: recordBoardColumnId,
recordIds: recordRowIdsByGroup,
recordIds: recordIdsByGroup,
}}
>
<Droppable droppableId={recordBoardColumnId}>
@ -54,7 +54,7 @@ export const RecordBoardColumn = ({
<StyledColumn>
<RecordBoardColumnCardsContainer
droppableProvided={droppableProvided}
recordIds={recordRowIdsByGroup}
recordIds={recordIdsByGroup}
/>
</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 { RecordBoardColumnContext } from '@/object-record/record-board/record-board-column/contexts/RecordBoardColumnContext';
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 { useRecoilValue } from 'recoil';
@ -18,8 +18,8 @@ export const RecordBoardColumnHeaderWrapper = ({
recordGroupDefinitionFamilyState(columnId),
);
const recordRowIdsByGroup = useRecoilComponentFamilyValueV2(
recordIndexRowIdsByGroupComponentFamilyState,
const recordIdsByGroup = useRecoilComponentFamilyValueV2(
recordIndexRecordIdsByGroupComponentFamilyState,
columnId,
);
@ -32,8 +32,8 @@ export const RecordBoardColumnHeaderWrapper = ({
value={{
columnId,
columnDefinition: recordGroupDefinition,
recordCount: recordRowIdsByGroup.length,
recordIds: recordRowIdsByGroup,
recordCount: recordIdsByGroup.length,
recordIds: recordIdsByGroup,
}}
>
<RecordBoardColumnHeader />

View File

@ -1,6 +1,6 @@
import { RecordBoardComponentInstanceContext } from '@/object-record/record-board/states/contexts/RecordBoardComponentInstanceContext';
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';
export const recordBoardSelectedRecordIdsComponentSelector =
@ -10,11 +10,15 @@ export const recordBoardSelectedRecordIdsComponentSelector =
get:
({ instanceId }) =>
({ get }) => {
const allRowIds = get(
recordIndexAllRowIdsComponentState.atomFamily({ instanceId }),
const allRecordIds = get(
// 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) =>
get(
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 { RecordGroupDefinition } from '@/object-record/record-group/types/RecordGroupDefinition';
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 { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue';
import { useSaveCurrentViewGroups } from '@/views/hooks/useSaveCurrentViewGroups';
@ -22,8 +22,9 @@ export const useRecordGroupVisibility = ({
recordGroupIdsComponentState,
);
const recordIndexRowIdsByGroupFamilyState = useRecoilComponentCallbackStateV2(
recordIndexRowIdsByGroupComponentFamilyState,
const recordIndexRecordIdsByGroupFamilyState =
useRecoilComponentCallbackStateV2(
recordIndexRecordIdsByGroupComponentFamilyState,
viewBarId,
);
@ -79,7 +80,7 @@ export const useRecordGroupVisibility = ({
const recordGroupRowIds = getSnapshotValue(
snapshot,
recordIndexRowIdsByGroupFamilyState(recordGroupId),
recordIndexRecordIdsByGroupFamilyState(recordGroupId),
);
if (recordGroupRowIds.length > 0) {
@ -107,7 +108,7 @@ export const useRecordGroupVisibility = ({
recordIndexRecordGroupIdsState,
objectOptionsDropdownRecordGroupHideState,
saveViewGroups,
recordIndexRowIdsByGroupFamilyState,
recordIndexRecordIdsByGroupFamilyState,
],
);

View File

@ -8,7 +8,6 @@ import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue';
import { useContext } from 'react';
import { useRecoilCallback } from 'recoil';
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
import { isDefined } from '~/utils/isDefined';
export const useSetRecordGroup = (viewId?: string) => {
const { objectMetadataItem } = useContext(RecordIndexRootPropsContext);
@ -26,28 +25,23 @@ export const useSetRecordGroup = (viewId?: string) => {
return useRecoilCallback(
({ snapshot, set }) =>
(recordGroups: RecordGroupDefinition[]) => {
if (recordGroups.length === 0) {
return;
}
const currentRecordGroupId = getSnapshotValue(
snapshot,
recordIndexRecordGroupIdsState,
);
const fieldMetadataId = recordGroups[0].fieldMetadataId;
const fieldMetadata = objectMetadataItem.fields.find(
const fieldMetadataId = recordGroups?.[0]?.fieldMetadataId;
const fieldMetadata = fieldMetadataId
? objectMetadataItem.fields.find(
(field) => field.id === fieldMetadataId,
);
)
: undefined;
const currentFieldMetadata = getSnapshotValue(
snapshot,
recordGroupFieldMetadataState,
);
// Set the field metadata linked to the record groups
if (
isDefined(fieldMetadata) &&
!isDeeplyEqual(fieldMetadata, currentFieldMetadata)
) {
if (!isDeeplyEqual(fieldMetadata, currentFieldMetadata)) {
set(recordGroupFieldMetadataState, fieldMetadata);
}
@ -67,6 +61,16 @@ export const useSetRecordGroup = (viewId?: string) => {
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)) {
return;
}

View File

@ -1,12 +1,13 @@
import { recordGroupDefinitionFamilyState } from '@/object-record/record-group/states/recordGroupDefinitionFamilyState';
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 { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext';
import { isDefined } from '~/utils/isDefined';
export const hiddenRecordGroupIdsComponentSelector = createComponentSelectorV2<
string[]
RecordGroupDefinition['id'][]
>({
key: 'hiddenRecordGroupIdsComponentSelector',
componentInstanceContext: ViewComponentInstanceContext,

View File

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

View File

@ -6,7 +6,7 @@ export const sortRecordGroupDefinitions = (
recordGroupSort: RecordGroupSort,
) => {
const visibleRecordGroups = recordGroupDefinitions.filter(
(boardGroup) => boardGroup.isVisible,
(recordGroup) => recordGroup.isVisible,
);
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 {
[fieldMetadataItem.name]: {
eq: currentRecordGroupDefinition.value,
@ -68,8 +72,6 @@ export const useFindManyParams = (
};
}
// TODO: Handle case when value is nullable
return {};
}, [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 { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext';
export const recordIndexRowIdsByGroupComponentFamilyState =
export const recordIndexRecordIdsByGroupComponentFamilyState =
createComponentFamilyStateV2<string[], RecordGroupDefinition['id']>({
key: 'recordIndexRowIdsByGroupComponentFamilyState',
key: 'recordIndexRecordIdsByGroupComponentFamilyState',
defaultValue: [],
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';
export const recordIndexRecordGroupIsDraggableSortComponentSelector =
createComponentSelectorV2({
createComponentSelectorV2<boolean>({
key: 'recordIndexRecordGroupIsDraggableSortComponentSelector',
componentInstanceContext: ViewComponentInstanceContext,
get:

View File

@ -2,7 +2,7 @@ import styled from '@emotion/styled';
import { isNonEmptyString, isNull } from '@sniptt/guards';
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 { RecordTableContextProvider } from '@/object-record/record-table/components/RecordTableContextProvider';
import { RecordTableStickyEffect } from '@/object-record/record-table/components/RecordTableStickyEffect';
@ -53,8 +53,8 @@ export const RecordTable = ({
recordTableId,
);
const allRowIds = useRecoilComponentValueV2(
recordIndexAllRowIdsComponentState,
const allRecordIds = useRecoilComponentValueV2(
recordIndexAllRecordIdsComponentSelector,
recordTableId,
);
@ -70,7 +70,7 @@ export const RecordTable = ({
const recordTableIsEmpty =
!isRecordTableInitialLoading &&
allRowIds.length === 0 &&
allRecordIds.length === 0 &&
isNull(pendingRecordId);
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 { RecordTableRow } from '@/object-record/record-table/record-table-row/components/RecordTableRow';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
export const RecordTableNoRecordGroupRows = () => {
const allRowIds = useRecoilComponentValueV2(
recordIndexAllRowIdsComponentState,
const allRecordIds = useRecoilComponentValueV2(
recordIndexAllRecordIdsComponentSelector,
);
return (
<>
{allRowIds.map((recordId, rowIndex) => {
{allRecordIds.map((recordId, rowIndex) => {
return (
<RecordTableRow
key={recordId}

View File

@ -1,37 +1,52 @@
import { useCurrentRecordGroupId } from '@/object-record/record-group/hooks/useCurrentRecordGroupId';
import { recordIndexAllRowIdsComponentState } from '@/object-record/record-index/states/recordIndexAllRowIdsComponentState';
import { recordIndexRowIdsByGroupComponentFamilyState } from '@/object-record/record-index/states/recordIndexRowIdsByGroupComponentFamilyState';
import { recordIndexRecordIdsByGroupComponentFamilyState } from '@/object-record/record-index/states/recordIndexRecordIdsByGroupComponentFamilyState';
import { recordIndexAllRecordIdsComponentSelector } from '@/object-record/record-index/states/selectors/recordIndexAllRecordIdsComponentSelector';
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 { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
import { useMemo } from 'react';
import { isDefined } from '~/utils/isDefined';
export const RecordTableRecordGroupRows = () => {
const recordGroupId = useCurrentRecordGroupId();
const currentRecordGroupId = useCurrentRecordGroupId();
const allRowIds = useRecoilComponentValueV2(
recordIndexAllRowIdsComponentState,
const allRecordIds = useRecoilComponentValueV2(
recordIndexAllRecordIdsComponentSelector,
);
const recordGroupRowIds = useRecoilComponentFamilyValueV2(
recordIndexRowIdsByGroupComponentFamilyState,
recordGroupId,
const recordIdsByGroup = useRecoilComponentFamilyValueV2(
recordIndexRecordIdsByGroupComponentFamilyState,
currentRecordGroupId,
);
const isRecordGroupTableSectionToggled = useRecoilComponentFamilyValueV2(
isRecordGroupTableSectionToggledComponentState,
currentRecordGroupId,
);
const rowIndexMap = useMemo(
() => new Map(allRowIds.map((id, index) => [id, index])),
[allRowIds],
() => new Map(allRecordIds.map((recordId, index) => [recordId, index])),
[allRecordIds],
);
return recordGroupRowIds.map((recordId) => {
return (
isRecordGroupTableSectionToggled &&
recordIdsByGroup.map((recordId) => {
const rowIndex = rowIndexMap.get(recordId);
if (!rowIndex) {
throw new Error(`Row index for record id ${recordId} not found`);
if (!isDefined(rowIndex)) {
return null;
}
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 { 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 { isRecordTableInitialLoadingComponentState } from '@/object-record/record-table/states/isRecordTableInitialLoadingComponentState';
import { recordTablePendingRecordIdComponentState } from '@/object-record/record-table/states/recordTablePendingRecordIdComponentState';
@ -20,8 +20,8 @@ export const RecordTableEmptyHandler = ({
recordTableId,
);
const allRowIds = useRecoilComponentValueV2(
recordIndexAllRowIdsComponentState,
const allRecordIds = useRecoilComponentValueV2(
recordIndexAllRecordIdsComponentSelector,
recordTableId,
);
@ -32,7 +32,7 @@ export const RecordTableEmptyHandler = ({
const recordTableIsEmpty =
!isRecordTableInitialLoading &&
allRowIds.length === 0 &&
allRecordIds.length === 0 &&
isNull(pendingRecordId);
if (recordTableIsEmpty) {

View File

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

View File

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

View File

@ -1,8 +1,7 @@
import { useRecoilCallback } from 'recoil';
import { recordGroupIdsComponentState } from '@/object-record/record-group/states/recordGroupIdsComponentState';
import { recordIndexAllRowIdsComponentState } from '@/object-record/record-index/states/recordIndexAllRowIdsComponentState';
import { recordIndexRowIdsByGroupComponentFamilyState } from '@/object-record/record-index/states/recordIndexRowIdsByGroupComponentFamilyState';
import { recordIndexRecordIdsByGroupComponentFamilyState } from '@/object-record/record-index/states/recordIndexRecordIdsByGroupComponentFamilyState';
import { recordIndexAllRecordIdsComponentSelector } from '@/object-record/record-index/states/selectors/recordIndexAllRecordIdsComponentSelector';
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
import { hasUserSelectedAllRowsComponentState } from '@/object-record/record-table/record-table-row/states/hasUserSelectedAllRowsFamilyState';
import { isRowSelectedComponentFamilyState } from '@/object-record/record-table/record-table-row/states/isRowSelectedComponentFamilyState';
@ -21,26 +20,26 @@ export const useSetRecordTableData = ({
recordTableId,
onEntityCountChange,
}: useSetRecordTableDataProps) => {
const recordIndexRowIdsByGroupFamilyState = useRecoilComponentCallbackStateV2(
recordIndexRowIdsByGroupComponentFamilyState,
const recordIndexRecordIdsByGroupFamilyState =
useRecoilComponentCallbackStateV2(
recordIndexRecordIdsByGroupComponentFamilyState,
recordTableId,
);
const recordIndexAllRowIdsState = useRecoilComponentCallbackStateV2(
recordIndexAllRowIdsComponentState,
const recordIndexAllRecordIdsSelector = useRecoilComponentCallbackStateV2(
recordIndexAllRecordIdsComponentSelector,
recordTableId,
);
const isRowSelectedFamilyState = useRecoilComponentCallbackStateV2(
isRowSelectedComponentFamilyState,
recordTableId,
);
const hasUserSelectedAllRowsState = useRecoilComponentCallbackStateV2(
hasUserSelectedAllRowsComponentState,
recordTableId,
);
const recordIndexRecordGroupIdsState = useRecoilComponentCallbackStateV2(
recordGroupIdsComponentState,
recordTableId,
);
return useRecoilCallback(
({ set, snapshot }) =>
@ -67,8 +66,8 @@ export const useSetRecordTableData = ({
const currentRowIds = getSnapshotValue(
snapshot,
currentRecordGroupId
? recordIndexRowIdsByGroupFamilyState(currentRecordGroupId)
: recordIndexAllRowIdsState,
? recordIndexRecordIdsByGroupFamilyState(currentRecordGroupId)
: recordIndexAllRecordIdsSelector,
);
const hasUserSelectedAllRows = getSnapshotValue(
@ -76,11 +75,6 @@ export const useSetRecordTableData = ({
hasUserSelectedAllRowsState,
);
const recordGroupIds = getSnapshotValue(
snapshot,
recordIndexRecordGroupIdsState,
);
const recordIds = records.map((record) => record.id);
if (!isDeeplyEqual(currentRowIds, recordIds)) {
@ -91,39 +85,21 @@ export const useSetRecordTableData = ({
}
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(
recordIndexRowIdsByGroupFamilyState(currentRecordGroupId),
recordIndexRecordIdsByGroupFamilyState(currentRecordGroupId),
recordIds,
);
for (const recordGroupId of recordGroupIds) {
const tableRowIdsByGroup =
recordGroupId !== currentRecordGroupId
? getSnapshotValue(
snapshot,
recordIndexRowIdsByGroupFamilyState(recordGroupId),
)
: recordIds;
allRowIds.push(...tableRowIdsByGroup);
}
set(recordIndexAllRowIdsState, allRowIds);
} else {
set(recordIndexAllRowIdsState, recordIds);
set(recordIndexAllRecordIdsSelector, recordIds);
}
onEntityCountChange(totalCount);
}
},
[
recordIndexRowIdsByGroupFamilyState,
recordIndexAllRowIdsState,
recordIndexRecordIdsByGroupFamilyState,
recordIndexAllRecordIdsSelector,
hasUserSelectedAllRowsState,
recordIndexRecordGroupIdsState,
onEntityCountChange,
isRowSelectedFamilyState,
],

View File

@ -3,7 +3,7 @@ import { useRecoilCallback } from 'recoil';
import { MoveFocusDirection } from '@/object-record/record-table/types/MoveFocusDirection';
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 { softFocusPositionComponentState } from '@/object-record/record-table/states/softFocusPositionComponentState';
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
@ -17,8 +17,8 @@ export const useRecordTableMoveFocus = (recordTableId?: string) => {
recordTableId,
);
const recordIndexAllRowIdsState = useRecoilComponentCallbackStateV2(
recordIndexAllRowIdsComponentState,
const recordIndexAllRecordIdsSelector = useRecoilComponentCallbackStateV2(
recordIndexAllRecordIdsComponentSelector,
recordTableId,
);
@ -47,7 +47,10 @@ export const useRecordTableMoveFocus = (recordTableId?: string) => {
const moveDown = useRecoilCallback(
({ snapshot }) =>
() => {
const allRowIds = getSnapshotValue(snapshot, recordIndexAllRowIdsState);
const allRecordIds = getSnapshotValue(
snapshot,
recordIndexAllRecordIdsSelector,
);
const softFocusPosition = getSnapshotValue(
snapshot,
softFocusPositionState,
@ -55,8 +58,8 @@ export const useRecordTableMoveFocus = (recordTableId?: string) => {
let newRowIndex = softFocusPosition.row + 1;
if (newRowIndex >= allRowIds.length) {
newRowIndex = allRowIds.length - 1;
if (newRowIndex >= allRecordIds.length) {
newRowIndex = allRecordIds.length - 1;
}
setSoftFocusPosition({
@ -64,7 +67,11 @@ export const useRecordTableMoveFocus = (recordTableId?: string) => {
row: newRowIndex,
});
},
[recordIndexAllRowIdsState, setSoftFocusPosition, softFocusPositionState],
[
recordIndexAllRecordIdsSelector,
setSoftFocusPosition,
softFocusPositionState,
],
);
const numberOfTableColumnsSelector = useRecoilComponentCallbackStateV2(
@ -75,7 +82,10 @@ export const useRecordTableMoveFocus = (recordTableId?: string) => {
const moveRight = useRecoilCallback(
({ snapshot }) =>
() => {
const allRowIds = getSnapshotValue(snapshot, recordIndexAllRowIdsState);
const allRecordIds = getSnapshotValue(
snapshot,
recordIndexAllRecordIdsSelector,
);
const softFocusPosition = getSnapshotValue(
snapshot,
softFocusPositionState,
@ -91,11 +101,11 @@ export const useRecordTableMoveFocus = (recordTableId?: string) => {
const isLastRowAndLastColumn =
currentColumnIndex === numberOfTableColumns - 1 &&
currentRowIndex === allRowIds.length - 1;
currentRowIndex === allRecordIds.length - 1;
const isLastColumnButNotLastRow =
currentColumnIndex === numberOfTableColumns - 1 &&
currentRowIndex !== allRowIds.length - 1;
currentRowIndex !== allRecordIds.length - 1;
const isNotLastColumn = currentColumnIndex !== numberOfTableColumns - 1;
@ -116,7 +126,7 @@ export const useRecordTableMoveFocus = (recordTableId?: string) => {
}
},
[
recordIndexAllRowIdsState,
recordIndexAllRecordIdsSelector,
softFocusPositionState,
numberOfTableColumnsSelector,
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 { 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 { useComputeNewRowPosition } from '@/object-record/record-table/hooks/useComputeNewRowPosition';
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 { isDefined } from '~/utils/isDefined';
export const RecordTableBodyDragDropContext = ({
export const RecordTableBodyDragDropContextProvider = ({
children,
}: {
children: ReactNode;
@ -22,8 +22,8 @@ export const RecordTableBodyDragDropContext = ({
objectNameSingular,
});
const allRowIds = useRecoilComponentValueV2(
recordIndexAllRowIdsComponentState,
const allRecordIds = useRecoilComponentValueV2(
recordIndexAllRecordIdsComponentSelector,
);
const { currentViewWithCombinedFiltersAndSorts } =
@ -43,7 +43,7 @@ export const RecordTableBodyDragDropContext = ({
return;
}
const computeResult = computeNewRowPosition(result, allRowIds);
const computeResult = computeNewRowPosition(result, allRecordIds);
if (!isDefined(computeResult)) {
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 { styled } from '@linaria/react';
import { ReactNode, useContext, useState } from 'react';
import { MOBILE_VIEWPORT, ThemeContext } from 'twenty-ui';
import { ReactNode, useState } from 'react';
import { v4 } from 'uuid';
const StyledTbody = styled.tbody<{
theme: Theme;
}>`
&.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);
}
}
}
`;
type RecordTableBodyDroppableProps = {
children: ReactNode;
recordGroupId?: string;
isDropDisabled?: boolean;
};
export const RecordTableBodyDroppable = ({
children,
}: {
children: ReactNode;
}) => {
recordGroupId,
isDropDisabled,
}: RecordTableBodyDroppableProps) => {
const [v4Persistable] = useState(v4());
const { theme } = useContext(ThemeContext);
return (
<Droppable droppableId={v4Persistable}>
<Droppable
droppableId={recordGroupId ?? v4Persistable}
isDropDisabled={isDropDisabled}
>
{(provided) => (
<StyledTbody
id="record-table-body"
theme={theme}
<RecordTableBody
id={`record-table-body${recordGroupId ? `-${recordGroupId}` : ''}`}
ref={provided.innerRef}
// eslint-disable-next-line react/jsx-props-no-spreading
{...provided.droppableProps}
>
{children}
{provided.placeholder}
</StyledTbody>
</RecordTableBody>
)}
</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 { 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 { RecordTableBodyLoading } from '@/object-record/record-table/record-table-body/components/RecordTableBodyLoading';
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';
export const RecordTableNoRecordGroupBody = () => {
const allRowIds = useRecoilComponentValueV2(
recordIndexAllRowIdsComponentState,
const allRecordIds = useRecoilComponentValueV2(
recordIndexAllRecordIdsComponentSelector,
);
const isRecordTableInitialLoading = useRecoilComponentValueV2(
isRecordTableInitialLoadingComponentState,
);
if (isRecordTableInitialLoading && allRowIds.length === 0) {
if (isRecordTableInitialLoading && allRecordIds.length === 0) {
return <RecordTableBodyLoading />;
}
return (
<RecordTableBodyDragDropContext>
<RecordTableBodyDragDropContextProvider>
<RecordTableBodyDroppable>
<RecordTablePendingRow />
<RecordTableNoRecordGroupRows />
</RecordTableBodyDroppable>
</RecordTableBodyDragDropContext>
</RecordTableBodyDragDropContextProvider>
);
};

View File

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

View File

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

View File

@ -4,10 +4,12 @@ import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadat
import { getLabelIdentifierFieldMetadataItem } from '@/object-metadata/utils/getLabelIdentifierFieldMetadataItem';
import { useCreateOneRecord } from '@/object-record/hooks/useCreateOneRecord';
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 { getScopeIdFromComponentId } from '@/ui/utilities/recoil-scope/utils/getScopeIdFromComponentId';
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
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 { isDefined } from '~/utils/isDefined';
@ -18,8 +20,13 @@ export const useUpsertRecord = ({
objectNameSingular: string;
recordTableId: string;
}) => {
const hasRecordGroups = useRecoilComponentValueV2(
hasRecordGroupsComponentSelector,
);
const { createOneRecord } = useCreateOneRecord({
objectNameSingular,
shouldMatchRootQueryFilter: hasRecordGroups,
});
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 { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
type RecordTableRowWrapperProps = {
recordId: string;
rowIndex: number;
isPendingRow?: boolean;
children: ReactNode;
};
export const RecordTableRowWrapper = ({
recordId,
rowIndex,
isPendingRow,
children,
}: {
recordId: string;
rowIndex: number;
isPendingRow?: boolean;
children: ReactNode;
}) => {
}: RecordTableRowWrapperProps) => {
const trRef = useRef<HTMLTableRowElement>(null);
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 { 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 { createComponentSelectorV2 } from '@/ui/utilities/state/component-state/utils/createComponentSelectorV2';
import { AllRowsSelectedStatus } from '../../types/AllRowSelectedStatus';
@ -12,9 +12,9 @@ export const allRowsSelectedStatusComponentSelector =
get:
({ instanceId }) =>
({ 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 !
recordIndexAllRowIdsComponentState.atomFamily({
recordIndexAllRecordIdsComponentSelector.selectorFamily({
instanceId,
}),
);
@ -30,7 +30,7 @@ export const allRowsSelectedStatusComponentSelector =
const allRowsSelectedStatus =
numberOfSelectedRows === 0
? 'none'
: selectedRowIds.length === allRowIds.length
: selectedRowIds.length === allRecordIds.length
? 'all'
: '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 { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext';
import { createComponentSelectorV2 } from '@/ui/utilities/state/component-state/utils/createComponentSelectorV2';
@ -11,19 +11,19 @@ export const selectedRowIdsComponentSelector = createComponentSelectorV2<
get:
({ instanceId }) =>
({ 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 !
recordIndexAllRowIdsComponentState.atomFamily({
recordIndexAllRecordIdsComponentSelector.selectorFamily({
instanceId,
}),
);
return allRowIds.filter(
(rowId) =>
return allRecordIds.filter(
(recordId) =>
get(
isRowSelectedComponentFamilyState.atomFamily({
instanceId,
familyKey: rowId,
familyKey: recordId,
}),
) === 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 { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext';
import { createComponentSelectorV2 } from '@/ui/utilities/state/component-state/utils/createComponentSelectorV2';
@ -11,19 +11,19 @@ export const unselectedRowIdsComponentSelector = createComponentSelectorV2<
get:
({ instanceId }) =>
({ 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 !
recordIndexAllRowIdsComponentState.atomFamily({
recordIndexAllRecordIdsComponentSelector.selectorFamily({
instanceId,
}),
);
return rowIds.filter(
(rowId) =>
return allRecordIds.filter(
(recordId) =>
get(
isRowSelectedComponentFamilyState.atomFamily({
instanceId,
familyKey: rowId,
familyKey: recordId,
}),
) === false,
);

View File

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

View File

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