diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/constants/DefaultRecordActionsConfig.tsx b/packages/twenty-front/src/modules/action-menu/actions/record-actions/constants/DefaultRecordActionsConfig.tsx index 31779f2fa59..28b4c9af685 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/record-actions/constants/DefaultRecordActionsConfig.tsx +++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/constants/DefaultRecordActionsConfig.tsx @@ -74,8 +74,9 @@ export const DEFAULT_RECORD_ACTIONS_CONFIG: Record< position: 0, isPinned: true, Icon: IconPlus, - shouldBeRegistered: ({ objectPermissions, isSoftDeleteFilterActive }) => - (objectPermissions.canUpdateObjectRecords && !isSoftDeleteFilterActive) ?? + shouldBeRegistered: ({ objectPermissions, hasAnySoftDeleteFilterOnView }) => + (objectPermissions.canUpdateObjectRecords && + !hasAnySoftDeleteFilterOnView) ?? false, availableOn: [ActionViewType.INDEX_PAGE_NO_SELECTION], component: , @@ -108,12 +109,12 @@ export const DEFAULT_RECORD_ACTIONS_CONFIG: Record< shouldBeRegistered: ({ selectedRecord, isFavorite, - isSoftDeleteFilterActive, + hasAnySoftDeleteFilterOnView, }) => !selectedRecord?.isRemote && !isFavorite && !isDefined(selectedRecord?.deletedAt) && - !isSoftDeleteFilterActive, + !hasAnySoftDeleteFilterOnView, availableOn: [ ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION, ActionViewType.SHOW_PAGE, @@ -132,14 +133,14 @@ export const DEFAULT_RECORD_ACTIONS_CONFIG: Record< shouldBeRegistered: ({ selectedRecord, isFavorite, - isSoftDeleteFilterActive, + hasAnySoftDeleteFilterOnView, }) => isDefined(selectedRecord) && !selectedRecord?.isRemote && isDefined(isFavorite) && isFavorite && !isDefined(selectedRecord?.deletedAt) && - !isSoftDeleteFilterActive, + !hasAnySoftDeleteFilterOnView, availableOn: [ ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION, ActionViewType.SHOW_PAGE, @@ -231,8 +232,8 @@ export const DEFAULT_RECORD_ACTIONS_CONFIG: Record< Icon: IconFileImport, accent: 'default', isPinned: false, - shouldBeRegistered: ({ isSoftDeleteFilterActive }) => - !isSoftDeleteFilterActive, + shouldBeRegistered: ({ hasAnySoftDeleteFilterOnView }) => + !hasAnySoftDeleteFilterOnView, availableOn: [ActionViewType.INDEX_PAGE_NO_SELECTION], component: , requiredPermissionFlag: PermissionFlagType.IMPORT_CSV, @@ -264,12 +265,12 @@ export const DEFAULT_RECORD_ACTIONS_CONFIG: Record< isPinned: true, shouldBeRegistered: ({ selectedRecord, - isSoftDeleteFilterActive, + hasAnySoftDeleteFilterOnView, objectPermissions, }) => (isDefined(selectedRecord) && !selectedRecord.isRemote && - !isSoftDeleteFilterActive && + !hasAnySoftDeleteFilterOnView && objectPermissions.canSoftDeleteObjectRecords && !isDefined(selectedRecord?.deletedAt)) ?? false, @@ -292,12 +293,12 @@ export const DEFAULT_RECORD_ACTIONS_CONFIG: Record< shouldBeRegistered: ({ objectPermissions, isRemote, - isSoftDeleteFilterActive, + hasAnySoftDeleteFilterOnView, numberOfSelectedRecords, }) => (objectPermissions.canSoftDeleteObjectRecords && !isRemote && - !isSoftDeleteFilterActive && + !hasAnySoftDeleteFilterOnView && isDefined(numberOfSelectedRecords) && numberOfSelectedRecords < BACKEND_BATCH_REQUEST_MAX_COUNT) ?? false, @@ -314,8 +315,8 @@ export const DEFAULT_RECORD_ACTIONS_CONFIG: Record< Icon: IconRotate2, accent: 'default', isPinned: false, - shouldBeRegistered: ({ isSoftDeleteFilterActive }) => - !isSoftDeleteFilterActive, + shouldBeRegistered: ({ hasAnySoftDeleteFilterOnView }) => + !hasAnySoftDeleteFilterOnView, availableOn: [ActionViewType.INDEX_PAGE_NO_SELECTION], component: , }, @@ -329,8 +330,8 @@ export const DEFAULT_RECORD_ACTIONS_CONFIG: Record< Icon: IconLayout, accent: 'default', isPinned: false, - shouldBeRegistered: ({ isSoftDeleteFilterActive }) => - !isSoftDeleteFilterActive, + shouldBeRegistered: ({ hasAnySoftDeleteFilterOnView }) => + !hasAnySoftDeleteFilterOnView, availableOn: [ActionViewType.INDEX_PAGE_NO_SELECTION], component: , }, @@ -344,8 +345,8 @@ export const DEFAULT_RECORD_ACTIONS_CONFIG: Record< Icon: IconEyeOff, accent: 'default', isPinned: false, - shouldBeRegistered: ({ isSoftDeleteFilterActive }) => - isDefined(isSoftDeleteFilterActive) && isSoftDeleteFilterActive, + shouldBeRegistered: ({ hasAnySoftDeleteFilterOnView }) => + isDefined(hasAnySoftDeleteFilterOnView) && hasAnySoftDeleteFilterOnView, availableOn: [ActionViewType.INDEX_PAGE_NO_SELECTION], component: , }, @@ -407,13 +408,13 @@ export const DEFAULT_RECORD_ACTIONS_CONFIG: Record< shouldBeRegistered: ({ objectPermissions, isRemote, - isSoftDeleteFilterActive, + hasAnySoftDeleteFilterOnView, numberOfSelectedRecords, }) => (objectPermissions.canDestroyObjectRecords && !isRemote && - isDefined(isSoftDeleteFilterActive) && - isSoftDeleteFilterActive && + isDefined(hasAnySoftDeleteFilterOnView) && + hasAnySoftDeleteFilterOnView && isDefined(numberOfSelectedRecords) && numberOfSelectedRecords < BACKEND_BATCH_REQUEST_MAX_COUNT) ?? false, @@ -435,13 +436,14 @@ export const DEFAULT_RECORD_ACTIONS_CONFIG: Record< objectPermissions, isRemote, isShowPage, - isSoftDeleteFilterActive, + hasAnySoftDeleteFilterOnView, }) => (!isRemote && isDefined(selectedRecord?.deletedAt) && objectPermissions.canSoftDeleteObjectRecords && ((isDefined(isShowPage) && isShowPage) || - (isDefined(isSoftDeleteFilterActive) && isSoftDeleteFilterActive))) ?? + (isDefined(hasAnySoftDeleteFilterOnView) && + hasAnySoftDeleteFilterOnView))) ?? false, availableOn: [ ActionViewType.SHOW_PAGE, @@ -462,13 +464,13 @@ export const DEFAULT_RECORD_ACTIONS_CONFIG: Record< shouldBeRegistered: ({ objectPermissions, isRemote, - isSoftDeleteFilterActive, + hasAnySoftDeleteFilterOnView, numberOfSelectedRecords, }) => (objectPermissions.canSoftDeleteObjectRecords && !isRemote && - isDefined(isSoftDeleteFilterActive) && - isSoftDeleteFilterActive && + isDefined(hasAnySoftDeleteFilterOnView) && + hasAnySoftDeleteFilterOnView && isDefined(numberOfSelectedRecords) && numberOfSelectedRecords < BACKEND_BATCH_REQUEST_MAX_COUNT) ?? false, diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/constants/WorkflowActionsConfig.tsx b/packages/twenty-front/src/modules/action-menu/actions/record-actions/constants/WorkflowActionsConfig.tsx index 79338014865..8058d507050 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/record-actions/constants/WorkflowActionsConfig.tsx +++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/constants/WorkflowActionsConfig.tsx @@ -202,8 +202,8 @@ export const WORKFLOW_ACTIONS_CONFIG = inheritActionsFromDefaultConfig({ Icon: IconHistoryToggle, accent: 'default', isPinned: true, - shouldBeRegistered: ({ isSoftDeleteFilterActive }) => - !isSoftDeleteFilterActive, + shouldBeRegistered: ({ hasAnySoftDeleteFilterOnView }) => + !hasAnySoftDeleteFilterOnView, availableOn: [ActionViewType.INDEX_PAGE_NO_SELECTION], component: ( { viewBarId: recordIndexId, }); - const { checkIsSoftDeleteFilter } = useCheckIsSoftDeleteFilter(); + const { isRecordFilterAboutSoftDelete } = useCheckIsSoftDeleteFilter(); const currentRecordFilters = useRecoilComponentValue( currentRecordFiltersComponentState, recordIndexId, ); - const deletedFilter = currentRecordFilters.find(checkIsSoftDeleteFilter); + const deletedFilter = currentRecordFilters.find( + isRecordFilterAboutSoftDelete, + ); const { removeRecordFilter } = useRemoveRecordFilter(); diff --git a/packages/twenty-front/src/modules/action-menu/actions/types/ShouldBeRegisteredFunctionParams.ts b/packages/twenty-front/src/modules/action-menu/actions/types/ShouldBeRegisteredFunctionParams.ts index 0567448a21d..4f4aa8fd492 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/types/ShouldBeRegisteredFunctionParams.ts +++ b/packages/twenty-front/src/modules/action-menu/actions/types/ShouldBeRegisteredFunctionParams.ts @@ -10,7 +10,7 @@ export type ShouldBeRegisteredFunctionParams = { objectPermissions: ObjectPermissions; recordFilters?: RecordFilter[]; isShowPage?: boolean; - isSoftDeleteFilterActive?: boolean; + hasAnySoftDeleteFilterOnView?: boolean; isInRightDrawer?: boolean; isFavorite?: boolean; isRemote?: boolean; diff --git a/packages/twenty-front/src/modules/action-menu/hooks/useShouldActionBeRegisteredParams.ts b/packages/twenty-front/src/modules/action-menu/hooks/useShouldActionBeRegisteredParams.ts index c7600e6c00c..6ecb29f9d38 100644 --- a/packages/twenty-front/src/modules/action-menu/hooks/useShouldActionBeRegisteredParams.ts +++ b/packages/twenty-front/src/modules/action-menu/hooks/useShouldActionBeRegisteredParams.ts @@ -10,8 +10,8 @@ import { useFavorites } from '@/favorites/hooks/useFavorites'; import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; import { useObjectPermissionsForObject } from '@/object-record/hooks/useObjectPermissionsForObject'; +import { hasAnySoftDeleteFilterOnViewComponentSelector } from '@/object-record/record-filter/states/hasAnySoftDeleteFilterOnView'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; -import { isSoftDeleteFilterActiveComponentState } from '@/object-record/record-table/states/isSoftDeleteFilterActiveComponentState'; import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; import { useContext } from 'react'; import { useRecoilCallback, useRecoilValue } from 'recoil'; @@ -51,8 +51,8 @@ export const useShouldActionBeRegisteredParams = ({ const { isInRightDrawer } = useContext(ActionMenuContext); - const isSoftDeleteFilterActive = useRecoilComponentValue( - isSoftDeleteFilterActiveComponentState, + const hasAnySoftDeleteFilterOnView = useRecoilComponentValue( + hasAnySoftDeleteFilterOnViewComponentSelector, ); const isShowPage = @@ -106,7 +106,7 @@ export const useShouldActionBeRegisteredParams = ({ objectPermissions, isNoteOrTask, isInRightDrawer, - isSoftDeleteFilterActive, + hasAnySoftDeleteFilterOnView, isShowPage, selectedRecord, numberOfSelectedRecords, diff --git a/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnHeader.tsx b/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnHeader.tsx index b7fd2b506e9..7b6301466d2 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnHeader.tsx +++ b/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnHeader.tsx @@ -7,10 +7,12 @@ import { RecordBoardColumnDropdownMenu } from '@/object-record/record-board/reco import { RecordBoardColumnHeaderAggregateDropdown } from '@/object-record/record-board/record-board-column/components/RecordBoardColumnHeaderAggregateDropdown'; import { RecordBoardColumnContext } from '@/object-record/record-board/record-board-column/contexts/RecordBoardColumnContext'; import { useAggregateRecordsForRecordBoardColumn } from '@/object-record/record-board/record-board-column/hooks/useAggregateRecordsForRecordBoardColumn'; +import { hasAnySoftDeleteFilterOnViewComponentSelector } from '@/object-record/record-filter/states/hasAnySoftDeleteFilterOnView'; import { RecordGroupDefinitionType } from '@/object-record/record-group/types/RecordGroupDefinition'; import { useCreateNewIndexRecord } from '@/object-record/record-table/hooks/useCreateNewIndexRecord'; import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown'; import { useToggleDropdown } from '@/ui/layout/dropdown/hooks/useToggleDropdown'; +import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; import { Tag } from 'twenty-ui/components'; import { IconDotsVertical, IconPlus } from 'twenty-ui/display'; import { LightIconButton } from 'twenty-ui/input'; @@ -80,6 +82,10 @@ export const RecordBoardColumnHeader = () => { const hasObjectUpdatePermissions = objectPermissions.canUpdateObjectRecords; + const hasAnySoftDeleteFilterOnView = useRecoilComponentValue( + hasAnySoftDeleteFilterOnViewComponentSelector, + ); + const { createNewIndexRecord } = useCreateNewIndexRecord({ objectMetadataItem: objectMetadataItem, }); @@ -145,18 +151,20 @@ export const RecordBoardColumnHeader = () => { }); }} /> - {hasObjectUpdatePermissions && ( - { - createNewIndexRecord({ - position: 'first', - [selectFieldMetadataItem.name]: columnDefinition.value, - }); - }} - /> - )} + {hasObjectUpdatePermissions && + !hasAnySoftDeleteFilterOnView && ( + { + createNewIndexRecord({ + position: 'first', + [selectFieldMetadataItem.name]: + columnDefinition.value, + }); + }} + /> + )} )} diff --git a/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnNewRecordButton.tsx b/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnNewRecordButton.tsx index 34079091313..ce62e0b46b6 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnNewRecordButton.tsx +++ b/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnNewRecordButton.tsx @@ -1,7 +1,9 @@ import { useObjectPermissionsForObject } from '@/object-record/hooks/useObjectPermissionsForObject'; import { RecordBoardContext } from '@/object-record/record-board/contexts/RecordBoardContext'; import { RecordBoardColumnContext } from '@/object-record/record-board/record-board-column/contexts/RecordBoardColumnContext'; +import { hasAnySoftDeleteFilterOnViewComponentSelector } from '@/object-record/record-filter/states/hasAnySoftDeleteFilterOnView'; import { useCreateNewIndexRecord } from '@/object-record/record-table/hooks/useCreateNewIndexRecord'; +import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; import { useTheme } from '@emotion/react'; import styled from '@emotion/styled'; import { useContext } from 'react'; @@ -32,6 +34,10 @@ export const RecordBoardColumnNewRecordButton = () => { const { columnDefinition } = useContext(RecordBoardColumnContext); + const hasAnySoftDeleteFilterOnView = useRecoilComponentValue( + hasAnySoftDeleteFilterOnViewComponentSelector, + ); + const objectPermissions = useObjectPermissionsForObject( objectMetadataItem.id, ); @@ -46,6 +52,10 @@ export const RecordBoardColumnNewRecordButton = () => { return null; } + if (hasAnySoftDeleteFilterOnView) { + return null; + } + return ( { diff --git a/packages/twenty-front/src/modules/object-record/record-filter/hooks/useCheckIsSoftDeleteFilter.ts b/packages/twenty-front/src/modules/object-record/record-filter/hooks/useCheckIsSoftDeleteFilter.ts index 4280974cb52..2ab17935a85 100644 --- a/packages/twenty-front/src/modules/object-record/record-filter/hooks/useCheckIsSoftDeleteFilter.ts +++ b/packages/twenty-front/src/modules/object-record/record-filter/hooks/useCheckIsSoftDeleteFilter.ts @@ -2,39 +2,33 @@ import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadat import { SOFT_DELETE_FILTER_FIELD_NAME } from '@/object-record/record-filter/constants/SoftDeleteFilterFieldName'; import { type RecordFilter } from '@/object-record/record-filter/types/RecordFilter'; import { RecordFilterOperand } from '@/object-record/record-filter/types/RecordFilterOperand'; -import { isSoftDeleteFilterActiveComponentState } from '@/object-record/record-table/states/isSoftDeleteFilterActiveComponentState'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; -import { isDefined } from 'twenty-shared/utils'; +import { getRecordFilterFieldMetadataItem } from '@/object-record/record-filter/utils/getRecordFilterFieldMetadataItem'; +import { isRecordFilterAboutSoftDelete as isRecordFilterAboutSoftDeleteUtil } from '@/object-record/record-filter/utils/isRecordFilterAboutSoftDelete'; export const useCheckIsSoftDeleteFilter = () => { const { objectMetadataItems } = useObjectMetadataItems(); - const isSoftDeleteFilterActive = useRecoilComponentValue( - isSoftDeleteFilterActiveComponentState, - ); + const isRecordFilterAboutSoftDelete = (recordFilter: RecordFilter) => { + return isRecordFilterAboutSoftDeleteUtil({ + recordFilter, + objectMetadataItems, + }); + }; - const checkIsSoftDeleteFilter = (recordFilter: RecordFilter) => { - const allFieldMetadataItems = objectMetadataItems.flatMap( - (objectMetadataItem) => objectMetadataItem.fields, - ); + const isSeeDeletedRecordsFilter = (recordFilter: RecordFilter) => { + const foundFieldMetadataItem = getRecordFilterFieldMetadataItem({ + recordFilter, + objectMetadataItems, + }); - const foundFieldMetadataItem = allFieldMetadataItems.find( - (fieldMetadataItem) => - fieldMetadataItem.id === recordFilter.fieldMetadataId, - ); - - if (!isDefined(foundFieldMetadataItem)) { - throw new Error( - `Field metadata item not found for field metadata id: ${recordFilter.fieldMetadataId}`, - ); - } + const isNotEmptyFilter = + recordFilter.operand === RecordFilterOperand.IsNotEmpty; return ( foundFieldMetadataItem.name === SOFT_DELETE_FILTER_FIELD_NAME && - isSoftDeleteFilterActive && - recordFilter.operand === RecordFilterOperand.IsNotEmpty + isNotEmptyFilter ); }; - return { checkIsSoftDeleteFilter }; + return { isRecordFilterAboutSoftDelete, isSeeDeletedRecordsFilter }; }; diff --git a/packages/twenty-front/src/modules/object-record/record-filter/states/hasAnySoftDeleteFilterOnView.ts b/packages/twenty-front/src/modules/object-record/record-filter/states/hasAnySoftDeleteFilterOnView.ts new file mode 100644 index 00000000000..0b223812e8a --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-filter/states/hasAnySoftDeleteFilterOnView.ts @@ -0,0 +1,29 @@ +import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; +import { RecordFiltersComponentInstanceContext } from '@/object-record/record-filter/states/context/RecordFiltersComponentInstanceContext'; +import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState'; +import { isRecordFilterAboutSoftDelete } from '@/object-record/record-filter/utils/isRecordFilterAboutSoftDelete'; +import { createComponentSelector } from '@/ui/utilities/state/component-state/utils/createComponentSelector'; + +export const hasAnySoftDeleteFilterOnViewComponentSelector = + createComponentSelector({ + key: 'hasAnySoftDeleteFilterOnViewComponentSelector', + componentInstanceContext: RecordFiltersComponentInstanceContext, + get: + ({ instanceId }) => + ({ get }) => { + const objectMetadataItems = get(objectMetadataItemsState); + const currentRecordFilters = get( + currentRecordFiltersComponentState.atomFamily({ instanceId }), + ); + + const hasAnySoftDeleteFilterOnView = currentRecordFilters.some( + (recordFilter) => { + return isRecordFilterAboutSoftDelete({ + recordFilter, + objectMetadataItems, + }); + }, + ); + return hasAnySoftDeleteFilterOnView; + }, + }); diff --git a/packages/twenty-front/src/modules/object-record/record-filter/utils/getRecordFilterFieldMetadataItem.ts b/packages/twenty-front/src/modules/object-record/record-filter/utils/getRecordFilterFieldMetadataItem.ts new file mode 100644 index 00000000000..4757fb6d9de --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-filter/utils/getRecordFilterFieldMetadataItem.ts @@ -0,0 +1,28 @@ +import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; +import { type RecordFilter } from '@/object-record/record-filter/types/RecordFilter'; +import { isDefined } from 'twenty-shared/utils'; + +export const getRecordFilterFieldMetadataItem = ({ + recordFilter, + objectMetadataItems, +}: { + recordFilter: RecordFilter; + objectMetadataItems: ObjectMetadataItem[]; +}) => { + const allFieldMetadataItems = objectMetadataItems.flatMap( + (objectMetadataItem) => objectMetadataItem.fields, + ); + + const foundFieldMetadataItem = allFieldMetadataItems.find( + (fieldMetadataItem) => + fieldMetadataItem.id === recordFilter.fieldMetadataId, + ); + + if (!isDefined(foundFieldMetadataItem)) { + throw new Error( + `Field metadata item not found for field metadata id: ${recordFilter.fieldMetadataId}`, + ); + } + + return foundFieldMetadataItem; +}; diff --git a/packages/twenty-front/src/modules/object-record/record-filter/utils/isRecordFilterAboutSoftDelete.ts b/packages/twenty-front/src/modules/object-record/record-filter/utils/isRecordFilterAboutSoftDelete.ts new file mode 100644 index 00000000000..cb73cddd431 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-filter/utils/isRecordFilterAboutSoftDelete.ts @@ -0,0 +1,29 @@ +import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; +import { SOFT_DELETE_FILTER_FIELD_NAME } from '@/object-record/record-filter/constants/SoftDeleteFilterFieldName'; +import { type RecordFilter } from '@/object-record/record-filter/types/RecordFilter'; +import { RecordFilterOperand } from '@/object-record/record-filter/types/RecordFilterOperand'; +import { getRecordFilterFieldMetadataItem } from '@/object-record/record-filter/utils/getRecordFilterFieldMetadataItem'; +import isEmpty from 'lodash.isempty'; + +export const isRecordFilterAboutSoftDelete = ({ + recordFilter, + objectMetadataItems, +}: { + recordFilter: RecordFilter; + objectMetadataItems: ObjectMetadataItem[]; +}) => { + const foundFieldMetadataItem = getRecordFilterFieldMetadataItem({ + recordFilter, + objectMetadataItems, + }); + + const valueIsNotEmptyFilter = + (recordFilter.operand === RecordFilterOperand.Is && + !isEmpty(recordFilter.value)) || + recordFilter.operand === RecordFilterOperand.IsNotEmpty; + + return ( + foundFieldMetadataItem.name === SOFT_DELETE_FILTER_FIELD_NAME && + valueIsNotEmptyFilter + ); +}; diff --git a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableAddNew.tsx b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableAddNew.tsx index ba4f500f548..26202638540 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableAddNew.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableAddNew.tsx @@ -1,4 +1,5 @@ import { useObjectPermissionsForObject } from '@/object-record/hooks/useObjectPermissionsForObject'; +import { hasAnySoftDeleteFilterOnViewComponentSelector } from '@/object-record/record-filter/states/hasAnySoftDeleteFilterOnView'; import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext'; import { useCreateNewIndexRecord } from '@/object-record/record-table/hooks/useCreateNewIndexRecord'; import { RecordTableActionRow } from '@/object-record/record-table/record-table-row/components/RecordTableActionRow'; @@ -24,6 +25,14 @@ export const RecordTableAddNew = () => { const hasObjectUpdatePermissions = objectPermissions.canUpdateObjectRecords; + const hasAnySoftDeleteFilterOnView = useRecoilComponentValue( + hasAnySoftDeleteFilterOnViewComponentSelector, + ); + + if (hasAnySoftDeleteFilterOnView) { + return null; + } + if (!hasObjectUpdatePermissions || !hasRecordTableFetchedAllRecords) { return null; } diff --git a/packages/twenty-front/src/modules/object-record/record-table/empty-state/components/RecordTableEmptyStateDisplay.tsx b/packages/twenty-front/src/modules/object-record/record-table/empty-state/components/RecordTableEmptyStateDisplay.tsx index acd024b12be..d9d5eb3064c 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/empty-state/components/RecordTableEmptyStateDisplay.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/empty-state/components/RecordTableEmptyStateDisplay.tsx @@ -1,6 +1,8 @@ import { useObjectPermissionsForObject } from '@/object-record/hooks/useObjectPermissionsForObject'; import { isObjectMetadataReadOnly } from '@/object-record/read-only/utils/isObjectMetadataReadOnly'; +import { hasAnySoftDeleteFilterOnViewComponentSelector } from '@/object-record/record-filter/states/hasAnySoftDeleteFilterOnView'; import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext'; +import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; import { type IconComponent } from 'twenty-ui/display'; import { Button } from 'twenty-ui/input'; import { @@ -44,6 +46,10 @@ export const RecordTableEmptyStateDisplay = ( objectMetadataItem, }); + const hasAnySoftDeleteFilterOnView = useRecoilComponentValue( + hasAnySoftDeleteFilterOnViewComponentSelector, + ); + return ( @@ -56,15 +62,17 @@ export const RecordTableEmptyStateDisplay = ( {'buttonComponent' in props && props.buttonComponent} - {'buttonTitle' in props && !isReadOnly && ( -