Fix export view missing column and viewGroups not persisted bug (#10584)
Fixes https://github.com/twentyhq/twenty/issues/10535 Also fixes missing columns in export view
This commit is contained in:
@ -41,6 +41,7 @@ const wrapper = getJestMetadataAndApolloMocksAndActionMenuWrapper({
|
||||
componentInstanceId: '1',
|
||||
contextStoreCurrentObjectMetadataNameSingular:
|
||||
personMockObjectMetadataItem.nameSingular,
|
||||
contextStoreCurrentViewId: 'my-view-id',
|
||||
contextStoreTargetedRecordsRule: {
|
||||
mode: 'selection',
|
||||
selectedRecordIds: [peopleMock[0].id, peopleMock[1].id],
|
||||
|
||||
@ -56,6 +56,7 @@ const getWrapper = (
|
||||
componentInstanceId: '1',
|
||||
contextStoreCurrentObjectMetadataNameSingular:
|
||||
personMockObjectMetadataItem.nameSingular,
|
||||
contextStoreCurrentViewId: 'my-view-id',
|
||||
contextStoreTargetedRecordsRule: {
|
||||
mode: 'selection',
|
||||
selectedRecordIds: [firstPeopleMock.id, secondPeopleMock.id],
|
||||
|
||||
@ -23,6 +23,7 @@ jest.mock('@/object-record/record-index/export/hooks/useExportRecords', () => ({
|
||||
const wrapper = getJestMetadataAndApolloMocksAndActionMenuWrapper({
|
||||
apolloMocks: [],
|
||||
componentInstanceId: '1',
|
||||
contextStoreCurrentViewId: 'my-view-id',
|
||||
contextStoreCurrentObjectMetadataNameSingular:
|
||||
personMockObjectMetadataItem.nameSingular,
|
||||
contextStoreTargetedRecordsRule: {
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import { ActionHookWithObjectMetadataItem } from '@/action-menu/actions/types/ActionHook';
|
||||
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
|
||||
|
||||
import { contextStoreFiltersComponentState } from '@/context-store/states/contextStoreFiltersComponentState';
|
||||
import { contextStoreNumberOfSelectedRecordsComponentState } from '@/context-store/states/contextStoreNumberOfSelectedRecordsComponentState';
|
||||
@ -11,6 +12,7 @@ import { useLazyFetchAllRecords } from '@/object-record/hooks/useLazyFetchAllRec
|
||||
import { useCheckIsSoftDeleteFilter } from '@/object-record/record-filter/hooks/useCheckIsSoftDeleteFilter';
|
||||
import { useFilterValueDependencies } from '@/object-record/record-filter/hooks/useFilterValueDependencies';
|
||||
import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable';
|
||||
import { getRecordIndexIdFromObjectNamePluralAndViewId } from '@/object-record/utils/getRecordIndexIdFromObjectNamePluralAndViewId';
|
||||
import { useHasObjectReadOnlyPermission } from '@/settings/roles/hooks/useHasObjectReadOnlyPermission';
|
||||
import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModal';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
@ -22,10 +24,21 @@ export const useDeleteMultipleRecordsAction: ActionHookWithObjectMetadataItem =
|
||||
const [isDeleteRecordsModalOpen, setIsDeleteRecordsModalOpen] =
|
||||
useState(false);
|
||||
|
||||
const contextStoreCurrentViewId = useRecoilComponentValueV2(
|
||||
contextStoreCurrentViewIdComponentState,
|
||||
);
|
||||
|
||||
if (!contextStoreCurrentViewId) {
|
||||
throw new Error('Current view ID is not defined');
|
||||
}
|
||||
|
||||
const hasObjectReadOnlyPermission = useHasObjectReadOnlyPermission();
|
||||
|
||||
const { resetTableRowSelection } = useRecordTable({
|
||||
recordTableId: objectMetadataItem.namePlural,
|
||||
recordTableId: getRecordIndexIdFromObjectNamePluralAndViewId(
|
||||
objectMetadataItem.namePlural,
|
||||
contextStoreCurrentViewId,
|
||||
),
|
||||
});
|
||||
|
||||
const { deleteManyRecords } = useDeleteManyRecords({
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import { ActionHookWithObjectMetadataItem } from '@/action-menu/actions/types/ActionHook';
|
||||
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
|
||||
|
||||
import { contextStoreFiltersComponentState } from '@/context-store/states/contextStoreFiltersComponentState';
|
||||
import { contextStoreNumberOfSelectedRecordsComponentState } from '@/context-store/states/contextStoreNumberOfSelectedRecordsComponentState';
|
||||
@ -12,6 +13,7 @@ import { useLazyFetchAllRecords } from '@/object-record/hooks/useLazyFetchAllRec
|
||||
import { useFilterValueDependencies } from '@/object-record/record-filter/hooks/useFilterValueDependencies';
|
||||
import { RecordFilterOperand } from '@/object-record/record-filter/types/RecordFilterOperand';
|
||||
import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable';
|
||||
import { getRecordIndexIdFromObjectNamePluralAndViewId } from '@/object-record/utils/getRecordIndexIdFromObjectNamePluralAndViewId';
|
||||
import { useHasObjectReadOnlyPermission } from '@/settings/roles/hooks/useHasObjectReadOnlyPermission';
|
||||
import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModal';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
@ -23,8 +25,19 @@ export const useDestroyMultipleRecordsAction: ActionHookWithObjectMetadataItem =
|
||||
const [isDestroyRecordsModalOpen, setIsDestroyRecordsModalOpen] =
|
||||
useState(false);
|
||||
|
||||
const contextStoreCurrentViewId = useRecoilComponentValueV2(
|
||||
contextStoreCurrentViewIdComponentState,
|
||||
);
|
||||
|
||||
if (!contextStoreCurrentViewId) {
|
||||
throw new Error('Current view ID is not defined');
|
||||
}
|
||||
|
||||
const { resetTableRowSelection } = useRecordTable({
|
||||
recordTableId: objectMetadataItem.namePlural,
|
||||
recordTableId: getRecordIndexIdFromObjectNamePluralAndViewId(
|
||||
objectMetadataItem.namePlural,
|
||||
contextStoreCurrentViewId,
|
||||
),
|
||||
});
|
||||
|
||||
const hasObjectReadOnlyPermission = useHasObjectReadOnlyPermission();
|
||||
|
||||
@ -1,16 +1,30 @@
|
||||
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
|
||||
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||
|
||||
import { useExportRecords } from '@/object-record/record-index/export/hooks/useExportRecords';
|
||||
import { getRecordIndexIdFromObjectNamePluralAndViewId } from '@/object-record/utils/getRecordIndexIdFromObjectNamePluralAndViewId';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
|
||||
export const useExportMultipleRecordsAction = ({
|
||||
objectMetadataItem,
|
||||
}: {
|
||||
objectMetadataItem: ObjectMetadataItem;
|
||||
}) => {
|
||||
const contextStoreCurrentViewId = useRecoilComponentValueV2(
|
||||
contextStoreCurrentViewIdComponentState,
|
||||
);
|
||||
|
||||
if (!contextStoreCurrentViewId) {
|
||||
throw new Error('Current view ID is not defined');
|
||||
}
|
||||
|
||||
const { download } = useExportRecords({
|
||||
delayMs: 100,
|
||||
objectMetadataItem,
|
||||
recordIndexId: objectMetadataItem.namePlural,
|
||||
recordIndexId: getRecordIndexIdFromObjectNamePluralAndViewId(
|
||||
objectMetadataItem.namePlural,
|
||||
contextStoreCurrentViewId,
|
||||
),
|
||||
filename: `${objectMetadataItem.nameSingular}.csv`,
|
||||
});
|
||||
|
||||
|
||||
@ -19,17 +19,16 @@ import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/Drop
|
||||
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 { useLingui } from '@lingui/react/macro';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
import { useSetRecoilState } from 'recoil';
|
||||
import { getSettingsPath } from '~/utils/navigation/getSettingsPath';
|
||||
import { useLingui } from '@lingui/react/macro';
|
||||
|
||||
export const ObjectOptionsDropdownHiddenRecordGroupsContent = () => {
|
||||
const { t } = useLingui();
|
||||
const {
|
||||
viewType,
|
||||
currentContentId,
|
||||
recordIndexId,
|
||||
objectMetadataItem,
|
||||
onContentChange,
|
||||
closeDropdown,
|
||||
@ -49,7 +48,6 @@ export const ObjectOptionsDropdownHiddenRecordGroupsContent = () => {
|
||||
|
||||
const { handleVisibilityChange: handleRecordGroupVisibilityChange } =
|
||||
useRecordGroupVisibility({
|
||||
viewBarId: recordIndexId,
|
||||
viewType,
|
||||
});
|
||||
|
||||
|
||||
@ -67,7 +67,6 @@ export const ObjectOptionsDropdownRecordGroupsContent = () => {
|
||||
handleVisibilityChange: handleRecordGroupVisibilityChange,
|
||||
handleHideEmptyRecordGroupChange,
|
||||
} = useRecordGroupVisibility({
|
||||
viewBarId: recordIndexId,
|
||||
viewType,
|
||||
});
|
||||
|
||||
|
||||
@ -27,7 +27,7 @@ export const useRecordGroupActions = ({
|
||||
const navigate = useNavigateSettings();
|
||||
const location = useLocation();
|
||||
|
||||
const { objectNameSingular, recordIndexId } = useRecordIndexContextOrThrow();
|
||||
const { objectNameSingular } = useRecordIndexContextOrThrow();
|
||||
|
||||
const { columnDefinition: recordGroupDefinition } = useContext(
|
||||
RecordBoardColumnContext,
|
||||
@ -43,7 +43,6 @@ export const useRecordGroupActions = ({
|
||||
|
||||
const { handleVisibilityChange: handleRecordGroupVisibilityChange } =
|
||||
useRecordGroupVisibility({
|
||||
viewBarId: recordIndexId,
|
||||
viewType,
|
||||
});
|
||||
|
||||
|
||||
@ -29,7 +29,7 @@ export const useRecordGroupReorder = ({
|
||||
visibleRecordGroupIdsComponentFamilySelector,
|
||||
);
|
||||
|
||||
const { saveViewGroups } = useSaveCurrentViewGroups(viewBarId);
|
||||
const { saveViewGroups } = useSaveCurrentViewGroups();
|
||||
|
||||
const handleOrderChange: OnDragEndResponder = useRecoilCallback(
|
||||
({ snapshot }) =>
|
||||
|
||||
@ -8,12 +8,10 @@ import { recordGroupDefinitionToViewGroup } from '@/views/utils/recordGroupDefin
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
|
||||
type UseRecordGroupVisibilityParams = {
|
||||
viewBarId: string;
|
||||
viewType: ViewType;
|
||||
};
|
||||
|
||||
export const useRecordGroupVisibility = ({
|
||||
viewBarId,
|
||||
viewType,
|
||||
}: UseRecordGroupVisibilityParams) => {
|
||||
const objectOptionsDropdownRecordGroupHideFamilyState =
|
||||
@ -21,7 +19,7 @@ export const useRecordGroupVisibility = ({
|
||||
recordIndexRecordGroupHideComponentFamilyState,
|
||||
);
|
||||
|
||||
const { saveViewGroup } = useSaveCurrentViewGroups(viewBarId);
|
||||
const { saveViewGroup } = useSaveCurrentViewGroups();
|
||||
|
||||
const handleVisibilityChange = useRecoilCallback(
|
||||
({ set }) =>
|
||||
|
||||
@ -6,6 +6,7 @@ import { contextStoreFiltersComponentState } from '@/context-store/states/contex
|
||||
import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState';
|
||||
import { computeContextStoreFilters } from '@/context-store/utils/computeContextStoreFilters';
|
||||
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||
import { useLazyFetchAllRecords } from '@/object-record/hooks/useLazyFetchAllRecords';
|
||||
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 { useFilterValueDependencies } from '@/object-record/record-filter/hooks/useFilterValueDependencies';
|
||||
@ -14,7 +15,6 @@ import { useFindManyRecordIndexTableParams } from '@/object-record/record-index/
|
||||
import { visibleTableColumnsComponentSelector } from '@/object-record/record-table/states/selectors/visibleTableColumnsComponentSelector';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { ViewType } from '@/views/types/ViewType';
|
||||
import { useLazyFetchAllRecords } from '@/object-record/hooks/useLazyFetchAllRecords';
|
||||
|
||||
export const sleep = (ms: number) =>
|
||||
new Promise((resolve) => setTimeout(resolve, ms));
|
||||
|
||||
@ -10,12 +10,12 @@ import {
|
||||
} from '@/object-record/record-index/export/hooks/useExportFetchRecords';
|
||||
import { ColumnDefinition } from '@/object-record/record-table/types/ColumnDefinition';
|
||||
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { saveAs } from 'file-saver';
|
||||
import { isDefined } from 'twenty-shared';
|
||||
import { RelationDefinitionType } from '~/generated-metadata/graphql';
|
||||
import { FieldMetadataType } from '~/generated/graphql';
|
||||
import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull';
|
||||
import { t } from '@lingui/core/macro';
|
||||
|
||||
type GenerateExportOptions = {
|
||||
columns: ColumnDefinition<FieldMetadata>[];
|
||||
|
||||
@ -80,15 +80,10 @@ describe('useApplyCurrentViewFilterGroupsToCurrentRecordFilterGroups', () => {
|
||||
wrapper: getJestMetadataAndApolloMocksAndActionMenuWrapper({
|
||||
apolloMocks: [],
|
||||
componentInstanceId: 'instanceId',
|
||||
contextStoreCurrentViewId: mockView.id,
|
||||
contextStoreCurrentObjectMetadataNameSingular:
|
||||
mockObjectMetadataItemNameSingular,
|
||||
onInitializeRecoilSnapshot: (snapshot) => {
|
||||
snapshot.set(
|
||||
contextStoreCurrentViewIdComponentState.atomFamily({
|
||||
instanceId: 'instanceId',
|
||||
}),
|
||||
mockView.id,
|
||||
);
|
||||
snapshot.set(prefetchViewsState, [mockView]);
|
||||
},
|
||||
}),
|
||||
|
||||
@ -85,13 +85,8 @@ describe('useApplyCurrentViewFiltersToCurrentRecordFilters', () => {
|
||||
componentInstanceId: 'instanceId',
|
||||
contextStoreCurrentObjectMetadataNameSingular:
|
||||
mockObjectMetadataItemNameSingular,
|
||||
contextStoreCurrentViewId: mockView.id,
|
||||
onInitializeRecoilSnapshot: (snapshot) => {
|
||||
snapshot.set(
|
||||
contextStoreCurrentViewIdComponentState.atomFamily({
|
||||
instanceId: 'instanceId',
|
||||
}),
|
||||
mockView.id,
|
||||
);
|
||||
snapshot.set(prefetchViewsState, [mockView]);
|
||||
},
|
||||
}),
|
||||
|
||||
@ -73,14 +73,8 @@ describe('useApplyCurrentViewSortsToCurrentRecordSorts', () => {
|
||||
componentInstanceId: 'instanceId',
|
||||
contextStoreCurrentObjectMetadataNameSingular:
|
||||
mockObjectMetadataItemNameSingular,
|
||||
contextStoreCurrentViewId: mockView.id,
|
||||
onInitializeRecoilSnapshot: (snapshot) => {
|
||||
snapshot.set(
|
||||
contextStoreCurrentViewIdComponentState.atomFamily({
|
||||
instanceId: 'instanceId',
|
||||
}),
|
||||
mockView.id,
|
||||
);
|
||||
|
||||
snapshot.set(prefetchViewsState, [mockView]);
|
||||
},
|
||||
}),
|
||||
|
||||
@ -9,7 +9,7 @@ import { isDefined } from 'twenty-shared';
|
||||
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
|
||||
import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull';
|
||||
|
||||
export const useSaveCurrentViewGroups = (viewBarComponentId?: string) => {
|
||||
export const useSaveCurrentViewGroups = () => {
|
||||
const { createViewGroupRecords, updateViewGroupRecords } =
|
||||
usePersistViewGroupRecords();
|
||||
|
||||
@ -17,7 +17,6 @@ export const useSaveCurrentViewGroups = (viewBarComponentId?: string) => {
|
||||
|
||||
const currentViewIdCallbackState = useRecoilComponentCallbackStateV2(
|
||||
contextStoreCurrentViewIdComponentState,
|
||||
viewBarComponentId,
|
||||
);
|
||||
|
||||
const saveViewGroup = useRecoilCallback(
|
||||
@ -31,7 +30,7 @@ export const useSaveCurrentViewGroups = (viewBarComponentId?: string) => {
|
||||
return;
|
||||
}
|
||||
|
||||
const view = await getViewFromPrefetchState(currentViewId);
|
||||
const view = getViewFromPrefetchState(currentViewId);
|
||||
|
||||
if (isUndefinedOrNull(view)) {
|
||||
return;
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import { PropsWithChildren, useEffect, useState } from 'react';
|
||||
|
||||
import { contextStoreCurrentObjectMetadataItemComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataItemComponentState';
|
||||
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
|
||||
import { contextStoreFiltersComponentState } from '@/context-store/states/contextStoreFiltersComponentState';
|
||||
import { contextStoreNumberOfSelectedRecordsComponentState } from '@/context-store/states/contextStoreNumberOfSelectedRecordsComponentState';
|
||||
import {
|
||||
@ -16,11 +17,13 @@ export type JestContextStoreSetterMocks = {
|
||||
contextStoreNumberOfSelectedRecords?: number;
|
||||
contextStoreFilters?: RecordFilter[];
|
||||
contextStoreCurrentObjectMetadataNameSingular?: string;
|
||||
contextStoreCurrentViewId?: string;
|
||||
};
|
||||
|
||||
type JestContextStoreSetterProps =
|
||||
PropsWithChildren<JestContextStoreSetterMocks>;
|
||||
export const JestContextStoreSetter = ({
|
||||
contextStoreCurrentViewId,
|
||||
contextStoreTargetedRecordsRule = {
|
||||
mode: 'selection',
|
||||
selectedRecordIds: [],
|
||||
@ -46,6 +49,10 @@ export const JestContextStoreSetter = ({
|
||||
contextStoreFiltersComponentState,
|
||||
);
|
||||
|
||||
const setContextStoreCurrentViewId = useSetRecoilComponentStateV2(
|
||||
contextStoreCurrentViewIdComponentState,
|
||||
);
|
||||
|
||||
const { objectMetadataItem } = useObjectMetadataItem({
|
||||
objectNameSingular: contextStoreCurrentObjectMetadataNameSingular,
|
||||
});
|
||||
@ -54,6 +61,7 @@ export const JestContextStoreSetter = ({
|
||||
|
||||
const [isLoaded, setIsLoaded] = useState(false);
|
||||
useEffect(() => {
|
||||
setContextStoreCurrentViewId(contextStoreCurrentViewId);
|
||||
setContextStoreTargetedRecordsRule(contextStoreTargetedRecordsRule);
|
||||
setContextStoreCurrentObjectMetadataItem(objectMetadataItem);
|
||||
setContextStoreNumberOfSelectedRecords(contextStoreNumberOfSelectedRecords);
|
||||
@ -70,6 +78,8 @@ export const JestContextStoreSetter = ({
|
||||
setcontextStoreFiltersComponentState,
|
||||
contextStoreFilters,
|
||||
objectMetadataItem,
|
||||
setContextStoreCurrentViewId,
|
||||
contextStoreCurrentViewId,
|
||||
]);
|
||||
|
||||
return isLoaded ? <>{children}</> : null;
|
||||
|
||||
@ -27,6 +27,7 @@ export const getJestMetadataAndApolloMocksAndActionMenuWrapper = ({
|
||||
apolloMocks,
|
||||
onInitializeRecoilSnapshot,
|
||||
contextStoreTargetedRecordsRule,
|
||||
contextStoreCurrentViewId,
|
||||
contextStoreNumberOfSelectedRecords,
|
||||
contextStoreCurrentObjectMetadataNameSingular,
|
||||
contextStoreFilters,
|
||||
@ -81,6 +82,7 @@ export const getJestMetadataAndApolloMocksAndActionMenuWrapper = ({
|
||||
}}
|
||||
>
|
||||
<JestContextStoreSetter
|
||||
contextStoreCurrentViewId={contextStoreCurrentViewId}
|
||||
contextStoreFilters={contextStoreFilters}
|
||||
contextStoreTargetedRecordsRule={
|
||||
contextStoreTargetedRecordsRule
|
||||
|
||||
@ -157,7 +157,7 @@ export class MigrateRichTextContentPatchCommand extends MaintainedWorkspacesMigr
|
||||
return await this.featureFlagRepository.exists({
|
||||
where: {
|
||||
workspaceId,
|
||||
key: FeatureFlagKey.IsRichTextV2Enabled,
|
||||
key: 'IS_RICH_TEXT_V2_ENABLED' as FeatureFlagKey,
|
||||
value: true,
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user