mirror of
https://github.com/twentyhq/twenty.git
synced 2024-12-23 12:02:10 +03:00
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:
parent
05149feb00
commit
a2d55a8694
@ -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}
|
||||||
/>
|
/>
|
||||||
|
@ -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,
|
||||||
],
|
],
|
||||||
|
@ -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,
|
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -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 {
|
||||||
|
@ -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>
|
||||||
)}
|
)}
|
||||||
|
@ -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 />
|
||||||
|
@ -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({
|
||||||
|
@ -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,
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
|
@ -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,
|
||||||
|
@ -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) => {
|
||||||
|
@ -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]);
|
||||||
|
|
||||||
|
@ -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,
|
|
||||||
});
|
|
@ -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,
|
||||||
});
|
});
|
@ -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,
|
||||||
|
),
|
||||||
|
});
|
@ -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:
|
||||||
|
@ -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({
|
||||||
|
@ -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}
|
||||||
|
@ -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}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})
|
||||||
);
|
);
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
@ -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) {
|
||||||
|
@ -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,
|
||||||
|
@ -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,
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
@ -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,
|
||||||
],
|
],
|
||||||
|
@ -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,
|
||||||
|
@ -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;
|
@ -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;
|
@ -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>
|
||||||
);
|
);
|
||||||
|
@ -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>
|
||||||
|
);
|
||||||
|
};
|
@ -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>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -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>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -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>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -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(
|
||||||
|
@ -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);
|
||||||
|
@ -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>
|
||||||
|
);
|
||||||
|
};
|
@ -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,
|
||||||
|
});
|
@ -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';
|
||||||
|
|
||||||
|
@ -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,
|
||||||
);
|
);
|
||||||
|
@ -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,
|
||||||
);
|
);
|
||||||
|
@ -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>;
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user