Refacto views (#10272)
In this huge (sorry!) PR: - introducing objectMetadataItem in contextStore instead of objectMetadataId which is more convenient - splitting some big hooks into smaller parts to avoid re-renders - removing Effects to avoid re-renders (especially onViewChange) - making the view prefetch separate from favorites to avoid re-renders - making the view prefetch load a state and add selectors on top of it to avoir re-renders As a result, the performance is WAY better (I suspect the favorite implementation to trigger a lot of re-renders unfortunately). However, we are still facing a random app freeze on view creation. I could not investigate the root cause. As this seems to be already there in the precedent release, we can move forward but this seems a urgent follow up to me ==> EDIT: I've found the root cause after a few ours of deep dive... an infinite loop in RecordTableNoRecordGroupBodyEffect... prastoin edit: close https://github.com/twentyhq/twenty/issues/10253 --------- Co-authored-by: Lucas Bordeau <bordeau.lucas@gmail.com> Co-authored-by: prastoin <paul@twenty.com>
This commit is contained in:
@ -1,9 +1,9 @@
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
|
||||
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
|
||||
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
|
||||
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
||||
import { useGetViewFromCache } from '@/views/hooks/useGetViewFromCache';
|
||||
import { currentViewIdComponentState } from '@/views/states/currentViewIdComponentState';
|
||||
import { useGetViewFromPrefetchState } from '@/views/hooks/useGetViewFromPrefetchState';
|
||||
import { unsavedToDeleteViewFilterGroupIdsComponentFamilyState } from '@/views/states/unsavedToDeleteViewFilterGroupIdsComponentFamilyState';
|
||||
import { unsavedToUpsertViewFilterGroupsComponentFamilyState } from '@/views/states/unsavedToUpsertViewFilterGroupsComponentFamilyState';
|
||||
import { isDefined } from 'twenty-shared';
|
||||
@ -24,11 +24,10 @@ export const useDeleteCombinedViewFilterGroup = (
|
||||
);
|
||||
|
||||
const currentViewIdCallbackState = useRecoilComponentCallbackStateV2(
|
||||
currentViewIdComponentState,
|
||||
viewBarComponentId,
|
||||
contextStoreCurrentViewIdComponentState,
|
||||
);
|
||||
|
||||
const { getViewFromCache } = useGetViewFromCache();
|
||||
const { getViewFromPrefetchState } = useGetViewFromPrefetchState();
|
||||
|
||||
const deleteCombinedViewFilterGroup = useRecoilCallback(
|
||||
({ snapshot, set }) =>
|
||||
@ -56,7 +55,7 @@ export const useDeleteCombinedViewFilterGroup = (
|
||||
return;
|
||||
}
|
||||
|
||||
const currentView = await getViewFromCache(currentViewId);
|
||||
const currentView = await getViewFromPrefetchState(currentViewId);
|
||||
|
||||
if (!currentView) {
|
||||
return;
|
||||
@ -99,7 +98,7 @@ export const useDeleteCombinedViewFilterGroup = (
|
||||
},
|
||||
[
|
||||
currentViewIdCallbackState,
|
||||
getViewFromCache,
|
||||
getViewFromPrefetchState,
|
||||
unsavedToDeleteViewFilterGroupIdsCallbackState,
|
||||
unsavedToUpsertViewFilterGroupsCallbackState,
|
||||
],
|
||||
|
||||
@ -116,6 +116,7 @@ export const useCreateOneRecord = <
|
||||
objectMetadataItem,
|
||||
objectMetadataItems,
|
||||
record: recordCreatedInCache,
|
||||
recordGqlFields: computedRecordGqlFields,
|
||||
computeReferences: false,
|
||||
});
|
||||
|
||||
|
||||
@ -17,6 +17,7 @@ import {
|
||||
ComponentDecorator,
|
||||
getCanvasElementForDropdownTesting,
|
||||
} from 'twenty-ui';
|
||||
import { ContextStoreDecorator } from '~/testing/decorators/ContextStoreDecorator';
|
||||
import { I18nFrontDecorator } from '~/testing/decorators/I18nFrontDecorator';
|
||||
import { IconsProviderDecorator } from '~/testing/decorators/IconsProviderDecorator';
|
||||
import { ObjectMetadataItemsDecorator } from '~/testing/decorators/ObjectMetadataItemsDecorator';
|
||||
@ -79,6 +80,7 @@ const meta: Meta<typeof MultipleFiltersDropdownButton> = {
|
||||
</RecordIndexContextProvider>
|
||||
);
|
||||
},
|
||||
ContextStoreDecorator,
|
||||
ObjectMetadataItemsDecorator,
|
||||
SnackBarDecorator,
|
||||
ComponentDecorator,
|
||||
|
||||
@ -36,7 +36,6 @@ export const ObjectOptionsDropdownRecordGroupFieldsContent = () => {
|
||||
const {
|
||||
viewType,
|
||||
currentContentId,
|
||||
recordIndexId,
|
||||
objectMetadataItem,
|
||||
onContentChange,
|
||||
resetContent,
|
||||
@ -64,9 +63,7 @@ export const ObjectOptionsDropdownRecordGroupFieldsContent = () => {
|
||||
const {
|
||||
handleRecordGroupFieldChange: setRecordGroupField,
|
||||
resetRecordGroupField,
|
||||
} = useHandleRecordGroupField({
|
||||
viewBarComponentId: recordIndexId,
|
||||
});
|
||||
} = useHandleRecordGroupField();
|
||||
|
||||
const newSelectFieldSettingsUrl = getSettingsPath(
|
||||
SettingsPath.ObjectNewFieldConfigure,
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
import { Meta, StoryObj } from '@storybook/react';
|
||||
import { ComponentDecorator } from 'twenty-ui';
|
||||
|
||||
import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext';
|
||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||
import { ObjectOptionsDropdownContent } from '@/object-record/object-options-dropdown/components/ObjectOptionsDropdownContent';
|
||||
import { OBJECT_OPTIONS_DROPDOWN_ID } from '@/object-record/object-options-dropdown/constants/ObjectOptionsDropdownId';
|
||||
@ -16,6 +15,7 @@ import { ViewType } from '@/views/types/ViewType';
|
||||
import { useEffect } from 'react';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import { useSetRecoilState } from 'recoil';
|
||||
import { ContextStoreDecorator } from '~/testing/decorators/ContextStoreDecorator';
|
||||
import { IconsProviderDecorator } from '~/testing/decorators/IconsProviderDecorator';
|
||||
import { ObjectMetadataItemsDecorator } from '~/testing/decorators/ObjectMetadataItemsDecorator';
|
||||
import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator';
|
||||
@ -45,21 +45,18 @@ const meta: Meta<typeof ObjectOptionsDropdownContent> = {
|
||||
value={{ instanceId, onColumnsChange: () => {} }}
|
||||
>
|
||||
<ViewComponentInstanceContext.Provider value={{ instanceId }}>
|
||||
<ContextStoreComponentInstanceContext.Provider
|
||||
value={{ instanceId }}
|
||||
<MemoryRouter
|
||||
initialEntries={['/one', '/two', { pathname: '/three' }]}
|
||||
initialIndex={1}
|
||||
>
|
||||
<MemoryRouter
|
||||
initialEntries={['/one', '/two', { pathname: '/three' }]}
|
||||
initialIndex={1}
|
||||
>
|
||||
<Story />
|
||||
</MemoryRouter>
|
||||
</ContextStoreComponentInstanceContext.Provider>
|
||||
<Story />
|
||||
</MemoryRouter>
|
||||
</ViewComponentInstanceContext.Provider>
|
||||
</RecordTableComponentInstanceContext.Provider>
|
||||
</RecordFiltersComponentInstanceContext.Provider>
|
||||
);
|
||||
},
|
||||
ContextStoreDecorator,
|
||||
ObjectMetadataItemsDecorator,
|
||||
SnackBarDecorator,
|
||||
ComponentDecorator,
|
||||
|
||||
@ -26,13 +26,12 @@ type useObjectOptionsForBoardParams = {
|
||||
export const useObjectOptionsForBoard = ({
|
||||
objectNameSingular,
|
||||
recordBoardId,
|
||||
viewBarId,
|
||||
}: useObjectOptionsForBoardParams) => {
|
||||
const [recordIndexFieldDefinitions, setRecordIndexFieldDefinitions] =
|
||||
useRecoilState(recordIndexFieldDefinitionsState);
|
||||
|
||||
const { saveViewFields } = useSaveCurrentViewFields(viewBarId);
|
||||
const { updateCurrentView } = useUpdateCurrentView(viewBarId);
|
||||
const { saveViewFields } = useSaveCurrentViewFields();
|
||||
const { updateCurrentView } = useUpdateCurrentView();
|
||||
|
||||
const [isCompactModeActive, setIsCompactModeActive] =
|
||||
useRecoilComponentStateV2(
|
||||
|
||||
@ -23,7 +23,7 @@ export const useRecordGroupReorder = ({
|
||||
viewBarId,
|
||||
viewType,
|
||||
}: UseRecordGroupHandlersParams) => {
|
||||
const setRecordGroup = useSetRecordGroup(viewBarId);
|
||||
const setRecordGroup = useSetRecordGroup();
|
||||
|
||||
const visibleRecordGroupIdsFamilySelector = useRecoilComponentCallbackStateV2(
|
||||
visibleRecordGroupIdsComponentFamilySelector,
|
||||
@ -78,7 +78,7 @@ export const useRecordGroupReorder = ({
|
||||
];
|
||||
}, []);
|
||||
|
||||
setRecordGroup(updatedRecordGroups);
|
||||
setRecordGroup(updatedRecordGroups, viewBarId);
|
||||
saveViewGroups(
|
||||
mapRecordGroupDefinitionsToViewGroups(updatedRecordGroups),
|
||||
);
|
||||
@ -86,6 +86,7 @@ export const useRecordGroupReorder = ({
|
||||
[
|
||||
saveViewGroups,
|
||||
setRecordGroup,
|
||||
viewBarId,
|
||||
viewType,
|
||||
visibleRecordGroupIdsFamilySelector,
|
||||
],
|
||||
|
||||
@ -1,32 +1,33 @@
|
||||
import { contextStoreCurrentObjectMetadataItemComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataItemComponentState';
|
||||
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 { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext';
|
||||
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
||||
import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue';
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
|
||||
|
||||
export const useSetRecordGroup = (viewId?: string) => {
|
||||
const { objectMetadataItem } = useRecordIndexContextOrThrow();
|
||||
|
||||
const recordIndexRecordGroupIdsState = useRecoilComponentCallbackStateV2(
|
||||
recordGroupIdsComponentState,
|
||||
viewId,
|
||||
);
|
||||
|
||||
const recordGroupFieldMetadataState = useRecoilComponentCallbackStateV2(
|
||||
recordGroupFieldMetadataComponentState,
|
||||
viewId,
|
||||
);
|
||||
|
||||
export const useSetRecordGroup = () => {
|
||||
return useRecoilCallback(
|
||||
({ snapshot, set }) =>
|
||||
(recordGroups: RecordGroupDefinition[]) => {
|
||||
(recordGroups: RecordGroupDefinition[], recordIndexId: string) => {
|
||||
const objectMetadataItem = snapshot
|
||||
.getLoadable(
|
||||
contextStoreCurrentObjectMetadataItemComponentState.atomFamily({
|
||||
instanceId: 'main-context-store',
|
||||
}),
|
||||
)
|
||||
.getValue();
|
||||
|
||||
if (!objectMetadataItem) {
|
||||
return;
|
||||
}
|
||||
|
||||
const currentRecordGroupIds = getSnapshotValue(
|
||||
snapshot,
|
||||
recordIndexRecordGroupIdsState,
|
||||
recordGroupIdsComponentState.atomFamily({
|
||||
instanceId: recordIndexId,
|
||||
}),
|
||||
);
|
||||
const fieldMetadataId = recordGroups?.[0]?.fieldMetadataId;
|
||||
const fieldMetadata = fieldMetadataId
|
||||
@ -36,12 +37,19 @@ export const useSetRecordGroup = (viewId?: string) => {
|
||||
: undefined;
|
||||
const currentFieldMetadata = getSnapshotValue(
|
||||
snapshot,
|
||||
recordGroupFieldMetadataState,
|
||||
recordGroupFieldMetadataComponentState.atomFamily({
|
||||
instanceId: recordIndexId,
|
||||
}),
|
||||
);
|
||||
|
||||
// Set the field metadata linked to the record groups
|
||||
if (!isDeeplyEqual(fieldMetadata, currentFieldMetadata)) {
|
||||
set(recordGroupFieldMetadataState, fieldMetadata);
|
||||
set(
|
||||
recordGroupFieldMetadataComponentState.atomFamily({
|
||||
instanceId: recordIndexId,
|
||||
}),
|
||||
fieldMetadata,
|
||||
);
|
||||
}
|
||||
|
||||
// Set the record groups by id
|
||||
@ -75,12 +83,13 @@ export const useSetRecordGroup = (viewId?: string) => {
|
||||
}
|
||||
|
||||
// Set the record group ids
|
||||
set(recordIndexRecordGroupIdsState, recordGroupIds);
|
||||
set(
|
||||
recordGroupIdsComponentState.atomFamily({
|
||||
instanceId: recordIndexId,
|
||||
}),
|
||||
recordGroupIds,
|
||||
);
|
||||
},
|
||||
[
|
||||
objectMetadataItem.fields,
|
||||
recordGroupFieldMetadataState,
|
||||
recordIndexRecordGroupIdsState,
|
||||
],
|
||||
[],
|
||||
);
|
||||
};
|
||||
|
||||
@ -1,52 +1,26 @@
|
||||
import styled from '@emotion/styled';
|
||||
import { useRecoilCallback, useRecoilState, useSetRecoilState } from 'recoil';
|
||||
import { isDefined } from 'twenty-shared';
|
||||
import { useRecoilState } from 'recoil';
|
||||
|
||||
import { useColumnDefinitionsFromFieldMetadata } from '@/object-metadata/hooks/useColumnDefinitionsFromFieldMetadata';
|
||||
import { ObjectOptionsDropdown } from '@/object-record/object-options-dropdown/components/ObjectOptionsDropdown';
|
||||
import { RecordIndexBoardContainer } from '@/object-record/record-index/components/RecordIndexBoardContainer';
|
||||
import { RecordIndexBoardDataLoader } from '@/object-record/record-index/components/RecordIndexBoardDataLoader';
|
||||
import { RecordIndexBoardDataLoaderEffect } from '@/object-record/record-index/components/RecordIndexBoardDataLoaderEffect';
|
||||
import { RecordIndexTableContainer } from '@/object-record/record-index/components/RecordIndexTableContainer';
|
||||
import { RecordIndexViewBarEffect } from '@/object-record/record-index/components/RecordIndexViewBarEffect';
|
||||
import { recordIndexFieldDefinitionsState } from '@/object-record/record-index/states/recordIndexFieldDefinitionsState';
|
||||
import { recordIndexFiltersState } from '@/object-record/record-index/states/recordIndexFiltersState';
|
||||
import { recordIndexIsCompactModeActiveState } from '@/object-record/record-index/states/recordIndexIsCompactModeActiveState';
|
||||
import { recordIndexKanbanFieldMetadataIdState } from '@/object-record/record-index/states/recordIndexKanbanFieldMetadataIdState';
|
||||
import { recordIndexSortsState } from '@/object-record/record-index/states/recordIndexSortsState';
|
||||
import { recordIndexViewTypeState } from '@/object-record/record-index/states/recordIndexViewTypeState';
|
||||
|
||||
import { InformationBannerWrapper } from '@/information-banner/components/InformationBannerWrapper';
|
||||
import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext';
|
||||
import { RecordFieldValueSelectorContextProvider } from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext';
|
||||
import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable';
|
||||
import { SpreadsheetImportProvider } from '@/spreadsheet-import/provider/components/SpreadsheetImportProvider';
|
||||
|
||||
import { RecordIndexActionMenu } from '@/action-menu/components/RecordIndexActionMenu';
|
||||
import { ContextStoreCurrentViewTypeEffect } from '@/context-store/components/ContextStoreCurrentViewTypeEffect';
|
||||
import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState';
|
||||
import { ContextStoreViewType } from '@/context-store/types/ContextStoreViewType';
|
||||
import { useFilterableFieldMetadataItems } from '@/object-record/record-filter/hooks/useFilterableFieldMetadataItems';
|
||||
import { useSetRecordGroup } from '@/object-record/record-group/hooks/useSetRecordGroup';
|
||||
import { RecordIndexFiltersToContextStoreEffect } from '@/object-record/record-index/components/RecordIndexFiltersToContextStoreEffect';
|
||||
import { RecordIndexTableContainerEffect } from '@/object-record/record-index/components/RecordIndexTableContainerEffect';
|
||||
import { recordIndexKanbanAggregateOperationState } from '@/object-record/record-index/states/recordIndexKanbanAggregateOperationState';
|
||||
import { recordIndexViewFilterGroupsState } from '@/object-record/record-index/states/recordIndexViewFilterGroupsState';
|
||||
import { viewFieldAggregateOperationState } from '@/object-record/record-table/record-table-footer/states/viewFieldAggregateOperationState';
|
||||
import { convertAggregateOperationToExtendedAggregateOperation } from '@/object-record/utils/convertAggregateOperationToExtendedAggregateOperation';
|
||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||
import { ViewBar } from '@/views/components/ViewBar';
|
||||
import { ViewField } from '@/views/types/ViewField';
|
||||
import { ViewGroup } from '@/views/types/ViewGroup';
|
||||
import { ViewType } from '@/views/types/ViewType';
|
||||
import { mapViewFieldsToColumnDefinitions } from '@/views/utils/mapViewFieldsToColumnDefinitions';
|
||||
import { mapViewFiltersToFilters } from '@/views/utils/mapViewFiltersToFilters';
|
||||
import { mapViewGroupsToRecordGroupDefinitions } from '@/views/utils/mapViewGroupsToRecordGroupDefinitions';
|
||||
import { mapViewSortsToSorts } from '@/views/utils/mapViewSortsToSorts';
|
||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||
import { useCallback } from 'react';
|
||||
import { FeatureFlagKey } from '~/generated/graphql';
|
||||
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
|
||||
|
||||
const StyledContainer = styled.div`
|
||||
display: flex;
|
||||
@ -64,9 +38,7 @@ const StyledContainerWithPadding = styled.div`
|
||||
`;
|
||||
|
||||
export const RecordIndexContainer = () => {
|
||||
const [recordIndexViewType, setRecordIndexViewType] = useRecoilState(
|
||||
recordIndexViewTypeState,
|
||||
);
|
||||
const [recordIndexViewType] = useRecoilState(recordIndexViewTypeState);
|
||||
|
||||
const {
|
||||
objectNamePlural,
|
||||
@ -75,128 +47,12 @@ export const RecordIndexContainer = () => {
|
||||
objectNameSingular,
|
||||
} = useRecordIndexContextOrThrow();
|
||||
|
||||
const setRecordGroup = useSetRecordGroup(recordIndexId);
|
||||
|
||||
const { columnDefinitions, sortDefinitions } =
|
||||
useColumnDefinitionsFromFieldMetadata(objectMetadataItem);
|
||||
|
||||
const setRecordIndexViewFilterGroups = useSetRecoilState(
|
||||
recordIndexViewFilterGroupsState,
|
||||
);
|
||||
const setRecordIndexFilters = useSetRecoilState(recordIndexFiltersState);
|
||||
const setRecordIndexSorts = useSetRecoilState(recordIndexSortsState);
|
||||
const setRecordIndexIsCompactModeActive = useSetRecoilState(
|
||||
recordIndexIsCompactModeActiveState,
|
||||
);
|
||||
const setRecordIndexViewKanbanFieldMetadataIdState = useSetRecoilState(
|
||||
recordIndexKanbanFieldMetadataIdState,
|
||||
);
|
||||
const setRecordIndexViewKanbanAggregateOperationState = useSetRecoilState(
|
||||
recordIndexKanbanAggregateOperationState,
|
||||
);
|
||||
|
||||
const {
|
||||
setTableViewFilterGroups,
|
||||
setTableFilters,
|
||||
setTableSorts,
|
||||
setTableColumns,
|
||||
} = useRecordTable({
|
||||
recordTableId: recordIndexId,
|
||||
});
|
||||
|
||||
const onViewFieldsChange = useRecoilCallback(
|
||||
({ set, snapshot }) =>
|
||||
(viewFields: ViewField[]) => {
|
||||
const newFieldDefinitions = mapViewFieldsToColumnDefinitions({
|
||||
viewFields,
|
||||
columnDefinitions,
|
||||
});
|
||||
|
||||
setTableColumns(newFieldDefinitions);
|
||||
|
||||
const existingRecordIndexFieldDefinitions = snapshot
|
||||
.getLoadable(recordIndexFieldDefinitionsState)
|
||||
.getValue();
|
||||
|
||||
if (
|
||||
!isDeeplyEqual(
|
||||
existingRecordIndexFieldDefinitions,
|
||||
newFieldDefinitions,
|
||||
)
|
||||
) {
|
||||
set(recordIndexFieldDefinitionsState, newFieldDefinitions);
|
||||
}
|
||||
|
||||
for (const viewField of viewFields) {
|
||||
const viewFieldMetadataType = objectMetadataItem.fields?.find(
|
||||
(field) => field.id === viewField.fieldMetadataId,
|
||||
)?.type;
|
||||
const aggregateOperationForViewField = snapshot
|
||||
.getLoadable(
|
||||
viewFieldAggregateOperationState({
|
||||
viewFieldId: viewField.id,
|
||||
}),
|
||||
)
|
||||
.getValue();
|
||||
|
||||
const convertedViewFieldAggregateOperation = isDefined(
|
||||
viewField.aggregateOperation,
|
||||
)
|
||||
? convertAggregateOperationToExtendedAggregateOperation(
|
||||
viewField.aggregateOperation,
|
||||
viewFieldMetadataType,
|
||||
)
|
||||
: viewField.aggregateOperation;
|
||||
|
||||
if (
|
||||
aggregateOperationForViewField !==
|
||||
convertedViewFieldAggregateOperation
|
||||
) {
|
||||
set(
|
||||
viewFieldAggregateOperationState({
|
||||
viewFieldId: viewField.id,
|
||||
}),
|
||||
convertedViewFieldAggregateOperation,
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
[columnDefinitions, objectMetadataItem.fields, setTableColumns],
|
||||
);
|
||||
|
||||
const onViewGroupsChange = useCallback(
|
||||
(viewGroups: ViewGroup[]) => {
|
||||
const newGroupDefinitions = mapViewGroupsToRecordGroupDefinitions({
|
||||
objectMetadataItem,
|
||||
viewGroups,
|
||||
});
|
||||
|
||||
setRecordGroup(newGroupDefinitions);
|
||||
},
|
||||
[objectMetadataItem, setRecordGroup],
|
||||
);
|
||||
|
||||
const setContextStoreTargetedRecordsRule = useSetRecoilComponentStateV2(
|
||||
contextStoreTargetedRecordsRuleComponentState,
|
||||
);
|
||||
|
||||
const { filterableFieldMetadataItems } = useFilterableFieldMetadataItems(
|
||||
objectMetadataItem.id,
|
||||
);
|
||||
|
||||
const isCommandMenuV2Enabled = useIsFeatureEnabled(
|
||||
FeatureFlagKey.IsCommandMenuV2Enabled,
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<ContextStoreCurrentViewTypeEffect
|
||||
viewType={
|
||||
recordIndexViewType === ViewType.Table
|
||||
? ContextStoreViewType.Table
|
||||
: ContextStoreViewType.Kanban
|
||||
}
|
||||
/>
|
||||
<StyledContainer>
|
||||
<InformationBannerWrapper />
|
||||
<RecordFieldValueSelectorContextProvider>
|
||||
@ -210,60 +66,6 @@ export const RecordIndexContainer = () => {
|
||||
viewType={recordIndexViewType ?? ViewType.Table}
|
||||
/>
|
||||
}
|
||||
onCurrentViewChange={(view) => {
|
||||
if (!view) {
|
||||
return;
|
||||
}
|
||||
|
||||
onViewFieldsChange(view.viewFields);
|
||||
onViewGroupsChange(view.viewGroups);
|
||||
setTableViewFilterGroups(view.viewFilterGroups ?? []);
|
||||
setTableFilters(
|
||||
mapViewFiltersToFilters(
|
||||
view.viewFilters,
|
||||
filterableFieldMetadataItems,
|
||||
),
|
||||
);
|
||||
setRecordIndexFilters(
|
||||
mapViewFiltersToFilters(
|
||||
view.viewFilters,
|
||||
filterableFieldMetadataItems,
|
||||
),
|
||||
);
|
||||
setRecordIndexViewFilterGroups(view.viewFilterGroups ?? []);
|
||||
setContextStoreTargetedRecordsRule((prev) => ({
|
||||
...prev,
|
||||
filters: mapViewFiltersToFilters(
|
||||
view.viewFilters,
|
||||
filterableFieldMetadataItems,
|
||||
),
|
||||
}));
|
||||
setTableSorts(
|
||||
mapViewSortsToSorts(view.viewSorts, sortDefinitions),
|
||||
);
|
||||
setRecordIndexSorts(
|
||||
mapViewSortsToSorts(view.viewSorts, sortDefinitions),
|
||||
);
|
||||
setRecordIndexViewType(view.type);
|
||||
setRecordIndexViewKanbanFieldMetadataIdState(
|
||||
view.kanbanFieldMetadataId,
|
||||
);
|
||||
const kanbanAggregateOperationFieldMetadataType =
|
||||
objectMetadataItem.fields?.find(
|
||||
(field) =>
|
||||
field.id === view.kanbanAggregateOperationFieldMetadataId,
|
||||
)?.type;
|
||||
setRecordIndexViewKanbanAggregateOperationState({
|
||||
operation: isDefined(view.kanbanAggregateOperation)
|
||||
? convertAggregateOperationToExtendedAggregateOperation(
|
||||
view.kanbanAggregateOperation,
|
||||
kanbanAggregateOperationFieldMetadataType,
|
||||
)
|
||||
: view.kanbanAggregateOperation,
|
||||
fieldMetadataId: view.kanbanAggregateOperationFieldMetadataId,
|
||||
});
|
||||
setRecordIndexIsCompactModeActive(view.isCompact);
|
||||
}}
|
||||
/>
|
||||
<RecordIndexViewBarEffect
|
||||
objectNamePlural={objectNamePlural}
|
||||
|
||||
@ -1,31 +0,0 @@
|
||||
import { contextStoreCurrentObjectMetadataIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataIdComponentState';
|
||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||
import { useObjectNameSingularFromPlural } from '@/object-metadata/hooks/useObjectNameSingularFromPlural';
|
||||
import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext';
|
||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
export const RecordIndexContainerContextStoreObjectMetadataEffect = () => {
|
||||
const setContextStoreCurrentObjectMetadataItem = useSetRecoilComponentStateV2(
|
||||
contextStoreCurrentObjectMetadataIdComponentState,
|
||||
);
|
||||
const { objectNamePlural } = useRecordIndexContextOrThrow();
|
||||
|
||||
const { objectNameSingular } = useObjectNameSingularFromPlural({
|
||||
objectNamePlural,
|
||||
});
|
||||
|
||||
const { objectMetadataItem } = useObjectMetadataItem({
|
||||
objectNameSingular,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
setContextStoreCurrentObjectMetadataItem(objectMetadataItem.id);
|
||||
|
||||
return () => {
|
||||
setContextStoreCurrentObjectMetadataItem(null);
|
||||
};
|
||||
}, [objectMetadataItem.id, setContextStoreCurrentObjectMetadataItem]);
|
||||
|
||||
return null;
|
||||
};
|
||||
@ -0,0 +1,97 @@
|
||||
import { RecordIndexContextProvider } from '@/object-record/record-index/contexts/RecordIndexContext';
|
||||
|
||||
import { ActionMenuComponentInstanceContext } from '@/action-menu/states/contexts/ActionMenuComponentInstanceContext';
|
||||
import { getActionMenuIdFromRecordIndexId } from '@/action-menu/utils/getActionMenuIdFromRecordIndexId';
|
||||
import { useContextStoreObjectMetadataItemOrThrow } from '@/context-store/hooks/useContextStoreObjectMetadataItemOrThrow';
|
||||
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
|
||||
import { mainContextStoreComponentInstanceIdState } from '@/context-store/states/mainContextStoreComponentInstanceId';
|
||||
import { lastShowPageRecordIdState } from '@/object-record/record-field/states/lastShowPageRecordId';
|
||||
import { RecordFiltersComponentInstanceContext } from '@/object-record/record-filter/states/context/RecordFiltersComponentInstanceContext';
|
||||
import { RecordIndexContainer } from '@/object-record/record-index/components/RecordIndexContainer';
|
||||
import { RecordIndexContainerContextStoreNumberOfSelectedRecordsEffect } from '@/object-record/record-index/components/RecordIndexContainerContextStoreNumberOfSelectedRecordsEffect';
|
||||
import { RecordIndexLoadBaseOnContextStoreEffect } from '@/object-record/record-index/components/RecordIndexLoadBaseOnContextStoreEffect';
|
||||
import { RecordIndexPageHeader } from '@/object-record/record-index/components/RecordIndexPageHeader';
|
||||
import { useHandleIndexIdentifierClick } from '@/object-record/record-index/hooks/useHandleIndexIdentifierClick';
|
||||
import { PageBody } from '@/ui/layout/page/components/PageBody';
|
||||
import { PageTitle } from '@/ui/utilities/page-title/components/PageTitle';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext';
|
||||
import styled from '@emotion/styled';
|
||||
import { useRecoilCallback, useRecoilValue } from 'recoil';
|
||||
import { capitalize } from 'twenty-shared';
|
||||
|
||||
const StyledIndexContainer = styled.div`
|
||||
display: flex;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
`;
|
||||
|
||||
export const RecordIndexContainerGater = () => {
|
||||
const mainContextStoreComponentInstanceId = useRecoilValue(
|
||||
mainContextStoreComponentInstanceIdState,
|
||||
);
|
||||
|
||||
const contextStoreCurrentViewId = useRecoilComponentValueV2(
|
||||
contextStoreCurrentViewIdComponentState,
|
||||
mainContextStoreComponentInstanceId,
|
||||
);
|
||||
|
||||
const { objectMetadataItem } = useContextStoreObjectMetadataItemOrThrow();
|
||||
|
||||
const recordIndexId = `${objectMetadataItem.namePlural}-${contextStoreCurrentViewId}`;
|
||||
|
||||
const handleIndexRecordsLoaded = useRecoilCallback(
|
||||
({ set }) =>
|
||||
() => {
|
||||
// TODO: find a better way to reset this state ?
|
||||
set(lastShowPageRecordIdState, null);
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
const { indexIdentifierUrl } = useHandleIndexIdentifierClick({
|
||||
objectMetadataItem,
|
||||
recordIndexId,
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
<RecordIndexContextProvider
|
||||
value={{
|
||||
recordIndexId,
|
||||
objectNamePlural: objectMetadataItem.namePlural,
|
||||
objectNameSingular: objectMetadataItem.nameSingular,
|
||||
objectMetadataItem,
|
||||
onIndexRecordsLoaded: handleIndexRecordsLoaded,
|
||||
indexIdentifierUrl,
|
||||
}}
|
||||
>
|
||||
<ViewComponentInstanceContext.Provider
|
||||
value={{ instanceId: recordIndexId }}
|
||||
>
|
||||
<RecordFiltersComponentInstanceContext.Provider
|
||||
value={{ instanceId: recordIndexId }}
|
||||
>
|
||||
<ActionMenuComponentInstanceContext.Provider
|
||||
value={{
|
||||
instanceId: getActionMenuIdFromRecordIndexId(recordIndexId),
|
||||
}}
|
||||
>
|
||||
<PageTitle
|
||||
title={`${capitalize(objectMetadataItem.namePlural)}`}
|
||||
/>
|
||||
<RecordIndexPageHeader />
|
||||
<PageBody>
|
||||
<StyledIndexContainer>
|
||||
<RecordIndexContainerContextStoreNumberOfSelectedRecordsEffect />
|
||||
<RecordIndexContainer />
|
||||
</StyledIndexContainer>
|
||||
</PageBody>
|
||||
</ActionMenuComponentInstanceContext.Provider>
|
||||
</RecordFiltersComponentInstanceContext.Provider>
|
||||
<RecordIndexLoadBaseOnContextStoreEffect />
|
||||
</ViewComponentInstanceContext.Provider>
|
||||
</RecordIndexContextProvider>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@ -0,0 +1,52 @@
|
||||
import { contextStoreCurrentObjectMetadataItemComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataItemComponentState';
|
||||
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
|
||||
import { useLoadRecordIndexStates } from '@/object-record/record-index/hooks/useLoadRecordIndexStates';
|
||||
import { prefetchViewFromViewIdFamilySelector } from '@/prefetch/states/selector/prefetchViewFromViewIdFamilySelector';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { isDefined } from 'twenty-shared';
|
||||
|
||||
export const RecordIndexLoadBaseOnContextStoreEffect = () => {
|
||||
const { loadRecordIndexStates } = useLoadRecordIndexStates();
|
||||
const contextStoreCurrentViewId = useRecoilComponentValueV2(
|
||||
contextStoreCurrentViewIdComponentState,
|
||||
);
|
||||
|
||||
const [loadedViewId, setLoadedViewId] = useState<string | undefined>(
|
||||
undefined,
|
||||
);
|
||||
|
||||
const view = useRecoilValue(
|
||||
prefetchViewFromViewIdFamilySelector({
|
||||
viewId: contextStoreCurrentViewId ?? '',
|
||||
}),
|
||||
);
|
||||
|
||||
const objectMetadataItem = useRecoilComponentValueV2(
|
||||
contextStoreCurrentObjectMetadataItemComponentState,
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (loadedViewId === contextStoreCurrentViewId) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isDefined(objectMetadataItem)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isDefined(view)) {
|
||||
loadRecordIndexStates(view, objectMetadataItem);
|
||||
setLoadedViewId(contextStoreCurrentViewId);
|
||||
}
|
||||
}, [
|
||||
contextStoreCurrentViewId,
|
||||
loadRecordIndexStates,
|
||||
loadedViewId,
|
||||
objectMetadataItem,
|
||||
view,
|
||||
]);
|
||||
|
||||
return <></>;
|
||||
};
|
||||
@ -1,7 +1,7 @@
|
||||
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
|
||||
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||
import { AppPath } from '@/types/AppPath';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { currentViewIdComponentState } from '@/views/states/currentViewIdComponentState';
|
||||
import { getAppPath } from '~/utils/navigation/getAppPath';
|
||||
|
||||
export const useHandleIndexIdentifierClick = ({
|
||||
@ -12,7 +12,7 @@ export const useHandleIndexIdentifierClick = ({
|
||||
objectMetadataItem: ObjectMetadataItem;
|
||||
}) => {
|
||||
const currentViewId = useRecoilComponentValueV2(
|
||||
currentViewIdComponentState,
|
||||
contextStoreCurrentViewIdComponentState,
|
||||
recordIndexId,
|
||||
);
|
||||
|
||||
|
||||
@ -1,29 +1,22 @@
|
||||
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
|
||||
import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
|
||||
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
||||
import { usePersistViewGroupRecords } from '@/views/hooks/internal/usePersistViewGroupRecords';
|
||||
import { useGetViewFromCache } from '@/views/hooks/useGetViewFromCache';
|
||||
import { currentViewIdComponentState } from '@/views/states/currentViewIdComponentState';
|
||||
import { useGetViewFromPrefetchState } from '@/views/hooks/useGetViewFromPrefetchState';
|
||||
import { ViewGroup } from '@/views/types/ViewGroup';
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
import { v4 } from 'uuid';
|
||||
import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull';
|
||||
|
||||
type UseHandleRecordGroupFieldParams = {
|
||||
viewBarComponentId: string;
|
||||
};
|
||||
|
||||
export const useHandleRecordGroupField = ({
|
||||
viewBarComponentId,
|
||||
}: UseHandleRecordGroupFieldParams) => {
|
||||
export const useHandleRecordGroupField = () => {
|
||||
const { createViewGroupRecords, deleteViewGroupRecords } =
|
||||
usePersistViewGroupRecords();
|
||||
|
||||
const currentViewIdCallbackState = useRecoilComponentCallbackStateV2(
|
||||
currentViewIdComponentState,
|
||||
viewBarComponentId,
|
||||
contextStoreCurrentViewIdComponentState,
|
||||
);
|
||||
|
||||
const { getViewFromCache } = useGetViewFromCache();
|
||||
const { getViewFromPrefetchState } = useGetViewFromPrefetchState();
|
||||
|
||||
const handleRecordGroupFieldChange = useRecoilCallback(
|
||||
({ snapshot }) =>
|
||||
@ -36,7 +29,7 @@ export const useHandleRecordGroupField = ({
|
||||
return;
|
||||
}
|
||||
|
||||
const view = await getViewFromCache(currentViewId);
|
||||
const view = await getViewFromPrefetchState(currentViewId);
|
||||
|
||||
if (isUndefinedOrNull(view)) {
|
||||
return;
|
||||
@ -105,7 +98,7 @@ export const useHandleRecordGroupField = ({
|
||||
createViewGroupRecords,
|
||||
deleteViewGroupRecords,
|
||||
currentViewIdCallbackState,
|
||||
getViewFromCache,
|
||||
getViewFromPrefetchState,
|
||||
],
|
||||
);
|
||||
|
||||
@ -120,7 +113,7 @@ export const useHandleRecordGroupField = ({
|
||||
return;
|
||||
}
|
||||
|
||||
const view = await getViewFromCache(currentViewId);
|
||||
const view = await getViewFromPrefetchState(currentViewId);
|
||||
|
||||
if (isUndefinedOrNull(view)) {
|
||||
return;
|
||||
@ -132,7 +125,11 @@ export const useHandleRecordGroupField = ({
|
||||
|
||||
await deleteViewGroupRecords(view.viewGroups);
|
||||
},
|
||||
[deleteViewGroupRecords, currentViewIdCallbackState, getViewFromCache],
|
||||
[
|
||||
deleteViewGroupRecords,
|
||||
currentViewIdCallbackState,
|
||||
getViewFromPrefetchState,
|
||||
],
|
||||
);
|
||||
|
||||
return { handleRecordGroupFieldChange, resetRecordGroupField };
|
||||
|
||||
@ -6,13 +6,14 @@ import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords';
|
||||
import { turnSortsIntoOrderBy } from '@/object-record/object-sort-dropdown/utils/turnSortsIntoOrderBy';
|
||||
import { useSetRecordIdsForColumn } from '@/object-record/record-board/hooks/useSetRecordIdsForColumn';
|
||||
import { useFilterValueDependencies } from '@/object-record/record-filter/hooks/useFilterValueDependencies';
|
||||
import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState';
|
||||
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';
|
||||
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 { isDefined } from 'twenty-shared';
|
||||
|
||||
type UseLoadRecordIndexBoardProps = {
|
||||
@ -41,14 +42,16 @@ export const useLoadRecordIndexBoardColumn = ({
|
||||
const recordIndexViewFilterGroups = useRecoilValue(
|
||||
recordIndexViewFilterGroupsState,
|
||||
);
|
||||
const recordIndexFilters = useRecoilValue(recordIndexFiltersState);
|
||||
const currentRecordFilters = useRecoilComponentValueV2(
|
||||
currentRecordFiltersComponentState,
|
||||
);
|
||||
const recordIndexSorts = useRecoilValue(recordIndexSortsState);
|
||||
|
||||
const { filterValueDependencies } = useFilterValueDependencies();
|
||||
|
||||
const requestFilters = computeViewRecordGqlOperationFilter(
|
||||
filterValueDependencies,
|
||||
recordIndexFilters,
|
||||
currentRecordFilters,
|
||||
objectMetadataItem?.fields ?? [],
|
||||
recordIndexViewFilterGroups,
|
||||
);
|
||||
|
||||
@ -0,0 +1,281 @@
|
||||
import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState';
|
||||
import { availableFieldMetadataItemsForFilterFamilySelector } from '@/object-metadata/states/availableFieldMetadataItemsForFilterFamilySelector';
|
||||
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||
import { formatFieldMetadataItemAsColumnDefinition } from '@/object-metadata/utils/formatFieldMetadataItemAsColumnDefinition';
|
||||
import { formatFieldMetadataItemsAsSortDefinitions } from '@/object-metadata/utils/formatFieldMetadataItemsAsSortDefinitions';
|
||||
import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata';
|
||||
import { useSetRecordGroup } from '@/object-record/record-group/hooks/useSetRecordGroup';
|
||||
import { recordIndexFieldDefinitionsState } from '@/object-record/record-index/states/recordIndexFieldDefinitionsState';
|
||||
import { recordIndexFiltersState } from '@/object-record/record-index/states/recordIndexFiltersState';
|
||||
import { recordIndexIsCompactModeActiveState } from '@/object-record/record-index/states/recordIndexIsCompactModeActiveState';
|
||||
import { recordIndexKanbanAggregateOperationState } from '@/object-record/record-index/states/recordIndexKanbanAggregateOperationState';
|
||||
import { recordIndexKanbanFieldMetadataIdState } from '@/object-record/record-index/states/recordIndexKanbanFieldMetadataIdState';
|
||||
import { recordIndexSortsState } from '@/object-record/record-index/states/recordIndexSortsState';
|
||||
import { recordIndexViewFilterGroupsState } from '@/object-record/record-index/states/recordIndexViewFilterGroupsState';
|
||||
import { recordIndexViewTypeState } from '@/object-record/record-index/states/recordIndexViewTypeState';
|
||||
import { useSetTableColumns } from '@/object-record/record-table/hooks/useSetTableColumns';
|
||||
import { viewFieldAggregateOperationState } from '@/object-record/record-table/record-table-footer/states/viewFieldAggregateOperationState';
|
||||
import { tableFiltersComponentState } from '@/object-record/record-table/states/tableFiltersComponentState';
|
||||
import { tableSortsComponentState } from '@/object-record/record-table/states/tableSortsComponentState';
|
||||
import { tableViewFilterGroupsComponentState } from '@/object-record/record-table/states/tableViewFilterGroupsComponentState';
|
||||
import { ColumnDefinition } from '@/object-record/record-table/types/ColumnDefinition';
|
||||
import { convertAggregateOperationToExtendedAggregateOperation } from '@/object-record/utils/convertAggregateOperationToExtendedAggregateOperation';
|
||||
import { filterAvailableTableColumns } from '@/object-record/utils/filterAvailableTableColumns';
|
||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||
import { View } from '@/views/types/View';
|
||||
import { ViewField } from '@/views/types/ViewField';
|
||||
import { ViewGroup } from '@/views/types/ViewGroup';
|
||||
import { mapViewFieldsToColumnDefinitions } from '@/views/utils/mapViewFieldsToColumnDefinitions';
|
||||
import { mapViewFiltersToFilters } from '@/views/utils/mapViewFiltersToFilters';
|
||||
import { mapViewGroupsToRecordGroupDefinitions } from '@/views/utils/mapViewGroupsToRecordGroupDefinitions';
|
||||
import { mapViewSortsToSorts } from '@/views/utils/mapViewSortsToSorts';
|
||||
import { useCallback } from 'react';
|
||||
import { useRecoilCallback, useSetRecoilState } from 'recoil';
|
||||
import { isDefined } from 'twenty-shared';
|
||||
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
|
||||
|
||||
export const useLoadRecordIndexStates = () => {
|
||||
const setContextStoreTargetedRecordsRuleComponentState =
|
||||
useSetRecoilComponentStateV2(contextStoreTargetedRecordsRuleComponentState);
|
||||
|
||||
const setRecordIndexViewFilterGroups = useSetRecoilState(
|
||||
recordIndexViewFilterGroupsState,
|
||||
);
|
||||
|
||||
const setRecordIndexFilters = useSetRecoilState(recordIndexFiltersState);
|
||||
const setRecordIndexSorts = useSetRecoilState(recordIndexSortsState);
|
||||
const setRecordIndexIsCompactModeActive = useSetRecoilState(
|
||||
recordIndexIsCompactModeActiveState,
|
||||
);
|
||||
const setRecordIndexViewType = useSetRecoilState(recordIndexViewTypeState);
|
||||
const setRecordIndexViewKanbanFieldMetadataIdState = useSetRecoilState(
|
||||
recordIndexKanbanFieldMetadataIdState,
|
||||
);
|
||||
const setRecordIndexViewKanbanAggregateOperationState = useSetRecoilState(
|
||||
recordIndexKanbanAggregateOperationState,
|
||||
);
|
||||
const setRecordGroup = useSetRecordGroup();
|
||||
|
||||
const { setTableColumns } = useSetTableColumns();
|
||||
|
||||
const onViewFieldsChange = useRecoilCallback(
|
||||
({ set, snapshot }) =>
|
||||
(
|
||||
viewFields: ViewField[],
|
||||
objectMetadataItem: ObjectMetadataItem,
|
||||
recordIndexId: string,
|
||||
) => {
|
||||
const activeFieldMetadataItems = objectMetadataItem.fields.filter(
|
||||
({ isActive, isSystem }) => isActive && !isSystem,
|
||||
);
|
||||
|
||||
const filterableFieldMetadataItems = snapshot
|
||||
.getLoadable(
|
||||
availableFieldMetadataItemsForFilterFamilySelector({
|
||||
objectMetadataItemId: objectMetadataItem.id,
|
||||
}),
|
||||
)
|
||||
.getValue();
|
||||
|
||||
const sortDefinitions = formatFieldMetadataItemsAsSortDefinitions({
|
||||
fields: activeFieldMetadataItems,
|
||||
});
|
||||
|
||||
const columnDefinitions: ColumnDefinition<FieldMetadata>[] =
|
||||
activeFieldMetadataItems
|
||||
.map((field, index) =>
|
||||
formatFieldMetadataItemAsColumnDefinition({
|
||||
position: index,
|
||||
field,
|
||||
objectMetadataItem,
|
||||
}),
|
||||
)
|
||||
.filter(filterAvailableTableColumns)
|
||||
.map((column) => {
|
||||
const existsInFilterDefinitions =
|
||||
filterableFieldMetadataItems.some(
|
||||
(fieldMetadataItem) =>
|
||||
fieldMetadataItem.id === column.fieldMetadataId,
|
||||
);
|
||||
const existsInSortDefinitions = sortDefinitions.some(
|
||||
(sort) => sort.fieldMetadataId === column.fieldMetadataId,
|
||||
);
|
||||
return {
|
||||
...column,
|
||||
isFilterable: existsInFilterDefinitions,
|
||||
isSortable: existsInSortDefinitions,
|
||||
};
|
||||
});
|
||||
|
||||
const newFieldDefinitions = mapViewFieldsToColumnDefinitions({
|
||||
viewFields,
|
||||
columnDefinitions,
|
||||
});
|
||||
|
||||
setTableColumns(newFieldDefinitions, recordIndexId);
|
||||
|
||||
const existingRecordIndexFieldDefinitions = snapshot
|
||||
.getLoadable(recordIndexFieldDefinitionsState)
|
||||
.getValue();
|
||||
if (
|
||||
!isDeeplyEqual(
|
||||
existingRecordIndexFieldDefinitions,
|
||||
newFieldDefinitions,
|
||||
)
|
||||
) {
|
||||
set(recordIndexFieldDefinitionsState, newFieldDefinitions);
|
||||
}
|
||||
|
||||
for (const viewField of viewFields) {
|
||||
const viewFieldMetadataType = objectMetadataItem.fields?.find(
|
||||
(field) => field.id === viewField.fieldMetadataId,
|
||||
)?.type;
|
||||
|
||||
const aggregateOperationForViewField = snapshot
|
||||
.getLoadable(
|
||||
viewFieldAggregateOperationState({
|
||||
viewFieldId: viewField.id,
|
||||
}),
|
||||
)
|
||||
.getValue();
|
||||
const convertedViewFieldAggregateOperation = isDefined(
|
||||
viewField.aggregateOperation,
|
||||
)
|
||||
? convertAggregateOperationToExtendedAggregateOperation(
|
||||
viewField.aggregateOperation,
|
||||
viewFieldMetadataType,
|
||||
)
|
||||
: viewField.aggregateOperation;
|
||||
|
||||
if (
|
||||
aggregateOperationForViewField !==
|
||||
convertedViewFieldAggregateOperation
|
||||
) {
|
||||
set(
|
||||
viewFieldAggregateOperationState({
|
||||
viewFieldId: viewField.id,
|
||||
}),
|
||||
convertedViewFieldAggregateOperation,
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
[setTableColumns],
|
||||
);
|
||||
|
||||
const onViewGroupsChange = useCallback(
|
||||
(
|
||||
viewGroups: ViewGroup[],
|
||||
objectMetadataItem: ObjectMetadataItem,
|
||||
recordIndexId: string,
|
||||
) => {
|
||||
const newGroupDefinitions = mapViewGroupsToRecordGroupDefinitions({
|
||||
objectMetadataItem,
|
||||
viewGroups,
|
||||
});
|
||||
|
||||
setRecordGroup(newGroupDefinitions, recordIndexId);
|
||||
},
|
||||
[setRecordGroup],
|
||||
);
|
||||
|
||||
const loadRecordIndexStates = useRecoilCallback(
|
||||
({ snapshot, set }) =>
|
||||
async (view: View, objectMetadataItem: ObjectMetadataItem) => {
|
||||
const recordIndexId = `${objectMetadataItem.namePlural}-${view.id}`;
|
||||
|
||||
const filterableFieldMetadataItems = snapshot
|
||||
.getLoadable(
|
||||
availableFieldMetadataItemsForFilterFamilySelector({
|
||||
objectMetadataItemId: objectMetadataItem.id,
|
||||
}),
|
||||
)
|
||||
.getValue();
|
||||
|
||||
onViewFieldsChange(view.viewFields, objectMetadataItem, recordIndexId);
|
||||
onViewGroupsChange(view.viewGroups, objectMetadataItem, recordIndexId);
|
||||
set(
|
||||
tableViewFilterGroupsComponentState.atomFamily({
|
||||
instanceId: recordIndexId,
|
||||
}),
|
||||
view.viewFilterGroups ?? [],
|
||||
);
|
||||
set(
|
||||
tableFiltersComponentState.atomFamily({
|
||||
instanceId: recordIndexId,
|
||||
}),
|
||||
mapViewFiltersToFilters(
|
||||
view.viewFilters,
|
||||
filterableFieldMetadataItems,
|
||||
),
|
||||
);
|
||||
setRecordIndexFilters(
|
||||
mapViewFiltersToFilters(
|
||||
view.viewFilters,
|
||||
filterableFieldMetadataItems,
|
||||
),
|
||||
);
|
||||
setRecordIndexViewFilterGroups(view.viewFilterGroups ?? []);
|
||||
setContextStoreTargetedRecordsRuleComponentState((prev) => ({
|
||||
...prev,
|
||||
filters: mapViewFiltersToFilters(
|
||||
view.viewFilters,
|
||||
filterableFieldMetadataItems,
|
||||
),
|
||||
}));
|
||||
|
||||
const activeFieldMetadataItems = objectMetadataItem.fields.filter(
|
||||
({ isActive, isSystem }) => isActive && !isSystem,
|
||||
);
|
||||
|
||||
const sortDefinitions = formatFieldMetadataItemsAsSortDefinitions({
|
||||
fields: activeFieldMetadataItems,
|
||||
});
|
||||
|
||||
set(
|
||||
tableSortsComponentState.atomFamily({
|
||||
instanceId: recordIndexId,
|
||||
}),
|
||||
mapViewSortsToSorts(view.viewSorts, sortDefinitions),
|
||||
);
|
||||
setRecordIndexSorts(
|
||||
mapViewSortsToSorts(view.viewSorts, sortDefinitions),
|
||||
);
|
||||
setRecordIndexViewType(view.type);
|
||||
setRecordIndexViewKanbanFieldMetadataIdState(
|
||||
view.kanbanFieldMetadataId,
|
||||
);
|
||||
const kanbanAggregateOperationFieldMetadataType =
|
||||
objectMetadataItem.fields?.find(
|
||||
(field) =>
|
||||
field.id === view.kanbanAggregateOperationFieldMetadataId,
|
||||
)?.type;
|
||||
setRecordIndexViewKanbanAggregateOperationState({
|
||||
operation: isDefined(view.kanbanAggregateOperation)
|
||||
? convertAggregateOperationToExtendedAggregateOperation(
|
||||
view.kanbanAggregateOperation,
|
||||
kanbanAggregateOperationFieldMetadataType,
|
||||
)
|
||||
: view.kanbanAggregateOperation,
|
||||
fieldMetadataId: view.kanbanAggregateOperationFieldMetadataId,
|
||||
});
|
||||
setRecordIndexIsCompactModeActive(view.isCompact);
|
||||
},
|
||||
[
|
||||
onViewFieldsChange,
|
||||
onViewGroupsChange,
|
||||
setContextStoreTargetedRecordsRuleComponentState,
|
||||
setRecordIndexFilters,
|
||||
setRecordIndexIsCompactModeActive,
|
||||
setRecordIndexSorts,
|
||||
setRecordIndexViewFilterGroups,
|
||||
setRecordIndexViewKanbanAggregateOperationState,
|
||||
setRecordIndexViewKanbanFieldMetadataIdState,
|
||||
setRecordIndexViewType,
|
||||
],
|
||||
);
|
||||
|
||||
return {
|
||||
loadRecordIndexStates,
|
||||
};
|
||||
};
|
||||
@ -3,9 +3,6 @@ import { ShowPageContainer } from '@/ui/layout/page/components/ShowPageContainer
|
||||
|
||||
import { InformationBannerDeletedRecord } from '@/information-banner/components/deleted-record/InformationBannerDeletedRecord';
|
||||
|
||||
import { ContextStoreCurrentViewTypeEffect } from '@/context-store/components/ContextStoreCurrentViewTypeEffect';
|
||||
import { ContextStoreViewType } from '@/context-store/types/ContextStoreViewType';
|
||||
import { RecordShowContainerContextStoreObjectMetadataIdEffect } from '@/object-record/record-show/components/RecordShowContainerContextStoreObjectMetadataIdEffect';
|
||||
import { RecordShowContainerContextStoreTargetedRecordsEffect } from '@/object-record/record-show/components/RecordShowContainerContextStoreTargetedRecordsEffect';
|
||||
import { useRecordShowContainerData } from '@/object-record/record-show/hooks/useRecordShowContainerData';
|
||||
import { useRecordShowContainerTabs } from '@/object-record/record-show/hooks/useRecordShowContainerTabs';
|
||||
@ -45,16 +42,9 @@ export const RecordShowContainer = ({
|
||||
|
||||
return (
|
||||
<>
|
||||
<RecordShowContainerContextStoreObjectMetadataIdEffect
|
||||
recordId={objectRecordId}
|
||||
objectNameSingular={objectNameSingular}
|
||||
/>
|
||||
<RecordShowContainerContextStoreTargetedRecordsEffect
|
||||
recordId={objectRecordId}
|
||||
/>
|
||||
<ContextStoreCurrentViewTypeEffect
|
||||
viewType={ContextStoreViewType.ShowPage}
|
||||
/>
|
||||
{recordFromStore && recordFromStore.deletedAt && (
|
||||
<InformationBannerDeletedRecord
|
||||
recordId={objectRecordId}
|
||||
|
||||
@ -1,30 +0,0 @@
|
||||
import { contextStoreCurrentObjectMetadataIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataIdComponentState';
|
||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
export const RecordShowContainerContextStoreObjectMetadataIdEffect = ({
|
||||
recordId,
|
||||
objectNameSingular,
|
||||
}: {
|
||||
recordId: string;
|
||||
objectNameSingular: string;
|
||||
}) => {
|
||||
const setContextStoreCurrentObjectMetadataId = useSetRecoilComponentStateV2(
|
||||
contextStoreCurrentObjectMetadataIdComponentState,
|
||||
);
|
||||
|
||||
const { objectMetadataItem } = useObjectMetadataItem({
|
||||
objectNameSingular: objectNameSingular,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
setContextStoreCurrentObjectMetadataId(objectMetadataItem?.id);
|
||||
|
||||
return () => {
|
||||
setContextStoreCurrentObjectMetadataId(null);
|
||||
};
|
||||
}, [recordId, setContextStoreCurrentObjectMetadataId, objectMetadataItem.id]);
|
||||
|
||||
return null;
|
||||
};
|
||||
@ -39,7 +39,6 @@ export const useRecordShowPagePagination = (
|
||||
const { filter, orderBy } =
|
||||
useQueryVariablesFromActiveFieldsOfViewOrDefaultView({
|
||||
objectMetadataItem,
|
||||
viewId: viewIdQueryParam,
|
||||
});
|
||||
|
||||
const { loading: loadingCursor, pageInfo: currentRecordsPageInfo } =
|
||||
|
||||
@ -23,14 +23,12 @@ import { useRecordPicker } from '@/object-record/relation-picker/hooks/useRecord
|
||||
import { RecordPickerComponentInstanceContext } from '@/object-record/relation-picker/states/contexts/RecordPickerComponentInstanceContext';
|
||||
import { RecordForSelect } from '@/object-record/relation-picker/types/RecordForSelect';
|
||||
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||
import { usePrefetchedData } from '@/prefetch/hooks/usePrefetchedData';
|
||||
import { PrefetchKey } from '@/prefetch/types/PrefetchKey';
|
||||
import { prefetchIndexViewIdFromObjectMetadataItemFamilySelector } from '@/prefetch/states/selector/prefetchIndexViewIdFromObjectMetadataItemFamilySelector';
|
||||
import { AppPath } from '@/types/AppPath';
|
||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||
import { DropdownScope } from '@/ui/layout/dropdown/scopes/DropdownScope';
|
||||
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
|
||||
import { View } from '@/views/types/View';
|
||||
import { ViewFilterOperand } from '@/views/types/ViewFilterOperand';
|
||||
import { useLingui } from '@lingui/react/macro';
|
||||
import { RelationDefinitionType } from '~/generated-metadata/graphql';
|
||||
@ -123,12 +121,10 @@ export const RecordDetailRelationSection = ({
|
||||
scopeId: dropdownId,
|
||||
});
|
||||
|
||||
const { records: views } = usePrefetchedData<View>(PrefetchKey.AllViews);
|
||||
|
||||
const indexView = views.find(
|
||||
(view) =>
|
||||
view.key === 'INDEX' &&
|
||||
view.objectMetadataId === relationObjectMetadataItem.id,
|
||||
const indexViewId = useRecoilValue(
|
||||
prefetchIndexViewIdFromObjectMetadataItemFamilySelector({
|
||||
objectMetadataItemId: relationObjectMetadataItem.id,
|
||||
}),
|
||||
);
|
||||
|
||||
const filterQueryParams = {
|
||||
@ -139,7 +135,7 @@ export const RecordDetailRelationSection = ({
|
||||
},
|
||||
},
|
||||
},
|
||||
view: indexView?.id,
|
||||
view: indexViewId,
|
||||
};
|
||||
|
||||
const filterLinkHref = getAppPath(
|
||||
|
||||
@ -75,7 +75,7 @@ export const RecordTableWithWrappers = ({
|
||||
ActionBarHotkeyScope.ActionBar,
|
||||
);
|
||||
|
||||
const { saveViewFields } = useSaveCurrentViewFields(viewBarId);
|
||||
const { saveViewFields } = useSaveCurrentViewFields();
|
||||
|
||||
const { deleteOneRecord } = useDeleteOneRecord({ objectNameSingular });
|
||||
|
||||
|
||||
@ -22,11 +22,9 @@ import { onColumnsChangeComponentState } from '@/object-record/record-table/stat
|
||||
import { onEntityCountChangeComponentState } from '@/object-record/record-table/states/onEntityCountChangeComponentState';
|
||||
import { onToggleColumnFilterComponentState } from '@/object-record/record-table/states/onToggleColumnFilterComponentState';
|
||||
import { onToggleColumnSortComponentState } from '@/object-record/record-table/states/onToggleColumnSortComponentState';
|
||||
import { tableColumnsComponentState } from '@/object-record/record-table/states/tableColumnsComponentState';
|
||||
import { tableFiltersComponentState } from '@/object-record/record-table/states/tableFiltersComponentState';
|
||||
import { tableLastRowVisibleComponentState } from '@/object-record/record-table/states/tableLastRowVisibleComponentState';
|
||||
import { tableSortsComponentState } from '@/object-record/record-table/states/tableSortsComponentState';
|
||||
import { tableViewFilterGroupsComponentState } from '@/object-record/record-table/states/tableViewFilterGroupsComponentState';
|
||||
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
|
||||
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||
@ -53,11 +51,6 @@ export const useRecordTable = (props?: useRecordTableProps) => {
|
||||
recordTableId,
|
||||
);
|
||||
|
||||
const tableColumnsState = useRecoilComponentCallbackStateV2(
|
||||
tableColumnsComponentState,
|
||||
recordTableId,
|
||||
);
|
||||
|
||||
const setAvailableTableColumns = useRecoilCallback(
|
||||
({ snapshot, set }) =>
|
||||
(columns: ColumnDefinition<FieldMetadata>[]) => {
|
||||
@ -74,29 +67,11 @@ export const useRecordTable = (props?: useRecordTableProps) => {
|
||||
[availableTableColumnsState],
|
||||
);
|
||||
|
||||
const setTableColumns = useRecoilCallback(
|
||||
({ snapshot, set }) =>
|
||||
(columns: ColumnDefinition<FieldMetadata>[]) => {
|
||||
const tableColumns = getSnapshotValue(snapshot, tableColumnsState);
|
||||
|
||||
if (isDeeplyEqual(tableColumns, columns)) {
|
||||
return;
|
||||
}
|
||||
set(tableColumnsState, columns);
|
||||
},
|
||||
[tableColumnsState],
|
||||
);
|
||||
|
||||
const setOnEntityCountChange = useSetRecoilComponentStateV2(
|
||||
onEntityCountChangeComponentState,
|
||||
recordTableId,
|
||||
);
|
||||
|
||||
const setTableViewFilterGroups = useSetRecoilComponentStateV2(
|
||||
tableViewFilterGroupsComponentState,
|
||||
recordTableId,
|
||||
);
|
||||
|
||||
const setTableFilters = useSetRecoilComponentStateV2(
|
||||
tableFiltersComponentState,
|
||||
recordTableId,
|
||||
@ -255,12 +230,10 @@ export const useRecordTable = (props?: useRecordTableProps) => {
|
||||
return {
|
||||
onColumnsChange,
|
||||
setAvailableTableColumns,
|
||||
setTableViewFilterGroups,
|
||||
setTableFilters,
|
||||
setTableSorts,
|
||||
setOnEntityCountChange,
|
||||
setRecordTableData,
|
||||
setTableColumns,
|
||||
leaveTableFocus,
|
||||
setRowSelected,
|
||||
resetTableRowSelection,
|
||||
|
||||
@ -0,0 +1,33 @@
|
||||
import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata';
|
||||
import { tableColumnsComponentState } from '@/object-record/record-table/states/tableColumnsComponentState';
|
||||
import { ColumnDefinition } from '@/object-record/record-table/types/ColumnDefinition';
|
||||
import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue';
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
|
||||
|
||||
export const useSetTableColumns = () => {
|
||||
const setTableColumns = useRecoilCallback(
|
||||
({ snapshot, set }) =>
|
||||
(columns: ColumnDefinition<FieldMetadata>[], recordTableId: string) => {
|
||||
const tableColumns = getSnapshotValue(
|
||||
snapshot,
|
||||
tableColumnsComponentState.atomFamily({
|
||||
instanceId: recordTableId,
|
||||
}),
|
||||
);
|
||||
|
||||
if (isDeeplyEqual(tableColumns, columns)) {
|
||||
return;
|
||||
}
|
||||
set(
|
||||
tableColumnsComponentState.atomFamily({
|
||||
instanceId: recordTableId,
|
||||
}),
|
||||
columns,
|
||||
);
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
return { setTableColumns };
|
||||
};
|
||||
@ -4,9 +4,12 @@ import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata'
|
||||
import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable';
|
||||
import { useMoveViewColumns } from '@/views/hooks/useMoveViewColumns';
|
||||
|
||||
import { useSetTableColumns } from '@/object-record/record-table/hooks/useSetTableColumns';
|
||||
import { availableTableColumnsComponentState } from '@/object-record/record-table/states/availableTableColumnsComponentState';
|
||||
import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext';
|
||||
import { visibleTableColumnsComponentSelector } from '@/object-record/record-table/states/selectors/visibleTableColumnsComponentSelector';
|
||||
import { tableColumnsComponentState } from '@/object-record/record-table/states/tableColumnsComponentState';
|
||||
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { ColumnDefinition } from '../types/ColumnDefinition';
|
||||
|
||||
@ -15,10 +18,12 @@ type useRecordTableProps = {
|
||||
};
|
||||
|
||||
export const useTableColumns = (props?: useRecordTableProps) => {
|
||||
const { onColumnsChange, setTableColumns } = useRecordTable({
|
||||
const { onColumnsChange } = useRecordTable({
|
||||
recordTableId: props?.recordTableId,
|
||||
});
|
||||
|
||||
const { setTableColumns } = useSetTableColumns();
|
||||
|
||||
const availableTableColumns = useRecoilComponentValueV2(
|
||||
availableTableColumnsComponentState,
|
||||
props?.recordTableId,
|
||||
@ -35,13 +40,18 @@ export const useTableColumns = (props?: useRecordTableProps) => {
|
||||
|
||||
const { handleColumnMove } = useMoveViewColumns();
|
||||
|
||||
const instanceId = useAvailableComponentInstanceIdOrThrow(
|
||||
RecordTableComponentInstanceContext,
|
||||
props?.recordTableId,
|
||||
);
|
||||
|
||||
const handleColumnsChange = useCallback(
|
||||
async (columns: ColumnDefinition<FieldMetadata>[]) => {
|
||||
setTableColumns(columns);
|
||||
setTableColumns(columns, instanceId);
|
||||
|
||||
await onColumnsChange?.(columns);
|
||||
},
|
||||
[onColumnsChange, setTableColumns],
|
||||
[setTableColumns, instanceId, onColumnsChange],
|
||||
);
|
||||
|
||||
const handleColumnVisibilityChange = useCallback(
|
||||
|
||||
@ -55,6 +55,8 @@ export const RecordTableNoRecordGroupBodyEffect = () => {
|
||||
lastShowPageRecordIdState,
|
||||
);
|
||||
|
||||
const [hasInitialized, setHasInitialized] = useState(false);
|
||||
|
||||
const { scrollToPosition } = useScrollToPosition();
|
||||
|
||||
useEffect(() => {
|
||||
@ -141,8 +143,11 @@ export const RecordTableNoRecordGroupBodyEffect = () => {
|
||||
return;
|
||||
}
|
||||
|
||||
findManyRecords();
|
||||
}, [currentWorkspaceMember, findManyRecords]);
|
||||
if (!hasInitialized) {
|
||||
findManyRecords();
|
||||
setHasInitialized(true);
|
||||
}
|
||||
}, [currentWorkspaceMember, findManyRecords, hasInitialized]);
|
||||
|
||||
return <></>;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user