mirror of
https://github.com/twentyhq/twenty.git
synced 2024-12-23 03:51:36 +03:00
feat: record board component state refactor (#8779)
Fix #8758 This PR is migrating the recoil component state from v1 to v2 for board. It also now share some states and logics between board and table, further can be done later. Lastly this PR fix an issue since the PR #8613 that was treating no-value as a normal record-group.
This commit is contained in:
parent
e96ad9a1f2
commit
812ed6ed69
@ -10,46 +10,50 @@ import { useObjectNamePluralFromSingular } from '@/object-metadata/hooks/useObje
|
||||
|
||||
import { useOptionsDropdown } from '@/object-record/object-options-dropdown/hooks/useOptionsDropdown';
|
||||
import { RecordGroupsVisibilityDropdownSection } from '@/object-record/record-group/components/RecordGroupsVisibilityDropdownSection';
|
||||
import { useRecordGroups } from '@/object-record/record-group/hooks/useRecordGroups';
|
||||
import { useRecordGroupVisibility } from '@/object-record/record-group/hooks/useRecordGroupVisibility';
|
||||
import { recordGroupFieldMetadataComponentState } from '@/object-record/record-group/states/recordGroupFieldMetadataComponentState';
|
||||
import { hiddenRecordGroupIdsComponentSelector } from '@/object-record/record-group/states/selectors/hiddenRecordGroupIdsComponentSelector';
|
||||
import { getSettingsPagePath } from '@/settings/utils/getSettingsPagePath';
|
||||
import { SettingsPath } from '@/types/SettingsPath';
|
||||
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader';
|
||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
|
||||
import { navigationMemorizedUrlState } from '@/ui/navigation/states/navigationMemorizedUrlState';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
import { useSetRecoilState } from 'recoil';
|
||||
|
||||
export const ObjectOptionsDropdownHiddenRecordGroupsContent = () => {
|
||||
const {
|
||||
currentContentId,
|
||||
viewType,
|
||||
recordIndexId,
|
||||
objectMetadataItem,
|
||||
onContentChange,
|
||||
closeDropdown,
|
||||
} = useOptionsDropdown();
|
||||
|
||||
const { objectNamePlural } = useObjectNamePluralFromSingular({
|
||||
objectNameSingular: objectMetadataItem.nameSingular,
|
||||
});
|
||||
const recordGroupFieldMetadata = useRecoilComponentValueV2(
|
||||
recordGroupFieldMetadataComponentState,
|
||||
);
|
||||
|
||||
const { hiddenRecordGroups, viewGroupFieldMetadataItem } = useRecordGroups({
|
||||
const hiddenRecordGroupIds = useRecoilComponentValueV2(
|
||||
hiddenRecordGroupIdsComponentSelector,
|
||||
);
|
||||
|
||||
const { objectNamePlural } = useObjectNamePluralFromSingular({
|
||||
objectNameSingular: objectMetadataItem.nameSingular,
|
||||
});
|
||||
|
||||
const { handleVisibilityChange: handleRecordGroupVisibilityChange } =
|
||||
useRecordGroupVisibility({
|
||||
viewBarId: recordIndexId,
|
||||
viewType,
|
||||
});
|
||||
|
||||
const viewGroupSettingsUrl = getSettingsPagePath(
|
||||
SettingsPath.ObjectFieldEdit,
|
||||
{
|
||||
objectSlug: objectNamePlural,
|
||||
fieldSlug: viewGroupFieldMetadataItem?.name ?? '',
|
||||
fieldSlug: recordGroupFieldMetadata?.name ?? '',
|
||||
},
|
||||
);
|
||||
|
||||
@ -61,11 +65,11 @@ export const ObjectOptionsDropdownHiddenRecordGroupsContent = () => {
|
||||
useEffect(() => {
|
||||
if (
|
||||
currentContentId === 'hiddenRecordGroups' &&
|
||||
hiddenRecordGroups.length === 0
|
||||
hiddenRecordGroupIds.length === 0
|
||||
) {
|
||||
onContentChange('recordGroups');
|
||||
}
|
||||
}, [hiddenRecordGroups, currentContentId, onContentChange]);
|
||||
}, [hiddenRecordGroupIds, currentContentId, onContentChange]);
|
||||
|
||||
return (
|
||||
<>
|
||||
@ -74,13 +78,13 @@ export const ObjectOptionsDropdownHiddenRecordGroupsContent = () => {
|
||||
StartIcon={IconChevronLeft}
|
||||
onClick={() => onContentChange('recordGroups')}
|
||||
>
|
||||
Hidden {viewGroupFieldMetadataItem?.label}
|
||||
Hidden {recordGroupFieldMetadata?.label}
|
||||
</DropdownMenuHeader>
|
||||
</DropdownMenuItemsContainer>
|
||||
|
||||
<RecordGroupsVisibilityDropdownSection
|
||||
title={`Hidden ${viewGroupFieldMetadataItem?.label}`}
|
||||
recordGroups={hiddenRecordGroups}
|
||||
title={`Hidden ${recordGroupFieldMetadata?.label}`}
|
||||
recordGroupIds={hiddenRecordGroupIds}
|
||||
onVisibilityChange={handleRecordGroupVisibilityChange}
|
||||
isDraggable={false}
|
||||
showSubheader={false}
|
||||
|
@ -15,7 +15,7 @@ import { useHandleToggleTrashColumnFilter } from '@/object-record/record-index/h
|
||||
|
||||
import { useObjectOptionsForBoard } from '@/object-record/object-options-dropdown/hooks/useObjectOptionsForBoard';
|
||||
import { useOptionsDropdown } from '@/object-record/object-options-dropdown/hooks/useOptionsDropdown';
|
||||
import { useRecordGroups } from '@/object-record/record-group/hooks/useRecordGroups';
|
||||
import { recordGroupFieldMetadataComponentState } from '@/object-record/record-group/states/recordGroupFieldMetadataComponentState';
|
||||
import {
|
||||
displayedExportProgress,
|
||||
useExportRecords,
|
||||
@ -26,6 +26,7 @@ import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenu
|
||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
|
||||
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { ViewType } from '@/views/types/ViewType';
|
||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||
|
||||
@ -44,6 +45,10 @@ export const ObjectOptionsDropdownMenuContent = () => {
|
||||
objectNameSingular: objectMetadataItem.nameSingular,
|
||||
});
|
||||
|
||||
const recordGroupFieldMetadata = useRecoilComponentValueV2(
|
||||
recordGroupFieldMetadataComponentState,
|
||||
);
|
||||
|
||||
useScopedHotkeys(
|
||||
[Key.Escape],
|
||||
() => {
|
||||
@ -64,10 +69,6 @@ export const ObjectOptionsDropdownMenuContent = () => {
|
||||
viewBarId: recordIndexId,
|
||||
});
|
||||
|
||||
const { viewGroupFieldMetadataItem } = useRecordGroups({
|
||||
objectNameSingular: objectMetadataItem.nameSingular,
|
||||
});
|
||||
|
||||
const { openObjectRecordsSpreasheetImportDialog } =
|
||||
useOpenObjectRecordsSpreadsheetImportDialog(
|
||||
objectMetadataItem.nameSingular,
|
||||
@ -113,7 +114,7 @@ export const ObjectOptionsDropdownMenuContent = () => {
|
||||
onClick={() => onContentChange('recordGroups')}
|
||||
LeftIcon={IconLayoutList}
|
||||
text="Group by"
|
||||
contextualText={viewGroupFieldMetadataItem?.label}
|
||||
contextualText={recordGroupFieldMetadata?.label}
|
||||
hasSubMenu
|
||||
/>
|
||||
)}
|
||||
|
@ -12,7 +12,7 @@ import { useObjectNamePluralFromSingular } from '@/object-metadata/hooks/useObje
|
||||
import { StyledInput } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterSelect';
|
||||
import { useOptionsDropdown } from '@/object-record/object-options-dropdown/hooks/useOptionsDropdown';
|
||||
import { useSearchRecordGroupField } from '@/object-record/object-options-dropdown/hooks/useSearchRecordGroupField';
|
||||
import { useRecordGroups } from '@/object-record/record-group/hooks/useRecordGroups';
|
||||
import { hiddenRecordGroupIdsComponentSelector } from '@/object-record/record-group/states/selectors/hiddenRecordGroupIdsComponentSelector';
|
||||
import { useHandleRecordGroupField } from '@/object-record/record-index/hooks/useHandleRecordGroupField';
|
||||
import { getSettingsPagePath } from '@/settings/utils/getSettingsPagePath';
|
||||
import { SettingsPath } from '@/types/SettingsPath';
|
||||
@ -20,6 +20,7 @@ import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenu
|
||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
|
||||
import { navigationMemorizedUrlState } from '@/ui/navigation/states/navigationMemorizedUrlState';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
import { useSetRecoilState } from 'recoil';
|
||||
|
||||
@ -38,9 +39,9 @@ export const ObjectOptionsDropdownRecordGroupFieldsContent = () => {
|
||||
objectNameSingular: objectMetadataItem.nameSingular,
|
||||
});
|
||||
|
||||
const { hiddenRecordGroups } = useRecordGroups({
|
||||
objectNameSingular: objectMetadataItem.nameSingular,
|
||||
});
|
||||
const hiddenRecordGroupIds = useRecoilComponentValueV2(
|
||||
hiddenRecordGroupIdsComponentSelector,
|
||||
);
|
||||
|
||||
const {
|
||||
recordGroupFieldSearchInput,
|
||||
@ -68,11 +69,11 @@ export const ObjectOptionsDropdownRecordGroupFieldsContent = () => {
|
||||
useEffect(() => {
|
||||
if (
|
||||
currentContentId === 'hiddenRecordGroups' &&
|
||||
hiddenRecordGroups.length === 0
|
||||
hiddenRecordGroupIds.length === 0
|
||||
) {
|
||||
onContentChange('recordGroups');
|
||||
}
|
||||
}, [hiddenRecordGroups, currentContentId, onContentChange]);
|
||||
}, [hiddenRecordGroupIds, currentContentId, onContentChange]);
|
||||
|
||||
return (
|
||||
<>
|
||||
|
@ -8,24 +8,21 @@ import {
|
||||
} from 'twenty-ui';
|
||||
|
||||
import { useOptionsDropdown } from '@/object-record/object-options-dropdown/hooks/useOptionsDropdown';
|
||||
import { useRecordGroups } from '@/object-record/record-group/hooks/useRecordGroups';
|
||||
import { hiddenRecordGroupIdsComponentSelector } from '@/object-record/record-group/states/selectors/hiddenRecordGroupIdsComponentSelector';
|
||||
import { RecordGroupSort } from '@/object-record/record-group/types/RecordGroupSort';
|
||||
import { recordIndexRecordGroupSortComponentState } from '@/object-record/record-index/states/recordIndexRecordGroupSortComponentState';
|
||||
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader';
|
||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||
|
||||
export const ObjectOptionsDropdownRecordGroupSortContent = () => {
|
||||
const {
|
||||
currentContentId,
|
||||
objectMetadataItem,
|
||||
onContentChange,
|
||||
closeDropdown,
|
||||
} = useOptionsDropdown();
|
||||
const { currentContentId, onContentChange, closeDropdown } =
|
||||
useOptionsDropdown();
|
||||
|
||||
const { hiddenRecordGroups } = useRecordGroups({
|
||||
objectNameSingular: objectMetadataItem.nameSingular,
|
||||
});
|
||||
const hiddenRecordGroupIds = useRecoilComponentValueV2(
|
||||
hiddenRecordGroupIdsComponentSelector,
|
||||
);
|
||||
|
||||
const setRecordGroupSort = useSetRecoilComponentStateV2(
|
||||
recordIndexRecordGroupSortComponentState,
|
||||
@ -39,11 +36,11 @@ export const ObjectOptionsDropdownRecordGroupSortContent = () => {
|
||||
useEffect(() => {
|
||||
if (
|
||||
currentContentId === 'hiddenRecordGroups' &&
|
||||
hiddenRecordGroups.length === 0
|
||||
hiddenRecordGroupIds.length === 0
|
||||
) {
|
||||
onContentChange('recordGroups');
|
||||
}
|
||||
}, [hiddenRecordGroups, currentContentId, onContentChange]);
|
||||
}, [hiddenRecordGroupIds, currentContentId, onContentChange]);
|
||||
|
||||
return (
|
||||
<>
|
||||
|
@ -13,8 +13,10 @@ import {
|
||||
import { useOptionsDropdown } from '@/object-record/object-options-dropdown/hooks/useOptionsDropdown';
|
||||
import { RecordGroupsVisibilityDropdownSection } from '@/object-record/record-group/components/RecordGroupsVisibilityDropdownSection';
|
||||
import { useRecordGroupReorder } from '@/object-record/record-group/hooks/useRecordGroupReorder';
|
||||
import { useRecordGroups } from '@/object-record/record-group/hooks/useRecordGroups';
|
||||
import { useRecordGroupVisibility } from '@/object-record/record-group/hooks/useRecordGroupVisibility';
|
||||
import { recordGroupFieldMetadataComponentState } from '@/object-record/record-group/states/recordGroupFieldMetadataComponentState';
|
||||
import { hiddenRecordGroupIdsComponentSelector } from '@/object-record/record-group/states/selectors/hiddenRecordGroupIdsComponentSelector';
|
||||
import { visibleRecordGroupIdsComponentSelector } from '@/object-record/record-group/states/selectors/visibleRecordGroupIdsComponentSelector';
|
||||
import { recordIndexRecordGroupHideComponentState } from '@/object-record/record-index/states/recordIndexRecordGroupHideComponentState';
|
||||
import { recordIndexRecordGroupIsDraggableSortComponentSelector } from '@/object-record/record-index/states/selectors/recordIndexRecordGroupIsDraggableSortComponentSelector';
|
||||
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader';
|
||||
@ -26,22 +28,20 @@ import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||
export const ObjectOptionsDropdownRecordGroupsContent = () => {
|
||||
const isViewGroupEnabled = useIsFeatureEnabled('IS_VIEW_GROUPS_ENABLED');
|
||||
|
||||
const {
|
||||
currentContentId,
|
||||
viewType,
|
||||
recordIndexId,
|
||||
objectMetadataItem,
|
||||
onContentChange,
|
||||
resetContent,
|
||||
} = useOptionsDropdown();
|
||||
const { currentContentId, recordIndexId, onContentChange, resetContent } =
|
||||
useOptionsDropdown();
|
||||
|
||||
const {
|
||||
hiddenRecordGroups,
|
||||
visibleRecordGroups,
|
||||
viewGroupFieldMetadataItem,
|
||||
} = useRecordGroups({
|
||||
objectNameSingular: objectMetadataItem.nameSingular,
|
||||
});
|
||||
const recordGroupFieldMetadata = useRecoilComponentValueV2(
|
||||
recordGroupFieldMetadataComponentState,
|
||||
);
|
||||
|
||||
const visibleRecordGroupIds = useRecoilComponentValueV2(
|
||||
visibleRecordGroupIdsComponentSelector,
|
||||
);
|
||||
|
||||
const hiddenRecordGroupIds = useRecoilComponentValueV2(
|
||||
hiddenRecordGroupIdsComponentSelector,
|
||||
);
|
||||
|
||||
const isDragableSortRecordGroup = useRecoilComponentValueV2(
|
||||
recordIndexRecordGroupIsDraggableSortComponentSelector,
|
||||
@ -56,23 +56,21 @@ export const ObjectOptionsDropdownRecordGroupsContent = () => {
|
||||
handleHideEmptyRecordGroupChange,
|
||||
} = useRecordGroupVisibility({
|
||||
viewBarId: recordIndexId,
|
||||
viewType,
|
||||
});
|
||||
|
||||
const { handleOrderChange: handleRecordGroupOrderChange } =
|
||||
useRecordGroupReorder({
|
||||
objectNameSingular: objectMetadataItem.nameSingular,
|
||||
viewBarId: recordIndexId,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (
|
||||
currentContentId === 'hiddenRecordGroups' &&
|
||||
hiddenRecordGroups.length === 0
|
||||
hiddenRecordGroupIds.length === 0
|
||||
) {
|
||||
onContentChange('recordGroups');
|
||||
}
|
||||
}, [hiddenRecordGroups, currentContentId, onContentChange]);
|
||||
}, [hiddenRecordGroupIds, currentContentId, onContentChange]);
|
||||
|
||||
return (
|
||||
<>
|
||||
@ -86,9 +84,9 @@ export const ObjectOptionsDropdownRecordGroupsContent = () => {
|
||||
onClick={() => onContentChange('recordGroupFields')}
|
||||
LeftIcon={IconLayoutList}
|
||||
text={
|
||||
!viewGroupFieldMetadataItem
|
||||
!recordGroupFieldMetadata
|
||||
? 'Group by'
|
||||
: `Group by "${viewGroupFieldMetadataItem.label}"`
|
||||
: `Group by "${recordGroupFieldMetadata.label}"`
|
||||
}
|
||||
hasSubMenu
|
||||
/>
|
||||
@ -108,12 +106,12 @@ export const ObjectOptionsDropdownRecordGroupsContent = () => {
|
||||
toggleSize="small"
|
||||
/>
|
||||
</DropdownMenuItemsContainer>
|
||||
{visibleRecordGroups.length > 0 && (
|
||||
{visibleRecordGroupIds.length > 0 && (
|
||||
<>
|
||||
<DropdownMenuSeparator />
|
||||
<RecordGroupsVisibilityDropdownSection
|
||||
title="Visible groups"
|
||||
recordGroups={visibleRecordGroups}
|
||||
recordGroupIds={visibleRecordGroupIds}
|
||||
onDragEnd={handleRecordGroupOrderChange}
|
||||
onVisibilityChange={handleRecordGroupVisibilityChange}
|
||||
isDraggable={isDragableSortRecordGroup}
|
||||
@ -121,14 +119,14 @@ export const ObjectOptionsDropdownRecordGroupsContent = () => {
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
{hiddenRecordGroups.length > 0 && (
|
||||
{hiddenRecordGroupIds.length > 0 && (
|
||||
<>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItemsContainer>
|
||||
<MenuItemNavigate
|
||||
onClick={() => onContentChange('hiddenRecordGroups')}
|
||||
LeftIcon={IconEyeOff}
|
||||
text={`Hidden ${viewGroupFieldMetadataItem?.label ?? ''}`}
|
||||
text={`Hidden ${recordGroupFieldMetadata?.label ?? ''}`}
|
||||
/>
|
||||
</DropdownMenuItemsContainer>
|
||||
</>
|
||||
|
@ -4,10 +4,11 @@ import { useRecoilState } from 'recoil';
|
||||
|
||||
import { useColumnDefinitionsFromFieldMetadata } from '@/object-metadata/hooks/useColumnDefinitionsFromFieldMetadata';
|
||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||
import { useRecordBoard } from '@/object-record/record-board/hooks/useRecordBoard';
|
||||
import { isRecordBoardCompactModeActiveComponentState } from '@/object-record/record-board/states/isRecordBoardCompactModeActiveComponentState';
|
||||
import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata';
|
||||
import { recordIndexFieldDefinitionsState } from '@/object-record/record-index/states/recordIndexFieldDefinitionsState';
|
||||
import { ColumnDefinition } from '@/object-record/record-table/types/ColumnDefinition';
|
||||
import { useRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentStateV2';
|
||||
import { useSaveCurrentViewFields } from '@/views/hooks/useSaveCurrentViewFields';
|
||||
import { useUpdateCurrentView } from '@/views/hooks/useUpdateCurrentView';
|
||||
import { GraphQLView } from '@/views/types/GraphQLView';
|
||||
@ -32,11 +33,12 @@ export const useObjectOptionsForBoard = ({
|
||||
|
||||
const { saveViewFields } = useSaveCurrentViewFields(viewBarId);
|
||||
const { updateCurrentView } = useUpdateCurrentView(viewBarId);
|
||||
const { isCompactModeActiveState } = useRecordBoard(recordBoardId);
|
||||
|
||||
const [isCompactModeActive, setIsCompactModeActive] = useRecoilState(
|
||||
isCompactModeActiveState,
|
||||
);
|
||||
const [isCompactModeActive, setIsCompactModeActive] =
|
||||
useRecoilComponentStateV2(
|
||||
isRecordBoardCompactModeActiveComponentState,
|
||||
recordBoardId,
|
||||
);
|
||||
|
||||
const { objectMetadataItem } = useObjectMetadataItem({
|
||||
objectNameSingular,
|
||||
|
@ -1,7 +1,7 @@
|
||||
import styled from '@emotion/styled';
|
||||
import { DragDropContext, OnDragEndResponder } from '@hello-pangea/dnd'; // Atlassian dnd does not support StrictMode from RN 18, so we use a fork @hello-pangea/dnd https://github.com/atlassian/react-beautiful-dnd/issues/2350
|
||||
import { useContext, useRef } from 'react';
|
||||
import { useRecoilCallback, useRecoilValue } from 'recoil';
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
import { Key } from 'ts-key-enum';
|
||||
|
||||
import { ActionBarHotkeyScope } from '@/action-menu/types/ActionBarHotKeyScope';
|
||||
@ -9,11 +9,15 @@ import { RecordBoardHeader } from '@/object-record/record-board/components/Recor
|
||||
import { RecordBoardStickyHeaderEffect } from '@/object-record/record-board/components/RecordBoardStickyHeaderEffect';
|
||||
import { RECORD_BOARD_CLICK_OUTSIDE_LISTENER_ID } from '@/object-record/record-board/constants/RecordBoardClickOutsideListenerId';
|
||||
import { RecordBoardContext } from '@/object-record/record-board/contexts/RecordBoardContext';
|
||||
import { useRecordBoardStates } from '@/object-record/record-board/hooks/internal/useRecordBoardStates';
|
||||
import { useRecordBoardSelection } from '@/object-record/record-board/hooks/useRecordBoardSelection';
|
||||
import { RecordBoardColumn } from '@/object-record/record-board/record-board-column/components/RecordBoardColumn';
|
||||
import { RecordBoardScope } from '@/object-record/record-board/scopes/RecordBoardScope';
|
||||
import { RecordBoardComponentInstanceContext } from '@/object-record/record-board/states/contexts/RecordBoardComponentInstanceContext';
|
||||
import { getDraggedRecordPosition } from '@/object-record/record-board/utils/getDraggedRecordPosition';
|
||||
import { recordGroupDefinitionFamilyState } from '@/object-record/record-group/states/recordGroupDefinitionFamilyState';
|
||||
import { visibleRecordGroupIdsComponentSelector } from '@/object-record/record-group/states/selectors/visibleRecordGroupIdsComponentSelector';
|
||||
import { recordIndexAllRowIdsComponentState } from '@/object-record/record-index/states/recordIndexAllRowIdsComponentState';
|
||||
import { recordIndexRowIdsByGroupComponentFamilyState } from '@/object-record/record-index/states/recordIndexRowIdsByGroupComponentFamilyState';
|
||||
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
|
||||
import { TableHotkeyScope } from '@/object-record/record-table/types/TableHotkeyScope';
|
||||
import { DragSelect } from '@/ui/utilities/drag-select/components/DragSelect';
|
||||
@ -21,6 +25,9 @@ import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
||||
import { useListenClickOutsideV2 } from '@/ui/utilities/pointer-event/hooks/useListenClickOutsideV2';
|
||||
import { getScopeIdFromComponentId } from '@/ui/utilities/recoil-scope/utils/getScopeIdFromComponentId';
|
||||
import { ScrollWrapper } from '@/ui/utilities/scroll/components/ScrollWrapper';
|
||||
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue';
|
||||
import { useScrollRestoration } from '~/hooks/useScrollRestoration';
|
||||
|
||||
const StyledContainer = styled.div`
|
||||
@ -58,14 +65,17 @@ export const RecordBoard = () => {
|
||||
useContext(RecordBoardContext);
|
||||
const boardRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const {
|
||||
columnIdsState,
|
||||
columnsFamilySelector,
|
||||
recordIdsByColumnIdFamilyState,
|
||||
allRecordIdsSelector,
|
||||
} = useRecordBoardStates(recordBoardId);
|
||||
const visibleRecordGroupIds = useRecoilComponentValueV2(
|
||||
visibleRecordGroupIdsComponentSelector,
|
||||
);
|
||||
|
||||
const columnIds = useRecoilValue(columnIdsState);
|
||||
const recordIndexRowIdsByGroupFamilyState = useRecoilComponentCallbackStateV2(
|
||||
recordIndexRowIdsByGroupComponentFamilyState,
|
||||
);
|
||||
|
||||
const recordIndexAllRowIdsState = useRecoilComponentCallbackStateV2(
|
||||
recordIndexAllRowIdsComponentState,
|
||||
);
|
||||
|
||||
const { resetRecordSelection, setRecordAsSelected } =
|
||||
useRecordBoardSelection(recordBoardId);
|
||||
@ -85,15 +95,16 @@ export const RecordBoard = () => {
|
||||
const selectAll = useRecoilCallback(
|
||||
({ snapshot }) =>
|
||||
() => {
|
||||
const allRecordIds = snapshot
|
||||
.getLoadable(allRecordIdsSelector())
|
||||
.getValue();
|
||||
const allRecordIds = getSnapshotValue(
|
||||
snapshot,
|
||||
recordIndexAllRowIdsState,
|
||||
);
|
||||
|
||||
for (const recordId of allRecordIds) {
|
||||
setRecordAsSelected(recordId, true);
|
||||
}
|
||||
},
|
||||
[allRecordIdsSelector, setRecordAsSelected],
|
||||
[recordIndexAllRowIdsState, setRecordAsSelected],
|
||||
);
|
||||
|
||||
useScopedHotkeys('ctrl+a,meta+a', selectAll, TableHotkeyScope.Table);
|
||||
@ -111,42 +122,40 @@ export const RecordBoard = () => {
|
||||
if (!result.destination) return;
|
||||
|
||||
const draggedRecordId = result.draggableId;
|
||||
const sourceColumnId = result.source.droppableId;
|
||||
const destinationColumnId = result.destination.droppableId;
|
||||
const sourceRecordGroupId = result.source.droppableId;
|
||||
const destinationRecordGroupId = result.destination.droppableId;
|
||||
const destinationIndexInColumn = result.destination.index;
|
||||
|
||||
if (!destinationColumnId || !selectFieldMetadataItem) return;
|
||||
if (!destinationRecordGroupId || !selectFieldMetadataItem) return;
|
||||
|
||||
const column = snapshot
|
||||
.getLoadable(columnsFamilySelector(destinationColumnId))
|
||||
.getValue();
|
||||
const recordGroup = getSnapshotValue(
|
||||
snapshot,
|
||||
recordGroupDefinitionFamilyState(destinationRecordGroupId),
|
||||
);
|
||||
|
||||
if (!column) return;
|
||||
if (!recordGroup) return;
|
||||
|
||||
const destinationColumnRecordIds = snapshot
|
||||
.getLoadable(recordIdsByColumnIdFamilyState(destinationColumnId))
|
||||
.getValue();
|
||||
const otherRecordsInDestinationColumn =
|
||||
sourceColumnId === destinationColumnId
|
||||
? destinationColumnRecordIds.filter(
|
||||
const destinationRecordByGroupIds = getSnapshotValue(
|
||||
snapshot,
|
||||
recordIndexRowIdsByGroupFamilyState(destinationRecordGroupId),
|
||||
);
|
||||
const otherRecordIdsInDestinationColumn =
|
||||
sourceRecordGroupId === destinationRecordGroupId
|
||||
? destinationRecordByGroupIds.filter(
|
||||
(recordId) => recordId !== draggedRecordId,
|
||||
)
|
||||
: destinationColumnRecordIds;
|
||||
: destinationRecordByGroupIds;
|
||||
|
||||
const recordBeforeId =
|
||||
otherRecordsInDestinationColumn[destinationIndexInColumn - 1];
|
||||
otherRecordIdsInDestinationColumn[destinationIndexInColumn - 1];
|
||||
const recordBefore = recordBeforeId
|
||||
? snapshot
|
||||
.getLoadable(recordStoreFamilyState(recordBeforeId))
|
||||
.getValue()
|
||||
? getSnapshotValue(snapshot, recordStoreFamilyState(recordBeforeId))
|
||||
: null;
|
||||
|
||||
const recordAfterId =
|
||||
otherRecordsInDestinationColumn[destinationIndexInColumn];
|
||||
otherRecordIdsInDestinationColumn[destinationIndexInColumn];
|
||||
const recordAfter = recordAfterId
|
||||
? snapshot
|
||||
.getLoadable(recordStoreFamilyState(recordAfterId))
|
||||
.getValue()
|
||||
? getSnapshotValue(snapshot, recordStoreFamilyState(recordAfterId))
|
||||
: null;
|
||||
|
||||
const draggedRecordPosition = getDraggedRecordPosition(
|
||||
@ -157,14 +166,13 @@ export const RecordBoard = () => {
|
||||
updateOneRecord({
|
||||
idToUpdate: draggedRecordId,
|
||||
updateOneRecordInput: {
|
||||
[selectFieldMetadataItem.name]: column.value,
|
||||
[selectFieldMetadataItem.name]: recordGroup.value,
|
||||
position: draggedRecordPosition,
|
||||
},
|
||||
});
|
||||
},
|
||||
[
|
||||
columnsFamilySelector,
|
||||
recordIdsByColumnIdFamilyState,
|
||||
recordIndexRowIdsByGroupFamilyState,
|
||||
selectFieldMetadataItem,
|
||||
updateOneRecord,
|
||||
],
|
||||
@ -182,32 +190,36 @@ export const RecordBoard = () => {
|
||||
onColumnsChange={() => {}}
|
||||
onFieldsChange={() => {}}
|
||||
>
|
||||
<ScrollWrapper contextProviderName="recordBoard">
|
||||
<RecordBoardStickyHeaderEffect />
|
||||
<StyledContainerContainer>
|
||||
<RecordBoardHeader />
|
||||
<StyledBoardContentContainer>
|
||||
<StyledContainer ref={boardRef}>
|
||||
<DragDropContext onDragEnd={handleDragEnd}>
|
||||
<StyledColumnContainer>
|
||||
{columnIds.map((columnId) => (
|
||||
<RecordBoardColumn
|
||||
key={columnId}
|
||||
recordBoardColumnId={columnId}
|
||||
/>
|
||||
))}
|
||||
</StyledColumnContainer>
|
||||
</DragDropContext>
|
||||
</StyledContainer>
|
||||
<RecordBoardScrollRestoreEffect />
|
||||
<DragSelect
|
||||
dragSelectable={boardRef}
|
||||
onDragSelectionStart={resetRecordSelection}
|
||||
onDragSelectionChange={setRecordAsSelected}
|
||||
/>
|
||||
</StyledBoardContentContainer>
|
||||
</StyledContainerContainer>
|
||||
</ScrollWrapper>
|
||||
<RecordBoardComponentInstanceContext.Provider
|
||||
value={{ instanceId: recordBoardId }}
|
||||
>
|
||||
<ScrollWrapper contextProviderName="recordBoard">
|
||||
<RecordBoardStickyHeaderEffect />
|
||||
<StyledContainerContainer>
|
||||
<RecordBoardHeader />
|
||||
<StyledBoardContentContainer>
|
||||
<StyledContainer ref={boardRef}>
|
||||
<DragDropContext onDragEnd={handleDragEnd}>
|
||||
<StyledColumnContainer>
|
||||
{visibleRecordGroupIds.map((recordGroupId) => (
|
||||
<RecordBoardColumn
|
||||
key={recordGroupId}
|
||||
recordBoardColumnId={recordGroupId}
|
||||
/>
|
||||
))}
|
||||
</StyledColumnContainer>
|
||||
</DragDropContext>
|
||||
</StyledContainer>
|
||||
<RecordBoardScrollRestoreEffect />
|
||||
<DragSelect
|
||||
dragSelectable={boardRef}
|
||||
onDragSelectionStart={resetRecordSelection}
|
||||
onDragSelectionChange={setRecordAsSelected}
|
||||
/>
|
||||
</StyledBoardContentContainer>
|
||||
</StyledContainerContainer>
|
||||
</ScrollWrapper>
|
||||
</RecordBoardComponentInstanceContext.Provider>
|
||||
</RecordBoardScope>
|
||||
);
|
||||
};
|
||||
|
@ -1,7 +1,6 @@
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
import { useRecordBoardStates } from '@/object-record/record-board/hooks/internal/useRecordBoardStates';
|
||||
import { RecordBoardColumnHeaderWrapper } from '@/object-record/record-board/record-board-column/components/RecordBoardColumnHeaderWrapper';
|
||||
import { visibleRecordGroupIdsComponentSelector } from '@/object-record/record-group/states/selectors/visibleRecordGroupIdsComponentSelector';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
const StyledHeaderContainer = styled.div`
|
||||
@ -24,14 +23,17 @@ const StyledHeaderContainer = styled.div`
|
||||
`;
|
||||
|
||||
export const RecordBoardHeader = () => {
|
||||
const { columnIdsState } = useRecordBoardStates();
|
||||
|
||||
const columnIds = useRecoilValue(columnIdsState);
|
||||
const visibleRecordGroupIds = useRecoilComponentValueV2(
|
||||
visibleRecordGroupIdsComponentSelector,
|
||||
);
|
||||
|
||||
return (
|
||||
<StyledHeaderContainer id="record-board-header">
|
||||
{columnIds.map((columnId) => (
|
||||
<RecordBoardColumnHeaderWrapper columnId={columnId} key={columnId} />
|
||||
{visibleRecordGroupIds.map((recordGroupId) => (
|
||||
<RecordBoardColumnHeaderWrapper
|
||||
columnId={recordGroupId}
|
||||
key={recordGroupId}
|
||||
/>
|
||||
))}
|
||||
</StyledHeaderContainer>
|
||||
);
|
||||
|
@ -1,103 +0,0 @@
|
||||
import { RecordBoardScopeInternalContext } from '@/object-record/record-board/scopes/scope-internal-context/RecordBoardScopeInternalContext';
|
||||
import { isRecordBoardCardSelectedComponentFamilyState } from '@/object-record/record-board/states/isRecordBoardCardSelectedComponentFamilyState';
|
||||
import { isRecordBoardCompactModeActiveComponentState } from '@/object-record/record-board/states/isRecordBoardCompactModeActiveComponentState';
|
||||
import { isRecordBoardFetchingRecordsByColumnFamilyState } from '@/object-record/record-board/states/isRecordBoardFetchingRecordsByColumnFamilyState';
|
||||
import { isRecordBoardFetchingRecordsComponentState } from '@/object-record/record-board/states/isRecordBoardFetchingRecordsComponentState';
|
||||
import { recordBoardColumnIdsComponentState } from '@/object-record/record-board/states/recordBoardColumnIdsComponentState';
|
||||
import { recordBoardFieldDefinitionsComponentState } from '@/object-record/record-board/states/recordBoardFieldDefinitionsComponentState';
|
||||
import { recordBoardFiltersComponentState } from '@/object-record/record-board/states/recordBoardFiltersComponentState';
|
||||
import { recordBoardKanbanFieldMetadataNameComponentState } from '@/object-record/record-board/states/recordBoardKanbanFieldMetadataNameComponentState';
|
||||
import { recordBoardObjectSingularNameComponentState } from '@/object-record/record-board/states/recordBoardObjectSingularNameComponentState';
|
||||
import { recordBoardRecordIdsByColumnIdComponentFamilyState } from '@/object-record/record-board/states/recordBoardRecordIdsByColumnIdComponentFamilyState';
|
||||
import { recordBoardShouldFetchMoreInColumnComponentFamilyState } from '@/object-record/record-board/states/recordBoardShouldFetchMoreInColumnComponentFamilyState';
|
||||
import { recordBoardSortsComponentState } from '@/object-record/record-board/states/recordBoardSortsComponentState';
|
||||
import { recordBoardAllRecordIdsComponentSelector } from '@/object-record/record-board/states/selectors/recordBoardAllRecordIdsComponentSelector';
|
||||
import { recordBoardColumnsComponentFamilySelector } from '@/object-record/record-board/states/selectors/recordBoardColumnsComponentFamilySelector';
|
||||
import { recordBoardSelectedRecordIdsComponentSelector } from '@/object-record/record-board/states/selectors/recordBoardSelectedRecordIdsComponentSelector';
|
||||
import { recordBoardShouldFetchMoreComponentSelector } from '@/object-record/record-board/states/selectors/recordBoardShouldFetchMoreComponentFamilySelector';
|
||||
import { recordBoardVisibleFieldDefinitionsComponentSelector } from '@/object-record/record-board/states/selectors/recordBoardVisibleFieldDefinitionsComponentSelector';
|
||||
import { useAvailableScopeIdOrThrow } from '@/ui/utilities/recoil-scope/scopes-internal/hooks/useAvailableScopeId';
|
||||
import { getScopeIdOrUndefinedFromComponentId } from '@/ui/utilities/recoil-scope/utils/getScopeIdOrUndefinedFromComponentId';
|
||||
import { extractComponentFamilyState } from '@/ui/utilities/state/component-state/utils/extractComponentFamilyState';
|
||||
import { extractComponentReadOnlySelector } from '@/ui/utilities/state/component-state/utils/extractComponentReadOnlySelector';
|
||||
import { extractComponentState } from '@/ui/utilities/state/component-state/utils/extractComponentState';
|
||||
|
||||
export const useRecordBoardStates = (recordBoardId?: string) => {
|
||||
const scopeId = useAvailableScopeIdOrThrow(
|
||||
RecordBoardScopeInternalContext,
|
||||
getScopeIdOrUndefinedFromComponentId(recordBoardId),
|
||||
);
|
||||
|
||||
return {
|
||||
scopeId,
|
||||
objectSingularNameState: extractComponentState(
|
||||
recordBoardObjectSingularNameComponentState,
|
||||
scopeId,
|
||||
),
|
||||
kanbanFieldMetadataNameState: extractComponentState(
|
||||
recordBoardKanbanFieldMetadataNameComponentState,
|
||||
scopeId,
|
||||
),
|
||||
isFetchingRecordState: extractComponentState(
|
||||
isRecordBoardFetchingRecordsComponentState,
|
||||
scopeId,
|
||||
),
|
||||
isFetchingRecordsByColumnState: extractComponentFamilyState(
|
||||
isRecordBoardFetchingRecordsByColumnFamilyState,
|
||||
scopeId,
|
||||
),
|
||||
columnIdsState: extractComponentState(
|
||||
recordBoardColumnIdsComponentState,
|
||||
scopeId,
|
||||
),
|
||||
columnsFamilySelector: extractComponentFamilyState(
|
||||
recordBoardColumnsComponentFamilySelector,
|
||||
scopeId,
|
||||
),
|
||||
|
||||
filtersState: extractComponentState(
|
||||
recordBoardFiltersComponentState,
|
||||
scopeId,
|
||||
),
|
||||
sortsState: extractComponentState(recordBoardSortsComponentState, scopeId),
|
||||
fieldDefinitionsState: extractComponentState(
|
||||
recordBoardFieldDefinitionsComponentState,
|
||||
scopeId,
|
||||
),
|
||||
visibleFieldDefinitionsState: extractComponentReadOnlySelector(
|
||||
recordBoardVisibleFieldDefinitionsComponentSelector,
|
||||
scopeId,
|
||||
),
|
||||
|
||||
recordIdsByColumnIdFamilyState: extractComponentFamilyState(
|
||||
recordBoardRecordIdsByColumnIdComponentFamilyState,
|
||||
scopeId,
|
||||
),
|
||||
isRecordBoardCardSelectedFamilyState: extractComponentFamilyState(
|
||||
isRecordBoardCardSelectedComponentFamilyState,
|
||||
scopeId,
|
||||
),
|
||||
allRecordIdsSelector: extractComponentReadOnlySelector(
|
||||
recordBoardAllRecordIdsComponentSelector,
|
||||
scopeId,
|
||||
),
|
||||
selectedRecordIdsSelector: extractComponentReadOnlySelector(
|
||||
recordBoardSelectedRecordIdsComponentSelector,
|
||||
scopeId,
|
||||
),
|
||||
|
||||
isCompactModeActiveState: extractComponentState(
|
||||
isRecordBoardCompactModeActiveComponentState,
|
||||
scopeId,
|
||||
),
|
||||
|
||||
shouldFetchMoreInColumnFamilyState: extractComponentFamilyState(
|
||||
recordBoardShouldFetchMoreInColumnComponentFamilyState,
|
||||
scopeId,
|
||||
),
|
||||
shouldFetchMoreSelector: extractComponentReadOnlySelector(
|
||||
recordBoardShouldFetchMoreComponentSelector,
|
||||
scopeId,
|
||||
),
|
||||
};
|
||||
};
|
@ -1,58 +0,0 @@
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
|
||||
import { useRecordBoardStates } from '@/object-record/record-board/hooks/internal/useRecordBoardStates';
|
||||
import { RecordGroupDefinition } from '@/object-record/record-group/types/RecordGroupDefinition';
|
||||
import { sortRecordGroupDefinitions } from '@/object-record/record-group/utils/sortRecordGroupDefinitions';
|
||||
import { recordIndexRecordGroupSortComponentState } from '@/object-record/record-index/states/recordIndexRecordGroupSortComponentState';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
|
||||
|
||||
export const useSetRecordBoardColumns = (recordBoardId?: string) => {
|
||||
const { scopeId, columnIdsState, columnsFamilySelector } =
|
||||
useRecordBoardStates(recordBoardId);
|
||||
|
||||
const recordGroupSort = useRecoilComponentValueV2(
|
||||
recordIndexRecordGroupSortComponentState,
|
||||
recordBoardId,
|
||||
);
|
||||
|
||||
const setColumns = useRecoilCallback(
|
||||
({ set, snapshot }) =>
|
||||
(columns: RecordGroupDefinition[]) => {
|
||||
const currentColumnsIds = snapshot
|
||||
.getLoadable(columnIdsState)
|
||||
.getValue();
|
||||
|
||||
const sortedColumns = sortRecordGroupDefinitions(
|
||||
columns,
|
||||
recordGroupSort,
|
||||
);
|
||||
|
||||
const columnIds = sortedColumns
|
||||
.filter(({ isVisible }) => isVisible)
|
||||
.map(({ id }) => id);
|
||||
|
||||
if (!isDeeplyEqual(currentColumnsIds, columnIds)) {
|
||||
set(columnIdsState, columnIds);
|
||||
}
|
||||
|
||||
columns.forEach((column) => {
|
||||
const currentColumn = snapshot
|
||||
.getLoadable(columnsFamilySelector(column.id))
|
||||
.getValue();
|
||||
|
||||
if (isDeeplyEqual(currentColumn, column)) {
|
||||
return;
|
||||
}
|
||||
|
||||
set(columnsFamilySelector(column.id), column);
|
||||
});
|
||||
},
|
||||
[columnIdsState, recordGroupSort, columnsFamilySelector],
|
||||
);
|
||||
|
||||
return {
|
||||
scopeId,
|
||||
setColumns,
|
||||
};
|
||||
};
|
@ -1,63 +0,0 @@
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
|
||||
import { useRecordBoardStates } from '@/object-record/record-board/hooks/internal/useRecordBoardStates';
|
||||
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||
import { sortRecordsByPosition } from '@/object-record/utils/sortRecordsByPosition';
|
||||
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
|
||||
|
||||
export const useSetRecordBoardRecordIds = (recordBoardId?: string) => {
|
||||
const {
|
||||
scopeId,
|
||||
recordIdsByColumnIdFamilyState,
|
||||
columnsFamilySelector,
|
||||
columnIdsState,
|
||||
kanbanFieldMetadataNameState,
|
||||
} = useRecordBoardStates(recordBoardId);
|
||||
|
||||
const setRecordIds = useRecoilCallback(
|
||||
({ set, snapshot }) =>
|
||||
(records: ObjectRecord[]) => {
|
||||
const columnIds = snapshot.getLoadable(columnIdsState).getValue();
|
||||
|
||||
columnIds.forEach((columnId) => {
|
||||
const column = snapshot
|
||||
.getLoadable(columnsFamilySelector(columnId))
|
||||
.getValue();
|
||||
|
||||
const existingColumnRecordIds = snapshot
|
||||
.getLoadable(recordIdsByColumnIdFamilyState(columnId))
|
||||
.getValue();
|
||||
|
||||
const kanbanFieldMetadataName = snapshot
|
||||
.getLoadable(kanbanFieldMetadataNameState)
|
||||
.getValue();
|
||||
|
||||
if (!kanbanFieldMetadataName) {
|
||||
return;
|
||||
}
|
||||
|
||||
const columnRecordIds = records
|
||||
.filter(
|
||||
(record) => record[kanbanFieldMetadataName] === column?.value,
|
||||
)
|
||||
.sort(sortRecordsByPosition)
|
||||
.map((record) => record.id);
|
||||
|
||||
if (!isDeeplyEqual(existingColumnRecordIds, columnRecordIds)) {
|
||||
set(recordIdsByColumnIdFamilyState(columnId), columnRecordIds);
|
||||
}
|
||||
});
|
||||
},
|
||||
[
|
||||
columnIdsState,
|
||||
columnsFamilySelector,
|
||||
recordIdsByColumnIdFamilyState,
|
||||
kanbanFieldMetadataNameState,
|
||||
],
|
||||
);
|
||||
|
||||
return {
|
||||
scopeId,
|
||||
setRecordIds,
|
||||
};
|
||||
};
|
@ -1,55 +0,0 @@
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
|
||||
import { useRecordBoardStates } from '@/object-record/record-board/hooks/internal/useRecordBoardStates';
|
||||
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||
import { sortRecordsByPosition } from '@/object-record/utils/sortRecordsByPosition';
|
||||
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
|
||||
|
||||
export const useSetRecordIdsForColumn = (recordBoardId?: string) => {
|
||||
const {
|
||||
scopeId,
|
||||
recordIdsByColumnIdFamilyState,
|
||||
columnsFamilySelector,
|
||||
kanbanFieldMetadataNameState,
|
||||
} = useRecordBoardStates(recordBoardId);
|
||||
|
||||
const setRecordIdsForColumn = useRecoilCallback(
|
||||
({ set, snapshot }) =>
|
||||
(columnId: string, records: ObjectRecord[]) => {
|
||||
const column = snapshot
|
||||
.getLoadable(columnsFamilySelector(columnId))
|
||||
.getValue();
|
||||
|
||||
const existingColumnRecordIds = snapshot
|
||||
.getLoadable(recordIdsByColumnIdFamilyState(columnId))
|
||||
.getValue();
|
||||
|
||||
const kanbanFieldMetadataName = snapshot
|
||||
.getLoadable(kanbanFieldMetadataNameState)
|
||||
.getValue();
|
||||
|
||||
if (!kanbanFieldMetadataName) {
|
||||
return;
|
||||
}
|
||||
|
||||
const columnRecordIds = records
|
||||
.filter((record) => record[kanbanFieldMetadataName] === column?.value)
|
||||
.sort(sortRecordsByPosition)
|
||||
.map((record) => record.id);
|
||||
|
||||
if (!isDeeplyEqual(existingColumnRecordIds, columnRecordIds)) {
|
||||
set(recordIdsByColumnIdFamilyState(columnId), columnRecordIds);
|
||||
}
|
||||
},
|
||||
[
|
||||
columnsFamilySelector,
|
||||
recordIdsByColumnIdFamilyState,
|
||||
kanbanFieldMetadataNameState,
|
||||
],
|
||||
);
|
||||
|
||||
return {
|
||||
scopeId,
|
||||
setRecordIdsForColumn,
|
||||
};
|
||||
};
|
@ -1,43 +0,0 @@
|
||||
import { useSetRecoilState } from 'recoil';
|
||||
|
||||
import { useRecordBoardStates } from '@/object-record/record-board/hooks/internal/useRecordBoardStates';
|
||||
import { useSetRecordBoardColumns } from '@/object-record/record-board/hooks/internal/useSetRecordBoardColumns';
|
||||
import { useSetRecordBoardRecordIds } from '@/object-record/record-board/hooks/internal/useSetRecordBoardRecordIds';
|
||||
import { useSetRecordIdsForColumn } from '@/object-record/record-board/hooks/internal/useSetRecordIdsForColumn';
|
||||
|
||||
export const useRecordBoard = (recordBoardId?: string) => {
|
||||
const {
|
||||
scopeId,
|
||||
fieldDefinitionsState,
|
||||
objectSingularNameState,
|
||||
selectedRecordIdsSelector,
|
||||
isCompactModeActiveState,
|
||||
kanbanFieldMetadataNameState,
|
||||
shouldFetchMoreSelector,
|
||||
isFetchingRecordsByColumnState,
|
||||
} = useRecordBoardStates(recordBoardId);
|
||||
|
||||
const { setColumns } = useSetRecordBoardColumns(recordBoardId);
|
||||
const { setRecordIds } = useSetRecordBoardRecordIds(recordBoardId);
|
||||
const { setRecordIdsForColumn } = useSetRecordIdsForColumn(recordBoardId);
|
||||
|
||||
const setFieldDefinitions = useSetRecoilState(fieldDefinitionsState);
|
||||
const setObjectSingularName = useSetRecoilState(objectSingularNameState);
|
||||
const setKanbanFieldMetadataName = useSetRecoilState(
|
||||
kanbanFieldMetadataNameState,
|
||||
);
|
||||
|
||||
return {
|
||||
scopeId,
|
||||
setColumns,
|
||||
setRecordIds,
|
||||
setFieldDefinitions,
|
||||
setObjectSingularName,
|
||||
setKanbanFieldMetadataName,
|
||||
selectedRecordIdsSelector,
|
||||
isCompactModeActiveState,
|
||||
shouldFetchMoreSelector,
|
||||
setRecordIdsForColumn,
|
||||
isFetchingRecordsByColumnState,
|
||||
};
|
||||
};
|
@ -2,13 +2,25 @@ import { useRecoilCallback } from 'recoil';
|
||||
|
||||
import { getActionMenuDropdownIdFromActionMenuId } from '@/action-menu/utils/getActionMenuDropdownIdFromActionMenuId';
|
||||
import { getActionMenuIdFromRecordIndexId } from '@/action-menu/utils/getActionMenuIdFromRecordIndexId';
|
||||
import { useRecordBoardStates } from '@/object-record/record-board/hooks/internal/useRecordBoardStates';
|
||||
import { isRecordBoardCardSelectedComponentFamilyState } from '@/object-record/record-board/states/isRecordBoardCardSelectedComponentFamilyState';
|
||||
import { recordBoardSelectedRecordIdsComponentSelector } from '@/object-record/record-board/states/selectors/recordBoardSelectedRecordIdsComponentSelector';
|
||||
import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState';
|
||||
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
||||
import { extractComponentState } from '@/ui/utilities/state/component-state/utils/extractComponentState';
|
||||
import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue';
|
||||
|
||||
export const useRecordBoardSelection = (recordBoardId: string) => {
|
||||
const { selectedRecordIdsSelector, isRecordBoardCardSelectedFamilyState } =
|
||||
useRecordBoardStates(recordBoardId);
|
||||
const isRecordBoardCardSelectedFamilyState =
|
||||
useRecoilComponentCallbackStateV2(
|
||||
isRecordBoardCardSelectedComponentFamilyState,
|
||||
recordBoardId,
|
||||
);
|
||||
|
||||
const recordBoardSelectedRecordIdsSelector =
|
||||
useRecoilComponentCallbackStateV2(
|
||||
recordBoardSelectedRecordIdsComponentSelector,
|
||||
recordBoardId,
|
||||
);
|
||||
|
||||
const isActionMenuDropdownOpenState = extractComponentState(
|
||||
isDropdownOpenComponentState,
|
||||
@ -22,9 +34,10 @@ export const useRecordBoardSelection = (recordBoardId: string) => {
|
||||
() => {
|
||||
set(isActionMenuDropdownOpenState, false);
|
||||
|
||||
const recordIds = snapshot
|
||||
.getLoadable(selectedRecordIdsSelector())
|
||||
.getValue();
|
||||
const recordIds = getSnapshotValue(
|
||||
snapshot,
|
||||
recordBoardSelectedRecordIdsSelector,
|
||||
);
|
||||
|
||||
for (const recordId of recordIds) {
|
||||
set(isRecordBoardCardSelectedFamilyState(recordId), false);
|
||||
@ -32,7 +45,7 @@ export const useRecordBoardSelection = (recordBoardId: string) => {
|
||||
},
|
||||
[
|
||||
isActionMenuDropdownOpenState,
|
||||
selectedRecordIdsSelector,
|
||||
recordBoardSelectedRecordIdsSelector,
|
||||
isRecordBoardCardSelectedFamilyState,
|
||||
],
|
||||
);
|
||||
|
@ -0,0 +1,110 @@
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
|
||||
import { recordGroupDefinitionFamilyState } from '@/object-record/record-group/states/recordGroupDefinitionFamilyState';
|
||||
import { recordGroupFieldMetadataComponentState } from '@/object-record/record-group/states/recordGroupFieldMetadataComponentState';
|
||||
import { visibleRecordGroupIdsComponentSelector } from '@/object-record/record-group/states/selectors/visibleRecordGroupIdsComponentSelector';
|
||||
import { recordIndexAllRowIdsComponentState } from '@/object-record/record-index/states/recordIndexAllRowIdsComponentState';
|
||||
import { recordIndexRowIdsByGroupComponentFamilyState } from '@/object-record/record-index/states/recordIndexRowIdsByGroupComponentFamilyState';
|
||||
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||
import { sortRecordsByPosition } from '@/object-record/utils/sortRecordsByPosition';
|
||||
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
||||
import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue';
|
||||
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
|
||||
import { isDefined } from '~/utils/isDefined';
|
||||
|
||||
export const useSetRecordBoardRecordIds = (recordBoardId?: string) => {
|
||||
const visibleRecordGroupIdsSelector = useRecoilComponentCallbackStateV2(
|
||||
visibleRecordGroupIdsComponentSelector,
|
||||
);
|
||||
|
||||
const recordGroupFieldMetadataState = useRecoilComponentCallbackStateV2(
|
||||
recordGroupFieldMetadataComponentState,
|
||||
recordBoardId,
|
||||
);
|
||||
|
||||
const recordIndexAllRowIdsState = useRecoilComponentCallbackStateV2(
|
||||
recordIndexAllRowIdsComponentState,
|
||||
recordBoardId,
|
||||
);
|
||||
|
||||
const recordIndexRowIdsByGroupFamilyState = useRecoilComponentCallbackStateV2(
|
||||
recordIndexRowIdsByGroupComponentFamilyState,
|
||||
recordBoardId,
|
||||
);
|
||||
|
||||
const setRecordIds = useRecoilCallback(
|
||||
({ set, snapshot }) =>
|
||||
(records: ObjectRecord[]) => {
|
||||
const existingAllRowIds = getSnapshotValue(
|
||||
snapshot,
|
||||
recordIndexAllRowIdsState,
|
||||
);
|
||||
|
||||
const recordGroupIds = getSnapshotValue(
|
||||
snapshot,
|
||||
visibleRecordGroupIdsSelector,
|
||||
);
|
||||
|
||||
for (const recordGroupId of recordGroupIds) {
|
||||
const recordGroup = getSnapshotValue(
|
||||
snapshot,
|
||||
recordGroupDefinitionFamilyState(recordGroupId),
|
||||
);
|
||||
|
||||
const existingRecordGroupRowIds = getSnapshotValue(
|
||||
snapshot,
|
||||
recordIndexRowIdsByGroupFamilyState(recordGroupId),
|
||||
);
|
||||
|
||||
const recordGroupFieldMetadata = getSnapshotValue(
|
||||
snapshot,
|
||||
recordGroupFieldMetadataState,
|
||||
);
|
||||
|
||||
if (!isDefined(recordGroupFieldMetadata)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const recordGroupRowIds = records
|
||||
.filter(
|
||||
(record) =>
|
||||
record[recordGroupFieldMetadata.name] === recordGroup?.value,
|
||||
)
|
||||
.sort(sortRecordsByPosition)
|
||||
.map((record) => record.id);
|
||||
|
||||
if (!isDeeplyEqual(existingRecordGroupRowIds, recordGroupRowIds)) {
|
||||
set(
|
||||
recordIndexRowIdsByGroupFamilyState(recordGroupId),
|
||||
recordGroupRowIds,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const allRowIds: string[] = [];
|
||||
|
||||
for (const recordGroupId of recordGroupIds) {
|
||||
const tableRowIdsByGroup = getSnapshotValue(
|
||||
snapshot,
|
||||
recordIndexRowIdsByGroupFamilyState(recordGroupId),
|
||||
);
|
||||
|
||||
allRowIds.push(...tableRowIdsByGroup);
|
||||
}
|
||||
|
||||
if (!isDeeplyEqual(existingAllRowIds, allRowIds)) {
|
||||
set(recordIndexAllRowIdsState, allRowIds);
|
||||
}
|
||||
},
|
||||
[
|
||||
visibleRecordGroupIdsSelector,
|
||||
recordIndexRowIdsByGroupFamilyState,
|
||||
recordGroupFieldMetadataState,
|
||||
recordIndexAllRowIdsState,
|
||||
],
|
||||
);
|
||||
|
||||
return {
|
||||
setRecordIds,
|
||||
};
|
||||
};
|
@ -0,0 +1,109 @@
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
|
||||
import { recordGroupDefinitionFamilyState } from '@/object-record/record-group/states/recordGroupDefinitionFamilyState';
|
||||
import { recordGroupFieldMetadataComponentState } from '@/object-record/record-group/states/recordGroupFieldMetadataComponentState';
|
||||
import { recordGroupIdsComponentState } from '@/object-record/record-group/states/recordGroupIdsComponentState';
|
||||
import { recordIndexAllRowIdsComponentState } from '@/object-record/record-index/states/recordIndexAllRowIdsComponentState';
|
||||
import { recordIndexRowIdsByGroupComponentFamilyState } from '@/object-record/record-index/states/recordIndexRowIdsByGroupComponentFamilyState';
|
||||
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||
import { sortRecordsByPosition } from '@/object-record/utils/sortRecordsByPosition';
|
||||
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
||||
import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue';
|
||||
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
|
||||
import { isDefined } from '~/utils/isDefined';
|
||||
|
||||
export const useSetRecordIdsForColumn = (recordBoardId?: string) => {
|
||||
const recordGroupIdsState = useRecoilComponentCallbackStateV2(
|
||||
recordGroupIdsComponentState,
|
||||
recordBoardId,
|
||||
);
|
||||
|
||||
const recordGroupFieldMetadataState = useRecoilComponentCallbackStateV2(
|
||||
recordGroupFieldMetadataComponentState,
|
||||
recordBoardId,
|
||||
);
|
||||
|
||||
const recordIndexAllRowIdsState = useRecoilComponentCallbackStateV2(
|
||||
recordIndexAllRowIdsComponentState,
|
||||
recordBoardId,
|
||||
);
|
||||
|
||||
const recordIndexRowIdsByGroupFamilyState = useRecoilComponentCallbackStateV2(
|
||||
recordIndexRowIdsByGroupComponentFamilyState,
|
||||
recordBoardId,
|
||||
);
|
||||
|
||||
const setRecordIdsForColumn = useRecoilCallback(
|
||||
({ set, snapshot }) =>
|
||||
(currentRecordGroupId: string, records: ObjectRecord[]) => {
|
||||
const existingAllRowIds = getSnapshotValue(
|
||||
snapshot,
|
||||
recordIndexAllRowIdsState,
|
||||
);
|
||||
|
||||
const recordGroupIds = getSnapshotValue(snapshot, recordGroupIdsState);
|
||||
|
||||
const recordGroup = getSnapshotValue(
|
||||
snapshot,
|
||||
recordGroupDefinitionFamilyState(currentRecordGroupId),
|
||||
);
|
||||
|
||||
const existingRecordGroupRowIds = getSnapshotValue(
|
||||
snapshot,
|
||||
recordIndexRowIdsByGroupFamilyState(currentRecordGroupId),
|
||||
);
|
||||
|
||||
const recordGroupFieldMetadata = getSnapshotValue(
|
||||
snapshot,
|
||||
recordGroupFieldMetadataState,
|
||||
);
|
||||
|
||||
if (!isDefined(recordGroupFieldMetadata)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const recordGroupRowIds = records
|
||||
.filter(
|
||||
(record) =>
|
||||
record[recordGroupFieldMetadata.name] === recordGroup?.value,
|
||||
)
|
||||
.sort(sortRecordsByPosition)
|
||||
.map((record) => record.id);
|
||||
|
||||
if (!isDeeplyEqual(existingRecordGroupRowIds, recordGroupRowIds)) {
|
||||
set(
|
||||
recordIndexRowIdsByGroupFamilyState(currentRecordGroupId),
|
||||
recordGroupRowIds,
|
||||
);
|
||||
}
|
||||
|
||||
const allRowIds: string[] = [];
|
||||
|
||||
for (const recordGroupId of recordGroupIds) {
|
||||
const tableRowIdsByGroup =
|
||||
recordGroupId !== currentRecordGroupId
|
||||
? getSnapshotValue(
|
||||
snapshot,
|
||||
recordIndexRowIdsByGroupFamilyState(recordGroupId),
|
||||
)
|
||||
: recordGroupRowIds;
|
||||
|
||||
allRowIds.push(...tableRowIdsByGroup);
|
||||
}
|
||||
|
||||
if (!isDeeplyEqual(existingAllRowIds, allRowIds)) {
|
||||
set(recordIndexAllRowIdsState, allRowIds);
|
||||
}
|
||||
},
|
||||
[
|
||||
recordGroupIdsState,
|
||||
recordIndexRowIdsByGroupFamilyState,
|
||||
recordGroupFieldMetadataState,
|
||||
recordIndexAllRowIdsState,
|
||||
],
|
||||
);
|
||||
|
||||
return {
|
||||
setRecordIdsForColumn,
|
||||
};
|
||||
};
|
@ -3,9 +3,11 @@ import { recordIndexActionMenuDropdownPositionComponentState } from '@/action-me
|
||||
import { getActionMenuDropdownIdFromActionMenuId } from '@/action-menu/utils/getActionMenuDropdownIdFromActionMenuId';
|
||||
import { getActionMenuIdFromRecordIndexId } from '@/action-menu/utils/getActionMenuIdFromRecordIndexId';
|
||||
import { RecordBoardContext } from '@/object-record/record-board/contexts/RecordBoardContext';
|
||||
import { useRecordBoardStates } from '@/object-record/record-board/hooks/internal/useRecordBoardStates';
|
||||
import { RecordBoardCardContext } from '@/object-record/record-board/record-board-card/contexts/RecordBoardCardContext';
|
||||
import { RecordBoardScopeInternalContext } from '@/object-record/record-board/scopes/scope-internal-context/RecordBoardScopeInternalContext';
|
||||
import { isRecordBoardCardSelectedComponentFamilyState } from '@/object-record/record-board/states/isRecordBoardCardSelectedComponentFamilyState';
|
||||
import { isRecordBoardCompactModeActiveComponentState } from '@/object-record/record-board/states/isRecordBoardCompactModeActiveComponentState';
|
||||
import { recordBoardVisibleFieldDefinitionsComponentSelector } from '@/object-record/record-board/states/selectors/recordBoardVisibleFieldDefinitionsComponentSelector';
|
||||
import {
|
||||
FieldContext,
|
||||
RecordUpdateHook,
|
||||
@ -22,11 +24,13 @@ import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||
import { TextInput } from '@/ui/input/components/TextInput';
|
||||
import { useAvailableScopeIdOrThrow } from '@/ui/utilities/recoil-scope/scopes-internal/hooks/useAvailableScopeId';
|
||||
import { RecordBoardScrollWrapperContext } from '@/ui/utilities/scroll/contexts/ScrollWrapperContexts';
|
||||
import { useRecoilComponentFamilyStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyStateV2';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { extractComponentState } from '@/ui/utilities/state/component-state/utils/extractComponentState';
|
||||
import styled from '@emotion/styled';
|
||||
import { ReactNode, useContext, useState } from 'react';
|
||||
import { InView, useInView } from 'react-intersection-observer';
|
||||
import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil';
|
||||
import { useRecoilValue, useSetRecoilState } from 'recoil';
|
||||
import {
|
||||
AnimatedEaseInOut,
|
||||
AvatarChipVariant,
|
||||
@ -157,27 +161,30 @@ export const RecordBoardCard = ({
|
||||
onCreateSuccess?: () => void;
|
||||
position?: 'first' | 'last';
|
||||
}) => {
|
||||
const [newLabelValue, setNewLabelValue] = useState('');
|
||||
const { handleBlur, handleInputEnter } = useAddNewCard();
|
||||
const { recordId } = useContext(RecordBoardCardContext);
|
||||
|
||||
const [newLabelValue, setNewLabelValue] = useState('');
|
||||
|
||||
const { handleBlur, handleInputEnter } = useAddNewCard();
|
||||
|
||||
const { updateOneRecord, objectMetadataItem } =
|
||||
useContext(RecordBoardContext);
|
||||
const {
|
||||
isCompactModeActiveState,
|
||||
isRecordBoardCardSelectedFamilyState,
|
||||
visibleFieldDefinitionsState,
|
||||
} = useRecordBoardStates();
|
||||
const isCompactModeActive = useRecoilValue(isCompactModeActiveState);
|
||||
|
||||
const visibleFieldDefinitions = useRecoilComponentValueV2(
|
||||
recordBoardVisibleFieldDefinitionsComponentSelector,
|
||||
);
|
||||
|
||||
const isCompactModeActive = useRecoilComponentValueV2(
|
||||
isRecordBoardCompactModeActiveComponentState,
|
||||
);
|
||||
|
||||
const [isCardExpanded, setIsCardExpanded] = useState(false);
|
||||
|
||||
const [isCurrentCardSelected, setIsCurrentCardSelected] = useRecoilState(
|
||||
isRecordBoardCardSelectedFamilyState(recordId),
|
||||
);
|
||||
|
||||
const visibleFieldDefinitions = useRecoilValue(
|
||||
visibleFieldDefinitionsState(),
|
||||
);
|
||||
const [isCurrentCardSelected, setIsCurrentCardSelected] =
|
||||
useRecoilComponentFamilyStateV2(
|
||||
isRecordBoardCardSelectedComponentFamilyState,
|
||||
recordId,
|
||||
);
|
||||
|
||||
const record = useRecoilValue(recordStoreFamilyState(recordId));
|
||||
|
||||
|
@ -1,10 +1,12 @@
|
||||
import styled from '@emotion/styled';
|
||||
import { Droppable } from '@hello-pangea/dnd';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
import { useRecordBoardStates } from '@/object-record/record-board/hooks/internal/useRecordBoardStates';
|
||||
import { RecordBoardColumnCardsContainer } from '@/object-record/record-board/record-board-column/components/RecordBoardColumnCardsContainer';
|
||||
import { RecordBoardColumnContext } from '@/object-record/record-board/record-board-column/contexts/RecordBoardColumnContext';
|
||||
import { recordGroupDefinitionFamilyState } from '@/object-record/record-group/states/recordGroupDefinitionFamilyState';
|
||||
import { recordIndexRowIdsByGroupComponentFamilyState } from '@/object-record/record-index/states/recordIndexRowIdsByGroupComponentFamilyState';
|
||||
import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValueV2';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
const StyledColumn = styled.div`
|
||||
background-color: ${({ theme }) => theme.background.primary};
|
||||
@ -25,27 +27,26 @@ type RecordBoardColumnProps = {
|
||||
export const RecordBoardColumn = ({
|
||||
recordBoardColumnId,
|
||||
}: RecordBoardColumnProps) => {
|
||||
const { columnsFamilySelector, recordIdsByColumnIdFamilyState } =
|
||||
useRecordBoardStates();
|
||||
const columnDefinition = useRecoilValue(
|
||||
columnsFamilySelector(recordBoardColumnId),
|
||||
const recordGroupDefinition = useRecoilValue(
|
||||
recordGroupDefinitionFamilyState(recordBoardColumnId),
|
||||
);
|
||||
|
||||
const recordIds = useRecoilValue(
|
||||
recordIdsByColumnIdFamilyState(recordBoardColumnId),
|
||||
const recordRowIdsByGroup = useRecoilComponentFamilyValueV2(
|
||||
recordIndexRowIdsByGroupComponentFamilyState,
|
||||
recordBoardColumnId,
|
||||
);
|
||||
|
||||
if (!columnDefinition) {
|
||||
if (!recordGroupDefinition) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<RecordBoardColumnContext.Provider
|
||||
value={{
|
||||
columnDefinition: columnDefinition,
|
||||
recordCount: recordIds.length,
|
||||
columnDefinition: recordGroupDefinition,
|
||||
recordCount: recordRowIdsByGroup.length,
|
||||
columnId: recordBoardColumnId,
|
||||
recordIds,
|
||||
recordIds: recordRowIdsByGroup,
|
||||
}}
|
||||
>
|
||||
<Droppable droppableId={recordBoardColumnId}>
|
||||
@ -53,7 +54,7 @@ export const RecordBoardColumn = ({
|
||||
<StyledColumn>
|
||||
<RecordBoardColumnCardsContainer
|
||||
droppableProvided={droppableProvided}
|
||||
recordIds={recordIds}
|
||||
recordIds={recordRowIdsByGroup}
|
||||
/>
|
||||
</StyledColumn>
|
||||
)}
|
||||
|
@ -5,7 +5,6 @@ import { useRecoilValue } from 'recoil';
|
||||
|
||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||
import { RecordBoardContext } from '@/object-record/record-board/contexts/RecordBoardContext';
|
||||
import { useRecordBoardStates } from '@/object-record/record-board/hooks/internal/useRecordBoardStates';
|
||||
import { RecordBoardColumnCardContainerSkeletonLoader } from '@/object-record/record-board/record-board-column/components/RecordBoardColumnCardContainerSkeletonLoader';
|
||||
import { RecordBoardColumnCardsMemo } from '@/object-record/record-board/record-board-column/components/RecordBoardColumnCardsMemo';
|
||||
import { RecordBoardColumnFetchMoreLoader } from '@/object-record/record-board/record-board-column/components/RecordBoardColumnFetchMoreLoader';
|
||||
@ -15,7 +14,10 @@ import { RecordBoardColumnNewRecordButton } from '@/object-record/record-board/r
|
||||
import { RecordBoardColumnContext } from '@/object-record/record-board/record-board-column/contexts/RecordBoardColumnContext';
|
||||
import { useIsOpportunitiesCompanyFieldDisabled } from '@/object-record/record-board/record-board-column/hooks/useIsOpportunitiesCompanyFieldDisabled';
|
||||
import { getNumberOfCardsPerColumnForSkeletonLoading } from '@/object-record/record-board/record-board-column/utils/getNumberOfCardsPerColumnForSkeletonLoading';
|
||||
import { isRecordBoardCompactModeActiveComponentState } from '@/object-record/record-board/states/isRecordBoardCompactModeActiveComponentState';
|
||||
import { recordBoardVisibleFieldDefinitionsComponentSelector } from '@/object-record/record-board/states/selectors/recordBoardVisibleFieldDefinitionsComponentSelector';
|
||||
import { isRecordIndexBoardColumnLoadingFamilyState } from '@/object-record/states/isRecordBoardColumnLoadingFamilyState';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
|
||||
const StyledColumnCardsContainer = styled.div`
|
||||
display: flex;
|
||||
@ -56,16 +58,16 @@ export const RecordBoardColumnCardsContainer = ({
|
||||
isRecordIndexBoardColumnLoadingFamilyState(columnId),
|
||||
);
|
||||
|
||||
const { isCompactModeActiveState, visibleFieldDefinitionsState } =
|
||||
useRecordBoardStates();
|
||||
|
||||
const visibleFieldDefinitions = useRecoilValue(
|
||||
visibleFieldDefinitionsState(),
|
||||
const visibleFieldDefinitions = useRecoilComponentValueV2(
|
||||
recordBoardVisibleFieldDefinitionsComponentSelector,
|
||||
);
|
||||
|
||||
const numberOfFields = visibleFieldDefinitions.length;
|
||||
|
||||
const isCompactModeActive = useRecoilValue(isCompactModeActiveState);
|
||||
const isCompactModeActive = useRecoilComponentValueV2(
|
||||
isRecordBoardCompactModeActiveComponentState,
|
||||
);
|
||||
|
||||
const { isOpportunitiesCompanyFieldDisabled } =
|
||||
useIsOpportunitiesCompanyFieldDisabled();
|
||||
|
||||
|
@ -5,7 +5,6 @@ import { useRecordGroupActions } from '@/object-record/record-group/hooks/useRec
|
||||
import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu';
|
||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||
import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside';
|
||||
import { ViewType } from '@/views/types/ViewType';
|
||||
import { MenuItem } from 'twenty-ui';
|
||||
|
||||
const StyledMenuContainer = styled.div`
|
||||
@ -26,9 +25,7 @@ export const RecordBoardColumnDropdownMenu = ({
|
||||
}: RecordBoardColumnDropdownMenuProps) => {
|
||||
const boardColumnMenuRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const recordGroupActions = useRecordGroupActions({
|
||||
viewType: ViewType.Kanban,
|
||||
});
|
||||
const recordGroupActions = useRecordGroupActions();
|
||||
|
||||
const closeMenu = useCallback(() => {
|
||||
onClose();
|
||||
|
@ -1,11 +1,13 @@
|
||||
import styled from '@emotion/styled';
|
||||
import { useContext, useEffect } from 'react';
|
||||
import { useInView } from 'react-intersection-observer';
|
||||
import styled from '@emotion/styled';
|
||||
import { useRecoilValue, useSetRecoilState } from 'recoil';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { GRAY_SCALE } from 'twenty-ui';
|
||||
|
||||
import { useRecordBoardStates } from '@/object-record/record-board/hooks/internal/useRecordBoardStates';
|
||||
import { RecordBoardColumnContext } from '@/object-record/record-board/record-board-column/contexts/RecordBoardColumnContext';
|
||||
import { isRecordBoardFetchingRecordsByColumnFamilyState } from '@/object-record/record-board/states/isRecordBoardFetchingRecordsByColumnFamilyState';
|
||||
import { recordBoardShouldFetchMoreInColumnComponentFamilyState } from '@/object-record/record-board/states/recordBoardShouldFetchMoreInColumnComponentFamilyState';
|
||||
import { useSetRecoilComponentFamilyStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentFamilyStateV2';
|
||||
|
||||
const StyledText = styled.div`
|
||||
align-items: center;
|
||||
@ -19,15 +21,14 @@ const StyledText = styled.div`
|
||||
|
||||
export const RecordBoardColumnFetchMoreLoader = () => {
|
||||
const { columnDefinition } = useContext(RecordBoardColumnContext);
|
||||
const { shouldFetchMoreInColumnFamilyState, isFetchingRecordsByColumnState } =
|
||||
useRecordBoardStates();
|
||||
|
||||
const isFetchingRecord = useRecoilValue(
|
||||
isFetchingRecordsByColumnState({ columnId: columnDefinition.id }),
|
||||
isRecordBoardFetchingRecordsByColumnFamilyState(columnDefinition.id),
|
||||
);
|
||||
|
||||
const setShouldFetchMore = useSetRecoilState(
|
||||
shouldFetchMoreInColumnFamilyState(columnDefinition.id),
|
||||
const setShouldFetchMore = useSetRecoilComponentFamilyStateV2(
|
||||
recordBoardShouldFetchMoreInColumnComponentFamilyState,
|
||||
columnDefinition.id,
|
||||
);
|
||||
|
||||
const { ref, inView } = useInView();
|
||||
|
@ -1,8 +1,10 @@
|
||||
import { isDefined } from 'twenty-ui';
|
||||
|
||||
import { useRecordBoardStates } from '@/object-record/record-board/hooks/internal/useRecordBoardStates';
|
||||
import { RecordBoardColumnHeader } from '@/object-record/record-board/record-board-column/components/RecordBoardColumnHeader';
|
||||
import { RecordBoardColumnContext } from '@/object-record/record-board/record-board-column/contexts/RecordBoardColumnContext';
|
||||
import { recordGroupDefinitionFamilyState } from '@/object-record/record-group/states/recordGroupDefinitionFamilyState';
|
||||
import { recordIndexRowIdsByGroupComponentFamilyState } from '@/object-record/record-index/states/recordIndexRowIdsByGroupComponentFamilyState';
|
||||
import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValueV2';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
type RecordBoardColumnHeaderWrapperProps = {
|
||||
@ -12,14 +14,16 @@ type RecordBoardColumnHeaderWrapperProps = {
|
||||
export const RecordBoardColumnHeaderWrapper = ({
|
||||
columnId,
|
||||
}: RecordBoardColumnHeaderWrapperProps) => {
|
||||
const { columnsFamilySelector, recordIdsByColumnIdFamilyState } =
|
||||
useRecordBoardStates();
|
||||
const recordGroupDefinition = useRecoilValue(
|
||||
recordGroupDefinitionFamilyState(columnId),
|
||||
);
|
||||
|
||||
const columnDefinition = useRecoilValue(columnsFamilySelector(columnId));
|
||||
const recordRowIdsByGroup = useRecoilComponentFamilyValueV2(
|
||||
recordIndexRowIdsByGroupComponentFamilyState,
|
||||
columnId,
|
||||
);
|
||||
|
||||
const recordIds = useRecoilValue(recordIdsByColumnIdFamilyState(columnId));
|
||||
|
||||
if (!isDefined(columnDefinition)) {
|
||||
if (!isDefined(recordGroupDefinition)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -27,9 +31,9 @@ export const RecordBoardColumnHeaderWrapper = ({
|
||||
<RecordBoardColumnContext.Provider
|
||||
value={{
|
||||
columnId,
|
||||
columnDefinition: columnDefinition,
|
||||
recordCount: recordIds.length,
|
||||
recordIds,
|
||||
columnDefinition: recordGroupDefinition,
|
||||
recordCount: recordRowIdsByGroup.length,
|
||||
recordIds: recordRowIdsByGroup,
|
||||
}}
|
||||
>
|
||||
<RecordBoardColumnHeader />
|
||||
|
@ -1,12 +1,12 @@
|
||||
import { useRecordBoardStates } from '@/object-record/record-board/hooks/internal/useRecordBoardStates';
|
||||
import { useAddNewCard } from '@/object-record/record-board/record-board-column/hooks/useAddNewCard';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { recordBoardVisibleFieldDefinitionsComponentSelector } from '@/object-record/record-board/states/selectors/recordBoardVisibleFieldDefinitionsComponentSelector';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
|
||||
export const useColumnNewCardActions = (columnId: string) => {
|
||||
const { visibleFieldDefinitionsState } = useRecordBoardStates();
|
||||
const visibleFieldDefinitions = useRecoilValue(
|
||||
visibleFieldDefinitionsState(),
|
||||
const visibleFieldDefinitions = useRecoilComponentValueV2(
|
||||
recordBoardVisibleFieldDefinitionsComponentSelector,
|
||||
);
|
||||
|
||||
const labelIdentifierField = visibleFieldDefinitions.find(
|
||||
(field) => field.isLabelIdentifier,
|
||||
);
|
||||
|
@ -0,0 +1,4 @@
|
||||
import { createComponentInstanceContext } from '@/ui/utilities/state/component-state/utils/createComponentInstanceContext';
|
||||
|
||||
export const RecordBoardComponentInstanceContext =
|
||||
createComponentInstanceContext();
|
@ -1,7 +1,9 @@
|
||||
import { createComponentFamilyState } from '@/ui/utilities/state/component-state/utils/createComponentFamilyState';
|
||||
import { RecordBoardComponentInstanceContext } from '@/object-record/record-board/states/contexts/RecordBoardComponentInstanceContext';
|
||||
import { createComponentFamilyStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentFamilyStateV2';
|
||||
|
||||
export const isRecordBoardCardSelectedComponentFamilyState =
|
||||
createComponentFamilyState<boolean, string>({
|
||||
createComponentFamilyStateV2<boolean, string>({
|
||||
key: 'isRecordBoardCardSelectedComponentFamilyState',
|
||||
defaultValue: false,
|
||||
componentInstanceContext: RecordBoardComponentInstanceContext,
|
||||
});
|
||||
|
@ -1,7 +1,9 @@
|
||||
import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState';
|
||||
import { RecordBoardComponentInstanceContext } from '@/object-record/record-board/states/contexts/RecordBoardComponentInstanceContext';
|
||||
import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2';
|
||||
|
||||
export const isRecordBoardCompactModeActiveComponentState =
|
||||
createComponentState<boolean>({
|
||||
createComponentStateV2<boolean>({
|
||||
key: 'isRecordBoardCompactModeActiveComponentState',
|
||||
defaultValue: false,
|
||||
componentInstanceContext: RecordBoardComponentInstanceContext,
|
||||
});
|
||||
|
@ -1,7 +1,10 @@
|
||||
import { createComponentFamilyState } from '@/ui/utilities/state/component-state/utils/createComponentFamilyState';
|
||||
import { RecordGroupDefinition } from '@/object-record/record-group/types/RecordGroupDefinition';
|
||||
import { atomFamily } from 'recoil';
|
||||
|
||||
export const isRecordBoardFetchingRecordsByColumnFamilyState =
|
||||
createComponentFamilyState<boolean, { columnId: string }>({
|
||||
key: 'isRecordBoardFetchingRecordsByColumnFamilyState',
|
||||
defaultValue: false,
|
||||
});
|
||||
export const isRecordBoardFetchingRecordsByColumnFamilyState = atomFamily<
|
||||
boolean,
|
||||
RecordGroupDefinition['id']
|
||||
>({
|
||||
key: 'isRecordBoardFetchingRecordsByColumnFamilyState',
|
||||
default: false,
|
||||
});
|
||||
|
@ -1,7 +0,0 @@
|
||||
import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState';
|
||||
|
||||
export const isRecordBoardFetchingRecordsComponentState =
|
||||
createComponentState<boolean>({
|
||||
key: 'isRecordBoardFetchingRecordsComponentState',
|
||||
defaultValue: false,
|
||||
});
|
@ -1,8 +0,0 @@
|
||||
import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState';
|
||||
|
||||
export const recordBoardColumnIdsComponentState = createComponentState<
|
||||
string[]
|
||||
>({
|
||||
key: 'recordBoardColumnIdsComponentState',
|
||||
defaultValue: [],
|
||||
});
|
@ -1,8 +0,0 @@
|
||||
import { RecordGroupDefinition } from '@/object-record/record-group/types/RecordGroupDefinition';
|
||||
import { createComponentFamilyState } from '@/ui/utilities/state/component-state/utils/createComponentFamilyState';
|
||||
|
||||
export const recordBoardColumnsComponentFamilyState =
|
||||
createComponentFamilyState<RecordGroupDefinition | undefined, string>({
|
||||
key: 'recordBoardColumnsComponentFamilyState',
|
||||
defaultValue: undefined,
|
||||
});
|
@ -1,10 +1,12 @@
|
||||
import { RecordBoardComponentInstanceContext } from '@/object-record/record-board/states/contexts/RecordBoardComponentInstanceContext';
|
||||
import { RecordBoardFieldDefinition } from '@/object-record/record-board/types/RecordBoardFieldDefinition';
|
||||
import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata';
|
||||
import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState';
|
||||
import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2';
|
||||
|
||||
export const recordBoardFieldDefinitionsComponentState = createComponentState<
|
||||
export const recordBoardFieldDefinitionsComponentState = createComponentStateV2<
|
||||
RecordBoardFieldDefinition<FieldMetadata>[]
|
||||
>({
|
||||
key: 'recordBoardFieldDefinitionsComponentState',
|
||||
defaultValue: [],
|
||||
componentInstanceContext: RecordBoardComponentInstanceContext,
|
||||
});
|
||||
|
@ -1,7 +0,0 @@
|
||||
import { Filter } from '@/object-record/object-filter-dropdown/types/Filter';
|
||||
import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState';
|
||||
|
||||
export const recordBoardFiltersComponentState = createComponentState<Filter[]>({
|
||||
key: 'recordBoardFiltersComponentState',
|
||||
defaultValue: [],
|
||||
});
|
@ -1,7 +0,0 @@
|
||||
import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState';
|
||||
|
||||
export const recordBoardKanbanFieldMetadataNameComponentState =
|
||||
createComponentState<string | undefined>({
|
||||
key: 'recordBoardKanbanFieldMetadataNameComponentState',
|
||||
defaultValue: undefined,
|
||||
});
|
@ -1,7 +0,0 @@
|
||||
import { createComponentFamilyState } from '@/ui/utilities/state/component-state/utils/createComponentFamilyState';
|
||||
|
||||
export const recordBoardRecordIdsByColumnIdComponentFamilyState =
|
||||
createComponentFamilyState<string[], string>({
|
||||
key: 'recordBoardRecordIdsByColumnIdComponentFamilyState',
|
||||
defaultValue: [],
|
||||
});
|
@ -1,7 +1,9 @@
|
||||
import { createComponentFamilyState } from '@/ui/utilities/state/component-state/utils/createComponentFamilyState';
|
||||
import { RecordBoardComponentInstanceContext } from '@/object-record/record-board/states/contexts/RecordBoardComponentInstanceContext';
|
||||
import { createComponentFamilyStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentFamilyStateV2';
|
||||
|
||||
export const recordBoardShouldFetchMoreInColumnComponentFamilyState =
|
||||
createComponentFamilyState<boolean, string>({
|
||||
key: 'onRecordBoardFetchMoreIrecordBoardShouldFetchMoreInColumnComponentFamilyStatesVisibleComponentFamilyState',
|
||||
createComponentFamilyStateV2<boolean, string>({
|
||||
key: 'recordBoardShouldFetchMoreInColumnComponentFamilyState',
|
||||
defaultValue: false,
|
||||
componentInstanceContext: RecordBoardComponentInstanceContext,
|
||||
});
|
||||
|
@ -1,7 +0,0 @@
|
||||
import { Sort } from '@/object-record/object-sort-dropdown/types/Sort';
|
||||
import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState';
|
||||
|
||||
export const recordBoardSortsComponentState = createComponentState<Sort[]>({
|
||||
key: 'recordBoardSortsComponentState',
|
||||
defaultValue: [],
|
||||
});
|
@ -1,26 +0,0 @@
|
||||
import { recordBoardColumnIdsComponentState } from '@/object-record/record-board/states/recordBoardColumnIdsComponentState';
|
||||
import { recordBoardRecordIdsByColumnIdComponentFamilyState } from '@/object-record/record-board/states/recordBoardRecordIdsByColumnIdComponentFamilyState';
|
||||
import { createComponentReadOnlySelector } from '@/ui/utilities/state/component-state/utils/createComponentReadOnlySelector';
|
||||
|
||||
export const recordBoardAllRecordIdsComponentSelector =
|
||||
createComponentReadOnlySelector<string[]>({
|
||||
key: 'recordBoardAllRecordIdsComponentSelector',
|
||||
get:
|
||||
({ scopeId }) =>
|
||||
({ get }) => {
|
||||
const columnIds = get(recordBoardColumnIdsComponentState({ scopeId }));
|
||||
|
||||
const recordIdsByColumn = columnIds.map((columnId) =>
|
||||
get(
|
||||
recordBoardRecordIdsByColumnIdComponentFamilyState({
|
||||
scopeId,
|
||||
familyKey: columnId,
|
||||
}),
|
||||
),
|
||||
);
|
||||
|
||||
const recordIds = recordIdsByColumn.flat();
|
||||
|
||||
return recordIds;
|
||||
},
|
||||
});
|
@ -1,41 +0,0 @@
|
||||
import { recordBoardColumnsComponentFamilyState } from '@/object-record/record-board/states/recordBoardColumnsComponentFamilyState';
|
||||
import { createComponentFamilySelector } from '@/ui/utilities/state/component-state/utils/createComponentFamilySelector';
|
||||
import { RecordGroupDefinition } from '@/object-record/record-group/types/RecordGroupDefinition';
|
||||
|
||||
export const recordBoardColumnsComponentFamilySelector =
|
||||
createComponentFamilySelector<RecordGroupDefinition | undefined, string>({
|
||||
key: 'recordBoardColumnsComponentFamilySelector',
|
||||
get:
|
||||
({
|
||||
scopeId,
|
||||
familyKey: columnId,
|
||||
}: {
|
||||
scopeId: string;
|
||||
familyKey: string;
|
||||
}) =>
|
||||
({ get }) => {
|
||||
return get(
|
||||
recordBoardColumnsComponentFamilyState({
|
||||
scopeId,
|
||||
familyKey: columnId,
|
||||
}),
|
||||
);
|
||||
},
|
||||
set:
|
||||
({
|
||||
scopeId,
|
||||
familyKey: columnId,
|
||||
}: {
|
||||
scopeId: string;
|
||||
familyKey: string;
|
||||
}) =>
|
||||
({ set }, newColumn) => {
|
||||
set(
|
||||
recordBoardColumnsComponentFamilyState({
|
||||
scopeId,
|
||||
familyKey: columnId,
|
||||
}),
|
||||
newColumn,
|
||||
);
|
||||
},
|
||||
});
|
@ -1,32 +1,24 @@
|
||||
import { RecordBoardComponentInstanceContext } from '@/object-record/record-board/states/contexts/RecordBoardComponentInstanceContext';
|
||||
import { isRecordBoardCardSelectedComponentFamilyState } from '@/object-record/record-board/states/isRecordBoardCardSelectedComponentFamilyState';
|
||||
import { recordBoardColumnIdsComponentState } from '@/object-record/record-board/states/recordBoardColumnIdsComponentState';
|
||||
import { recordBoardRecordIdsByColumnIdComponentFamilyState } from '@/object-record/record-board/states/recordBoardRecordIdsByColumnIdComponentFamilyState';
|
||||
import { createComponentReadOnlySelector } from '@/ui/utilities/state/component-state/utils/createComponentReadOnlySelector';
|
||||
import { recordIndexAllRowIdsComponentState } from '@/object-record/record-index/states/recordIndexAllRowIdsComponentState';
|
||||
import { createComponentSelectorV2 } from '@/ui/utilities/state/component-state/utils/createComponentSelectorV2';
|
||||
|
||||
export const recordBoardSelectedRecordIdsComponentSelector =
|
||||
createComponentReadOnlySelector<string[]>({
|
||||
createComponentSelectorV2<string[]>({
|
||||
key: 'recordBoardSelectedRecordIdsSelector',
|
||||
componentInstanceContext: RecordBoardComponentInstanceContext,
|
||||
get:
|
||||
({ scopeId }) =>
|
||||
({ instanceId }) =>
|
||||
({ get }) => {
|
||||
const columnIds = get(recordBoardColumnIdsComponentState({ scopeId }));
|
||||
|
||||
const recordIdsByColumn = columnIds.map((columnId) =>
|
||||
get(
|
||||
recordBoardRecordIdsByColumnIdComponentFamilyState({
|
||||
scopeId,
|
||||
familyKey: columnId,
|
||||
}),
|
||||
),
|
||||
const allRowIds = get(
|
||||
recordIndexAllRowIdsComponentState.atomFamily({ instanceId }),
|
||||
);
|
||||
|
||||
const recordIds = recordIdsByColumn.flat();
|
||||
|
||||
return recordIds.filter(
|
||||
return allRowIds.filter(
|
||||
(recordId) =>
|
||||
get(
|
||||
isRecordBoardCardSelectedComponentFamilyState({
|
||||
scopeId,
|
||||
isRecordBoardCardSelectedComponentFamilyState.atomFamily({
|
||||
instanceId,
|
||||
familyKey: recordId,
|
||||
}),
|
||||
) === true,
|
||||
|
@ -1,28 +0,0 @@
|
||||
import { recordBoardColumnIdsComponentState } from '@/object-record/record-board/states/recordBoardColumnIdsComponentState';
|
||||
import { recordBoardShouldFetchMoreInColumnComponentFamilyState } from '@/object-record/record-board/states/recordBoardShouldFetchMoreInColumnComponentFamilyState';
|
||||
import { createComponentReadOnlySelector } from '@/ui/utilities/state/component-state/utils/createComponentReadOnlySelector';
|
||||
|
||||
export const recordBoardShouldFetchMoreComponentSelector =
|
||||
createComponentReadOnlySelector<boolean>({
|
||||
key: 'recordBoardShouldFetchMoreComponentSelector',
|
||||
get:
|
||||
({ scopeId }: { scopeId: string }) =>
|
||||
({ get }) => {
|
||||
const columnIds = get(
|
||||
recordBoardColumnIdsComponentState({
|
||||
scopeId,
|
||||
}),
|
||||
);
|
||||
|
||||
const shouldFetchMoreInColumns = columnIds.map((columnId) => {
|
||||
return get(
|
||||
recordBoardShouldFetchMoreInColumnComponentFamilyState({
|
||||
scopeId,
|
||||
familyKey: columnId,
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
return shouldFetchMoreInColumns.some(Boolean);
|
||||
},
|
||||
});
|
@ -1,13 +1,17 @@
|
||||
import { RecordBoardComponentInstanceContext } from '@/object-record/record-board/states/contexts/RecordBoardComponentInstanceContext';
|
||||
import { recordBoardFieldDefinitionsComponentState } from '@/object-record/record-board/states/recordBoardFieldDefinitionsComponentState';
|
||||
import { createComponentReadOnlySelector } from '@/ui/utilities/state/component-state/utils/createComponentReadOnlySelector';
|
||||
import { createComponentSelectorV2 } from '@/ui/utilities/state/component-state/utils/createComponentSelectorV2';
|
||||
|
||||
export const recordBoardVisibleFieldDefinitionsComponentSelector =
|
||||
createComponentReadOnlySelector({
|
||||
createComponentSelectorV2({
|
||||
key: 'recordBoardVisibleFieldDefinitionsComponentSelector',
|
||||
get:
|
||||
({ scopeId }) =>
|
||||
({ instanceId }) =>
|
||||
({ get }) =>
|
||||
get(recordBoardFieldDefinitionsComponentState({ scopeId }))
|
||||
get(
|
||||
recordBoardFieldDefinitionsComponentState.atomFamily({ instanceId }),
|
||||
)
|
||||
.filter((field) => field.isVisible)
|
||||
.sort((a, b) => a.position - b.position),
|
||||
componentInstanceContext: RecordBoardComponentInstanceContext,
|
||||
});
|
||||
|
@ -1,31 +1,45 @@
|
||||
import { IconEye, IconEyeOff, MenuItemDraggable, Tag } from 'twenty-ui';
|
||||
|
||||
import { recordGroupDefinitionFamilyState } from '@/object-record/record-group/states/recordGroupDefinitionFamilyState';
|
||||
import {
|
||||
RecordGroupDefinition,
|
||||
RecordGroupDefinitionType,
|
||||
} from '@/object-record/record-group/types/RecordGroupDefinition';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { isDefined } from '~/utils/isDefined';
|
||||
|
||||
type RecordGroupMenuItemDraggableProps = {
|
||||
recordGroup: RecordGroupDefinition;
|
||||
recordGroupId: string;
|
||||
showDragGrip?: boolean;
|
||||
isDraggable?: boolean;
|
||||
onVisibilityChange: (viewGroup: RecordGroupDefinition) => void;
|
||||
onVisibilityChange: (recordGroup: RecordGroupDefinition) => void;
|
||||
};
|
||||
|
||||
export const RecordGroupMenuItemDraggable = ({
|
||||
recordGroup,
|
||||
recordGroupId,
|
||||
showDragGrip,
|
||||
isDraggable,
|
||||
onVisibilityChange,
|
||||
}: RecordGroupMenuItemDraggableProps) => {
|
||||
const recordGroup = useRecoilValue(
|
||||
recordGroupDefinitionFamilyState(recordGroupId),
|
||||
);
|
||||
|
||||
if (!isDefined(recordGroup)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const isNoValue = recordGroup.type === RecordGroupDefinitionType.NoValue;
|
||||
|
||||
const getIconButtons = (recordGroup: RecordGroupDefinition) => {
|
||||
const iconButtons = [
|
||||
{
|
||||
Icon: recordGroup.isVisible ? IconEyeOff : IconEye,
|
||||
onClick: () => onVisibilityChange(recordGroup),
|
||||
onClick: () =>
|
||||
onVisibilityChange({
|
||||
...recordGroup,
|
||||
isVisible: !recordGroup.isVisible,
|
||||
}),
|
||||
},
|
||||
].filter(isDefined);
|
||||
|
||||
|
@ -13,17 +13,17 @@ import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/Drop
|
||||
import { StyledDropdownMenuSubheader } from '@/ui/layout/dropdown/components/StyledDropdownMenuSubheader';
|
||||
|
||||
type RecordGroupsVisibilityDropdownSectionProps = {
|
||||
recordGroups: RecordGroupDefinition[];
|
||||
recordGroupIds: string[];
|
||||
isDraggable: boolean;
|
||||
onDragEnd?: OnDragEndResponder;
|
||||
onVisibilityChange: (viewGroup: RecordGroupDefinition) => void;
|
||||
onVisibilityChange: (recordGroup: RecordGroupDefinition) => void;
|
||||
title: string;
|
||||
showSubheader?: boolean;
|
||||
showDragGrip: boolean;
|
||||
};
|
||||
|
||||
export const RecordGroupsVisibilityDropdownSection = ({
|
||||
recordGroups,
|
||||
recordGroupIds,
|
||||
isDraggable,
|
||||
onDragEnd,
|
||||
onVisibilityChange,
|
||||
@ -43,12 +43,13 @@ export const RecordGroupsVisibilityDropdownSection = ({
|
||||
<StyledDropdownMenuSubheader>{title}</StyledDropdownMenuSubheader>
|
||||
)}
|
||||
<DropdownMenuItemsContainer>
|
||||
{!!recordGroups.length && (
|
||||
{recordGroupIds.length > 0 && (
|
||||
<>
|
||||
{!isDraggable ? (
|
||||
recordGroups.map((recordGroup) => (
|
||||
recordGroupIds.map((recordGroupId) => (
|
||||
<RecordGroupMenuItemDraggable
|
||||
recordGroup={recordGroup}
|
||||
key={recordGroupId}
|
||||
recordGroupId={recordGroupId}
|
||||
onVisibilityChange={onVisibilityChange}
|
||||
showDragGrip={showDragGrip}
|
||||
isDraggable={isDraggable}
|
||||
@ -59,14 +60,14 @@ export const RecordGroupsVisibilityDropdownSection = ({
|
||||
onDragEnd={handleOnDrag}
|
||||
draggableItems={
|
||||
<>
|
||||
{recordGroups.map((recordGroup, index) => (
|
||||
{recordGroupIds.map((recordGroupId, index) => (
|
||||
<DraggableItem
|
||||
key={recordGroup.id}
|
||||
draggableId={recordGroup.id}
|
||||
key={recordGroupId}
|
||||
draggableId={recordGroupId}
|
||||
index={index + 1}
|
||||
itemComponent={
|
||||
<RecordGroupMenuItemDraggable
|
||||
recordGroup={recordGroup}
|
||||
recordGroupId={recordGroupId}
|
||||
onVisibilityChange={onVisibilityChange}
|
||||
showDragGrip={showDragGrip}
|
||||
isDraggable={isDraggable}
|
||||
|
@ -1,37 +1,14 @@
|
||||
import { RecordGroupContext } from '@/object-record/record-group/states/context/RecordGroupContext';
|
||||
import { hasRecordGroupDefinitionsComponentSelector } from '@/object-record/record-group/states/hasRecordGroupDefinitionsComponentSelector';
|
||||
import { recordGroupDefinitionsComponentState } from '@/object-record/record-group/states/recordGroupDefinitionsComponentState';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { useContext, useMemo } from 'react';
|
||||
import { recordGroupDefinitionFamilyState } from '@/object-record/record-group/states/recordGroupDefinitionFamilyState';
|
||||
import { useContext } from 'react';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
export const useCurrentRecordGroupDefinition = (recordTableId?: string) => {
|
||||
export const useCurrentRecordGroupDefinition = () => {
|
||||
const context = useContext(RecordGroupContext);
|
||||
|
||||
const hasRecordGroups = useRecoilComponentValueV2(
|
||||
hasRecordGroupDefinitionsComponentSelector,
|
||||
recordTableId,
|
||||
const recordGroupDefinition = useRecoilValue(
|
||||
recordGroupDefinitionFamilyState(context?.recordGroupId),
|
||||
);
|
||||
|
||||
const recordGroupDefinitions = useRecoilComponentValueV2(
|
||||
recordGroupDefinitionsComponentState,
|
||||
recordTableId,
|
||||
);
|
||||
|
||||
const recordGroupDefinition = useMemo(() => {
|
||||
if (!hasRecordGroups) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (!context) {
|
||||
throw new Error(
|
||||
'useCurrentRecordGroupDefinition must be used within a RecordGroupContextProvider.',
|
||||
);
|
||||
}
|
||||
|
||||
return recordGroupDefinitions.find(
|
||||
({ id }) => id === context.recordGroupId,
|
||||
);
|
||||
}, [context, hasRecordGroups, recordGroupDefinitions]);
|
||||
|
||||
return recordGroupDefinition;
|
||||
};
|
||||
|
@ -2,24 +2,18 @@ import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadata
|
||||
import { getFieldSlug } from '@/object-metadata/utils/getFieldSlug';
|
||||
import { getObjectSlug } from '@/object-metadata/utils/getObjectSlug';
|
||||
import { RecordBoardColumnContext } from '@/object-record/record-board/record-board-column/contexts/RecordBoardColumnContext';
|
||||
import { useRecordGroups } from '@/object-record/record-group/hooks/useRecordGroups';
|
||||
import { useRecordGroupVisibility } from '@/object-record/record-group/hooks/useRecordGroupVisibility';
|
||||
import { recordGroupFieldMetadataComponentState } from '@/object-record/record-group/states/recordGroupFieldMetadataComponentState';
|
||||
import { RecordGroupAction } from '@/object-record/record-group/types/RecordGroupActions';
|
||||
import { RecordIndexRootPropsContext } from '@/object-record/record-index/contexts/RecordIndexRootPropsContext';
|
||||
import { navigationMemorizedUrlState } from '@/ui/navigation/states/navigationMemorizedUrlState';
|
||||
import { ViewType } from '@/views/types/ViewType';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { useCallback, useContext, useMemo } from 'react';
|
||||
import { useLocation, useNavigate } from 'react-router-dom';
|
||||
import { useSetRecoilState } from 'recoil';
|
||||
import { IconEyeOff, IconSettings, isDefined } from 'twenty-ui';
|
||||
|
||||
type UseRecordGroupActionsParams = {
|
||||
viewType: ViewType;
|
||||
};
|
||||
|
||||
export const useRecordGroupActions = ({
|
||||
viewType,
|
||||
}: UseRecordGroupActionsParams) => {
|
||||
export const useRecordGroupActions = () => {
|
||||
const navigate = useNavigate();
|
||||
const location = useLocation();
|
||||
|
||||
@ -35,14 +29,13 @@ export const useRecordGroupActions = ({
|
||||
objectNameSingular,
|
||||
});
|
||||
|
||||
const { viewGroupFieldMetadataItem } = useRecordGroups({
|
||||
objectNameSingular,
|
||||
});
|
||||
const recordGroupFieldMetadata = useRecoilComponentValueV2(
|
||||
recordGroupFieldMetadataComponentState,
|
||||
);
|
||||
|
||||
const { handleVisibilityChange: handleRecordGroupVisibilityChange } =
|
||||
useRecordGroupVisibility({
|
||||
viewBarId: recordIndexId,
|
||||
viewType,
|
||||
});
|
||||
|
||||
const setNavigationMemorizedUrl = useSetRecoilState(
|
||||
@ -52,11 +45,11 @@ export const useRecordGroupActions = ({
|
||||
const navigateToSelectSettings = useCallback(() => {
|
||||
setNavigationMemorizedUrl(location.pathname + location.search);
|
||||
|
||||
if (!isDefined(viewGroupFieldMetadataItem)) {
|
||||
throw new Error('viewGroupFieldMetadataItem is not a non-empty string');
|
||||
if (!isDefined(recordGroupFieldMetadata)) {
|
||||
throw new Error('recordGroupFieldMetadata is not a non-empty string');
|
||||
}
|
||||
|
||||
const settingsPath = `/settings/objects/${getObjectSlug(objectMetadataItem)}/${getFieldSlug(viewGroupFieldMetadataItem)}`;
|
||||
const settingsPath = `/settings/objects/${getObjectSlug(objectMetadataItem)}/${getFieldSlug(recordGroupFieldMetadata)}`;
|
||||
|
||||
navigate(settingsPath);
|
||||
}, [
|
||||
@ -65,7 +58,7 @@ export const useRecordGroupActions = ({
|
||||
location.search,
|
||||
navigate,
|
||||
objectMetadataItem,
|
||||
viewGroupFieldMetadataItem,
|
||||
recordGroupFieldMetadata,
|
||||
]);
|
||||
|
||||
const recordGroupActions: RecordGroupAction[] = useMemo(
|
||||
|
@ -1,59 +1,89 @@
|
||||
import { OnDragEndResponder } from '@hello-pangea/dnd';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import { useRecordGroups } from '@/object-record/record-group/hooks/useRecordGroups';
|
||||
import { recordGroupDefinitionsComponentState } from '@/object-record/record-group/states/recordGroupDefinitionsComponentState';
|
||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||
import { useSetRecordGroup } from '@/object-record/record-group/hooks/useSetRecordGroup';
|
||||
import { recordGroupDefinitionFamilyState } from '@/object-record/record-group/states/recordGroupDefinitionFamilyState';
|
||||
import { visibleRecordGroupIdsComponentSelector } from '@/object-record/record-group/states/selectors/visibleRecordGroupIdsComponentSelector';
|
||||
import { RecordGroupDefinition } from '@/object-record/record-group/types/RecordGroupDefinition';
|
||||
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
||||
import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue';
|
||||
import { useSaveCurrentViewGroups } from '@/views/hooks/useSaveCurrentViewGroups';
|
||||
import { mapRecordGroupDefinitionsToViewGroups } from '@/views/utils/mapRecordGroupDefinitionsToViewGroups';
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
import { moveArrayItem } from '~/utils/array/moveArrayItem';
|
||||
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
|
||||
import { isDefined } from '~/utils/isDefined';
|
||||
|
||||
type UseRecordGroupHandlersParams = {
|
||||
objectNameSingular: string;
|
||||
viewBarId: string;
|
||||
};
|
||||
|
||||
export const useRecordGroupReorder = ({
|
||||
objectNameSingular,
|
||||
viewBarId,
|
||||
}: UseRecordGroupHandlersParams) => {
|
||||
const setRecordGroupDefinitions = useSetRecoilComponentStateV2(
|
||||
recordGroupDefinitionsComponentState,
|
||||
);
|
||||
const setRecordGroup = useSetRecordGroup(viewBarId);
|
||||
|
||||
const { visibleRecordGroups } = useRecordGroups({
|
||||
objectNameSingular: objectNameSingular,
|
||||
});
|
||||
const visibleRecordGroupIdsSelector = useRecoilComponentCallbackStateV2(
|
||||
visibleRecordGroupIdsComponentSelector,
|
||||
);
|
||||
|
||||
const { saveViewGroups } = useSaveCurrentViewGroups(viewBarId);
|
||||
|
||||
const handleOrderChange: OnDragEndResponder = useCallback(
|
||||
(result) => {
|
||||
if (!result.destination) {
|
||||
return;
|
||||
}
|
||||
const handleOrderChange: OnDragEndResponder = useRecoilCallback(
|
||||
({ snapshot }) =>
|
||||
(result) => {
|
||||
if (!result.destination) {
|
||||
return;
|
||||
}
|
||||
|
||||
const reorderedVisibleBoardGroups = moveArrayItem(visibleRecordGroups, {
|
||||
fromIndex: result.source.index - 1,
|
||||
toIndex: result.destination.index - 1,
|
||||
});
|
||||
const visibleRecordGroupIds = getSnapshotValue(
|
||||
snapshot,
|
||||
visibleRecordGroupIdsSelector,
|
||||
);
|
||||
|
||||
if (isDeeplyEqual(visibleRecordGroups, reorderedVisibleBoardGroups))
|
||||
return;
|
||||
const reorderedVisibleRecordGroupIds = moveArrayItem(
|
||||
visibleRecordGroupIds,
|
||||
{
|
||||
fromIndex: result.source.index - 1,
|
||||
toIndex: result.destination.index - 1,
|
||||
},
|
||||
);
|
||||
|
||||
const updatedGroups = [...reorderedVisibleBoardGroups].map(
|
||||
(group, index) => ({ ...group, position: index }),
|
||||
);
|
||||
if (
|
||||
isDeeplyEqual(visibleRecordGroupIds, reorderedVisibleRecordGroupIds)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
setRecordGroupDefinitions(updatedGroups);
|
||||
saveViewGroups(mapRecordGroupDefinitionsToViewGroups(updatedGroups));
|
||||
},
|
||||
[saveViewGroups, setRecordGroupDefinitions, visibleRecordGroups],
|
||||
const updatedRecordGroups = reorderedVisibleRecordGroupIds.reduce<
|
||||
RecordGroupDefinition[]
|
||||
>((acc, recordGroupId, index) => {
|
||||
const recordGroupDefinition = getSnapshotValue(
|
||||
snapshot,
|
||||
recordGroupDefinitionFamilyState(recordGroupId),
|
||||
);
|
||||
|
||||
if (!isDefined(recordGroupDefinition)) {
|
||||
return acc;
|
||||
}
|
||||
|
||||
return [
|
||||
...acc,
|
||||
{
|
||||
...recordGroupDefinition,
|
||||
position: index,
|
||||
},
|
||||
];
|
||||
}, []);
|
||||
|
||||
setRecordGroup(updatedRecordGroups);
|
||||
saveViewGroups(
|
||||
mapRecordGroupDefinitionsToViewGroups(updatedRecordGroups),
|
||||
);
|
||||
},
|
||||
[saveViewGroups, setRecordGroup, visibleRecordGroupIdsSelector],
|
||||
);
|
||||
|
||||
return {
|
||||
visibleRecordGroups,
|
||||
handleOrderChange,
|
||||
};
|
||||
};
|
||||
|
@ -1,125 +1,113 @@
|
||||
import { useRecordBoardStates } from '@/object-record/record-board/hooks/internal/useRecordBoardStates';
|
||||
import { recordGroupDefinitionsComponentState } from '@/object-record/record-group/states/recordGroupDefinitionsComponentState';
|
||||
import { recordGroupDefinitionFamilyState } from '@/object-record/record-group/states/recordGroupDefinitionFamilyState';
|
||||
import { recordGroupIdsComponentState } from '@/object-record/record-group/states/recordGroupIdsComponentState';
|
||||
import { RecordGroupDefinition } from '@/object-record/record-group/types/RecordGroupDefinition';
|
||||
import { recordIndexRecordGroupHideComponentState } from '@/object-record/record-index/states/recordIndexRecordGroupHideComponentState';
|
||||
import { tableRowIdsByGroupComponentFamilyState } from '@/object-record/record-table/states/tableRowIdsByGroupComponentFamilyState';
|
||||
import { recordIndexRowIdsByGroupComponentFamilyState } from '@/object-record/record-index/states/recordIndexRowIdsByGroupComponentFamilyState';
|
||||
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
||||
import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue';
|
||||
import { useSaveCurrentViewGroups } from '@/views/hooks/useSaveCurrentViewGroups';
|
||||
import { ViewType } from '@/views/types/ViewType';
|
||||
import { mapRecordGroupDefinitionsToViewGroups } from '@/views/utils/mapRecordGroupDefinitionsToViewGroups';
|
||||
import { recordGroupDefinitionToViewGroup } from '@/views/utils/recordGroupDefinitionToViewGroup';
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
import { isDefined } from '~/utils/isDefined';
|
||||
|
||||
type UseRecordGroupVisibilityParams = {
|
||||
viewBarId: string;
|
||||
viewType: ViewType;
|
||||
};
|
||||
|
||||
export const useRecordGroupVisibility = ({
|
||||
viewBarId,
|
||||
viewType,
|
||||
}: UseRecordGroupVisibilityParams) => {
|
||||
const recordGroupDefinitionsState = useRecoilComponentCallbackStateV2(
|
||||
recordGroupDefinitionsComponentState,
|
||||
const recordIndexRecordGroupIdsState = useRecoilComponentCallbackStateV2(
|
||||
recordGroupIdsComponentState,
|
||||
);
|
||||
|
||||
const tableRowIdsByGroupFamilyState = useRecoilComponentCallbackStateV2(
|
||||
tableRowIdsByGroupComponentFamilyState,
|
||||
const recordIndexRowIdsByGroupFamilyState = useRecoilComponentCallbackStateV2(
|
||||
recordIndexRowIdsByGroupComponentFamilyState,
|
||||
viewBarId,
|
||||
);
|
||||
|
||||
const { recordIdsByColumnIdFamilyState } = useRecordBoardStates(viewBarId);
|
||||
|
||||
const objectOptionsDropdownRecordGroupHideState =
|
||||
useRecoilComponentCallbackStateV2(recordIndexRecordGroupHideComponentState);
|
||||
|
||||
const { saveViewGroups } = useSaveCurrentViewGroups(viewBarId);
|
||||
const { saveViewGroup, saveViewGroups } = useSaveCurrentViewGroups(viewBarId);
|
||||
|
||||
const handleVisibilityChange = useRecoilCallback(
|
||||
({ snapshot, set }) =>
|
||||
async (updatedRecordGroupDefinition: RecordGroupDefinition) => {
|
||||
const recordGroupDefinitions = getSnapshotValue(
|
||||
snapshot,
|
||||
recordGroupDefinitionsState,
|
||||
({ set }) =>
|
||||
async (updatedRecordGroup: RecordGroupDefinition) => {
|
||||
set(
|
||||
recordGroupDefinitionFamilyState(updatedRecordGroup.id),
|
||||
updatedRecordGroup,
|
||||
);
|
||||
|
||||
const updatedRecordGroupDefinitions = recordGroupDefinitions.map(
|
||||
(groupDefinition) =>
|
||||
groupDefinition.id === updatedRecordGroupDefinition.id
|
||||
? {
|
||||
...groupDefinition,
|
||||
isVisible: !groupDefinition.isVisible,
|
||||
}
|
||||
: groupDefinition,
|
||||
);
|
||||
|
||||
set(recordGroupDefinitionsState, updatedRecordGroupDefinitions);
|
||||
|
||||
saveViewGroups(
|
||||
mapRecordGroupDefinitionsToViewGroups(updatedRecordGroupDefinitions),
|
||||
);
|
||||
saveViewGroup(recordGroupDefinitionToViewGroup(updatedRecordGroup));
|
||||
|
||||
// If visibility is manually toggled, we should reset the hideEmptyRecordGroup state
|
||||
set(objectOptionsDropdownRecordGroupHideState, false);
|
||||
},
|
||||
[
|
||||
objectOptionsDropdownRecordGroupHideState,
|
||||
recordGroupDefinitionsState,
|
||||
saveViewGroups,
|
||||
],
|
||||
[saveViewGroup, objectOptionsDropdownRecordGroupHideState],
|
||||
);
|
||||
|
||||
const handleHideEmptyRecordGroupChange = useRecoilCallback(
|
||||
({ snapshot, set }) =>
|
||||
async () => {
|
||||
const recordGroupDefinitions = getSnapshotValue(
|
||||
const updatedRecordGroupDefinitions: RecordGroupDefinition[] = [];
|
||||
const recordGroupIds = getSnapshotValue(
|
||||
snapshot,
|
||||
recordGroupDefinitionsState,
|
||||
recordIndexRecordGroupIdsState,
|
||||
);
|
||||
|
||||
const currentHideState = getSnapshotValue(
|
||||
snapshot,
|
||||
objectOptionsDropdownRecordGroupHideState,
|
||||
);
|
||||
const newHideState = !currentHideState;
|
||||
|
||||
set(objectOptionsDropdownRecordGroupHideState, !currentHideState);
|
||||
set(objectOptionsDropdownRecordGroupHideState, newHideState);
|
||||
|
||||
const updatedRecordGroupDefinitions = recordGroupDefinitions.map(
|
||||
(recordGroup) => {
|
||||
// TODO: Maybe we can improve that and only use one state for both table and board
|
||||
const recordGroupRowIds =
|
||||
viewType === ViewType.Table
|
||||
? getSnapshotValue(
|
||||
snapshot,
|
||||
tableRowIdsByGroupFamilyState(recordGroup.id),
|
||||
)
|
||||
: getSnapshotValue(
|
||||
snapshot,
|
||||
recordIdsByColumnIdFamilyState(recordGroup.id),
|
||||
);
|
||||
for (const recordGroupId of recordGroupIds) {
|
||||
const recordGroup = getSnapshotValue(
|
||||
snapshot,
|
||||
recordGroupDefinitionFamilyState(recordGroupId),
|
||||
);
|
||||
|
||||
if (recordGroupRowIds.length > 0) {
|
||||
return recordGroup;
|
||||
}
|
||||
if (!isDefined(recordGroup)) {
|
||||
throw new Error(
|
||||
`Record group with id ${recordGroupId} not found in snapshot`,
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
...recordGroup,
|
||||
isVisible: currentHideState,
|
||||
};
|
||||
},
|
||||
);
|
||||
const recordGroupRowIds = getSnapshotValue(
|
||||
snapshot,
|
||||
recordIndexRowIdsByGroupFamilyState(recordGroupId),
|
||||
);
|
||||
|
||||
if (recordGroupRowIds.length > 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const updatedRecordGroup = {
|
||||
...recordGroup,
|
||||
isVisible: !newHideState,
|
||||
};
|
||||
|
||||
set(
|
||||
recordGroupDefinitionFamilyState(recordGroupId),
|
||||
updatedRecordGroup,
|
||||
);
|
||||
|
||||
updatedRecordGroupDefinitions.push(updatedRecordGroup);
|
||||
}
|
||||
|
||||
saveViewGroups(
|
||||
mapRecordGroupDefinitionsToViewGroups(updatedRecordGroupDefinitions),
|
||||
);
|
||||
},
|
||||
[
|
||||
recordGroupDefinitionsState,
|
||||
recordIndexRecordGroupIdsState,
|
||||
objectOptionsDropdownRecordGroupHideState,
|
||||
saveViewGroups,
|
||||
viewType,
|
||||
tableRowIdsByGroupFamilyState,
|
||||
recordIdsByColumnIdFamilyState,
|
||||
recordIndexRowIdsByGroupFamilyState,
|
||||
],
|
||||
);
|
||||
|
||||
|
@ -1,58 +0,0 @@
|
||||
import { useMemo } from 'react';
|
||||
|
||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||
import { recordGroupDefinitionsComponentState } from '@/object-record/record-group/states/recordGroupDefinitionsComponentState';
|
||||
import { sortRecordGroupDefinitions } from '@/object-record/record-group/utils/sortRecordGroupDefinitions';
|
||||
import { recordIndexRecordGroupSortComponentState } from '@/object-record/record-index/states/recordIndexRecordGroupSortComponentState';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
|
||||
type UseRecordGroupsParams = {
|
||||
objectNameSingular: string;
|
||||
};
|
||||
|
||||
export const useRecordGroups = ({
|
||||
objectNameSingular,
|
||||
}: UseRecordGroupsParams) => {
|
||||
const recordGroupDefinitions = useRecoilComponentValueV2(
|
||||
recordGroupDefinitionsComponentState,
|
||||
);
|
||||
|
||||
const recordGroupSort = useRecoilComponentValueV2(
|
||||
recordIndexRecordGroupSortComponentState,
|
||||
);
|
||||
|
||||
const { objectMetadataItem } = useObjectMetadataItem({
|
||||
objectNameSingular,
|
||||
});
|
||||
|
||||
const viewGroupFieldMetadataItem = useMemo(() => {
|
||||
if (recordGroupDefinitions.length === 0) return null;
|
||||
// We're assuming that all groups have the same fieldMetadataId for now
|
||||
const fieldMetadataId =
|
||||
'fieldMetadataId' in recordGroupDefinitions[0]
|
||||
? recordGroupDefinitions[0].fieldMetadataId
|
||||
: null;
|
||||
|
||||
if (!fieldMetadataId) return null;
|
||||
|
||||
return objectMetadataItem.fields.find(
|
||||
(field) => field.id === fieldMetadataId,
|
||||
);
|
||||
}, [objectMetadataItem, recordGroupDefinitions]);
|
||||
|
||||
const visibleRecordGroups = useMemo(
|
||||
() => sortRecordGroupDefinitions(recordGroupDefinitions, recordGroupSort),
|
||||
[recordGroupDefinitions, recordGroupSort],
|
||||
);
|
||||
|
||||
const hiddenRecordGroups = useMemo(
|
||||
() => recordGroupDefinitions.filter((boardGroup) => !boardGroup.isVisible),
|
||||
[recordGroupDefinitions],
|
||||
);
|
||||
|
||||
return {
|
||||
hiddenRecordGroups,
|
||||
visibleRecordGroups,
|
||||
viewGroupFieldMetadataItem,
|
||||
};
|
||||
};
|
@ -0,0 +1,83 @@
|
||||
import { recordGroupDefinitionFamilyState } from '@/object-record/record-group/states/recordGroupDefinitionFamilyState';
|
||||
import { recordGroupFieldMetadataComponentState } from '@/object-record/record-group/states/recordGroupFieldMetadataComponentState';
|
||||
import { recordGroupIdsComponentState } from '@/object-record/record-group/states/recordGroupIdsComponentState';
|
||||
import { RecordGroupDefinition } from '@/object-record/record-group/types/RecordGroupDefinition';
|
||||
import { RecordIndexRootPropsContext } from '@/object-record/record-index/contexts/RecordIndexRootPropsContext';
|
||||
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
||||
import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue';
|
||||
import { useContext } from 'react';
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
|
||||
import { isDefined } from '~/utils/isDefined';
|
||||
|
||||
export const useSetRecordGroup = (viewId?: string) => {
|
||||
const { objectMetadataItem } = useContext(RecordIndexRootPropsContext);
|
||||
|
||||
const recordIndexRecordGroupIdsState = useRecoilComponentCallbackStateV2(
|
||||
recordGroupIdsComponentState,
|
||||
viewId,
|
||||
);
|
||||
|
||||
const recordGroupFieldMetadataState = useRecoilComponentCallbackStateV2(
|
||||
recordGroupFieldMetadataComponentState,
|
||||
viewId,
|
||||
);
|
||||
|
||||
return useRecoilCallback(
|
||||
({ snapshot, set }) =>
|
||||
(recordGroups: RecordGroupDefinition[]) => {
|
||||
if (recordGroups.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const currentRecordGroupId = getSnapshotValue(
|
||||
snapshot,
|
||||
recordIndexRecordGroupIdsState,
|
||||
);
|
||||
const fieldMetadataId = recordGroups[0].fieldMetadataId;
|
||||
const fieldMetadata = objectMetadataItem.fields.find(
|
||||
(field) => field.id === fieldMetadataId,
|
||||
);
|
||||
const currentFieldMetadata = getSnapshotValue(
|
||||
snapshot,
|
||||
recordGroupFieldMetadataState,
|
||||
);
|
||||
|
||||
// Set the field metadata linked to the record groups
|
||||
if (
|
||||
isDefined(fieldMetadata) &&
|
||||
!isDeeplyEqual(fieldMetadata, currentFieldMetadata)
|
||||
) {
|
||||
set(recordGroupFieldMetadataState, fieldMetadata);
|
||||
}
|
||||
|
||||
// Set the record groups by id
|
||||
recordGroups.forEach((recordGroup) => {
|
||||
const existingRecordGroup = getSnapshotValue(
|
||||
snapshot,
|
||||
recordGroupDefinitionFamilyState(recordGroup.id),
|
||||
);
|
||||
|
||||
if (isDeeplyEqual(existingRecordGroup, recordGroup)) {
|
||||
return;
|
||||
}
|
||||
|
||||
set(recordGroupDefinitionFamilyState(recordGroup.id), recordGroup);
|
||||
});
|
||||
|
||||
const recordGroupIds = recordGroups.map(({ id }) => id);
|
||||
|
||||
if (isDeeplyEqual(currentRecordGroupId, recordGroupIds)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the record group ids
|
||||
set(recordIndexRecordGroupIdsState, recordGroupIds);
|
||||
},
|
||||
[
|
||||
objectMetadataItem.fields,
|
||||
recordGroupFieldMetadataState,
|
||||
recordIndexRecordGroupIdsState,
|
||||
],
|
||||
);
|
||||
};
|
@ -0,0 +1,10 @@
|
||||
import { RecordGroupDefinition } from '@/object-record/record-group/types/RecordGroupDefinition';
|
||||
import { atomFamily } from 'recoil';
|
||||
|
||||
export const recordGroupDefinitionFamilyState = atomFamily<
|
||||
RecordGroupDefinition | undefined,
|
||||
RecordGroupDefinition['id']
|
||||
>({
|
||||
key: 'recordGroupDefinitionFamilyState',
|
||||
default: undefined,
|
||||
});
|
@ -0,0 +1,11 @@
|
||||
import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
|
||||
import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2';
|
||||
import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext';
|
||||
|
||||
export const recordGroupFieldMetadataComponentState = createComponentStateV2<
|
||||
FieldMetadataItem | undefined
|
||||
>({
|
||||
key: 'recordGroupFieldMetadataComponentState',
|
||||
defaultValue: undefined,
|
||||
componentInstanceContext: ViewComponentInstanceContext,
|
||||
});
|
@ -2,10 +2,10 @@ import { RecordGroupDefinition } from '@/object-record/record-group/types/Record
|
||||
import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2';
|
||||
import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext';
|
||||
|
||||
export const recordGroupDefinitionsComponentState = createComponentStateV2<
|
||||
RecordGroupDefinition[]
|
||||
export const recordGroupIdsComponentState = createComponentStateV2<
|
||||
RecordGroupDefinition['id'][]
|
||||
>({
|
||||
key: 'recordGroupDefinitionsComponentState',
|
||||
key: 'recordGroupIdsComponentState',
|
||||
defaultValue: [],
|
||||
componentInstanceContext: ViewComponentInstanceContext,
|
||||
});
|
@ -1,21 +1,21 @@
|
||||
import { recordGroupDefinitionsComponentState } from '@/object-record/record-group/states/recordGroupDefinitionsComponentState';
|
||||
import { recordGroupIdsComponentState } from '@/object-record/record-group/states/recordGroupIdsComponentState';
|
||||
|
||||
import { createComponentSelectorV2 } from '@/ui/utilities/state/component-state/utils/createComponentSelectorV2';
|
||||
import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext';
|
||||
|
||||
export const hasRecordGroupDefinitionsComponentSelector =
|
||||
export const hasRecordGroupsComponentSelector =
|
||||
createComponentSelectorV2<boolean>({
|
||||
key: 'hasRecordGroupDefinitionsComponentSelector',
|
||||
key: 'hasRecordGroupsComponentSelector',
|
||||
componentInstanceContext: ViewComponentInstanceContext,
|
||||
get:
|
||||
({ instanceId }) =>
|
||||
({ get }) => {
|
||||
const recordGroupDefinitions = get(
|
||||
recordGroupDefinitionsComponentState.atomFamily({
|
||||
const recordGroupIds = get(
|
||||
recordGroupIdsComponentState.atomFamily({
|
||||
instanceId,
|
||||
}),
|
||||
);
|
||||
|
||||
return recordGroupDefinitions.length > 0;
|
||||
return recordGroupIds.length > 0;
|
||||
},
|
||||
});
|
@ -0,0 +1,34 @@
|
||||
import { recordGroupDefinitionFamilyState } from '@/object-record/record-group/states/recordGroupDefinitionFamilyState';
|
||||
import { recordGroupIdsComponentState } from '@/object-record/record-group/states/recordGroupIdsComponentState';
|
||||
|
||||
import { createComponentSelectorV2 } from '@/ui/utilities/state/component-state/utils/createComponentSelectorV2';
|
||||
import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext';
|
||||
import { isDefined } from '~/utils/isDefined';
|
||||
|
||||
export const hiddenRecordGroupIdsComponentSelector = createComponentSelectorV2<
|
||||
string[]
|
||||
>({
|
||||
key: 'hiddenRecordGroupIdsComponentSelector',
|
||||
componentInstanceContext: ViewComponentInstanceContext,
|
||||
get:
|
||||
({ instanceId }) =>
|
||||
({ get }) => {
|
||||
const recordGroupIds = get(
|
||||
recordGroupIdsComponentState.atomFamily({
|
||||
instanceId,
|
||||
}),
|
||||
);
|
||||
|
||||
return recordGroupIds.filter((recordGroupId) => {
|
||||
const recordGroupDefinition = get(
|
||||
recordGroupDefinitionFamilyState(recordGroupId),
|
||||
);
|
||||
|
||||
if (!isDefined(recordGroupDefinition)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return !recordGroupDefinition.isVisible;
|
||||
});
|
||||
},
|
||||
});
|
@ -0,0 +1,37 @@
|
||||
import { recordGroupDefinitionFamilyState } from '@/object-record/record-group/states/recordGroupDefinitionFamilyState';
|
||||
import { recordGroupIdsComponentState } from '@/object-record/record-group/states/recordGroupIdsComponentState';
|
||||
import { RecordGroupDefinition } from '@/object-record/record-group/types/RecordGroupDefinition';
|
||||
|
||||
import { createComponentSelectorV2 } from '@/ui/utilities/state/component-state/utils/createComponentSelectorV2';
|
||||
import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext';
|
||||
import { isDefined } from '~/utils/isDefined';
|
||||
|
||||
export const recordGroupDefinitionsComponentSelector =
|
||||
createComponentSelectorV2<RecordGroupDefinition[]>({
|
||||
key: 'recordGroupDefinitionsComponentSelector',
|
||||
componentInstanceContext: ViewComponentInstanceContext,
|
||||
get:
|
||||
({ instanceId }) =>
|
||||
({ get }) => {
|
||||
const recordGroupIds = get(
|
||||
recordGroupIdsComponentState.atomFamily({
|
||||
instanceId,
|
||||
}),
|
||||
);
|
||||
|
||||
return recordGroupIds.reduce<RecordGroupDefinition[]>(
|
||||
(acc, recordGroupId) => {
|
||||
const recordGroupDefinition = get(
|
||||
recordGroupDefinitionFamilyState(recordGroupId),
|
||||
);
|
||||
|
||||
if (!isDefined(recordGroupDefinition)) {
|
||||
return acc;
|
||||
}
|
||||
|
||||
return [...acc, recordGroupDefinition];
|
||||
},
|
||||
[],
|
||||
);
|
||||
},
|
||||
});
|
@ -0,0 +1,63 @@
|
||||
import { recordGroupDefinitionFamilyState } from '@/object-record/record-group/states/recordGroupDefinitionFamilyState';
|
||||
import { recordGroupIdsComponentState } from '@/object-record/record-group/states/recordGroupIdsComponentState';
|
||||
import { RecordGroupDefinition } from '@/object-record/record-group/types/RecordGroupDefinition';
|
||||
import { RecordGroupSort } from '@/object-record/record-group/types/RecordGroupSort';
|
||||
import { sortedInsert } from '@/object-record/record-group/utils/sortedInsert';
|
||||
import { recordIndexRecordGroupSortComponentState } from '@/object-record/record-index/states/recordIndexRecordGroupSortComponentState';
|
||||
|
||||
import { createComponentSelectorV2 } from '@/ui/utilities/state/component-state/utils/createComponentSelectorV2';
|
||||
import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext';
|
||||
import { isDefined } from '~/utils/isDefined';
|
||||
|
||||
export const visibleRecordGroupIdsComponentSelector = createComponentSelectorV2<
|
||||
string[]
|
||||
>({
|
||||
key: 'visibleRecordGroupIdsComponentSelector',
|
||||
componentInstanceContext: ViewComponentInstanceContext,
|
||||
get:
|
||||
({ instanceId }) =>
|
||||
({ get }) => {
|
||||
const recordGroupSort = get(
|
||||
recordIndexRecordGroupSortComponentState.atomFamily({
|
||||
instanceId,
|
||||
}),
|
||||
);
|
||||
const recordGroupIds = get(
|
||||
recordGroupIdsComponentState.atomFamily({
|
||||
instanceId,
|
||||
}),
|
||||
);
|
||||
|
||||
const result: RecordGroupDefinition[] = [];
|
||||
|
||||
const comparator = (
|
||||
a: RecordGroupDefinition,
|
||||
b: RecordGroupDefinition,
|
||||
) => {
|
||||
switch (recordGroupSort) {
|
||||
case RecordGroupSort.Alphabetical:
|
||||
return a.title.localeCompare(b.title);
|
||||
case RecordGroupSort.ReverseAlphabetical:
|
||||
return b.title.localeCompare(a.title);
|
||||
case RecordGroupSort.Manual:
|
||||
default:
|
||||
return a.position - b.position;
|
||||
}
|
||||
};
|
||||
|
||||
for (const recordGroupId of recordGroupIds) {
|
||||
const recordGroupDefinition = get(
|
||||
recordGroupDefinitionFamilyState(recordGroupId),
|
||||
);
|
||||
|
||||
if (
|
||||
isDefined(recordGroupDefinition) &&
|
||||
recordGroupDefinition.isVisible
|
||||
) {
|
||||
sortedInsert(result, recordGroupDefinition, comparator);
|
||||
}
|
||||
}
|
||||
|
||||
return result.map(({ id }) => id);
|
||||
},
|
||||
});
|
@ -5,7 +5,7 @@ export const sortRecordGroupDefinitions = (
|
||||
recordGroupDefinitions: RecordGroupDefinition[],
|
||||
recordGroupSort: RecordGroupSort,
|
||||
) => {
|
||||
const visibleGroups = recordGroupDefinitions.filter(
|
||||
const visibleRecordGroups = recordGroupDefinitions.filter(
|
||||
(boardGroup) => boardGroup.isVisible,
|
||||
);
|
||||
|
||||
@ -17,15 +17,15 @@ export const sortRecordGroupDefinitions = (
|
||||
|
||||
switch (recordGroupSort) {
|
||||
case RecordGroupSort.Alphabetical:
|
||||
return visibleGroups.sort((a, b) =>
|
||||
return visibleRecordGroups.sort((a, b) =>
|
||||
compareAlphabetical(a.title.toLowerCase(), b.title.toLowerCase()),
|
||||
);
|
||||
case RecordGroupSort.ReverseAlphabetical:
|
||||
return visibleGroups.sort((a, b) =>
|
||||
return visibleRecordGroups.sort((a, b) =>
|
||||
compareAlphabetical(a.title.toLowerCase(), b.title.toLowerCase(), true),
|
||||
);
|
||||
case RecordGroupSort.Manual:
|
||||
default:
|
||||
return visibleGroups.sort((a, b) => a.position - b.position);
|
||||
return visibleRecordGroups.sort((a, b) => a.position - b.position);
|
||||
}
|
||||
};
|
||||
|
@ -0,0 +1,20 @@
|
||||
export const sortedInsert = <T>(
|
||||
array: T[],
|
||||
item: T,
|
||||
comparator: (a: T, b: T) => number,
|
||||
) => {
|
||||
let low = 0;
|
||||
let high = array.length;
|
||||
|
||||
while (low < high) {
|
||||
const mid = Math.floor((low + high) / 2);
|
||||
|
||||
if (comparator(item, array[mid]) < 0) {
|
||||
high = mid;
|
||||
} else {
|
||||
low = mid + 1;
|
||||
}
|
||||
}
|
||||
|
||||
array.splice(low, 0, item);
|
||||
};
|
@ -5,7 +5,7 @@ import { isRecordBoardFetchingRecordsByColumnFamilyState } from '@/object-record
|
||||
import { recordBoardShouldFetchMoreInColumnComponentFamilyState } from '@/object-record/record-board/states/recordBoardShouldFetchMoreInColumnComponentFamilyState';
|
||||
import { useLoadRecordIndexBoardColumn } from '@/object-record/record-index/hooks/useLoadRecordIndexBoardColumn';
|
||||
import { isRecordIndexBoardColumnLoadingFamilyState } from '@/object-record/states/isRecordBoardColumnLoadingFamilyState';
|
||||
import { getScopeIdFromComponentId } from '@/ui/utilities/recoil-scope/utils/getScopeIdFromComponentId';
|
||||
import { useRecoilComponentFamilyStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyStateV2';
|
||||
|
||||
export const RecordIndexBoardColumnLoaderEffect = ({
|
||||
objectNameSingular,
|
||||
@ -18,20 +18,14 @@ export const RecordIndexBoardColumnLoaderEffect = ({
|
||||
boardFieldMetadataId: string | null;
|
||||
columnId: string;
|
||||
}) => {
|
||||
const [shouldFetchMore, setShouldFetchMore] = useRecoilState(
|
||||
recordBoardShouldFetchMoreInColumnComponentFamilyState({
|
||||
scopeId: getScopeIdFromComponentId(recordBoardId),
|
||||
familyKey: columnId,
|
||||
}),
|
||||
const [shouldFetchMore, setShouldFetchMore] = useRecoilComponentFamilyStateV2(
|
||||
recordBoardShouldFetchMoreInColumnComponentFamilyState,
|
||||
columnId,
|
||||
recordBoardId,
|
||||
);
|
||||
|
||||
const [loadingRecordsForThisColumn, setLoadingRecordsForThisColumn] =
|
||||
useRecoilState(
|
||||
isRecordBoardFetchingRecordsByColumnFamilyState({
|
||||
scopeId: getScopeIdFromComponentId(recordBoardId),
|
||||
familyKey: { columnId },
|
||||
}),
|
||||
);
|
||||
useRecoilState(isRecordBoardFetchingRecordsByColumnFamilyState(columnId));
|
||||
|
||||
const { fetchMoreRecords, loading, records, hasNextPage } =
|
||||
useLoadRecordIndexBoardColumn({
|
||||
|
@ -1,9 +1,10 @@
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||
import { useRecordBoardStates } from '@/object-record/record-board/hooks/internal/useRecordBoardStates';
|
||||
import { visibleRecordGroupIdsComponentSelector } from '@/object-record/record-group/states/selectors/visibleRecordGroupIdsComponentSelector';
|
||||
import { RecordIndexBoardColumnLoaderEffect } from '@/object-record/record-index/components/RecordIndexBoardColumnLoaderEffect';
|
||||
import { recordIndexKanbanFieldMetadataIdState } from '@/object-record/record-index/states/recordIndexKanbanFieldMetadataIdState';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
|
||||
type RecordIndexBoardDataLoaderProps = {
|
||||
objectNameSingular: string;
|
||||
@ -18,6 +19,10 @@ export const RecordIndexBoardDataLoader = ({
|
||||
objectNameSingular,
|
||||
});
|
||||
|
||||
const visibleRecordGroupIds = useRecoilComponentValueV2(
|
||||
visibleRecordGroupIdsComponentSelector,
|
||||
);
|
||||
|
||||
const recordIndexKanbanFieldMetadataId = useRecoilValue(
|
||||
recordIndexKanbanFieldMetadataIdState,
|
||||
);
|
||||
@ -26,18 +31,14 @@ export const RecordIndexBoardDataLoader = ({
|
||||
(field) => field.id === recordIndexKanbanFieldMetadataId,
|
||||
);
|
||||
|
||||
const { columnIdsState } = useRecordBoardStates(recordBoardId);
|
||||
|
||||
const columnIds = useRecoilValue(columnIdsState);
|
||||
|
||||
return (
|
||||
<>
|
||||
{columnIds.map((columnId, index) => (
|
||||
{visibleRecordGroupIds.map((recordGroupId, index) => (
|
||||
<RecordIndexBoardColumnLoaderEffect
|
||||
objectNameSingular={objectNameSingular}
|
||||
boardFieldMetadataId={recordIndexKanbanFieldMetadataId}
|
||||
recordBoardId={recordBoardId}
|
||||
columnId={columnId}
|
||||
columnId={recordGroupId}
|
||||
key={index}
|
||||
/>
|
||||
))}
|
||||
|
@ -1,101 +1,52 @@
|
||||
import { useEffect } from 'react';
|
||||
import { useRecoilValue, useSetRecoilState } from 'recoil';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState';
|
||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||
import { useRecordBoard } from '@/object-record/record-board/hooks/useRecordBoard';
|
||||
import { recordGroupDefinitionsComponentState } from '@/object-record/record-group/states/recordGroupDefinitionsComponentState';
|
||||
import { isRecordBoardCompactModeActiveComponentState } from '@/object-record/record-board/states/isRecordBoardCompactModeActiveComponentState';
|
||||
import { recordBoardFieldDefinitionsComponentState } from '@/object-record/record-board/states/recordBoardFieldDefinitionsComponentState';
|
||||
import { recordBoardSelectedRecordIdsComponentSelector } from '@/object-record/record-board/states/selectors/recordBoardSelectedRecordIdsComponentSelector';
|
||||
import { recordIndexFieldDefinitionsState } from '@/object-record/record-index/states/recordIndexFieldDefinitionsState';
|
||||
import { recordIndexIsCompactModeActiveState } from '@/object-record/record-index/states/recordIndexIsCompactModeActiveState';
|
||||
import { recordIndexKanbanFieldMetadataIdState } from '@/object-record/record-index/states/recordIndexKanbanFieldMetadataIdState';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
||||
import { isDefined } from '~/utils/isDefined';
|
||||
|
||||
type RecordIndexBoardDataLoaderEffectProps = {
|
||||
objectNameSingular: string;
|
||||
recordBoardId: string;
|
||||
};
|
||||
|
||||
export const RecordIndexBoardDataLoaderEffect = ({
|
||||
objectNameSingular,
|
||||
recordBoardId,
|
||||
}: RecordIndexBoardDataLoaderEffectProps) => {
|
||||
const { objectMetadataItem } = useObjectMetadataItem({
|
||||
objectNameSingular,
|
||||
});
|
||||
|
||||
const recordIndexFieldDefinitions = useRecoilValue(
|
||||
recordIndexFieldDefinitionsState,
|
||||
);
|
||||
|
||||
const recordGroupDefinitions = useRecoilComponentValueV2(
|
||||
recordGroupDefinitionsComponentState,
|
||||
);
|
||||
|
||||
const recordIndexKanbanFieldMetadataId = useRecoilValue(
|
||||
recordIndexKanbanFieldMetadataIdState,
|
||||
);
|
||||
|
||||
const recordIndexIsCompactModeActive = useRecoilValue(
|
||||
recordIndexIsCompactModeActiveState,
|
||||
);
|
||||
|
||||
const { isCompactModeActiveState } = useRecordBoard(recordBoardId);
|
||||
const setRecordBoardFieldDefinitions = useSetRecoilComponentStateV2(
|
||||
recordBoardFieldDefinitionsComponentState,
|
||||
recordBoardId,
|
||||
);
|
||||
|
||||
const setIsCompactModeActive = useSetRecoilState(isCompactModeActiveState);
|
||||
const selectedRecordIds = useRecoilComponentValueV2(
|
||||
recordBoardSelectedRecordIdsComponentSelector,
|
||||
recordBoardId,
|
||||
);
|
||||
|
||||
const setIsCompactModeActive = useSetRecoilComponentStateV2(
|
||||
isRecordBoardCompactModeActiveComponentState,
|
||||
recordBoardId,
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
setIsCompactModeActive(recordIndexIsCompactModeActive);
|
||||
}, [recordIndexIsCompactModeActive, setIsCompactModeActive]);
|
||||
|
||||
const {
|
||||
setColumns,
|
||||
setObjectSingularName,
|
||||
selectedRecordIdsSelector,
|
||||
setFieldDefinitions,
|
||||
setKanbanFieldMetadataName,
|
||||
} = useRecordBoard(recordBoardId);
|
||||
|
||||
useEffect(() => {
|
||||
setFieldDefinitions(recordIndexFieldDefinitions);
|
||||
}, [recordIndexFieldDefinitions, setFieldDefinitions]);
|
||||
|
||||
useEffect(() => {
|
||||
setObjectSingularName(objectNameSingular);
|
||||
}, [objectNameSingular, setObjectSingularName]);
|
||||
|
||||
useEffect(() => {
|
||||
setColumns(recordGroupDefinitions);
|
||||
}, [recordGroupDefinitions, setColumns]);
|
||||
|
||||
// TODO: Remove this duplicate useEffect by ensuring it's not here because
|
||||
// We want it to be triggered by a change of objectMetadataItem, which would be an anti-pattern
|
||||
// As it is an unnecessary dependency
|
||||
useEffect(() => {
|
||||
setFieldDefinitions(recordIndexFieldDefinitions);
|
||||
}, [objectMetadataItem, setFieldDefinitions, recordIndexFieldDefinitions]);
|
||||
|
||||
useEffect(() => {
|
||||
if (isDefined(recordIndexKanbanFieldMetadataId)) {
|
||||
const kanbanFieldMetadataName = objectMetadataItem?.fields.find(
|
||||
(field) =>
|
||||
field.type === FieldMetadataType.Select &&
|
||||
field.id === recordIndexKanbanFieldMetadataId,
|
||||
)?.name;
|
||||
|
||||
if (isDefined(kanbanFieldMetadataName)) {
|
||||
setKanbanFieldMetadataName(kanbanFieldMetadataName);
|
||||
}
|
||||
}
|
||||
}, [
|
||||
objectMetadataItem,
|
||||
recordIndexKanbanFieldMetadataId,
|
||||
setKanbanFieldMetadataName,
|
||||
]);
|
||||
|
||||
const selectedRecordIds = useRecoilValue(selectedRecordIdsSelector());
|
||||
setRecordBoardFieldDefinitions(recordIndexFieldDefinitions);
|
||||
}, [recordIndexFieldDefinitions, setRecordBoardFieldDefinitions]);
|
||||
|
||||
const setContextStoreTargetedRecords = useSetRecoilComponentStateV2(
|
||||
contextStoreTargetedRecordsRuleComponentState,
|
||||
|
@ -24,11 +24,9 @@ import { SpreadsheetImportProvider } from '@/spreadsheet-import/provider/compone
|
||||
|
||||
import { RecordIndexActionMenu } from '@/action-menu/components/RecordIndexActionMenu';
|
||||
import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState';
|
||||
import { useRecordBoard } from '@/object-record/record-board/hooks/useRecordBoard';
|
||||
import { recordGroupDefinitionsComponentState } from '@/object-record/record-group/states/recordGroupDefinitionsComponentState';
|
||||
import { useSetRecordGroup } from '@/object-record/record-group/hooks/useSetRecordGroup';
|
||||
import { RecordIndexFiltersToContextStoreEffect } from '@/object-record/record-index/components/RecordIndexFiltersToContextStoreEffect';
|
||||
import { recordIndexViewFilterGroupsState } from '@/object-record/record-index/states/recordIndexViewFilterGroupsState';
|
||||
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||
import { ViewBar } from '@/views/components/ViewBar';
|
||||
import { ViewField } from '@/views/types/ViewField';
|
||||
@ -38,7 +36,7 @@ import { mapViewFieldsToColumnDefinitions } from '@/views/utils/mapViewFieldsToC
|
||||
import { mapViewFiltersToFilters } from '@/views/utils/mapViewFiltersToFilters';
|
||||
import { mapViewGroupsToRecordGroupDefinitions } from '@/views/utils/mapViewGroupsToRecordGroupDefinitions';
|
||||
import { mapViewSortsToSorts } from '@/views/utils/mapViewSortsToSorts';
|
||||
import { useContext } from 'react';
|
||||
import { useCallback, useContext } from 'react';
|
||||
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
|
||||
|
||||
const StyledContainer = styled.div`
|
||||
@ -68,9 +66,7 @@ export const RecordIndexContainer = () => {
|
||||
objectNameSingular,
|
||||
} = useContext(RecordIndexRootPropsContext);
|
||||
|
||||
const recordGroupDefinitionsCallbackState = useRecoilComponentCallbackStateV2(
|
||||
recordGroupDefinitionsComponentState,
|
||||
);
|
||||
const setRecordGroup = useSetRecordGroup(recordIndexId);
|
||||
|
||||
const { columnDefinitions, filterDefinitions, sortDefinitions } =
|
||||
useColumnDefinitionsFromFieldMetadata(objectMetadataItem);
|
||||
@ -96,8 +92,6 @@ export const RecordIndexContainer = () => {
|
||||
recordTableId: recordIndexId,
|
||||
});
|
||||
|
||||
const { setColumns } = useRecordBoard(recordIndexId);
|
||||
|
||||
const onViewFieldsChange = useRecoilCallback(
|
||||
({ set, snapshot }) =>
|
||||
(viewFields: ViewField[]) => {
|
||||
@ -124,30 +118,16 @@ export const RecordIndexContainer = () => {
|
||||
[columnDefinitions, setTableColumns],
|
||||
);
|
||||
|
||||
const onViewGroupsChange = useRecoilCallback(
|
||||
({ set, snapshot }) =>
|
||||
(viewGroups: ViewGroup[]) => {
|
||||
const newGroupDefinitions = mapViewGroupsToRecordGroupDefinitions({
|
||||
objectMetadataItem,
|
||||
viewGroups,
|
||||
});
|
||||
const onViewGroupsChange = useCallback(
|
||||
(viewGroups: ViewGroup[]) => {
|
||||
const newGroupDefinitions = mapViewGroupsToRecordGroupDefinitions({
|
||||
objectMetadataItem,
|
||||
viewGroups,
|
||||
});
|
||||
|
||||
setColumns(newGroupDefinitions);
|
||||
|
||||
const existingRecordIndexGroupDefinitions = snapshot
|
||||
.getLoadable(recordGroupDefinitionsCallbackState)
|
||||
.getValue();
|
||||
|
||||
if (
|
||||
!isDeeplyEqual(
|
||||
existingRecordIndexGroupDefinitions,
|
||||
newGroupDefinitions,
|
||||
)
|
||||
) {
|
||||
set(recordGroupDefinitionsCallbackState, newGroupDefinitions);
|
||||
}
|
||||
},
|
||||
[objectMetadataItem, recordGroupDefinitionsCallbackState, setColumns],
|
||||
setRecordGroup(newGroupDefinitions);
|
||||
},
|
||||
[objectMetadataItem, setRecordGroup],
|
||||
);
|
||||
|
||||
const setContextStoreTargetedRecordsRule = useSetRecoilComponentStateV2(
|
||||
@ -229,10 +209,7 @@ export const RecordIndexContainer = () => {
|
||||
objectNameSingular={objectNameSingular}
|
||||
recordBoardId={recordIndexId}
|
||||
/>
|
||||
<RecordIndexBoardDataLoaderEffect
|
||||
objectNameSingular={objectNameSingular}
|
||||
recordBoardId={recordIndexId}
|
||||
/>
|
||||
<RecordIndexBoardDataLoaderEffect recordBoardId={recordIndexId} />
|
||||
</StyledContainerWithPadding>
|
||||
)}
|
||||
<RecordIndexActionMenu />
|
||||
|
@ -1,8 +1,9 @@
|
||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||
import { useRecordBoardStates } from '@/object-record/record-board/hooks/internal/useRecordBoardStates';
|
||||
import { useAddNewCard } from '@/object-record/record-board/record-board-column/hooks/useAddNewCard';
|
||||
import { useIsOpportunitiesCompanyFieldDisabled } from '@/object-record/record-board/record-board-column/hooks/useIsOpportunitiesCompanyFieldDisabled';
|
||||
import { recordBoardVisibleFieldDefinitionsComponentSelector } from '@/object-record/record-board/states/selectors/recordBoardVisibleFieldDefinitionsComponentSelector';
|
||||
import { visibleRecordGroupIdsComponentSelector } from '@/object-record/record-group/states/selectors/visibleRecordGroupIdsComponentSelector';
|
||||
import { RecordGroupDefinition } from '@/object-record/record-group/types/RecordGroupDefinition';
|
||||
import { RecordIndexPageKanbanAddMenuItem } from '@/object-record/record-index/components/RecordIndexPageKanbanAddMenuItem';
|
||||
import { RecordIndexRootPropsContext } from '@/object-record/record-index/contexts/RecordIndexRootPropsContext';
|
||||
@ -11,6 +12,7 @@ import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||
import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu';
|
||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import styled from '@emotion/styled';
|
||||
import { useCallback, useContext } from 'react';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
@ -32,6 +34,10 @@ export const RecordIndexPageKanbanAddButton = () => {
|
||||
);
|
||||
const { objectMetadataItem } = useObjectMetadataItem({ objectNameSingular });
|
||||
|
||||
const visibleRecordGroupIds = useRecoilComponentValueV2(
|
||||
visibleRecordGroupIdsComponentSelector,
|
||||
);
|
||||
|
||||
const recordIndexKanbanFieldMetadataId = useRecoilValue(
|
||||
recordIndexKanbanFieldMetadataIdState,
|
||||
);
|
||||
@ -42,12 +48,11 @@ export const RecordIndexPageKanbanAddButton = () => {
|
||||
const isOpportunity =
|
||||
objectMetadataItem.nameSingular === CoreObjectNameSingular.Opportunity;
|
||||
|
||||
const { columnIdsState, visibleFieldDefinitionsState } =
|
||||
useRecordBoardStates(recordIndexId);
|
||||
const columnIds = useRecoilValue(columnIdsState);
|
||||
const visibleFieldDefinitions = useRecoilValue(
|
||||
visibleFieldDefinitionsState(),
|
||||
const visibleFieldDefinitions = useRecoilComponentValueV2(
|
||||
recordBoardVisibleFieldDefinitionsComponentSelector,
|
||||
recordIndexId,
|
||||
);
|
||||
|
||||
const labelIdentifierField = visibleFieldDefinitions.find(
|
||||
(field) => field.isLabelIdentifier,
|
||||
);
|
||||
@ -101,11 +106,10 @@ export const RecordIndexPageKanbanAddButton = () => {
|
||||
dropdownComponents={
|
||||
<StyledDropDownMenu>
|
||||
<StyledDropdownMenuItemsContainer>
|
||||
{columnIds.map((columnId) => (
|
||||
{visibleRecordGroupIds.map((recordGroupId) => (
|
||||
<RecordIndexPageKanbanAddMenuItem
|
||||
key={columnId}
|
||||
columnId={columnId}
|
||||
recordIndexId={recordIndexId}
|
||||
key={recordGroupId}
|
||||
columnId={recordGroupId}
|
||||
onItemClick={handleItemClick}
|
||||
/>
|
||||
))}
|
||||
|
@ -1,7 +1,9 @@
|
||||
import { recordGroupDefinitionFamilyState } from '@/object-record/record-group/states/recordGroupDefinitionFamilyState';
|
||||
import { RecordGroupDefinitionType } from '@/object-record/record-group/types/RecordGroupDefinition';
|
||||
import { useRecordIndexPageKanbanAddMenuItem } from '@/object-record/record-index/hooks/useRecordIndexPageKanbanAddMenuItem';
|
||||
import styled from '@emotion/styled';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { MenuItem, Tag } from 'twenty-ui';
|
||||
import { isDefined } from '~/utils/isDefined';
|
||||
|
||||
const StyledMenuItem = styled(MenuItem)`
|
||||
width: calc(100% - 2 * var(--horizontal-padding));
|
||||
@ -9,20 +11,18 @@ const StyledMenuItem = styled(MenuItem)`
|
||||
|
||||
type RecordIndexPageKanbanAddMenuItemProps = {
|
||||
columnId: string;
|
||||
recordIndexId: string;
|
||||
onItemClick: (columnDefinition: any) => void;
|
||||
};
|
||||
|
||||
export const RecordIndexPageKanbanAddMenuItem = ({
|
||||
columnId,
|
||||
recordIndexId,
|
||||
onItemClick,
|
||||
}: RecordIndexPageKanbanAddMenuItemProps) => {
|
||||
const { columnDefinition } = useRecordIndexPageKanbanAddMenuItem(
|
||||
recordIndexId,
|
||||
columnId,
|
||||
const recordGroupDefinition = useRecoilValue(
|
||||
recordGroupDefinitionFamilyState(columnId),
|
||||
);
|
||||
if (!columnDefinition) {
|
||||
|
||||
if (!isDefined(recordGroupDefinition)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -31,24 +31,24 @@ export const RecordIndexPageKanbanAddMenuItem = ({
|
||||
text={
|
||||
<Tag
|
||||
variant={
|
||||
columnDefinition.type === RecordGroupDefinitionType.Value
|
||||
recordGroupDefinition.type === RecordGroupDefinitionType.Value
|
||||
? 'solid'
|
||||
: 'outline'
|
||||
}
|
||||
color={
|
||||
columnDefinition.type === RecordGroupDefinitionType.Value
|
||||
? columnDefinition.color
|
||||
recordGroupDefinition.type === RecordGroupDefinitionType.Value
|
||||
? recordGroupDefinition.color
|
||||
: 'transparent'
|
||||
}
|
||||
text={columnDefinition.title}
|
||||
text={recordGroupDefinition.title}
|
||||
weight={
|
||||
columnDefinition.type === RecordGroupDefinitionType.Value
|
||||
recordGroupDefinition.type === RecordGroupDefinitionType.Value
|
||||
? 'regular'
|
||||
: 'medium'
|
||||
}
|
||||
/>
|
||||
}
|
||||
onClick={() => onItemClick(columnDefinition)}
|
||||
onClick={() => onItemClick(recordGroupDefinition)}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
@ -8,14 +8,12 @@ import {
|
||||
|
||||
import { PERSON_FRAGMENT_WITH_DEPTH_ZERO_RELATIONS } from '@/object-record/hooks/__mocks__/personFragments';
|
||||
import { useObjectOptionsForBoard } from '@/object-record/object-options-dropdown/hooks/useObjectOptionsForBoard';
|
||||
import { useRecordBoard } from '@/object-record/record-board/hooks/useRecordBoard';
|
||||
import { recordBoardKanbanFieldMetadataNameComponentState } from '@/object-record/record-board/states/recordBoardKanbanFieldMetadataNameComponentState';
|
||||
import { extractComponentState } from '@/ui/utilities/state/component-state/utils/extractComponentState';
|
||||
import { recordGroupFieldMetadataComponentState } from '@/object-record/record-group/states/recordGroupFieldMetadataComponentState';
|
||||
import { useRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentStateV2';
|
||||
import { ViewType } from '@/views/types/ViewType';
|
||||
import { MockedResponse } from '@apollo/client/testing';
|
||||
import { expect } from '@storybook/test';
|
||||
import gql from 'graphql-tag';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { getJestMetadataAndApolloMocksAndContextStoreWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksAndContextStoreWrapper';
|
||||
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
|
||||
|
||||
@ -232,10 +230,12 @@ describe('useRecordData', () => {
|
||||
const callback = jest.fn();
|
||||
const { result } = renderHook(
|
||||
() => {
|
||||
const kanbanFieldNameState = extractComponentState(
|
||||
recordBoardKanbanFieldMetadataNameComponentState,
|
||||
recordIndexId,
|
||||
);
|
||||
const [recordGroupFieldMetadata, setRecordGroupFieldMetadata] =
|
||||
useRecoilComponentStateV2(
|
||||
recordGroupFieldMetadataComponentState,
|
||||
recordIndexId,
|
||||
);
|
||||
|
||||
return {
|
||||
tableData: useExportFetchRecords({
|
||||
recordIndexId,
|
||||
@ -246,8 +246,8 @@ describe('useRecordData', () => {
|
||||
delayMs: 0,
|
||||
viewType: ViewType.Kanban,
|
||||
}),
|
||||
useRecordBoardHook: useRecordBoard(recordIndexId),
|
||||
kanbanFieldName: useRecoilValue(kanbanFieldNameState),
|
||||
kanbanFieldName: recordGroupFieldMetadata?.name,
|
||||
setRecordGroupFieldMetadata,
|
||||
kanbanData: useObjectOptionsForBoard({
|
||||
objectNameSingular: objectMetadataItem.nameSingular,
|
||||
recordBoardId: recordIndexId,
|
||||
@ -269,9 +269,7 @@ describe('useRecordData', () => {
|
||||
);
|
||||
|
||||
await act(async () => {
|
||||
result.current.useRecordBoardHook.setKanbanFieldMetadataName(
|
||||
updatedAtFieldMetadataItem?.name,
|
||||
);
|
||||
result.current.setRecordGroupFieldMetadata(updatedAtFieldMetadataItem);
|
||||
});
|
||||
|
||||
await act(async () => {
|
||||
@ -322,10 +320,12 @@ describe('useRecordData', () => {
|
||||
const callback = jest.fn();
|
||||
const { result } = renderHook(
|
||||
() => {
|
||||
const kanbanFieldNameState = extractComponentState(
|
||||
recordBoardKanbanFieldMetadataNameComponentState,
|
||||
recordIndexId,
|
||||
);
|
||||
const [recordGroupFieldMetadata, setRecordGroupFieldMetadata] =
|
||||
useRecoilComponentStateV2(
|
||||
recordGroupFieldMetadataComponentState,
|
||||
recordIndexId,
|
||||
);
|
||||
|
||||
return {
|
||||
tableData: useExportFetchRecords({
|
||||
recordIndexId,
|
||||
@ -336,8 +336,9 @@ describe('useRecordData', () => {
|
||||
delayMs: 0,
|
||||
viewType: ViewType.Table,
|
||||
}),
|
||||
setKanbanFieldName: useRecordBoard(recordIndexId),
|
||||
kanbanFieldName: useRecoilValue(kanbanFieldNameState),
|
||||
objectMetadataItem,
|
||||
kanbanFieldName: recordGroupFieldMetadata?.name,
|
||||
setRecordGroupFieldMetadata,
|
||||
kanbanData: useObjectOptionsForBoard({
|
||||
objectNameSingular: objectMetadataItem.nameSingular,
|
||||
recordBoardId: recordIndexId,
|
||||
@ -351,9 +352,14 @@ describe('useRecordData', () => {
|
||||
);
|
||||
|
||||
await act(async () => {
|
||||
result.current.setKanbanFieldName.setKanbanFieldMetadataName(
|
||||
result.current.kanbanData.hiddenBoardFields[0].metadata.fieldName,
|
||||
);
|
||||
const fieldMetadataItem =
|
||||
result.current.objectMetadataItem?.fields.find(
|
||||
(fieldMetadata) =>
|
||||
fieldMetadata.id ===
|
||||
result.current.kanbanData.hiddenBoardFields[0].fieldMetadataId,
|
||||
);
|
||||
|
||||
result.current.setRecordGroupFieldMetadata(fieldMetadataItem);
|
||||
});
|
||||
|
||||
await act(async () => {
|
||||
|
@ -1,5 +1,4 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata';
|
||||
import { ColumnDefinition } from '@/object-record/record-table/types/ColumnDefinition';
|
||||
@ -13,7 +12,7 @@ import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||
import { useLazyFindManyRecords } from '@/object-record/hooks/useLazyFindManyRecords';
|
||||
import { EXPORT_TABLE_DATA_DEFAULT_PAGE_SIZE } from '@/object-record/object-options-dropdown/constants/ExportTableDataDefaultPageSize';
|
||||
import { useObjectOptionsForBoard } from '@/object-record/object-options-dropdown/hooks/useObjectOptionsForBoard';
|
||||
import { useRecordBoardStates } from '@/object-record/record-board/hooks/internal/useRecordBoardStates';
|
||||
import { recordGroupFieldMetadataComponentState } from '@/object-record/record-group/states/recordGroupFieldMetadataComponentState';
|
||||
import { useFindManyParams } from '@/object-record/record-index/hooks/useLoadRecordIndexTable';
|
||||
import { visibleTableColumnsComponentSelector } from '@/object-record/record-table/states/selectors/visibleTableColumnsComponentSelector';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
@ -68,10 +67,13 @@ export const useExportFetchRecords = ({
|
||||
viewBarId: recordIndexId,
|
||||
});
|
||||
|
||||
const { kanbanFieldMetadataNameState } = useRecordBoardStates(recordIndexId);
|
||||
const kanbanFieldMetadataName = useRecoilValue(kanbanFieldMetadataNameState);
|
||||
const recordGroupFieldMetadata = useRecoilComponentValueV2(
|
||||
recordGroupFieldMetadataComponentState,
|
||||
recordIndexId,
|
||||
);
|
||||
|
||||
const hiddenKanbanFieldColumn = hiddenBoardFields.find(
|
||||
(column) => column.metadata.fieldName === kanbanFieldMetadataName,
|
||||
(column) => column.metadata.fieldName === recordGroupFieldMetadata?.name,
|
||||
);
|
||||
const columns = useRecoilComponentValueV2(
|
||||
visibleTableColumnsComponentSelector,
|
||||
|
@ -1,12 +1,13 @@
|
||||
import { useEffect } from 'react';
|
||||
import { useRecoilValue, useSetRecoilState } from 'recoil';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||
import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords';
|
||||
import { turnSortsIntoOrderBy } from '@/object-record/object-sort-dropdown/utils/turnSortsIntoOrderBy';
|
||||
import { useRecordBoard } from '@/object-record/record-board/hooks/useRecordBoard';
|
||||
import { useSetRecordBoardRecordIds } from '@/object-record/record-board/hooks/useSetRecordBoardRecordIds';
|
||||
import { isRecordBoardCompactModeActiveComponentState } from '@/object-record/record-board/states/isRecordBoardCompactModeActiveComponentState';
|
||||
import { recordBoardFieldDefinitionsComponentState } from '@/object-record/record-board/states/recordBoardFieldDefinitionsComponentState';
|
||||
import { computeViewRecordGqlOperationFilter } from '@/object-record/record-filter/utils/computeViewRecordGqlOperationFilter';
|
||||
import { recordGroupDefinitionsComponentState } from '@/object-record/record-group/states/recordGroupDefinitionsComponentState';
|
||||
import { useRecordBoardRecordGqlFields } from '@/object-record/record-index/hooks/useRecordBoardRecordGqlFields';
|
||||
import { recordIndexFieldDefinitionsState } from '@/object-record/record-index/states/recordIndexFieldDefinitionsState';
|
||||
import { recordIndexFiltersState } from '@/object-record/record-index/states/recordIndexFiltersState';
|
||||
@ -14,7 +15,7 @@ import { recordIndexIsCompactModeActiveState } from '@/object-record/record-inde
|
||||
import { recordIndexSortsState } from '@/object-record/record-index/states/recordIndexSortsState';
|
||||
import { recordIndexViewFilterGroupsState } from '@/object-record/record-index/states/recordIndexViewFilterGroupsState';
|
||||
import { useUpsertRecordsInStore } from '@/object-record/record-store/hooks/useUpsertRecordsInStore';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||
import { useSetRecordCountInCurrentView } from '@/views/hooks/useSetRecordCountInCurrentView';
|
||||
|
||||
type UseLoadRecordIndexBoardProps = {
|
||||
@ -31,33 +32,28 @@ export const useLoadRecordIndexBoard = ({
|
||||
const { objectMetadataItem } = useObjectMetadataItem({
|
||||
objectNameSingular,
|
||||
});
|
||||
const {
|
||||
setRecordIds: setRecordIdsInBoard,
|
||||
setFieldDefinitions,
|
||||
setColumns,
|
||||
isCompactModeActiveState,
|
||||
} = useRecordBoard(recordBoardId);
|
||||
|
||||
const setRecordBoardFieldDefinitions = useSetRecoilComponentStateV2(
|
||||
recordBoardFieldDefinitionsComponentState,
|
||||
recordBoardId,
|
||||
);
|
||||
|
||||
const { setRecordIds: setRecordIdsInBoard } =
|
||||
useSetRecordBoardRecordIds(recordBoardId);
|
||||
|
||||
const { upsertRecords: upsertRecordsInStore } = useUpsertRecordsInStore();
|
||||
|
||||
const recordIndexFieldDefinitions = useRecoilValue(
|
||||
recordIndexFieldDefinitionsState,
|
||||
);
|
||||
useEffect(() => {
|
||||
setFieldDefinitions(recordIndexFieldDefinitions);
|
||||
}, [recordIndexFieldDefinitions, setFieldDefinitions]);
|
||||
setRecordBoardFieldDefinitions(recordIndexFieldDefinitions);
|
||||
}, [recordIndexFieldDefinitions, setRecordBoardFieldDefinitions]);
|
||||
|
||||
const recordIndexViewFilterGroups = useRecoilValue(
|
||||
recordIndexViewFilterGroupsState,
|
||||
);
|
||||
|
||||
const recordGroupDefinitions = useRecoilComponentValueV2(
|
||||
recordGroupDefinitionsComponentState,
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
setColumns(recordGroupDefinitions);
|
||||
}, [recordGroupDefinitions, setColumns]);
|
||||
|
||||
const recordIndexFilters = useRecoilValue(recordIndexFiltersState);
|
||||
const recordIndexSorts = useRecoilValue(recordIndexSortsState);
|
||||
const requestFilters = computeViewRecordGqlOperationFilter(
|
||||
@ -92,7 +88,10 @@ export const useLoadRecordIndexBoard = ({
|
||||
const { setRecordCountInCurrentView } =
|
||||
useSetRecordCountInCurrentView(viewBarId);
|
||||
|
||||
const setIsCompactModeActive = useSetRecoilState(isCompactModeActiveState);
|
||||
const setIsCompactModeActive = useSetRecoilComponentStateV2(
|
||||
isRecordBoardCompactModeActiveComponentState,
|
||||
recordBoardId,
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
setRecordIdsInBoard(records);
|
||||
|
@ -4,9 +4,9 @@ import { useRecoilValue } from 'recoil';
|
||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||
import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords';
|
||||
import { turnSortsIntoOrderBy } from '@/object-record/object-sort-dropdown/utils/turnSortsIntoOrderBy';
|
||||
import { useRecordBoardStates } from '@/object-record/record-board/hooks/internal/useRecordBoardStates';
|
||||
import { useRecordBoard } from '@/object-record/record-board/hooks/useRecordBoard';
|
||||
import { useSetRecordIdsForColumn } from '@/object-record/record-board/hooks/useSetRecordIdsForColumn';
|
||||
import { computeViewRecordGqlOperationFilter } from '@/object-record/record-filter/utils/computeViewRecordGqlOperationFilter';
|
||||
import { recordGroupDefinitionFamilyState } from '@/object-record/record-group/states/recordGroupDefinitionFamilyState';
|
||||
import { useRecordBoardRecordGqlFields } from '@/object-record/record-index/hooks/useRecordBoardRecordGqlFields';
|
||||
import { recordIndexFiltersState } from '@/object-record/record-index/states/recordIndexFiltersState';
|
||||
import { recordIndexSortsState } from '@/object-record/record-index/states/recordIndexSortsState';
|
||||
@ -30,16 +30,18 @@ export const useLoadRecordIndexBoardColumn = ({
|
||||
const { objectMetadataItem } = useObjectMetadataItem({
|
||||
objectNameSingular,
|
||||
});
|
||||
const { setRecordIdsForColumn } = useRecordBoard(recordBoardId);
|
||||
const { columnsFamilySelector } = useRecordBoardStates(recordBoardId);
|
||||
const { setRecordIdsForColumn } = useSetRecordIdsForColumn(recordBoardId);
|
||||
const { upsertRecords: upsertRecordsInStore } = useUpsertRecordsInStore();
|
||||
|
||||
const recordGroupDefinition = useRecoilValue(
|
||||
recordGroupDefinitionFamilyState(columnId),
|
||||
);
|
||||
|
||||
const recordIndexViewFilterGroups = useRecoilValue(
|
||||
recordIndexViewFilterGroupsState,
|
||||
);
|
||||
const recordIndexFilters = useRecoilValue(recordIndexFiltersState);
|
||||
const recordIndexSorts = useRecoilValue(recordIndexSortsState);
|
||||
const columnDefinition = useRecoilValue(columnsFamilySelector(columnId));
|
||||
|
||||
const requestFilters = computeViewRecordGqlOperationFilter(
|
||||
recordIndexFilters,
|
||||
@ -60,9 +62,9 @@ export const useLoadRecordIndexBoardColumn = ({
|
||||
const filter = {
|
||||
...requestFilters,
|
||||
[recordIndexKanbanFieldMetadataItem?.name ?? '']: isDefined(
|
||||
columnDefinition?.value,
|
||||
recordGroupDefinition?.value,
|
||||
)
|
||||
? { in: [columnDefinition?.value] }
|
||||
? { in: [recordGroupDefinition?.value] }
|
||||
: { is: 'NULL' },
|
||||
};
|
||||
|
||||
|
@ -27,8 +27,7 @@ export const useFindManyParams = (
|
||||
objectNameSingular,
|
||||
});
|
||||
|
||||
const currentRecordGroupDefinition =
|
||||
useCurrentRecordGroupDefinition(recordTableId);
|
||||
const currentRecordGroupDefinition = useCurrentRecordGroupDefinition();
|
||||
|
||||
const tableViewFilterGroups = useRecoilComponentValueV2(
|
||||
tableViewFilterGroupsComponentState,
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||
import { getObjectMetadataIdentifierFields } from '@/object-metadata/utils/getObjectMetadataIdentifierFields';
|
||||
import { hasPositionField } from '@/object-metadata/utils/hasPositionField';
|
||||
import { useRecordBoardStates } from '@/object-record/record-board/hooks/internal/useRecordBoardStates';
|
||||
import { recordBoardVisibleFieldDefinitionsComponentSelector } from '@/object-record/record-board/states/selectors/recordBoardVisibleFieldDefinitionsComponentSelector';
|
||||
import { recordGroupFieldMetadataComponentState } from '@/object-record/record-group/states/recordGroupFieldMetadataComponentState';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { isDefined } from '~/utils/isDefined';
|
||||
|
||||
export const useRecordBoardRecordGqlFields = ({
|
||||
@ -13,15 +13,17 @@ export const useRecordBoardRecordGqlFields = ({
|
||||
recordBoardId: string;
|
||||
objectMetadataItem: ObjectMetadataItem;
|
||||
}) => {
|
||||
const { kanbanFieldMetadataNameState, visibleFieldDefinitionsState } =
|
||||
useRecordBoardStates(recordBoardId);
|
||||
const visibleFieldDefinitions = useRecoilComponentValueV2(
|
||||
recordBoardVisibleFieldDefinitionsComponentSelector,
|
||||
recordBoardId,
|
||||
);
|
||||
|
||||
const { imageIdentifierFieldMetadataItem, labelIdentifierFieldMetadataItem } =
|
||||
getObjectMetadataIdentifierFields({ objectMetadataItem });
|
||||
|
||||
const kanbanFieldMetadataName = useRecoilValue(kanbanFieldMetadataNameState);
|
||||
const visibleFieldDefinitions = useRecoilValue(
|
||||
visibleFieldDefinitionsState(),
|
||||
const recordGroupFieldMetadata = useRecoilComponentValueV2(
|
||||
recordGroupFieldMetadataComponentState,
|
||||
recordBoardId,
|
||||
);
|
||||
|
||||
const identifierQueryFields: Record<string, boolean> = {};
|
||||
@ -59,8 +61,8 @@ export const useRecordBoardRecordGqlFields = ({
|
||||
},
|
||||
};
|
||||
|
||||
if (isDefined(kanbanFieldMetadataName)) {
|
||||
recordGqlFields[kanbanFieldMetadataName] = true;
|
||||
if (isDefined(recordGroupFieldMetadata?.name)) {
|
||||
recordGqlFields[recordGroupFieldMetadata.name] = true;
|
||||
}
|
||||
|
||||
return recordGqlFields;
|
||||
|
@ -1,12 +0,0 @@
|
||||
import { useRecordBoardStates } from '@/object-record/record-board/hooks/internal/useRecordBoardStates';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
export const useRecordIndexPageKanbanAddMenuItem = (
|
||||
recordIndexId: string,
|
||||
columnId: string,
|
||||
) => {
|
||||
const { columnsFamilySelector } = useRecordBoardStates(recordIndexId);
|
||||
const columnDefinition = useRecoilValue(columnsFamilySelector(columnId));
|
||||
|
||||
return { columnDefinition };
|
||||
};
|
@ -0,0 +1,10 @@
|
||||
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,
|
||||
});
|
@ -1,10 +1,10 @@
|
||||
import { RecordGroupDefinition } from '@/object-record/record-group/types/RecordGroupDefinition';
|
||||
import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext';
|
||||
import { createComponentFamilyStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentFamilyStateV2';
|
||||
import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext';
|
||||
|
||||
export const tableRowIdsByGroupComponentFamilyState =
|
||||
export const recordIndexRowIdsByGroupComponentFamilyState =
|
||||
createComponentFamilyStateV2<string[], RecordGroupDefinition['id']>({
|
||||
key: 'tableRowIdsByGroupComponentFamilyState',
|
||||
key: 'recordIndexRowIdsByGroupComponentFamilyState',
|
||||
defaultValue: [],
|
||||
componentInstanceContext: RecordTableComponentInstanceContext,
|
||||
componentInstanceContext: ViewComponentInstanceContext,
|
||||
});
|
@ -1,7 +1,8 @@
|
||||
import styled from '@emotion/styled';
|
||||
import { isNonEmptyString, isNull } from '@sniptt/guards';
|
||||
|
||||
import { hasRecordGroupDefinitionsComponentSelector } from '@/object-record/record-group/states/hasRecordGroupDefinitionsComponentSelector';
|
||||
import { hasRecordGroupsComponentSelector } from '@/object-record/record-group/states/selectors/hasRecordGroupsComponentSelector';
|
||||
import { recordIndexAllRowIdsComponentState } from '@/object-record/record-index/states/recordIndexAllRowIdsComponentState';
|
||||
import { RecordTableComponentInstance } from '@/object-record/record-table/components/RecordTableComponentInstance';
|
||||
import { RecordTableContextProvider } from '@/object-record/record-table/components/RecordTableContextProvider';
|
||||
import { RecordTableStickyEffect } from '@/object-record/record-table/components/RecordTableStickyEffect';
|
||||
@ -16,7 +17,6 @@ import { RecordTableRecordGroupsBody } from '@/object-record/record-table/record
|
||||
import { RecordTableHeader } from '@/object-record/record-table/record-table-header/components/RecordTableHeader';
|
||||
import { isRecordTableInitialLoadingComponentState } from '@/object-record/record-table/states/isRecordTableInitialLoadingComponentState';
|
||||
import { recordTablePendingRecordIdComponentState } from '@/object-record/record-table/states/recordTablePendingRecordIdComponentState';
|
||||
import { tableAllRowIdsComponentState } from '@/object-record/record-table/states/tableAllRowIdsComponentState';
|
||||
import { DragSelect } from '@/ui/utilities/drag-select/components/DragSelect';
|
||||
import { useClickOutsideListener } from '@/ui/utilities/pointer-event/hooks/useClickOutsideListener';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
@ -53,8 +53,8 @@ export const RecordTable = ({
|
||||
recordTableId,
|
||||
);
|
||||
|
||||
const tableRowIds = useRecoilComponentValueV2(
|
||||
tableAllRowIdsComponentState,
|
||||
const allRowIds = useRecoilComponentValueV2(
|
||||
recordIndexAllRowIdsComponentState,
|
||||
recordTableId,
|
||||
);
|
||||
|
||||
@ -64,13 +64,13 @@ export const RecordTable = ({
|
||||
);
|
||||
|
||||
const hasRecordGroups = useRecoilComponentValueV2(
|
||||
hasRecordGroupDefinitionsComponentSelector,
|
||||
hasRecordGroupsComponentSelector,
|
||||
recordTableId,
|
||||
);
|
||||
|
||||
const recordTableIsEmpty =
|
||||
!isRecordTableInitialLoading &&
|
||||
tableRowIds.length === 0 &&
|
||||
allRowIds.length === 0 &&
|
||||
isNull(pendingRecordId);
|
||||
|
||||
const { resetTableRowSelection, setRowSelected } = useRecordTable({
|
||||
@ -109,9 +109,7 @@ export const RecordTable = ({
|
||||
{!hasRecordGroups ? (
|
||||
<RecordTableNoRecordGroupBody />
|
||||
) : (
|
||||
<RecordTableRecordGroupsBody
|
||||
objectNameSingular={objectNameSingular}
|
||||
/>
|
||||
<RecordTableRecordGroupsBody />
|
||||
)}
|
||||
<RecordTableStickyEffect />
|
||||
</StyledTable>
|
||||
|
@ -1,14 +1,16 @@
|
||||
import { recordIndexAllRowIdsComponentState } from '@/object-record/record-index/states/recordIndexAllRowIdsComponentState';
|
||||
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 { tableAllRowIdsComponentState } from '@/object-record/record-table/states/tableAllRowIdsComponentState';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
|
||||
export const RecordTableNoRecordGroupRows = () => {
|
||||
const rowIds = useRecoilComponentValueV2(tableAllRowIdsComponentState);
|
||||
const allRowIds = useRecoilComponentValueV2(
|
||||
recordIndexAllRowIdsComponentState,
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
{rowIds.map((recordId, rowIndex) => {
|
||||
{allRowIds.map((recordId, rowIndex) => {
|
||||
return (
|
||||
<RecordTableRow
|
||||
key={recordId}
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { useCurrentRecordGroupId } from '@/object-record/record-group/hooks/useCurrentRecordGroupId';
|
||||
import { recordIndexAllRowIdsComponentState } from '@/object-record/record-index/states/recordIndexAllRowIdsComponentState';
|
||||
import { recordIndexRowIdsByGroupComponentFamilyState } from '@/object-record/record-index/states/recordIndexRowIdsByGroupComponentFamilyState';
|
||||
import { RecordTableRow } from '@/object-record/record-table/record-table-row/components/RecordTableRow';
|
||||
import { tableAllRowIdsComponentState } from '@/object-record/record-table/states/tableAllRowIdsComponentState';
|
||||
import { tableRowIdsByGroupComponentFamilyState } from '@/object-record/record-table/states/tableRowIdsByGroupComponentFamilyState';
|
||||
import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValueV2';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { useMemo } from 'react';
|
||||
@ -9,10 +9,12 @@ import { useMemo } from 'react';
|
||||
export const RecordTableRecordGroupRows = () => {
|
||||
const recordGroupId = useCurrentRecordGroupId();
|
||||
|
||||
const allRowIds = useRecoilComponentValueV2(tableAllRowIdsComponentState);
|
||||
const allRowIds = useRecoilComponentValueV2(
|
||||
recordIndexAllRowIdsComponentState,
|
||||
);
|
||||
|
||||
const recordGroupRowIds = useRecoilComponentFamilyValueV2(
|
||||
tableRowIdsByGroupComponentFamilyState,
|
||||
recordIndexRowIdsByGroupComponentFamilyState,
|
||||
recordGroupId,
|
||||
);
|
||||
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { isNull } from '@sniptt/guards';
|
||||
|
||||
import { recordIndexAllRowIdsComponentState } from '@/object-record/record-index/states/recordIndexAllRowIdsComponentState';
|
||||
import { RecordTableEmptyState } from '@/object-record/record-table/empty-state/components/RecordTableEmptyState';
|
||||
import { isRecordTableInitialLoadingComponentState } from '@/object-record/record-table/states/isRecordTableInitialLoadingComponentState';
|
||||
import { recordTablePendingRecordIdComponentState } from '@/object-record/record-table/states/recordTablePendingRecordIdComponentState';
|
||||
import { tableAllRowIdsComponentState } from '@/object-record/record-table/states/tableAllRowIdsComponentState';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
|
||||
type RecordTableEmptyHandlerProps = {
|
||||
@ -20,8 +20,8 @@ export const RecordTableEmptyHandler = ({
|
||||
recordTableId,
|
||||
);
|
||||
|
||||
const tableRowIds = useRecoilComponentValueV2(
|
||||
tableAllRowIdsComponentState,
|
||||
const allRowIds = useRecoilComponentValueV2(
|
||||
recordIndexAllRowIdsComponentState,
|
||||
recordTableId,
|
||||
);
|
||||
|
||||
@ -32,7 +32,7 @@ export const RecordTableEmptyHandler = ({
|
||||
|
||||
const recordTableIsEmpty =
|
||||
!isRecordTableInitialLoading &&
|
||||
tableRowIds.length === 0 &&
|
||||
allRowIds.length === 0 &&
|
||||
isNull(pendingRecordId);
|
||||
|
||||
if (recordTableIsEmpty) {
|
||||
|
@ -2,10 +2,10 @@ import { useRecoilCallback } from 'recoil';
|
||||
|
||||
import { getActionMenuDropdownIdFromActionMenuId } from '@/action-menu/utils/getActionMenuDropdownIdFromActionMenuId';
|
||||
import { getActionMenuIdFromRecordIndexId } from '@/action-menu/utils/getActionMenuIdFromRecordIndexId';
|
||||
import { recordIndexAllRowIdsComponentState } from '@/object-record/record-index/states/recordIndexAllRowIdsComponentState';
|
||||
import { hasUserSelectedAllRowsComponentState } from '@/object-record/record-table/record-table-row/states/hasUserSelectedAllRowsFamilyState';
|
||||
import { isRowSelectedComponentFamilyState } from '@/object-record/record-table/record-table-row/states/isRowSelectedComponentFamilyState';
|
||||
import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext';
|
||||
import { tableAllRowIdsComponentState } from '@/object-record/record-table/states/tableAllRowIdsComponentState';
|
||||
import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState';
|
||||
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
|
||||
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
|
||||
@ -18,8 +18,8 @@ export const useResetTableRowSelection = (recordTableId?: string) => {
|
||||
recordTableId,
|
||||
);
|
||||
|
||||
const tableAllRowIdsState = useRecoilComponentCallbackStateV2(
|
||||
tableAllRowIdsComponentState,
|
||||
const recordIndexAllRowIdsState = useRecoilComponentCallbackStateV2(
|
||||
recordIndexAllRowIdsComponentState,
|
||||
recordTableIdFromContext,
|
||||
);
|
||||
|
||||
@ -43,9 +43,9 @@ export const useResetTableRowSelection = (recordTableId?: string) => {
|
||||
return useRecoilCallback(
|
||||
({ set, snapshot }) =>
|
||||
() => {
|
||||
const tableRowIds = getSnapshotValue(snapshot, tableAllRowIdsState);
|
||||
const allRowIds = getSnapshotValue(snapshot, recordIndexAllRowIdsState);
|
||||
|
||||
for (const rowId of tableRowIds) {
|
||||
for (const rowId of allRowIds) {
|
||||
set(isRowSelectedFamilyState(rowId), false);
|
||||
}
|
||||
|
||||
@ -54,7 +54,7 @@ export const useResetTableRowSelection = (recordTableId?: string) => {
|
||||
set(isActionMenuDropdownOpenState, false);
|
||||
},
|
||||
[
|
||||
tableAllRowIdsState,
|
||||
recordIndexAllRowIdsState,
|
||||
hasUserSelectedAllRowsState,
|
||||
isActionMenuDropdownOpenState,
|
||||
isRowSelectedFamilyState,
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
|
||||
import { recordIndexAllRowIdsComponentState } from '@/object-record/record-index/states/recordIndexAllRowIdsComponentState';
|
||||
import { isRowSelectedComponentFamilyState } from '@/object-record/record-table/record-table-row/states/isRowSelectedComponentFamilyState';
|
||||
import { allRowsSelectedStatusComponentSelector } from '@/object-record/record-table/states/selectors/allRowsSelectedStatusComponentSelector';
|
||||
import { tableAllRowIdsComponentState } from '@/object-record/record-table/states/tableAllRowIdsComponentState';
|
||||
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
|
||||
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
||||
|
||||
@ -15,8 +15,8 @@ export const useSelectAllRows = (recordTableId?: string) => {
|
||||
isRowSelectedComponentFamilyState,
|
||||
recordTableId,
|
||||
);
|
||||
const tableAllRowIdsState = useRecoilComponentCallbackStateV2(
|
||||
tableAllRowIdsComponentState,
|
||||
const recordIndexAllRowIdsState = useRecoilComponentCallbackStateV2(
|
||||
recordIndexAllRowIdsComponentState,
|
||||
recordTableId,
|
||||
);
|
||||
|
||||
@ -28,24 +28,24 @@ export const useSelectAllRows = (recordTableId?: string) => {
|
||||
allRowsSelectedStatusSelector,
|
||||
);
|
||||
|
||||
const tableRowIds = getSnapshotValue(snapshot, tableAllRowIdsState);
|
||||
const allRowIds = getSnapshotValue(snapshot, recordIndexAllRowIdsState);
|
||||
|
||||
if (
|
||||
allRowsSelectedStatus === 'none' ||
|
||||
allRowsSelectedStatus === 'some'
|
||||
) {
|
||||
for (const rowId of tableRowIds) {
|
||||
for (const rowId of allRowIds) {
|
||||
set(isRowSelectedFamilyState(rowId), true);
|
||||
}
|
||||
} else {
|
||||
for (const rowId of tableRowIds) {
|
||||
for (const rowId of allRowIds) {
|
||||
set(isRowSelectedFamilyState(rowId), false);
|
||||
}
|
||||
}
|
||||
},
|
||||
[
|
||||
allRowsSelectedStatusSelector,
|
||||
tableAllRowIdsState,
|
||||
recordIndexAllRowIdsState,
|
||||
isRowSelectedFamilyState,
|
||||
],
|
||||
);
|
||||
|
@ -1,11 +1,11 @@
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
|
||||
import { recordGroupDefinitionsComponentState } from '@/object-record/record-group/states/recordGroupDefinitionsComponentState';
|
||||
import { recordGroupIdsComponentState } from '@/object-record/record-group/states/recordGroupIdsComponentState';
|
||||
import { recordIndexAllRowIdsComponentState } from '@/object-record/record-index/states/recordIndexAllRowIdsComponentState';
|
||||
import { recordIndexRowIdsByGroupComponentFamilyState } from '@/object-record/record-index/states/recordIndexRowIdsByGroupComponentFamilyState';
|
||||
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
|
||||
import { hasUserSelectedAllRowsComponentState } from '@/object-record/record-table/record-table-row/states/hasUserSelectedAllRowsFamilyState';
|
||||
import { isRowSelectedComponentFamilyState } from '@/object-record/record-table/record-table-row/states/isRowSelectedComponentFamilyState';
|
||||
import { tableAllRowIdsComponentState } from '@/object-record/record-table/states/tableAllRowIdsComponentState';
|
||||
import { tableRowIdsByGroupComponentFamilyState } from '@/object-record/record-table/states/tableRowIdsByGroupComponentFamilyState';
|
||||
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
|
||||
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
||||
@ -21,12 +21,12 @@ export const useSetRecordTableData = ({
|
||||
recordTableId,
|
||||
onEntityCountChange,
|
||||
}: useSetRecordTableDataProps) => {
|
||||
const tableRowIdsByGroupFamilyState = useRecoilComponentCallbackStateV2(
|
||||
tableRowIdsByGroupComponentFamilyState,
|
||||
const recordIndexRowIdsByGroupFamilyState = useRecoilComponentCallbackStateV2(
|
||||
recordIndexRowIdsByGroupComponentFamilyState,
|
||||
recordTableId,
|
||||
);
|
||||
const tableAllRowIdsState = useRecoilComponentCallbackStateV2(
|
||||
tableAllRowIdsComponentState,
|
||||
const recordIndexAllRowIdsState = useRecoilComponentCallbackStateV2(
|
||||
recordIndexAllRowIdsComponentState,
|
||||
recordTableId,
|
||||
);
|
||||
const isRowSelectedFamilyState = useRecoilComponentCallbackStateV2(
|
||||
@ -37,8 +37,8 @@ export const useSetRecordTableData = ({
|
||||
hasUserSelectedAllRowsComponentState,
|
||||
recordTableId,
|
||||
);
|
||||
const recordGroupDefinitionsState = useRecoilComponentCallbackStateV2(
|
||||
recordGroupDefinitionsComponentState,
|
||||
const recordIndexRecordGroupIdsState = useRecoilComponentCallbackStateV2(
|
||||
recordGroupIdsComponentState,
|
||||
recordTableId,
|
||||
);
|
||||
|
||||
@ -46,11 +46,11 @@ export const useSetRecordTableData = ({
|
||||
({ set, snapshot }) =>
|
||||
<T extends ObjectRecord>({
|
||||
records,
|
||||
recordGroupId,
|
||||
currentRecordGroupId,
|
||||
totalCount,
|
||||
}: {
|
||||
records: T[];
|
||||
recordGroupId?: string;
|
||||
currentRecordGroupId?: string;
|
||||
totalCount?: number;
|
||||
}) => {
|
||||
for (const record of records) {
|
||||
@ -66,9 +66,9 @@ export const useSetRecordTableData = ({
|
||||
|
||||
const currentRowIds = getSnapshotValue(
|
||||
snapshot,
|
||||
recordGroupId
|
||||
? tableRowIdsByGroupFamilyState(recordGroupId)
|
||||
: tableAllRowIdsState,
|
||||
currentRecordGroupId
|
||||
? recordIndexRowIdsByGroupFamilyState(currentRecordGroupId)
|
||||
: recordIndexAllRowIdsState,
|
||||
);
|
||||
|
||||
const hasUserSelectedAllRows = getSnapshotValue(
|
||||
@ -76,9 +76,9 @@ export const useSetRecordTableData = ({
|
||||
hasUserSelectedAllRowsState,
|
||||
);
|
||||
|
||||
const recordGroupDefinitions = getSnapshotValue(
|
||||
const recordGroupIds = getSnapshotValue(
|
||||
snapshot,
|
||||
recordGroupDefinitionsState,
|
||||
recordIndexRecordGroupIdsState,
|
||||
);
|
||||
|
||||
const recordIds = records.map((record) => record.id);
|
||||
@ -90,39 +90,42 @@ export const useSetRecordTableData = ({
|
||||
}
|
||||
}
|
||||
|
||||
if (isDefined(recordGroupId)) {
|
||||
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(tableRowIdsByGroupFamilyState(recordGroupId), recordIds);
|
||||
set(
|
||||
recordIndexRowIdsByGroupFamilyState(currentRecordGroupId),
|
||||
recordIds,
|
||||
);
|
||||
|
||||
for (const recordGroupDefinition of recordGroupDefinitions) {
|
||||
for (const recordGroupId of recordGroupIds) {
|
||||
const tableRowIdsByGroup =
|
||||
recordGroupDefinition.id !== recordGroupId
|
||||
recordGroupId !== currentRecordGroupId
|
||||
? getSnapshotValue(
|
||||
snapshot,
|
||||
tableRowIdsByGroupFamilyState(recordGroupDefinition.id),
|
||||
recordIndexRowIdsByGroupFamilyState(recordGroupId),
|
||||
)
|
||||
: recordIds;
|
||||
|
||||
allRowIds.push(...tableRowIdsByGroup);
|
||||
}
|
||||
set(tableAllRowIdsState, allRowIds);
|
||||
set(recordIndexAllRowIdsState, allRowIds);
|
||||
} else {
|
||||
set(tableAllRowIdsState, recordIds);
|
||||
set(recordIndexAllRowIdsState, recordIds);
|
||||
}
|
||||
|
||||
onEntityCountChange(totalCount);
|
||||
}
|
||||
},
|
||||
[
|
||||
tableRowIdsByGroupFamilyState,
|
||||
tableAllRowIdsState,
|
||||
recordGroupDefinitionsState,
|
||||
recordIndexRowIdsByGroupFamilyState,
|
||||
recordIndexAllRowIdsState,
|
||||
hasUserSelectedAllRowsState,
|
||||
recordIndexRecordGroupIdsState,
|
||||
onEntityCountChange,
|
||||
isRowSelectedFamilyState,
|
||||
hasUserSelectedAllRowsState,
|
||||
],
|
||||
);
|
||||
};
|
||||
|
@ -3,9 +3,9 @@ import { useRecoilCallback } from 'recoil';
|
||||
import { MoveFocusDirection } from '@/object-record/record-table/types/MoveFocusDirection';
|
||||
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
|
||||
|
||||
import { recordIndexAllRowIdsComponentState } from '@/object-record/record-index/states/recordIndexAllRowIdsComponentState';
|
||||
import { numberOfTableColumnsComponentSelector } from '@/object-record/record-table/states/selectors/numberOfTableColumnsComponentSelector';
|
||||
import { softFocusPositionComponentState } from '@/object-record/record-table/states/softFocusPositionComponentState';
|
||||
import { tableAllRowIdsComponentState } from '@/object-record/record-table/states/tableAllRowIdsComponentState';
|
||||
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
||||
import { useSetSoftFocusPosition } from './internal/useSetSoftFocusPosition';
|
||||
|
||||
@ -17,8 +17,8 @@ export const useRecordTableMoveFocus = (recordTableId?: string) => {
|
||||
recordTableId,
|
||||
);
|
||||
|
||||
const tableAllRowIdsState = useRecoilComponentCallbackStateV2(
|
||||
tableAllRowIdsComponentState,
|
||||
const recordIndexAllRowIdsState = useRecoilComponentCallbackStateV2(
|
||||
recordIndexAllRowIdsComponentState,
|
||||
recordTableId,
|
||||
);
|
||||
|
||||
@ -47,7 +47,7 @@ export const useRecordTableMoveFocus = (recordTableId?: string) => {
|
||||
const moveDown = useRecoilCallback(
|
||||
({ snapshot }) =>
|
||||
() => {
|
||||
const allRowIds = getSnapshotValue(snapshot, tableAllRowIdsState);
|
||||
const allRowIds = getSnapshotValue(snapshot, recordIndexAllRowIdsState);
|
||||
const softFocusPosition = getSnapshotValue(
|
||||
snapshot,
|
||||
softFocusPositionState,
|
||||
@ -64,7 +64,7 @@ export const useRecordTableMoveFocus = (recordTableId?: string) => {
|
||||
row: newRowIndex,
|
||||
});
|
||||
},
|
||||
[tableAllRowIdsState, setSoftFocusPosition, softFocusPositionState],
|
||||
[recordIndexAllRowIdsState, setSoftFocusPosition, softFocusPositionState],
|
||||
);
|
||||
|
||||
const numberOfTableColumnsSelector = useRecoilComponentCallbackStateV2(
|
||||
@ -75,7 +75,7 @@ export const useRecordTableMoveFocus = (recordTableId?: string) => {
|
||||
const moveRight = useRecoilCallback(
|
||||
({ snapshot }) =>
|
||||
() => {
|
||||
const allRowIds = getSnapshotValue(snapshot, tableAllRowIdsState);
|
||||
const allRowIds = getSnapshotValue(snapshot, recordIndexAllRowIdsState);
|
||||
const softFocusPosition = getSnapshotValue(
|
||||
snapshot,
|
||||
softFocusPositionState,
|
||||
@ -116,7 +116,7 @@ export const useRecordTableMoveFocus = (recordTableId?: string) => {
|
||||
}
|
||||
},
|
||||
[
|
||||
tableAllRowIdsState,
|
||||
recordIndexAllRowIdsState,
|
||||
softFocusPositionState,
|
||||
numberOfTableColumnsSelector,
|
||||
setSoftFocusPosition,
|
||||
|
@ -3,10 +3,10 @@ import { ReactNode, useContext } from 'react';
|
||||
import { useSetRecoilState } from 'recoil';
|
||||
|
||||
import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord';
|
||||
import { recordIndexAllRowIdsComponentState } from '@/object-record/record-index/states/recordIndexAllRowIdsComponentState';
|
||||
import { 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 { tableAllRowIdsComponentState } from '@/object-record/record-table/states/tableAllRowIdsComponentState';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { useGetCurrentView } from '@/views/hooks/useGetCurrentView';
|
||||
import { isDefined } from '~/utils/isDefined';
|
||||
@ -22,8 +22,8 @@ export const RecordTableBodyDragDropContext = ({
|
||||
objectNameSingular,
|
||||
});
|
||||
|
||||
const tableAllRowIds = useRecoilComponentValueV2(
|
||||
tableAllRowIdsComponentState,
|
||||
const allRowIds = useRecoilComponentValueV2(
|
||||
recordIndexAllRowIdsComponentState,
|
||||
);
|
||||
|
||||
const { currentViewWithCombinedFiltersAndSorts } =
|
||||
@ -43,7 +43,7 @@ export const RecordTableBodyDragDropContext = ({
|
||||
return;
|
||||
}
|
||||
|
||||
const computeResult = computeNewRowPosition(result, tableAllRowIds);
|
||||
const computeResult = computeNewRowPosition(result, allRowIds);
|
||||
|
||||
if (!isDefined(computeResult)) {
|
||||
return;
|
||||
|
@ -1,22 +1,22 @@
|
||||
import { recordIndexAllRowIdsComponentState } from '@/object-record/record-index/states/recordIndexAllRowIdsComponentState';
|
||||
import { RecordTableNoRecordGroupRows } from '@/object-record/record-table/components/RecordTableNoRecordGroupRows';
|
||||
import { RecordTableBodyDragDropContext } from '@/object-record/record-table/record-table-body/components/RecordTableBodyDragDropContext';
|
||||
import { RecordTableBodyDroppable } from '@/object-record/record-table/record-table-body/components/RecordTableBodyDroppable';
|
||||
import { RecordTableBodyLoading } from '@/object-record/record-table/record-table-body/components/RecordTableBodyLoading';
|
||||
import { RecordTablePendingRow } from '@/object-record/record-table/record-table-row/components/RecordTablePendingRow';
|
||||
import { isRecordTableInitialLoadingComponentState } from '@/object-record/record-table/states/isRecordTableInitialLoadingComponentState';
|
||||
import { tableAllRowIdsComponentState } from '@/object-record/record-table/states/tableAllRowIdsComponentState';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
|
||||
export const RecordTableNoRecordGroupBody = () => {
|
||||
const tableAllRowIds = useRecoilComponentValueV2(
|
||||
tableAllRowIdsComponentState,
|
||||
const allRowIds = useRecoilComponentValueV2(
|
||||
recordIndexAllRowIdsComponentState,
|
||||
);
|
||||
|
||||
const isRecordTableInitialLoading = useRecoilComponentValueV2(
|
||||
isRecordTableInitialLoadingComponentState,
|
||||
);
|
||||
|
||||
if (isRecordTableInitialLoading && tableAllRowIds.length === 0) {
|
||||
if (isRecordTableInitialLoading && allRowIds.length === 0) {
|
||||
return <RecordTableBodyLoading />;
|
||||
}
|
||||
|
||||
|
@ -56,7 +56,7 @@ export const RecordTableRecordGroupBodyEffect = () => {
|
||||
if (!loading) {
|
||||
setRecordTableData({
|
||||
records,
|
||||
recordGroupId,
|
||||
currentRecordGroupId: recordGroupId,
|
||||
totalCount,
|
||||
});
|
||||
}
|
||||
|
@ -1,18 +1,15 @@
|
||||
import { RecordGroupContext } from '@/object-record/record-group/states/context/RecordGroupContext';
|
||||
import { recordGroupDefinitionsComponentState } from '@/object-record/record-group/states/recordGroupDefinitionsComponentState';
|
||||
import { recordGroupIdsComponentState } from '@/object-record/record-group/states/recordGroupIdsComponentState';
|
||||
import { RecordTableRecordGroupBodyEffect } from '@/object-record/record-table/record-table-body/components/RecordTableRecordGroupBodyEffect';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
|
||||
export const RecordTableRecordGroupBodyEffects = () => {
|
||||
const recordGroupDefinitions = useRecoilComponentValueV2(
|
||||
recordGroupDefinitionsComponentState,
|
||||
const recordGroupIds = useRecoilComponentValueV2(
|
||||
recordGroupIdsComponentState,
|
||||
);
|
||||
|
||||
return recordGroupDefinitions.map((recordGroupDefinition) => (
|
||||
<RecordGroupContext.Provider
|
||||
key={recordGroupDefinition.id}
|
||||
value={{ recordGroupId: recordGroupDefinition.id }}
|
||||
>
|
||||
return recordGroupIds.map((recordGroupId) => (
|
||||
<RecordGroupContext.Provider key={recordGroupId} value={{ recordGroupId }}>
|
||||
<RecordTableRecordGroupBodyEffect />
|
||||
</RecordGroupContext.Provider>
|
||||
));
|
||||
|
@ -1,32 +1,28 @@
|
||||
import { useRecordGroups } from '@/object-record/record-group/hooks/useRecordGroups';
|
||||
import { RecordGroupContext } from '@/object-record/record-group/states/context/RecordGroupContext';
|
||||
import { visibleRecordGroupIdsComponentSelector } from '@/object-record/record-group/states/selectors/visibleRecordGroupIdsComponentSelector';
|
||||
import { recordIndexAllRowIdsComponentState } from '@/object-record/record-index/states/recordIndexAllRowIdsComponentState';
|
||||
import { RecordTableRecordGroupRows } from '@/object-record/record-table/components/RecordTableRecordGroupRows';
|
||||
import { RecordTableBodyDragDropContext } from '@/object-record/record-table/record-table-body/components/RecordTableBodyDragDropContext';
|
||||
import { RecordTableBodyDroppable } from '@/object-record/record-table/record-table-body/components/RecordTableBodyDroppable';
|
||||
import { RecordTableBodyLoading } from '@/object-record/record-table/record-table-body/components/RecordTableBodyLoading';
|
||||
import { RecordTablePendingRow } from '@/object-record/record-table/record-table-row/components/RecordTablePendingRow';
|
||||
import { isRecordTableInitialLoadingComponentState } from '@/object-record/record-table/states/isRecordTableInitialLoadingComponentState';
|
||||
import { tableAllRowIdsComponentState } from '@/object-record/record-table/states/tableAllRowIdsComponentState';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
|
||||
type RecordTableRecordGroupsBodyProps = {
|
||||
objectNameSingular: string;
|
||||
};
|
||||
|
||||
export const RecordTableRecordGroupsBody = ({
|
||||
objectNameSingular,
|
||||
}: RecordTableRecordGroupsBodyProps) => {
|
||||
const tableAllRowIds = useRecoilComponentValueV2(
|
||||
tableAllRowIdsComponentState,
|
||||
export const RecordTableRecordGroupsBody = () => {
|
||||
const allRowIds = useRecoilComponentValueV2(
|
||||
recordIndexAllRowIdsComponentState,
|
||||
);
|
||||
|
||||
const isRecordTableInitialLoading = useRecoilComponentValueV2(
|
||||
isRecordTableInitialLoadingComponentState,
|
||||
);
|
||||
|
||||
const { visibleRecordGroups } = useRecordGroups({ objectNameSingular });
|
||||
const visibleRecordGroupIds = useRecoilComponentValueV2(
|
||||
visibleRecordGroupIdsComponentSelector,
|
||||
);
|
||||
|
||||
if (isRecordTableInitialLoading && tableAllRowIds.length === 0) {
|
||||
if (isRecordTableInitialLoading && allRowIds.length === 0) {
|
||||
return <RecordTableBodyLoading />;
|
||||
}
|
||||
|
||||
@ -34,10 +30,10 @@ export const RecordTableRecordGroupsBody = ({
|
||||
<RecordTableBodyDragDropContext>
|
||||
<RecordTableBodyDroppable>
|
||||
<RecordTablePendingRow />
|
||||
{visibleRecordGroups.map((recordGroupDefinition) => (
|
||||
{visibleRecordGroupIds.map((recordGroupId) => (
|
||||
<RecordGroupContext.Provider
|
||||
key={recordGroupDefinition.id}
|
||||
value={{ recordGroupId: recordGroupDefinition.id }}
|
||||
key={recordGroupId}
|
||||
value={{ recordGroupId }}
|
||||
>
|
||||
<RecordTableRecordGroupRows />
|
||||
</RecordGroupContext.Provider>
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { selectedRowIdsComponentSelector } from '@/object-record/record-table/states/selectors/selectedRowIdsComponentSelector';
|
||||
|
||||
import { recordIndexAllRowIdsComponentState } from '@/object-record/record-index/states/recordIndexAllRowIdsComponentState';
|
||||
import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext';
|
||||
import { tableAllRowIdsComponentState } from '@/object-record/record-table/states/tableAllRowIdsComponentState';
|
||||
import { createComponentSelectorV2 } from '@/ui/utilities/state/component-state/utils/createComponentSelectorV2';
|
||||
import { AllRowsSelectedStatus } from '../../types/AllRowSelectedStatus';
|
||||
|
||||
@ -12,8 +12,9 @@ export const allRowsSelectedStatusComponentSelector =
|
||||
get:
|
||||
({ instanceId }) =>
|
||||
({ get }) => {
|
||||
const tableRowIds = get(
|
||||
tableAllRowIdsComponentState.atomFamily({
|
||||
const allRowIds = get(
|
||||
// TODO: Working because instanceId is the same, but we're not in the same context, should be changed !
|
||||
recordIndexAllRowIdsComponentState.atomFamily({
|
||||
instanceId,
|
||||
}),
|
||||
);
|
||||
@ -29,7 +30,7 @@ export const allRowsSelectedStatusComponentSelector =
|
||||
const allRowsSelectedStatus =
|
||||
numberOfSelectedRows === 0
|
||||
? 'none'
|
||||
: selectedRowIds.length === tableRowIds.length
|
||||
: selectedRowIds.length === allRowIds.length
|
||||
? 'all'
|
||||
: 'some';
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { recordIndexAllRowIdsComponentState } from '@/object-record/record-index/states/recordIndexAllRowIdsComponentState';
|
||||
import { isRowSelectedComponentFamilyState } from '@/object-record/record-table/record-table-row/states/isRowSelectedComponentFamilyState';
|
||||
import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext';
|
||||
import { tableAllRowIdsComponentState } from '@/object-record/record-table/states/tableAllRowIdsComponentState';
|
||||
import { createComponentSelectorV2 } from '@/ui/utilities/state/component-state/utils/createComponentSelectorV2';
|
||||
|
||||
export const selectedRowIdsComponentSelector = createComponentSelectorV2<
|
||||
@ -11,13 +11,14 @@ export const selectedRowIdsComponentSelector = createComponentSelectorV2<
|
||||
get:
|
||||
({ instanceId }) =>
|
||||
({ get }) => {
|
||||
const rowIds = get(
|
||||
tableAllRowIdsComponentState.atomFamily({
|
||||
const allRowIds = get(
|
||||
// TODO: Working because instanceId is the same, but we're not in the same context, should be changed !
|
||||
recordIndexAllRowIdsComponentState.atomFamily({
|
||||
instanceId,
|
||||
}),
|
||||
);
|
||||
|
||||
return rowIds.filter(
|
||||
return allRowIds.filter(
|
||||
(rowId) =>
|
||||
get(
|
||||
isRowSelectedComponentFamilyState.atomFamily({
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { recordIndexAllRowIdsComponentState } from '@/object-record/record-index/states/recordIndexAllRowIdsComponentState';
|
||||
import { isRowSelectedComponentFamilyState } from '@/object-record/record-table/record-table-row/states/isRowSelectedComponentFamilyState';
|
||||
import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext';
|
||||
import { tableAllRowIdsComponentState } from '@/object-record/record-table/states/tableAllRowIdsComponentState';
|
||||
import { createComponentSelectorV2 } from '@/ui/utilities/state/component-state/utils/createComponentSelectorV2';
|
||||
|
||||
export const unselectedRowIdsComponentSelector = createComponentSelectorV2<
|
||||
@ -12,7 +12,8 @@ export const unselectedRowIdsComponentSelector = createComponentSelectorV2<
|
||||
({ instanceId }) =>
|
||||
({ get }) => {
|
||||
const rowIds = get(
|
||||
tableAllRowIdsComponentState.atomFamily({
|
||||
// TODO: Working because instanceId is the same, but we're not in the same context, should be changed !
|
||||
recordIndexAllRowIdsComponentState.atomFamily({
|
||||
instanceId,
|
||||
}),
|
||||
);
|
||||
|
@ -1,8 +0,0 @@
|
||||
import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext';
|
||||
import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2';
|
||||
|
||||
export const tableAllRowIdsComponentState = createComponentStateV2<string[]>({
|
||||
key: 'tableAllRowIdsComponentState',
|
||||
defaultValue: [],
|
||||
componentInstanceContext: RecordTableComponentInstanceContext,
|
||||
});
|
@ -0,0 +1,30 @@
|
||||
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
|
||||
import { ComponentFamilyStateV2 } from '@/ui/utilities/state/component-state/types/ComponentFamilyStateV2';
|
||||
import { globalComponentInstanceContextMap } from '@/ui/utilities/state/component-state/utils/globalComponentInstanceContextMap';
|
||||
import { SerializableParam, useRecoilState } from 'recoil';
|
||||
|
||||
export const useRecoilComponentFamilyStateV2 = <
|
||||
StateType,
|
||||
FamilyKey extends SerializableParam,
|
||||
>(
|
||||
componentState: ComponentFamilyStateV2<StateType, FamilyKey>,
|
||||
familyKey: FamilyKey,
|
||||
instanceIdFromProps?: string,
|
||||
) => {
|
||||
const componentInstanceContext = globalComponentInstanceContextMap.get(
|
||||
componentState.key,
|
||||
);
|
||||
|
||||
if (!componentInstanceContext) {
|
||||
throw new Error(
|
||||
`Instance context for key "${componentState.key}" is not defined`,
|
||||
);
|
||||
}
|
||||
|
||||
const instanceId = useAvailableComponentInstanceIdOrThrow(
|
||||
componentInstanceContext,
|
||||
instanceIdFromProps,
|
||||
);
|
||||
|
||||
return useRecoilState(componentState.atomFamily({ instanceId, familyKey }));
|
||||
};
|
@ -20,6 +20,56 @@ export const useSaveCurrentViewGroups = (viewBarComponentId?: string) => {
|
||||
viewBarComponentId,
|
||||
);
|
||||
|
||||
const saveViewGroup = useRecoilCallback(
|
||||
({ snapshot }) =>
|
||||
async (viewGroupToSave: ViewGroup) => {
|
||||
const currentViewId = snapshot
|
||||
.getLoadable(currentViewIdCallbackState)
|
||||
.getValue();
|
||||
|
||||
if (!currentViewId) {
|
||||
return;
|
||||
}
|
||||
|
||||
const view = await getViewFromCache(currentViewId);
|
||||
|
||||
if (isUndefinedOrNull(view)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const currentViewGroups = view.viewGroups;
|
||||
|
||||
const existingField = currentViewGroups.find(
|
||||
(currentViewGroup) =>
|
||||
currentViewGroup.fieldValue === viewGroupToSave.fieldValue,
|
||||
);
|
||||
|
||||
if (isUndefinedOrNull(existingField)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
isDeeplyEqual(
|
||||
{
|
||||
position: existingField.position,
|
||||
isVisible: existingField.isVisible,
|
||||
},
|
||||
{
|
||||
position: viewGroupToSave.position,
|
||||
isVisible: viewGroupToSave.isVisible,
|
||||
},
|
||||
)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
await updateViewGroupRecords([
|
||||
{ ...viewGroupToSave, id: existingField.id },
|
||||
]);
|
||||
},
|
||||
[currentViewIdCallbackState, getViewFromCache, updateViewGroupRecords],
|
||||
);
|
||||
|
||||
const saveViewGroups = useRecoilCallback(
|
||||
({ snapshot }) =>
|
||||
async (viewGroupsToSave: ViewGroup[]) => {
|
||||
@ -91,6 +141,7 @@ export const useSaveCurrentViewGroups = (viewBarComponentId?: string) => {
|
||||
);
|
||||
|
||||
return {
|
||||
saveViewGroup,
|
||||
saveViewGroups,
|
||||
};
|
||||
};
|
||||
|
@ -1,17 +1,9 @@
|
||||
import { RecordGroupDefinition } from '@/object-record/record-group/types/RecordGroupDefinition';
|
||||
import { ViewGroup } from '@/views/types/ViewGroup';
|
||||
import { recordGroupDefinitionToViewGroup } from '@/views/utils/recordGroupDefinitionToViewGroup';
|
||||
|
||||
export const mapRecordGroupDefinitionsToViewGroups = (
|
||||
groupDefinitions: RecordGroupDefinition[],
|
||||
): ViewGroup[] => {
|
||||
return groupDefinitions.map(
|
||||
(groupDefinition): ViewGroup => ({
|
||||
__typename: 'ViewGroup',
|
||||
id: groupDefinition.id,
|
||||
fieldMetadataId: groupDefinition.fieldMetadataId,
|
||||
position: groupDefinition.position,
|
||||
isVisible: groupDefinition.isVisible ?? true,
|
||||
fieldValue: groupDefinition.value ?? '',
|
||||
}),
|
||||
);
|
||||
return groupDefinitions.map(recordGroupDefinitionToViewGroup);
|
||||
};
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { v4 } from 'uuid';
|
||||
import { isDefined } from '~/utils/isDefined';
|
||||
|
||||
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||
@ -42,16 +43,7 @@ export const mapViewGroupsToRecordGroupDefinitions = ({
|
||||
);
|
||||
|
||||
if (!selectedOption) {
|
||||
return {
|
||||
id: 'no-value',
|
||||
title: 'No Value',
|
||||
type: RecordGroupDefinitionType.NoValue,
|
||||
value: null,
|
||||
position: viewGroup.position,
|
||||
isVisible: viewGroup.isVisible,
|
||||
fieldMetadataId: selectFieldMetadataItem.id,
|
||||
color: 'transparent',
|
||||
} satisfies RecordGroupDefinition;
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
@ -65,8 +57,32 @@ export const mapViewGroupsToRecordGroupDefinitions = ({
|
||||
isVisible: viewGroup.isVisible,
|
||||
} as RecordGroupDefinition;
|
||||
})
|
||||
.filter(isDefined)
|
||||
.sort((a, b) => a.position - b.position);
|
||||
.filter(isDefined);
|
||||
|
||||
return recordGroupDefinitionsFromViewGroups;
|
||||
if (selectFieldMetadataItem.isNullable === true) {
|
||||
const viewGroup = viewGroups.find(
|
||||
(viewGroup) => viewGroup.fieldValue === '',
|
||||
);
|
||||
|
||||
const noValueColumn = {
|
||||
id: viewGroup?.id ?? v4(),
|
||||
title: 'No Value',
|
||||
type: RecordGroupDefinitionType.NoValue,
|
||||
value: null,
|
||||
position:
|
||||
viewGroup?.position ??
|
||||
recordGroupDefinitionsFromViewGroups
|
||||
.map((option) => option.position)
|
||||
.reduce((a, b) => Math.max(a, b), 0) + 1,
|
||||
isVisible: viewGroup?.isVisible ?? true,
|
||||
fieldMetadataId: selectFieldMetadataItem.id,
|
||||
color: 'transparent',
|
||||
} satisfies RecordGroupDefinition;
|
||||
|
||||
return [...recordGroupDefinitionsFromViewGroups, noValueColumn];
|
||||
}
|
||||
|
||||
return recordGroupDefinitionsFromViewGroups.sort(
|
||||
(a, b) => a.position - b.position,
|
||||
);
|
||||
};
|
||||
|
@ -0,0 +1,15 @@
|
||||
import { RecordGroupDefinition } from '@/object-record/record-group/types/RecordGroupDefinition';
|
||||
import { ViewGroup } from '@/views/types/ViewGroup';
|
||||
|
||||
export const recordGroupDefinitionToViewGroup = (
|
||||
recordGroup: RecordGroupDefinition,
|
||||
): ViewGroup => {
|
||||
return {
|
||||
__typename: 'ViewGroup',
|
||||
id: recordGroup.id,
|
||||
fieldMetadataId: recordGroup.fieldMetadataId,
|
||||
position: recordGroup.position,
|
||||
isVisible: recordGroup.isVisible ?? true,
|
||||
fieldValue: recordGroup.value ?? '',
|
||||
};
|
||||
};
|
Loading…
Reference in New Issue
Block a user