Files
twenty/packages/twenty-front/src/modules/action-menu/hooks/useShouldActionBeRegisteredParams.ts
T
Marie da5ae34109 [permissions] Filter tabs + registered actions according to permissions (#12657)
Note and task tabs in side panel should only show if user has reading
permission on them.

"Go to companies", "Go to workflows", etc. in command menu should only
show is user has reading permission on related objects.

<img width="507" alt="Capture d’écran 2025-06-17 à 11 09 50"
src="https://github.com/user-attachments/assets/3a2a4c25-0b9b-4ee6-b18f-b019b8a56d47"
/>
<img width="505" alt="Capture d’écran 2025-06-17 à 11 09 56"
src="https://github.com/user-attachments/assets/8a219955-cc8e-4dbf-a4f9-a50e1aaa4b59"
/>

**How to test** 
Assign a user with a custom role that has **no** read permissions on
notes/tasks/workflows/companies/opportunities/people (no need to test
them all but at least one between note and tasks; workflows; one between
companies/opportunities/people). Check that you don't see the related
tab / action.

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
2025-06-18 15:12:58 +00:00

110 lines
4.1 KiB
TypeScript

import { ShouldBeRegisteredFunctionParams } from '@/action-menu/actions/types/ShouldBeRegisteredFunctionParams';
import { getActionViewType } from '@/action-menu/actions/utils/getActionViewType';
import { ActionMenuContext } from '@/action-menu/contexts/ActionMenuContext';
import { objectPermissionsFamilySelector } from '@/auth/states/objectPermissionsFamilySelector';
import { contextStoreCurrentViewTypeComponentState } from '@/context-store/states/contextStoreCurrentViewTypeComponentState';
import { contextStoreNumberOfSelectedRecordsComponentState } from '@/context-store/states/contextStoreNumberOfSelectedRecordsComponentState';
import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState';
import { ContextStoreViewType } from '@/context-store/types/ContextStoreViewType';
import { useFavorites } from '@/favorites/hooks/useFavorites';
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
import { useObjectPermissionsForObject } from '@/object-record/hooks/useObjectPermissionsForObject';
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
import { isSoftDeleteFilterActiveComponentState } from '@/object-record/record-table/states/isSoftDeleteFilterActiveComponentState';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
import { useContext } from 'react';
import { useRecoilCallback, useRecoilValue } from 'recoil';
import { FeatureFlagKey } from '~/generated-metadata/graphql';
export const useShouldActionBeRegisteredParams = ({
objectMetadataItem,
}: {
objectMetadataItem?: ObjectMetadataItem;
}): ShouldBeRegisteredFunctionParams => {
const { sortedFavorites: favorites } = useFavorites();
const contextStoreTargetedRecordsRule = useRecoilComponentValueV2(
contextStoreTargetedRecordsRuleComponentState,
);
const recordId =
contextStoreTargetedRecordsRule.mode === 'selection'
? contextStoreTargetedRecordsRule.selectedRecordIds[0]
: undefined;
const foundFavorite = favorites?.find(
(favorite) => favorite.recordId === recordId,
);
const isFavorite = !!foundFavorite;
const selectedRecord =
useRecoilValue(recordStoreFamilyState(recordId ?? '')) || undefined;
const objectPermissions = useObjectPermissionsForObject(
objectMetadataItem?.id,
);
const isNoteOrTask =
objectMetadataItem?.nameSingular === CoreObjectNameSingular.Note ||
objectMetadataItem?.nameSingular === CoreObjectNameSingular.Task;
const { isInRightDrawer } = useContext(ActionMenuContext);
const isSoftDeleteFilterActive = useRecoilComponentValueV2(
isSoftDeleteFilterActiveComponentState,
);
const isShowPage =
useRecoilComponentValueV2(contextStoreCurrentViewTypeComponentState) ===
ContextStoreViewType.ShowPage;
const isWorkflowEnabled = useIsFeatureEnabled(
FeatureFlagKey.IS_WORKFLOW_ENABLED,
);
const numberOfSelectedRecords = useRecoilComponentValueV2(
contextStoreNumberOfSelectedRecordsComponentState,
);
const contextStoreCurrentViewType = useRecoilComponentValueV2(
contextStoreCurrentViewTypeComponentState,
);
const viewType = getActionViewType(
contextStoreCurrentViewType,
contextStoreTargetedRecordsRule,
);
const getObjectReadPermission = useRecoilCallback(
({ snapshot }) =>
(objectMetadataNameSingular: string) => {
return snapshot
.getLoadable(
objectPermissionsFamilySelector({
objectNameSingular: objectMetadataNameSingular,
}),
)
.getValue().canRead;
},
[],
);
return {
objectMetadataItem,
isFavorite,
objectPermissions,
isNoteOrTask,
isInRightDrawer,
isSoftDeleteFilterActive,
isShowPage,
selectedRecord,
isWorkflowEnabled,
numberOfSelectedRecords,
viewType: viewType ?? undefined,
getTargetObjectReadPermission: getObjectReadPermission,
};
};