refactor(command-menu-item): rename Actions to CommandMenuItem (#18489)
actions are being renamed to command menu item, they will be migrated to server and will be served as headless front components --------- Co-authored-by: Raphaël Bosi <71827178+bosiraphael@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
import { CommandMenuContext } from '@/command-menu-item/contexts/CommandMenuContext';
|
||||
import { CommandMenuComponentInstanceContext } from '@/command-menu/states/contexts/CommandMenuComponentInstanceContext';
|
||||
import { getCommandMenuDropdownIdFromCommandMenuId } from '@/command-menu-item/utils/getCommandMenuDropdownIdFromCommandMenuId';
|
||||
import { getSidePanelCommandMenuDropdownIdFromCommandMenuId } from '@/command-menu-item/utils/getSidePanelCommandMenuDropdownIdFromCommandMenuId';
|
||||
import { useSidePanelMenu } from '@/side-panel/hooks/useSidePanelMenu';
|
||||
import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown';
|
||||
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
|
||||
import { useContext } from 'react';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
export const useCloseCommandMenu = ({
|
||||
closeSidePanelOnShowPageOptionsExecution = false,
|
||||
closeSidePanelOnCommandMenuListExecution = true,
|
||||
}: {
|
||||
closeSidePanelOnShowPageOptionsExecution?: boolean;
|
||||
closeSidePanelOnCommandMenuListExecution?: boolean;
|
||||
} = {}) => {
|
||||
const { containerType, isInSidePanel } = useContext(CommandMenuContext);
|
||||
|
||||
const { closeSidePanelMenu } = useSidePanelMenu();
|
||||
|
||||
const { closeDropdown } = useCloseDropdown();
|
||||
|
||||
const commandMenuId = useAvailableComponentInstanceIdOrThrow(
|
||||
CommandMenuComponentInstanceContext,
|
||||
);
|
||||
|
||||
const dropdownId = isInSidePanel
|
||||
? getSidePanelCommandMenuDropdownIdFromCommandMenuId(commandMenuId)
|
||||
: getCommandMenuDropdownIdFromCommandMenuId(commandMenuId);
|
||||
|
||||
const closeCommandMenu = () => {
|
||||
if (containerType === 'command-menu-list') {
|
||||
if (
|
||||
isDefined(closeSidePanelOnCommandMenuListExecution) &&
|
||||
!closeSidePanelOnCommandMenuListExecution
|
||||
) {
|
||||
return;
|
||||
}
|
||||
closeSidePanelMenu();
|
||||
}
|
||||
|
||||
if (
|
||||
containerType === 'index-page-dropdown' ||
|
||||
containerType === 'command-menu-show-page-dropdown'
|
||||
) {
|
||||
closeDropdown(dropdownId);
|
||||
}
|
||||
|
||||
if (
|
||||
containerType === 'command-menu-show-page-dropdown' &&
|
||||
isDefined(closeSidePanelOnShowPageOptionsExecution) &&
|
||||
closeSidePanelOnShowPageOptionsExecution
|
||||
) {
|
||||
closeSidePanelMenu();
|
||||
}
|
||||
};
|
||||
|
||||
return { closeCommandMenu };
|
||||
};
|
||||
+156
@@ -0,0 +1,156 @@
|
||||
import { CommandMenuContext } from '@/command-menu-item/contexts/CommandMenuContext';
|
||||
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
||||
import { objectPermissionsFamilySelector } from '@/auth/states/objectPermissionsFamilySelector';
|
||||
import { contextStoreCurrentObjectMetadataItemIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataItemIdComponentState';
|
||||
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 { usePrefetchedNavigationMenuItemsData } from '@/navigation-menu-item/hooks/usePrefetchedNavigationMenuItemsData';
|
||||
import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems';
|
||||
import { useObjectPermissionsForObject } from '@/object-record/hooks/useObjectPermissionsForObject';
|
||||
import { hasAnySoftDeleteFilterOnViewComponentSelector } from '@/object-record/record-filter/states/hasAnySoftDeleteFilterOnView';
|
||||
import { useRecordIndexIdFromCurrentContextStore } from '@/object-record/record-index/hooks/useRecordIndexIdFromCurrentContextStore';
|
||||
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
|
||||
import { useAtomComponentSelectorValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentSelectorValue';
|
||||
import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue';
|
||||
import { useAtomFamilyStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomFamilyStateValue';
|
||||
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
|
||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||
import { useStore } from 'jotai';
|
||||
import { useContext } from 'react';
|
||||
import {
|
||||
CoreObjectNameSingular,
|
||||
type CommandMenuContextApi,
|
||||
} from 'twenty-shared/types';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { FeatureFlagKey } from '~/generated-metadata/graphql';
|
||||
|
||||
export const useCommandMenuContextApi = (): CommandMenuContextApi => {
|
||||
const store = useStore();
|
||||
|
||||
const { isInSidePanel } = useContext(CommandMenuContext);
|
||||
|
||||
const contextStoreCurrentObjectMetadataItemId = useAtomComponentStateValue(
|
||||
contextStoreCurrentObjectMetadataItemIdComponentState,
|
||||
);
|
||||
|
||||
const contextStoreTargetedRecordsRule = useAtomComponentStateValue(
|
||||
contextStoreTargetedRecordsRuleComponentState,
|
||||
);
|
||||
|
||||
const isNavigationMenuItemEditingEnabled = useIsFeatureEnabled(
|
||||
FeatureFlagKey.IS_NAVIGATION_MENU_ITEM_EDITING_ENABLED,
|
||||
);
|
||||
|
||||
const { objectMetadataItems } = useObjectMetadataItems();
|
||||
|
||||
const objectMetadataItem = objectMetadataItems.find(
|
||||
(item) => item.id === contextStoreCurrentObjectMetadataItemId,
|
||||
);
|
||||
|
||||
const { sortedFavorites: favorites } = useFavorites();
|
||||
const { navigationMenuItems } = usePrefetchedNavigationMenuItemsData();
|
||||
|
||||
const recordId =
|
||||
contextStoreTargetedRecordsRule.mode === 'selection'
|
||||
? contextStoreTargetedRecordsRule.selectedRecordIds[0]
|
||||
: undefined;
|
||||
|
||||
const isFavorite = (() => {
|
||||
if (!isDefined(recordId)) return false;
|
||||
|
||||
if (isNavigationMenuItemEditingEnabled && isDefined(objectMetadataItem)) {
|
||||
return !!navigationMenuItems?.find(
|
||||
(item) =>
|
||||
item.targetRecordId === recordId &&
|
||||
item.targetObjectMetadataId === objectMetadataItem.id,
|
||||
);
|
||||
}
|
||||
|
||||
return !!favorites?.find((favorite) => favorite.recordId === recordId);
|
||||
})();
|
||||
|
||||
const selectedRecord =
|
||||
useAtomFamilyStateValue(recordStoreFamilyState, recordId ?? '') ||
|
||||
undefined;
|
||||
|
||||
const objectPermissionsFromHook = useObjectPermissionsForObject(
|
||||
objectMetadataItem?.id ?? '',
|
||||
);
|
||||
const objectPermissions = isDefined(objectMetadataItem)
|
||||
? objectPermissionsFromHook
|
||||
: {
|
||||
canReadObjectRecords: false,
|
||||
canUpdateObjectRecords: false,
|
||||
canSoftDeleteObjectRecords: false,
|
||||
canDestroyObjectRecords: false,
|
||||
restrictedFields: {},
|
||||
objectMetadataId: '',
|
||||
rowLevelPermissionPredicates: [],
|
||||
rowLevelPermissionPredicateGroups: [],
|
||||
};
|
||||
|
||||
const isNoteOrTask =
|
||||
objectMetadataItem?.nameSingular === CoreObjectNameSingular.Note ||
|
||||
objectMetadataItem?.nameSingular === CoreObjectNameSingular.Task;
|
||||
|
||||
const isRemote = objectMetadataItem?.isRemote ?? false;
|
||||
|
||||
const { recordIndexId } = useRecordIndexIdFromCurrentContextStore();
|
||||
|
||||
const hasAnySoftDeleteFilterOnView = useAtomComponentSelectorValue(
|
||||
hasAnySoftDeleteFilterOnViewComponentSelector,
|
||||
recordIndexId,
|
||||
);
|
||||
|
||||
const isShowPage =
|
||||
useAtomComponentStateValue(contextStoreCurrentViewTypeComponentState) ===
|
||||
ContextStoreViewType.ShowPage;
|
||||
|
||||
const contextStoreNumberOfSelectedRecords = useAtomComponentStateValue(
|
||||
contextStoreNumberOfSelectedRecordsComponentState,
|
||||
);
|
||||
|
||||
const isSelectAll = contextStoreTargetedRecordsRule.mode === 'exclusion';
|
||||
|
||||
const currentWorkspace = useAtomStateValue(currentWorkspaceState);
|
||||
|
||||
const featureFlags: Record<string, boolean> = {};
|
||||
|
||||
for (const flag of currentWorkspace?.featureFlags ?? []) {
|
||||
featureFlags[flag.key] = flag.value === true;
|
||||
}
|
||||
|
||||
const targetObjectReadPermissions: Record<string, boolean> = {};
|
||||
const targetObjectWritePermissions: Record<string, boolean> = {};
|
||||
|
||||
for (const metadataItem of objectMetadataItems) {
|
||||
const permissions = store.get(
|
||||
objectPermissionsFamilySelector.selectorFamily({
|
||||
objectNameSingular: metadataItem.nameSingular,
|
||||
}),
|
||||
);
|
||||
targetObjectReadPermissions[metadataItem.nameSingular] =
|
||||
permissions.canRead;
|
||||
targetObjectWritePermissions[metadataItem.nameSingular] =
|
||||
permissions.canUpdate;
|
||||
}
|
||||
|
||||
return {
|
||||
isShowPage,
|
||||
isInSidePanel,
|
||||
isFavorite,
|
||||
isRemote,
|
||||
isNoteOrTask,
|
||||
isSelectAll,
|
||||
hasAnySoftDeleteFilterOnView,
|
||||
numberOfSelectedRecords: contextStoreNumberOfSelectedRecords,
|
||||
objectPermissions,
|
||||
selectedRecord: selectedRecord as CommandMenuContextApi['selectedRecord'],
|
||||
featureFlags,
|
||||
targetObjectReadPermissions,
|
||||
targetObjectWritePermissions,
|
||||
};
|
||||
};
|
||||
+22
-22
@@ -1,8 +1,8 @@
|
||||
import { Action } from '@/action-menu/actions/components/Action';
|
||||
import { HeadlessFrontComponentAction } from '@/action-menu/actions/display/components/HeadlessFrontComponentAction';
|
||||
import { ActionScope } from '@/action-menu/actions/types/ActionScope';
|
||||
import { ActionType } from '@/action-menu/actions/types/ActionType';
|
||||
import { ActionMenuContext } from '@/action-menu/contexts/ActionMenuContext';
|
||||
import { Command } from '@/command-menu-item/display/components/Command';
|
||||
import { HeadlessFrontComponentCommandMenuItem } from '@/command-menu-item/display/components/HeadlessFrontComponentCommandMenuItem';
|
||||
import { CommandMenuItemScope } from '@/command-menu-item/types/CommandMenuItemScope';
|
||||
import { CommandMenuItemType } from '@/command-menu-item/types/CommandMenuItemType';
|
||||
import { CommandMenuContext } from '@/command-menu-item/contexts/CommandMenuContext';
|
||||
import { useOpenFrontComponentInSidePanel } from '@/side-panel/hooks/useOpenFrontComponentInSidePanel';
|
||||
import { contextStoreCurrentObjectMetadataItemIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataItemIdComponentState';
|
||||
import { contextStoreIsPageInEditModeComponentState } from '@/context-store/states/contextStoreIsPageInEditModeComponentState';
|
||||
@@ -34,9 +34,9 @@ type CommandMenuItemWithFrontComponent = CommandMenuItemFieldsFragment & {
|
||||
conditionalAvailabilityExpression?: string | null;
|
||||
};
|
||||
|
||||
type BuildActionFromItemParams = {
|
||||
type BuildCommandMenuItemFromFrontComponentParams = {
|
||||
item: CommandMenuItemWithFrontComponent;
|
||||
scope: ActionScope;
|
||||
scope: CommandMenuItemScope;
|
||||
index: number;
|
||||
isPinned: boolean;
|
||||
getIcon: ReturnType<typeof useIcons>['getIcon'];
|
||||
@@ -59,7 +59,7 @@ type BuildActionFromItemParams = {
|
||||
|
||||
// TODO: we should remove this backward compatibility logic in the future
|
||||
// once we have migrated all command menu items
|
||||
const buildActionFromItem = ({
|
||||
const buildCommandMenuItemFromFrontComponent = ({
|
||||
item,
|
||||
scope,
|
||||
index,
|
||||
@@ -69,7 +69,7 @@ const buildActionFromItem = ({
|
||||
mountHeadlessFrontComponent,
|
||||
mountContext,
|
||||
commandMenuContextApi,
|
||||
}: BuildActionFromItemParams) => {
|
||||
}: BuildCommandMenuItemFromFrontComponentParams) => {
|
||||
const displayLabel = item.label;
|
||||
|
||||
const Icon = getIcon(item.icon, COMMAND_MENU_DEFAULT_ICON);
|
||||
@@ -95,7 +95,7 @@ const buildActionFromItem = ({
|
||||
};
|
||||
|
||||
return {
|
||||
type: ActionType.FrontComponent,
|
||||
type: CommandMenuItemType.FrontComponent,
|
||||
key: `command-menu-item-front-component-${item.id}`,
|
||||
scope,
|
||||
label: displayLabel,
|
||||
@@ -109,12 +109,12 @@ const buildActionFromItem = ({
|
||||
commandMenuContextApi,
|
||||
),
|
||||
component: isHeadless ? (
|
||||
<HeadlessFrontComponentAction
|
||||
<HeadlessFrontComponentCommandMenuItem
|
||||
frontComponentId={item.frontComponentId}
|
||||
onClick={handleClick}
|
||||
/>
|
||||
) : (
|
||||
<Action onClick={handleClick} />
|
||||
<Command onClick={handleClick} />
|
||||
),
|
||||
};
|
||||
};
|
||||
@@ -130,7 +130,7 @@ export const useCommandMenuItemFrontComponentActions = (
|
||||
contextStoreIsPageInEditModeComponentState,
|
||||
);
|
||||
|
||||
const { actionMenuType } = useContext(ActionMenuContext);
|
||||
const { containerType } = useContext(CommandMenuContext);
|
||||
|
||||
const contextStoreCurrentObjectMetadataItemId = useAtomComponentStateValue(
|
||||
contextStoreCurrentObjectMetadataItemIdComponentState,
|
||||
@@ -166,8 +166,8 @@ export const useCommandMenuItemFrontComponentActions = (
|
||||
const { data } = useFindManyCommandMenuItemsQuery({
|
||||
skip:
|
||||
!isCommandMenuItemEnabled ||
|
||||
(actionMenuType !== 'command-menu' &&
|
||||
actionMenuType !== 'command-menu-show-page-action-menu-dropdown'),
|
||||
(containerType !== 'command-menu-list' &&
|
||||
containerType !== 'command-menu-show-page-dropdown'),
|
||||
});
|
||||
|
||||
const frontComponentItems =
|
||||
@@ -200,10 +200,10 @@ export const useCommandMenuItemFrontComponentActions = (
|
||||
);
|
||||
});
|
||||
|
||||
const globalActions = globalItems.map((item, index) =>
|
||||
buildActionFromItem({
|
||||
const globalCommandMenuItems = globalItems.map((item, index) =>
|
||||
buildCommandMenuItemFromFrontComponent({
|
||||
item,
|
||||
scope: ActionScope.Global,
|
||||
scope: CommandMenuItemScope.Global,
|
||||
index,
|
||||
isPinned: !contextStoreIsPageInEditMode && item.isPinned,
|
||||
getIcon,
|
||||
@@ -213,10 +213,10 @@ export const useCommandMenuItemFrontComponentActions = (
|
||||
}),
|
||||
);
|
||||
|
||||
const recordScopedActions = recordScopedItems.map((item, index) =>
|
||||
buildActionFromItem({
|
||||
const recordScopedCommandMenuItems = recordScopedItems.map((item, index) =>
|
||||
buildCommandMenuItemFromFrontComponent({
|
||||
item,
|
||||
scope: ActionScope.RecordSelection,
|
||||
scope: CommandMenuItemScope.RecordSelection,
|
||||
index,
|
||||
isPinned: !contextStoreIsPageInEditMode && item.isPinned,
|
||||
getIcon,
|
||||
@@ -227,5 +227,5 @@ export const useCommandMenuItemFrontComponentActions = (
|
||||
}),
|
||||
);
|
||||
|
||||
return [...globalActions, ...recordScopedActions];
|
||||
return [...globalCommandMenuItems, ...recordScopedCommandMenuItems];
|
||||
};
|
||||
|
||||
+96
@@ -0,0 +1,96 @@
|
||||
import { useRecordAgnosticCommands } from '@/command-menu-item/record-agnostic/hooks/useRecordAgnosticCommands';
|
||||
import { useRelatedRecordCommands } from '@/command-menu-item/record-agnostic/hooks/useRelatedRecordCommands';
|
||||
import { CommandMenuItemViewType } from 'twenty-shared/types';
|
||||
import { type ShouldBeRegisteredFunctionParams } from '@/command-menu-item/types/ShouldBeRegisteredFunctionParams';
|
||||
import { getCommandMenuItemConfig } from '@/command-menu-item/utils/getCommandMenuItemConfig';
|
||||
import { getCommandMenuItemViewType } from '@/command-menu-item/utils/getCommandMenuItemViewType';
|
||||
import { contextStoreCurrentViewTypeComponentState } from '@/context-store/states/contextStoreCurrentViewTypeComponentState';
|
||||
import { contextStoreIsPageInEditModeComponentState } from '@/context-store/states/contextStoreIsPageInEditModeComponentState';
|
||||
import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState';
|
||||
import { usePermissionFlagMap } from '@/settings/roles/hooks/usePermissionFlagMap';
|
||||
import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { useIcons } from 'twenty-ui/display';
|
||||
|
||||
export const useRegisteredCommandMenuItems = (
|
||||
shouldBeRegisteredParams: ShouldBeRegisteredFunctionParams,
|
||||
) => {
|
||||
const { objectMetadataItem } = shouldBeRegisteredParams;
|
||||
|
||||
const { getIcon } = useIcons();
|
||||
|
||||
const contextStoreTargetedRecordsRule = useAtomComponentStateValue(
|
||||
contextStoreTargetedRecordsRuleComponentState,
|
||||
);
|
||||
|
||||
const contextStoreCurrentViewType = useAtomComponentStateValue(
|
||||
contextStoreCurrentViewTypeComponentState,
|
||||
);
|
||||
|
||||
const contextStoreIsPageInEditMode = useAtomComponentStateValue(
|
||||
contextStoreIsPageInEditModeComponentState,
|
||||
);
|
||||
|
||||
const viewType = getCommandMenuItemViewType(
|
||||
contextStoreCurrentViewType,
|
||||
contextStoreTargetedRecordsRule,
|
||||
);
|
||||
|
||||
const recordCommandMenuItemsConfig = getCommandMenuItemConfig({
|
||||
objectMetadataItem,
|
||||
});
|
||||
|
||||
const relatedRecordCommandMenuItemsConfig = useRelatedRecordCommands({
|
||||
sourceObjectMetadataItem: objectMetadataItem,
|
||||
getIcon,
|
||||
startPosition: Object.keys(recordCommandMenuItemsConfig).length + 1,
|
||||
});
|
||||
|
||||
const recordAgnosticCommandMenuItemsConfig = useRecordAgnosticCommands();
|
||||
|
||||
const commandMenuItemsConfig = {
|
||||
...recordCommandMenuItemsConfig,
|
||||
...relatedRecordCommandMenuItemsConfig,
|
||||
...recordAgnosticCommandMenuItemsConfig,
|
||||
};
|
||||
|
||||
const permissionMap = usePermissionFlagMap();
|
||||
|
||||
const commandMenuItemsToRegister = Object.values(
|
||||
commandMenuItemsConfig,
|
||||
).filter((commandMenuItem) => {
|
||||
if (contextStoreIsPageInEditMode) {
|
||||
return (
|
||||
isDefined(commandMenuItem.availableOn) &&
|
||||
commandMenuItem.availableOn.includes(
|
||||
CommandMenuItemViewType.PAGE_EDIT_MODE,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if (isDefined(viewType)) {
|
||||
return (
|
||||
commandMenuItem.availableOn?.includes(viewType) ||
|
||||
commandMenuItem.availableOn?.includes(CommandMenuItemViewType.GLOBAL)
|
||||
);
|
||||
}
|
||||
|
||||
return commandMenuItem.availableOn?.includes(
|
||||
CommandMenuItemViewType.GLOBAL,
|
||||
);
|
||||
});
|
||||
|
||||
const commandMenuItems = commandMenuItemsToRegister
|
||||
.filter((commandMenuItem) => {
|
||||
if (
|
||||
isDefined(commandMenuItem.requiredPermissionFlag) &&
|
||||
!permissionMap[commandMenuItem.requiredPermissionFlag]
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
return commandMenuItem.shouldBeRegistered(shouldBeRegisteredParams);
|
||||
})
|
||||
.sort((a, b) => a.position - b.position);
|
||||
|
||||
return commandMenuItems;
|
||||
};
|
||||
+163
@@ -0,0 +1,163 @@
|
||||
import { type ShouldBeRegisteredFunctionParams } from '@/command-menu-item/types/ShouldBeRegisteredFunctionParams';
|
||||
import { getCommandMenuItemViewType } from '@/command-menu-item/utils/getCommandMenuItemViewType';
|
||||
import { CommandMenuContext } from '@/command-menu-item/contexts/CommandMenuContext';
|
||||
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
||||
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 { usePrefetchedNavigationMenuItemsData } from '@/navigation-menu-item/hooks/usePrefetchedNavigationMenuItemsData';
|
||||
import { CoreObjectNameSingular } from 'twenty-shared/types';
|
||||
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 { useRecordIndexIdFromCurrentContextStore } from '@/object-record/record-index/hooks/useRecordIndexIdFromCurrentContextStore';
|
||||
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
|
||||
import { useAtomComponentSelectorValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentSelectorValue';
|
||||
import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue';
|
||||
import { useAtomFamilyStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomFamilyStateValue';
|
||||
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
|
||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||
import { useStore } from 'jotai';
|
||||
import { useCallback, useContext, useMemo } from 'react';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { FeatureFlagKey } from '~/generated-metadata/graphql';
|
||||
|
||||
export const useShouldCommandMenuItemBeRegisteredParams = ({
|
||||
objectMetadataItem,
|
||||
}: {
|
||||
objectMetadataItem?: ObjectMetadataItem;
|
||||
}): ShouldBeRegisteredFunctionParams => {
|
||||
const store = useStore();
|
||||
const { sortedFavorites: favorites } = useFavorites();
|
||||
const { navigationMenuItems } = usePrefetchedNavigationMenuItemsData();
|
||||
const isNavigationMenuItemEditingEnabled = useIsFeatureEnabled(
|
||||
FeatureFlagKey.IS_NAVIGATION_MENU_ITEM_EDITING_ENABLED,
|
||||
);
|
||||
|
||||
const contextStoreTargetedRecordsRule = useAtomComponentStateValue(
|
||||
contextStoreTargetedRecordsRuleComponentState,
|
||||
);
|
||||
|
||||
const recordId =
|
||||
contextStoreTargetedRecordsRule.mode === 'selection'
|
||||
? contextStoreTargetedRecordsRule.selectedRecordIds[0]
|
||||
: undefined;
|
||||
|
||||
const isFavorite = useMemo(() => {
|
||||
if (!isDefined(recordId)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isNavigationMenuItemEditingEnabled && isDefined(objectMetadataItem)) {
|
||||
const foundNavigationMenuItem = navigationMenuItems?.find(
|
||||
(item) =>
|
||||
item.targetRecordId === recordId &&
|
||||
item.targetObjectMetadataId === objectMetadataItem.id,
|
||||
);
|
||||
return !!foundNavigationMenuItem;
|
||||
}
|
||||
|
||||
const foundFavorite = favorites?.find(
|
||||
(favorite) => favorite.recordId === recordId,
|
||||
);
|
||||
return !!foundFavorite;
|
||||
}, [
|
||||
recordId,
|
||||
isNavigationMenuItemEditingEnabled,
|
||||
objectMetadataItem,
|
||||
navigationMenuItems,
|
||||
favorites,
|
||||
]);
|
||||
|
||||
const selectedRecord =
|
||||
useAtomFamilyStateValue(recordStoreFamilyState, recordId ?? '') ||
|
||||
undefined;
|
||||
|
||||
const objectPermissions = useObjectPermissionsForObject(
|
||||
objectMetadataItem?.id ?? '',
|
||||
);
|
||||
|
||||
const isNoteOrTask =
|
||||
objectMetadataItem?.nameSingular === CoreObjectNameSingular.Note ||
|
||||
objectMetadataItem?.nameSingular === CoreObjectNameSingular.Task;
|
||||
|
||||
const { isInSidePanel } = useContext(CommandMenuContext);
|
||||
|
||||
const { recordIndexId } = useRecordIndexIdFromCurrentContextStore();
|
||||
|
||||
const hasAnySoftDeleteFilterOnView = useAtomComponentSelectorValue(
|
||||
hasAnySoftDeleteFilterOnViewComponentSelector,
|
||||
recordIndexId,
|
||||
);
|
||||
|
||||
const isShowPage =
|
||||
useAtomComponentStateValue(contextStoreCurrentViewTypeComponentState) ===
|
||||
ContextStoreViewType.ShowPage;
|
||||
|
||||
const contextStoreNumberOfSelectedRecords = useAtomComponentStateValue(
|
||||
contextStoreNumberOfSelectedRecordsComponentState,
|
||||
);
|
||||
|
||||
const contextStoreCurrentViewType = useAtomComponentStateValue(
|
||||
contextStoreCurrentViewTypeComponentState,
|
||||
);
|
||||
|
||||
const viewType = getCommandMenuItemViewType(
|
||||
contextStoreCurrentViewType,
|
||||
contextStoreTargetedRecordsRule,
|
||||
);
|
||||
|
||||
const isSelectAll = contextStoreTargetedRecordsRule.mode === 'exclusion';
|
||||
|
||||
const getObjectReadPermission = useCallback(
|
||||
(objectMetadataNameSingular: string) => {
|
||||
return store.get(
|
||||
objectPermissionsFamilySelector.selectorFamily({
|
||||
objectNameSingular: objectMetadataNameSingular,
|
||||
}),
|
||||
).canRead;
|
||||
},
|
||||
[store],
|
||||
);
|
||||
|
||||
const getObjectWritePermission = useCallback(
|
||||
(objectMetadataNameSingular: string) => {
|
||||
return store.get(
|
||||
objectPermissionsFamilySelector.selectorFamily({
|
||||
objectNameSingular: objectMetadataNameSingular,
|
||||
}),
|
||||
).canUpdate;
|
||||
},
|
||||
[store],
|
||||
);
|
||||
|
||||
const currentWorkspace = useAtomStateValue(currentWorkspaceState);
|
||||
|
||||
const isFeatureFlagEnabled = (featureFlagKey: FeatureFlagKey) => {
|
||||
const featureFlag = currentWorkspace?.featureFlags?.find(
|
||||
(flag) => flag.key === featureFlagKey,
|
||||
);
|
||||
|
||||
return featureFlag?.value === true;
|
||||
};
|
||||
|
||||
return {
|
||||
objectMetadataItem,
|
||||
isFavorite,
|
||||
objectPermissions,
|
||||
isNoteOrTask,
|
||||
isInSidePanel,
|
||||
hasAnySoftDeleteFilterOnView,
|
||||
isShowPage,
|
||||
isSelectAll,
|
||||
selectedRecord,
|
||||
numberOfSelectedRecords: contextStoreNumberOfSelectedRecords,
|
||||
viewType: viewType ?? undefined,
|
||||
getTargetObjectReadPermission: getObjectReadPermission,
|
||||
getTargetObjectWritePermission: getObjectWritePermission,
|
||||
isFeatureFlagEnabled,
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user