mirror of
				https://github.com/lingble/twenty.git
				synced 2025-10-31 04:37:56 +00:00 
			
		
		
		
	improve command menu actions ordering
This commit is contained in:
		| @@ -1,4 +1,8 @@ | |||||||
| import { useActionMenuEntries } from '@/action-menu/hooks/useActionMenuEntries'; | import { useActionMenuEntries } from '@/action-menu/hooks/useActionMenuEntries'; | ||||||
|  | import { | ||||||
|  |   ActionMenuEntryScope, | ||||||
|  |   ActionMenuEntryType, | ||||||
|  | } from '@/action-menu/types/ActionMenuEntry'; | ||||||
| import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/SnackBar'; | import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/SnackBar'; | ||||||
| import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar'; | import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar'; | ||||||
| import { useAllActiveWorkflowVersions } from '@/workflow/hooks/useAllActiveWorkflowVersions'; | import { useAllActiveWorkflowVersions } from '@/workflow/hooks/useAllActiveWorkflowVersions'; | ||||||
| @@ -28,9 +32,9 @@ export const WorkflowRunActionEffect = () => { | |||||||
|       activeWorkflowVersion, |       activeWorkflowVersion, | ||||||
|     ] of activeWorkflowVersions.entries()) { |     ] of activeWorkflowVersions.entries()) { | ||||||
|       addActionMenuEntry({ |       addActionMenuEntry({ | ||||||
|         type: 'workflow-run', |         type: ActionMenuEntryType.WorkflowRun, | ||||||
|         key: `workflow-run-${activeWorkflowVersion.id}`, |         key: `workflow-run-${activeWorkflowVersion.id}`, | ||||||
|         scope: 'global', |         scope: ActionMenuEntryScope.Global, | ||||||
|         label: capitalize(activeWorkflowVersion.workflow.name), |         label: capitalize(activeWorkflowVersion.workflow.name), | ||||||
|         position: index, |         position: index, | ||||||
|         Icon: IconSettingsAutomation, |         Icon: IconSettingsAutomation, | ||||||
|   | |||||||
| @@ -1,5 +1,9 @@ | |||||||
| import { ActionMenuContext } from '@/action-menu/contexts/ActionMenuContext'; | import { ActionMenuContext } from '@/action-menu/contexts/ActionMenuContext'; | ||||||
| import { useActionMenuEntries } from '@/action-menu/hooks/useActionMenuEntries'; | import { useActionMenuEntries } from '@/action-menu/hooks/useActionMenuEntries'; | ||||||
|  | import { | ||||||
|  |   ActionMenuEntryScope, | ||||||
|  |   ActionMenuEntryType, | ||||||
|  | } from '@/action-menu/types/ActionMenuEntry'; | ||||||
| import { contextStoreFiltersComponentState } from '@/context-store/states/contextStoreFiltersComponentState'; | import { contextStoreFiltersComponentState } from '@/context-store/states/contextStoreFiltersComponentState'; | ||||||
| import { contextStoreNumberOfSelectedRecordsComponentState } from '@/context-store/states/contextStoreNumberOfSelectedRecordsComponentState'; | import { contextStoreNumberOfSelectedRecordsComponentState } from '@/context-store/states/contextStoreNumberOfSelectedRecordsComponentState'; | ||||||
| import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState'; | import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState'; | ||||||
| @@ -105,8 +109,8 @@ export const DeleteRecordsActionEffect = ({ | |||||||
|   useEffect(() => { |   useEffect(() => { | ||||||
|     if (canDelete) { |     if (canDelete) { | ||||||
|       addActionMenuEntry({ |       addActionMenuEntry({ | ||||||
|         type: 'standard', |         type: ActionMenuEntryType.Standard, | ||||||
|         scope: 'record-selection', |         scope: ActionMenuEntryScope.RecordSelection, | ||||||
|         key: 'delete', |         key: 'delete', | ||||||
|         label: 'Delete', |         label: 'Delete', | ||||||
|         position, |         position, | ||||||
|   | |||||||
| @@ -4,6 +4,10 @@ import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; | |||||||
| import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; | import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; | ||||||
| import { IconDatabaseExport } from 'twenty-ui'; | import { IconDatabaseExport } from 'twenty-ui'; | ||||||
|  |  | ||||||
|  | import { | ||||||
|  |   ActionMenuEntryScope, | ||||||
|  |   ActionMenuEntryType, | ||||||
|  | } from '@/action-menu/types/ActionMenuEntry'; | ||||||
| import { | import { | ||||||
|   displayedExportProgress, |   displayedExportProgress, | ||||||
|   useExportRecords, |   useExportRecords, | ||||||
| @@ -31,8 +35,11 @@ export const ExportRecordsActionEffect = ({ | |||||||
|  |  | ||||||
|   useEffect(() => { |   useEffect(() => { | ||||||
|     addActionMenuEntry({ |     addActionMenuEntry({ | ||||||
|       type: 'standard', |       type: ActionMenuEntryType.Standard, | ||||||
|       scope: 'record-selection', |       scope: | ||||||
|  |         contextStoreNumberOfSelectedRecords > 0 | ||||||
|  |           ? ActionMenuEntryScope.RecordSelection | ||||||
|  |           : ActionMenuEntryScope.Global, | ||||||
|       key: 'export', |       key: 'export', | ||||||
|       position, |       position, | ||||||
|       label: displayedExportProgress( |       label: displayedExportProgress( | ||||||
|   | |||||||
| @@ -1,4 +1,8 @@ | |||||||
| import { useActionMenuEntries } from '@/action-menu/hooks/useActionMenuEntries'; | import { useActionMenuEntries } from '@/action-menu/hooks/useActionMenuEntries'; | ||||||
|  | import { | ||||||
|  |   ActionMenuEntryScope, | ||||||
|  |   ActionMenuEntryType, | ||||||
|  | } from '@/action-menu/types/ActionMenuEntry'; | ||||||
| import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState'; | import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState'; | ||||||
| import { useCreateFavorite } from '@/favorites/hooks/useCreateFavorite'; | import { useCreateFavorite } from '@/favorites/hooks/useCreateFavorite'; | ||||||
| import { useDeleteFavorite } from '@/favorites/hooks/useDeleteFavorite'; | import { useDeleteFavorite } from '@/favorites/hooks/useDeleteFavorite'; | ||||||
| @@ -50,8 +54,8 @@ export const ManageFavoritesActionEffect = ({ | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     addActionMenuEntry({ |     addActionMenuEntry({ | ||||||
|       type: 'standard', |       type: ActionMenuEntryType.Standard, | ||||||
|       scope: 'record-selection', |       scope: ActionMenuEntryScope.RecordSelection, | ||||||
|       key: 'manage-favorites', |       key: 'manage-favorites', | ||||||
|       label: isFavorite ? 'Remove from favorites' : 'Add to favorites', |       label: isFavorite ? 'Remove from favorites' : 'Add to favorites', | ||||||
|       position, |       position, | ||||||
|   | |||||||
| @@ -1,4 +1,8 @@ | |||||||
| import { useActionMenuEntries } from '@/action-menu/hooks/useActionMenuEntries'; | import { useActionMenuEntries } from '@/action-menu/hooks/useActionMenuEntries'; | ||||||
|  | import { | ||||||
|  |   ActionMenuEntryScope, | ||||||
|  |   ActionMenuEntryType, | ||||||
|  | } from '@/action-menu/types/ActionMenuEntry'; | ||||||
| import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState'; | import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState'; | ||||||
| import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; | import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; | ||||||
| import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; | import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; | ||||||
| @@ -55,9 +59,9 @@ export const WorkflowRunRecordActionEffect = ({ | |||||||
|       activeWorkflowVersion, |       activeWorkflowVersion, | ||||||
|     ] of activeWorkflowVersions.entries()) { |     ] of activeWorkflowVersions.entries()) { | ||||||
|       addActionMenuEntry({ |       addActionMenuEntry({ | ||||||
|         type: 'workflow-run', |         type: ActionMenuEntryType.WorkflowRun, | ||||||
|         key: `workflow-run-${activeWorkflowVersion.id}`, |         key: `workflow-run-${activeWorkflowVersion.id}`, | ||||||
|         scope: 'record-selection', |         scope: ActionMenuEntryScope.RecordSelection, | ||||||
|         label: capitalize(activeWorkflowVersion.workflow.name), |         label: capitalize(activeWorkflowVersion.workflow.name), | ||||||
|         position: index, |         position: index, | ||||||
|         Icon: IconSettingsAutomation, |         Icon: IconSettingsAutomation, | ||||||
|   | |||||||
| @@ -1,5 +1,6 @@ | |||||||
| import { actionMenuEntriesComponentSelector } from '@/action-menu/states/actionMenuEntriesComponentSelector'; | import { actionMenuEntriesComponentSelector } from '@/action-menu/states/actionMenuEntriesComponentSelector'; | ||||||
| import { ActionMenuComponentInstanceContext } from '@/action-menu/states/contexts/ActionMenuComponentInstanceContext'; | import { ActionMenuComponentInstanceContext } from '@/action-menu/states/contexts/ActionMenuComponentInstanceContext'; | ||||||
|  | import { ActionMenuEntryScope } from '@/action-menu/types/ActionMenuEntry'; | ||||||
| import { RightDrawerActionMenuDropdownHotkeyScope } from '@/action-menu/types/RightDrawerActionMenuDropdownHotkeyScope'; | import { RightDrawerActionMenuDropdownHotkeyScope } from '@/action-menu/types/RightDrawerActionMenuDropdownHotkeyScope'; | ||||||
| import { getRightDrawerActionMenuDropdownIdFromActionMenuId } from '@/action-menu/utils/getRightDrawerActionMenuDropdownIdFromActionMenuId'; | import { getRightDrawerActionMenuDropdownIdFromActionMenuId } from '@/action-menu/utils/getRightDrawerActionMenuDropdownIdFromActionMenuId'; | ||||||
| import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown'; | import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown'; | ||||||
| @@ -67,7 +68,8 @@ export const RightDrawerActionMenuDropdown = () => { | |||||||
|         <DropdownMenuItemsContainer> |         <DropdownMenuItemsContainer> | ||||||
|           {actionMenuEntries |           {actionMenuEntries | ||||||
|             .filter( |             .filter( | ||||||
|               (actionMenuEntry) => actionMenuEntry.scope === 'record-selection', |               (actionMenuEntry) => | ||||||
|  |                 actionMenuEntry.scope === ActionMenuEntryScope.RecordSelection, | ||||||
|             ) |             ) | ||||||
|             .map((actionMenuEntry, index) => ( |             .map((actionMenuEntry, index) => ( | ||||||
|               <MenuItem |               <MenuItem | ||||||
|   | |||||||
| @@ -5,7 +5,11 @@ import { RecoilRoot } from 'recoil'; | |||||||
| import { RecordIndexActionMenuBar } from '@/action-menu/components/RecordIndexActionMenuBar'; | import { RecordIndexActionMenuBar } from '@/action-menu/components/RecordIndexActionMenuBar'; | ||||||
| import { actionMenuEntriesComponentState } from '@/action-menu/states/actionMenuEntriesComponentState'; | import { actionMenuEntriesComponentState } from '@/action-menu/states/actionMenuEntriesComponentState'; | ||||||
| import { ActionMenuComponentInstanceContext } from '@/action-menu/states/contexts/ActionMenuComponentInstanceContext'; | import { ActionMenuComponentInstanceContext } from '@/action-menu/states/contexts/ActionMenuComponentInstanceContext'; | ||||||
| import { ActionMenuEntry } from '@/action-menu/types/ActionMenuEntry'; | import { | ||||||
|  |   ActionMenuEntry, | ||||||
|  |   ActionMenuEntryScope, | ||||||
|  |   ActionMenuEntryType, | ||||||
|  | } from '@/action-menu/types/ActionMenuEntry'; | ||||||
| import { getActionBarIdFromActionMenuId } from '@/action-menu/utils/getActionBarIdFromActionMenuId'; | import { getActionBarIdFromActionMenuId } from '@/action-menu/utils/getActionBarIdFromActionMenuId'; | ||||||
| import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext'; | import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext'; | ||||||
| import { contextStoreNumberOfSelectedRecordsComponentState } from '@/context-store/states/contextStoreNumberOfSelectedRecordsComponentState'; | import { contextStoreNumberOfSelectedRecordsComponentState } from '@/context-store/states/contextStoreNumberOfSelectedRecordsComponentState'; | ||||||
| @@ -48,8 +52,8 @@ const meta: Meta<typeof RecordIndexActionMenuBar> = { | |||||||
|  |  | ||||||
|             map.set('delete', { |             map.set('delete', { | ||||||
|               isPinned: true, |               isPinned: true, | ||||||
|               scope: 'record-selection', |               scope: ActionMenuEntryScope.RecordSelection, | ||||||
|               type: 'standard', |               type: ActionMenuEntryType.Standard, | ||||||
|               key: 'delete', |               key: 'delete', | ||||||
|               label: 'Delete', |               label: 'Delete', | ||||||
|               position: 0, |               position: 0, | ||||||
|   | |||||||
| @@ -1,4 +1,8 @@ | |||||||
| import { RecordIndexActionMenuBarEntry } from '@/action-menu/components/RecordIndexActionMenuBarEntry'; | import { RecordIndexActionMenuBarEntry } from '@/action-menu/components/RecordIndexActionMenuBarEntry'; | ||||||
|  | import { | ||||||
|  |   ActionMenuEntryScope, | ||||||
|  |   ActionMenuEntryType, | ||||||
|  | } from '@/action-menu/types/ActionMenuEntry'; | ||||||
| import { expect, jest } from '@storybook/jest'; | import { expect, jest } from '@storybook/jest'; | ||||||
| import { Meta, StoryObj } from '@storybook/react'; | import { Meta, StoryObj } from '@storybook/react'; | ||||||
| import { userEvent, within } from '@storybook/testing-library'; | import { userEvent, within } from '@storybook/testing-library'; | ||||||
| @@ -21,8 +25,8 @@ const markAsDoneMock = jest.fn(); | |||||||
| export const Default: Story = { | export const Default: Story = { | ||||||
|   args: { |   args: { | ||||||
|     entry: { |     entry: { | ||||||
|       type: 'standard', |       type: ActionMenuEntryType.Standard, | ||||||
|       scope: 'record-selection', |       scope: ActionMenuEntryScope.RecordSelection, | ||||||
|       key: 'delete', |       key: 'delete', | ||||||
|       label: 'Delete', |       label: 'Delete', | ||||||
|       position: 0, |       position: 0, | ||||||
| @@ -35,8 +39,8 @@ export const Default: Story = { | |||||||
| export const WithDangerAccent: Story = { | export const WithDangerAccent: Story = { | ||||||
|   args: { |   args: { | ||||||
|     entry: { |     entry: { | ||||||
|       type: 'standard', |       type: ActionMenuEntryType.Standard, | ||||||
|       scope: 'record-selection', |       scope: ActionMenuEntryScope.RecordSelection, | ||||||
|       key: 'delete', |       key: 'delete', | ||||||
|       label: 'Delete', |       label: 'Delete', | ||||||
|       position: 0, |       position: 0, | ||||||
| @@ -50,8 +54,8 @@ export const WithDangerAccent: Story = { | |||||||
| export const WithInteraction: Story = { | export const WithInteraction: Story = { | ||||||
|   args: { |   args: { | ||||||
|     entry: { |     entry: { | ||||||
|       type: 'standard', |       type: ActionMenuEntryType.Standard, | ||||||
|       scope: 'record-selection', |       scope: ActionMenuEntryScope.RecordSelection, | ||||||
|       key: 'markAsDone', |       key: 'markAsDone', | ||||||
|       label: 'Mark as done', |       label: 'Mark as done', | ||||||
|       position: 0, |       position: 0, | ||||||
|   | |||||||
| @@ -7,7 +7,11 @@ import { RecordIndexActionMenuDropdown } from '@/action-menu/components/RecordIn | |||||||
| import { actionMenuEntriesComponentState } from '@/action-menu/states/actionMenuEntriesComponentState'; | import { actionMenuEntriesComponentState } from '@/action-menu/states/actionMenuEntriesComponentState'; | ||||||
| import { ActionMenuComponentInstanceContext } from '@/action-menu/states/contexts/ActionMenuComponentInstanceContext'; | import { ActionMenuComponentInstanceContext } from '@/action-menu/states/contexts/ActionMenuComponentInstanceContext'; | ||||||
| import { recordIndexActionMenuDropdownPositionComponentState } from '@/action-menu/states/recordIndexActionMenuDropdownPositionComponentState'; | import { recordIndexActionMenuDropdownPositionComponentState } from '@/action-menu/states/recordIndexActionMenuDropdownPositionComponentState'; | ||||||
| import { ActionMenuEntry } from '@/action-menu/types/ActionMenuEntry'; | import { | ||||||
|  |   ActionMenuEntry, | ||||||
|  |   ActionMenuEntryScope, | ||||||
|  |   ActionMenuEntryType, | ||||||
|  | } from '@/action-menu/types/ActionMenuEntry'; | ||||||
| import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState'; | import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState'; | ||||||
| import { extractComponentState } from '@/ui/utilities/state/component-state/utils/extractComponentState'; | import { extractComponentState } from '@/ui/utilities/state/component-state/utils/extractComponentState'; | ||||||
| import { IconCheckbox, IconHeart, IconTrash } from 'twenty-ui'; | import { IconCheckbox, IconHeart, IconTrash } from 'twenty-ui'; | ||||||
| @@ -41,8 +45,8 @@ const meta: Meta<typeof RecordIndexActionMenuDropdown> = { | |||||||
|           ); |           ); | ||||||
|  |  | ||||||
|           map.set('delete', { |           map.set('delete', { | ||||||
|             type: 'standard', |             type: ActionMenuEntryType.Standard, | ||||||
|             scope: 'record-selection', |             scope: ActionMenuEntryScope.RecordSelection, | ||||||
|             key: 'delete', |             key: 'delete', | ||||||
|             label: 'Delete', |             label: 'Delete', | ||||||
|             position: 0, |             position: 0, | ||||||
| @@ -51,8 +55,8 @@ const meta: Meta<typeof RecordIndexActionMenuDropdown> = { | |||||||
|           }); |           }); | ||||||
|  |  | ||||||
|           map.set('markAsDone', { |           map.set('markAsDone', { | ||||||
|             type: 'standard', |             type: ActionMenuEntryType.Standard, | ||||||
|             scope: 'record-selection', |             scope: ActionMenuEntryScope.RecordSelection, | ||||||
|             key: 'markAsDone', |             key: 'markAsDone', | ||||||
|             label: 'Mark as done', |             label: 'Mark as done', | ||||||
|             position: 1, |             position: 1, | ||||||
| @@ -61,8 +65,8 @@ const meta: Meta<typeof RecordIndexActionMenuDropdown> = { | |||||||
|           }); |           }); | ||||||
|  |  | ||||||
|           map.set('addToFavorites', { |           map.set('addToFavorites', { | ||||||
|             type: 'standard', |             type: ActionMenuEntryType.Standard, | ||||||
|             scope: 'record-selection', |             scope: ActionMenuEntryScope.RecordSelection, | ||||||
|             key: 'addToFavorites', |             key: 'addToFavorites', | ||||||
|             label: 'Add to favorites', |             label: 'Add to favorites', | ||||||
|             position: 2, |             position: 2, | ||||||
|   | |||||||
| @@ -5,7 +5,11 @@ import { RecoilRoot } from 'recoil'; | |||||||
| import { RightDrawerActionMenuDropdown } from '@/action-menu/components/RightDrawerActionMenuDropdown'; | import { RightDrawerActionMenuDropdown } from '@/action-menu/components/RightDrawerActionMenuDropdown'; | ||||||
| import { actionMenuEntriesComponentState } from '@/action-menu/states/actionMenuEntriesComponentState'; | import { actionMenuEntriesComponentState } from '@/action-menu/states/actionMenuEntriesComponentState'; | ||||||
| import { ActionMenuComponentInstanceContext } from '@/action-menu/states/contexts/ActionMenuComponentInstanceContext'; | import { ActionMenuComponentInstanceContext } from '@/action-menu/states/contexts/ActionMenuComponentInstanceContext'; | ||||||
| import { ActionMenuEntry } from '@/action-menu/types/ActionMenuEntry'; | import { | ||||||
|  |   ActionMenuEntry, | ||||||
|  |   ActionMenuEntryScope, | ||||||
|  |   ActionMenuEntryType, | ||||||
|  | } from '@/action-menu/types/ActionMenuEntry'; | ||||||
| import { contextStoreNumberOfSelectedRecordsComponentState } from '@/context-store/states/contextStoreNumberOfSelectedRecordsComponentState'; | import { contextStoreNumberOfSelectedRecordsComponentState } from '@/context-store/states/contextStoreNumberOfSelectedRecordsComponentState'; | ||||||
| import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState'; | import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState'; | ||||||
| import { userEvent, waitFor, within } from '@storybook/test'; | import { userEvent, waitFor, within } from '@storybook/test'; | ||||||
| @@ -54,8 +58,8 @@ const meta: Meta<typeof RightDrawerActionMenuDropdown> = { | |||||||
|           ); |           ); | ||||||
|  |  | ||||||
|           map.set('addToFavorites', { |           map.set('addToFavorites', { | ||||||
|             type: 'standard', |             type: ActionMenuEntryType.Standard, | ||||||
|             scope: 'record-selection', |             scope: ActionMenuEntryScope.RecordSelection, | ||||||
|             key: 'addToFavorites', |             key: 'addToFavorites', | ||||||
|             label: 'Add to favorites', |             label: 'Add to favorites', | ||||||
|             position: 0, |             position: 0, | ||||||
| @@ -64,8 +68,8 @@ const meta: Meta<typeof RightDrawerActionMenuDropdown> = { | |||||||
|           }); |           }); | ||||||
|  |  | ||||||
|           map.set('export', { |           map.set('export', { | ||||||
|             type: 'standard', |             type: ActionMenuEntryType.Standard, | ||||||
|             scope: 'record-selection', |             scope: ActionMenuEntryScope.RecordSelection, | ||||||
|             key: 'export', |             key: 'export', | ||||||
|             label: 'Export', |             label: 'Export', | ||||||
|             position: 1, |             position: 1, | ||||||
| @@ -74,8 +78,8 @@ const meta: Meta<typeof RightDrawerActionMenuDropdown> = { | |||||||
|           }); |           }); | ||||||
|  |  | ||||||
|           map.set('delete', { |           map.set('delete', { | ||||||
|             type: 'standard', |             type: ActionMenuEntryType.Standard, | ||||||
|             scope: 'record-selection', |             scope: ActionMenuEntryScope.RecordSelection, | ||||||
|             key: 'delete', |             key: 'delete', | ||||||
|             label: 'Delete', |             label: 'Delete', | ||||||
|             position: 2, |             position: 2, | ||||||
|   | |||||||
| @@ -1,9 +1,19 @@ | |||||||
| import { MouseEvent, ReactNode } from 'react'; | import { MouseEvent, ReactNode } from 'react'; | ||||||
| import { IconComponent, MenuItemAccent } from 'twenty-ui'; | import { IconComponent, MenuItemAccent } from 'twenty-ui'; | ||||||
|  |  | ||||||
|  | export enum ActionMenuEntryType { | ||||||
|  |   Standard = 'Standard', | ||||||
|  |   WorkflowRun = 'WorkflowRun', | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export enum ActionMenuEntryScope { | ||||||
|  |   Global = 'Global', | ||||||
|  |   RecordSelection = 'RecordSelection', | ||||||
|  | } | ||||||
|  |  | ||||||
| export type ActionMenuEntry = { | export type ActionMenuEntry = { | ||||||
|   type: 'standard' | 'workflow-run'; |   type: ActionMenuEntryType; | ||||||
|   scope: 'global' | 'record-selection'; |   scope: ActionMenuEntryScope; | ||||||
|   key: string; |   key: string; | ||||||
|   label: string; |   label: string; | ||||||
|   position: number; |   position: number; | ||||||
|   | |||||||
| @@ -12,7 +12,11 @@ import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu'; | |||||||
| import { commandMenuCommandsState } from '@/command-menu/states/commandMenuCommandsState'; | import { commandMenuCommandsState } from '@/command-menu/states/commandMenuCommandsState'; | ||||||
| import { commandMenuSearchState } from '@/command-menu/states/commandMenuSearchState'; | import { commandMenuSearchState } from '@/command-menu/states/commandMenuSearchState'; | ||||||
| import { isCommandMenuOpenedState } from '@/command-menu/states/isCommandMenuOpenedState'; | import { isCommandMenuOpenedState } from '@/command-menu/states/isCommandMenuOpenedState'; | ||||||
| import { Command, CommandType } from '@/command-menu/types/Command'; | import { | ||||||
|  |   Command, | ||||||
|  |   CommandScope, | ||||||
|  |   CommandType, | ||||||
|  | } from '@/command-menu/types/Command'; | ||||||
| import { Company } from '@/companies/types/Company'; | import { Company } from '@/companies/types/Company'; | ||||||
| import { contextStoreNumberOfSelectedRecordsComponentState } from '@/context-store/states/contextStoreNumberOfSelectedRecordsComponentState'; | import { contextStoreNumberOfSelectedRecordsComponentState } from '@/context-store/states/contextStoreNumberOfSelectedRecordsComponentState'; | ||||||
| import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState'; | import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState'; | ||||||
| @@ -363,20 +367,45 @@ export const CommandMenu = () => { | |||||||
|         : true) && cmd.type === CommandType.Create, |         : true) && cmd.type === CommandType.Create, | ||||||
|   ); |   ); | ||||||
|  |  | ||||||
|   const matchingStandardActionCommands = commandMenuCommands.filter( |   const matchingStandardActionRecordSelectionCommands = | ||||||
|  |     commandMenuCommands.filter( | ||||||
|       (cmd) => |       (cmd) => | ||||||
|         (deferredCommandMenuSearch.length > 0 |         (deferredCommandMenuSearch.length > 0 | ||||||
|           ? checkInShortcuts(cmd, deferredCommandMenuSearch) || |           ? checkInShortcuts(cmd, deferredCommandMenuSearch) || | ||||||
|             checkInLabels(cmd, deferredCommandMenuSearch) |             checkInLabels(cmd, deferredCommandMenuSearch) | ||||||
|         : true) && cmd.type === CommandType.StandardAction, |           : true) && | ||||||
|  |         cmd.type === CommandType.StandardAction && | ||||||
|  |         cmd.scope === CommandScope.RecordSelection, | ||||||
|     ); |     ); | ||||||
|  |  | ||||||
|   const matchingWorkflowRunCommands = commandMenuCommands.filter( |   const matchingStandardActionGlobalCommands = commandMenuCommands.filter( | ||||||
|     (cmd) => |     (cmd) => | ||||||
|       (deferredCommandMenuSearch.length > 0 |       (deferredCommandMenuSearch.length > 0 | ||||||
|         ? checkInShortcuts(cmd, deferredCommandMenuSearch) || |         ? checkInShortcuts(cmd, deferredCommandMenuSearch) || | ||||||
|           checkInLabels(cmd, deferredCommandMenuSearch) |           checkInLabels(cmd, deferredCommandMenuSearch) | ||||||
|         : true) && cmd.type === CommandType.WorkflowRun, |         : true) && | ||||||
|  |       cmd.type === CommandType.StandardAction && | ||||||
|  |       cmd.scope === CommandScope.Global, | ||||||
|  |   ); | ||||||
|  |  | ||||||
|  |   const matchingWorkflowRunRecordSelectionCommands = commandMenuCommands.filter( | ||||||
|  |     (cmd) => | ||||||
|  |       (deferredCommandMenuSearch.length > 0 | ||||||
|  |         ? checkInShortcuts(cmd, deferredCommandMenuSearch) || | ||||||
|  |           checkInLabels(cmd, deferredCommandMenuSearch) | ||||||
|  |         : true) && | ||||||
|  |       cmd.type === CommandType.WorkflowRun && | ||||||
|  |       cmd.scope === CommandScope.RecordSelection, | ||||||
|  |   ); | ||||||
|  |  | ||||||
|  |   const matchingWorkflowRunGlobalCommands = commandMenuCommands.filter( | ||||||
|  |     (cmd) => | ||||||
|  |       (deferredCommandMenuSearch.length > 0 | ||||||
|  |         ? checkInShortcuts(cmd, deferredCommandMenuSearch) || | ||||||
|  |           checkInLabels(cmd, deferredCommandMenuSearch) | ||||||
|  |         : true) && | ||||||
|  |       cmd.type === CommandType.WorkflowRun && | ||||||
|  |       cmd.scope === CommandScope.Global, | ||||||
|   ); |   ); | ||||||
|  |  | ||||||
|   useListenClickOutside({ |   useListenClickOutside({ | ||||||
| @@ -404,8 +433,10 @@ export const CommandMenu = () => { | |||||||
|  |  | ||||||
|   const selectableItemIds = copilotCommands |   const selectableItemIds = copilotCommands | ||||||
|     .map((cmd) => cmd.id) |     .map((cmd) => cmd.id) | ||||||
|     .concat(matchingStandardActionCommands.map((cmd) => cmd.id)) |     .concat(matchingStandardActionRecordSelectionCommands.map((cmd) => cmd.id)) | ||||||
|     .concat(matchingWorkflowRunCommands.map((cmd) => cmd.id)) |     .concat(matchingWorkflowRunRecordSelectionCommands.map((cmd) => cmd.id)) | ||||||
|  |     .concat(matchingStandardActionGlobalCommands.map((cmd) => cmd.id)) | ||||||
|  |     .concat(matchingWorkflowRunGlobalCommands.map((cmd) => cmd.id)) | ||||||
|     .concat(matchingCreateCommand.map((cmd) => cmd.id)) |     .concat(matchingCreateCommand.map((cmd) => cmd.id)) | ||||||
|     .concat(matchingNavigateCommand.map((cmd) => cmd.id)) |     .concat(matchingNavigateCommand.map((cmd) => cmd.id)) | ||||||
|     .concat(people?.map((person) => person.id)) |     .concat(people?.map((person) => person.id)) | ||||||
| @@ -422,8 +453,10 @@ export const CommandMenu = () => { | |||||||
|     ); |     ); | ||||||
|  |  | ||||||
|   const isNoResults = |   const isNoResults = | ||||||
|     !matchingStandardActionCommands.length && |     !matchingStandardActionRecordSelectionCommands.length && | ||||||
|     !matchingWorkflowRunCommands.length && |     !matchingWorkflowRunRecordSelectionCommands.length && | ||||||
|  |     !matchingStandardActionGlobalCommands.length && | ||||||
|  |     !matchingWorkflowRunGlobalCommands.length && | ||||||
|     !matchingCreateCommand.length && |     !matchingCreateCommand.length && | ||||||
|     !matchingNavigateCommand.length && |     !matchingNavigateCommand.length && | ||||||
|     !people?.length && |     !people?.length && | ||||||
| @@ -599,38 +632,82 @@ export const CommandMenu = () => { | |||||||
|                       </SelectableItem> |                       </SelectableItem> | ||||||
|                     </CommandGroup> |                     </CommandGroup> | ||||||
|                   )} |                   )} | ||||||
|                   <CommandGroup heading="Standard Actions"> |                   <CommandGroup heading="Record Selection"> | ||||||
|                     {matchingStandardActionCommands?.map( |                     {matchingStandardActionRecordSelectionCommands?.map( | ||||||
|                       (standardActionCommand) => ( |                       (standardActionrecordSelectionCommand) => ( | ||||||
|                         <SelectableItem |                         <SelectableItem | ||||||
|                           itemId={standardActionCommand.id} |                           itemId={standardActionrecordSelectionCommand.id} | ||||||
|                           key={standardActionCommand.id} |                           key={standardActionrecordSelectionCommand.id} | ||||||
|                         > |                         > | ||||||
|                           <CommandMenuItem |                           <CommandMenuItem | ||||||
|                             id={standardActionCommand.id} |                             id={standardActionrecordSelectionCommand.id} | ||||||
|                             label={standardActionCommand.label} |                             label={standardActionrecordSelectionCommand.label} | ||||||
|                             Icon={standardActionCommand.Icon} |                             Icon={standardActionrecordSelectionCommand.Icon} | ||||||
|                             onClick={standardActionCommand.onCommandClick} |                             onClick={ | ||||||
|  |                               standardActionrecordSelectionCommand.onCommandClick | ||||||
|  |                             } | ||||||
|  |                           /> | ||||||
|  |                         </SelectableItem> | ||||||
|  |                       ), | ||||||
|  |                     )} | ||||||
|  |                     {matchingWorkflowRunRecordSelectionCommands?.map( | ||||||
|  |                       (workflowRunRecordSelectionCommand) => ( | ||||||
|  |                         <SelectableItem | ||||||
|  |                           itemId={workflowRunRecordSelectionCommand.id} | ||||||
|  |                           key={workflowRunRecordSelectionCommand.id} | ||||||
|  |                         > | ||||||
|  |                           <CommandMenuItem | ||||||
|  |                             id={workflowRunRecordSelectionCommand.id} | ||||||
|  |                             label={workflowRunRecordSelectionCommand.label} | ||||||
|  |                             Icon={workflowRunRecordSelectionCommand.Icon} | ||||||
|  |                             onClick={ | ||||||
|  |                               workflowRunRecordSelectionCommand.onCommandClick | ||||||
|  |                             } | ||||||
|                           /> |                           /> | ||||||
|                         </SelectableItem> |                         </SelectableItem> | ||||||
|                       ), |                       ), | ||||||
|                     )} |                     )} | ||||||
|                   </CommandGroup> |                   </CommandGroup> | ||||||
|                   <CommandGroup heading="Workflows"> |                   {matchingStandardActionGlobalCommands?.length > 0 && ( | ||||||
|                     {matchingWorkflowRunCommands?.map((workflowRunCommand) => ( |                     <CommandGroup heading="View"> | ||||||
|  |                       {matchingStandardActionGlobalCommands?.map( | ||||||
|  |                         (standardActionGlobalCommand) => ( | ||||||
|                           <SelectableItem |                           <SelectableItem | ||||||
|                         itemId={workflowRunCommand.id} |                             itemId={standardActionGlobalCommand.id} | ||||||
|                         key={workflowRunCommand.id} |                             key={standardActionGlobalCommand.id} | ||||||
|                           > |                           > | ||||||
|                             <CommandMenuItem |                             <CommandMenuItem | ||||||
|                           id={workflowRunCommand.id} |                               id={standardActionGlobalCommand.id} | ||||||
|                           label={workflowRunCommand.label} |                               label={standardActionGlobalCommand.label} | ||||||
|                           Icon={workflowRunCommand.Icon} |                               Icon={standardActionGlobalCommand.Icon} | ||||||
|                           onClick={workflowRunCommand.onCommandClick} |                               onClick={ | ||||||
|  |                                 standardActionGlobalCommand.onCommandClick | ||||||
|  |                               } | ||||||
|                             /> |                             /> | ||||||
|                           </SelectableItem> |                           </SelectableItem> | ||||||
|                     ))} |                         ), | ||||||
|  |                       )} | ||||||
|                     </CommandGroup> |                     </CommandGroup> | ||||||
|  |                   )} | ||||||
|  |                   {matchingWorkflowRunGlobalCommands?.length > 0 && ( | ||||||
|  |                     <CommandGroup heading="Workflows"> | ||||||
|  |                       {matchingWorkflowRunGlobalCommands?.map( | ||||||
|  |                         (workflowRunGlobalCommand) => ( | ||||||
|  |                           <SelectableItem | ||||||
|  |                             itemId={workflowRunGlobalCommand.id} | ||||||
|  |                             key={workflowRunGlobalCommand.id} | ||||||
|  |                           > | ||||||
|  |                             <CommandMenuItem | ||||||
|  |                               id={workflowRunGlobalCommand.id} | ||||||
|  |                               label={workflowRunGlobalCommand.label} | ||||||
|  |                               Icon={workflowRunGlobalCommand.Icon} | ||||||
|  |                               onClick={workflowRunGlobalCommand.onCommandClick} | ||||||
|  |                             /> | ||||||
|  |                           </SelectableItem> | ||||||
|  |                         ), | ||||||
|  |                       )} | ||||||
|  |                     </CommandGroup> | ||||||
|  |                   )} | ||||||
|  |  | ||||||
|                   {commandGroups.map(({ heading, items, renderItem }) => |                   {commandGroups.map(({ heading, items, renderItem }) => | ||||||
|                     items?.length ? ( |                     items?.length ? ( | ||||||
|   | |||||||
| @@ -1,5 +1,4 @@ | |||||||
| import { IconComponent } from 'twenty-ui'; | import { IconComponent } from 'twenty-ui'; | ||||||
|  |  | ||||||
| export enum CommandType { | export enum CommandType { | ||||||
|   Navigate = 'Navigate', |   Navigate = 'Navigate', | ||||||
|   Create = 'Create', |   Create = 'Create', | ||||||
| @@ -7,15 +6,17 @@ export enum CommandType { | |||||||
|   WorkflowRun = 'WorkflowRun', |   WorkflowRun = 'WorkflowRun', | ||||||
| } | } | ||||||
|  |  | ||||||
|  | export enum CommandScope { | ||||||
|  |   Global = 'Global', | ||||||
|  |   RecordSelection = 'RecordSelection', | ||||||
|  | } | ||||||
|  |  | ||||||
| export type Command = { | export type Command = { | ||||||
|   id: string; |   id: string; | ||||||
|   to?: string; |   to?: string; | ||||||
|   label: string; |   label: string; | ||||||
|   type?: |   type?: CommandType; | ||||||
|     | CommandType.Navigate |   scope?: CommandScope; | ||||||
|     | CommandType.Create |  | ||||||
|     | CommandType.StandardAction |  | ||||||
|     | CommandType.WorkflowRun; |  | ||||||
|   Icon?: IconComponent; |   Icon?: IconComponent; | ||||||
|   firstHotKey?: string; |   firstHotKey?: string; | ||||||
|   secondHotKey?: string; |   secondHotKey?: string; | ||||||
|   | |||||||
| @@ -1,30 +1,52 @@ | |||||||
| import { ActionMenuEntry } from '@/action-menu/types/ActionMenuEntry'; | import { | ||||||
|  |   ActionMenuEntry, | ||||||
|  |   ActionMenuEntryScope, | ||||||
|  |   ActionMenuEntryType, | ||||||
|  | } from '@/action-menu/types/ActionMenuEntry'; | ||||||
| import { COMMAND_MENU_COMMANDS } from '@/command-menu/constants/CommandMenuCommands'; | import { COMMAND_MENU_COMMANDS } from '@/command-menu/constants/CommandMenuCommands'; | ||||||
| import { CommandType } from '@/command-menu/types/Command'; | import { | ||||||
|  |   Command, | ||||||
|  |   CommandScope, | ||||||
|  |   CommandType, | ||||||
|  | } from '@/command-menu/types/Command'; | ||||||
|  |  | ||||||
| export const computeCommandMenuCommands = ( | export const computeCommandMenuCommands = ( | ||||||
|   actionMenuEntries: ActionMenuEntry[], |   actionMenuEntries: ActionMenuEntry[], | ||||||
| ) => { | ): Command[] => { | ||||||
|   const commands = Object.values(COMMAND_MENU_COMMANDS); |   const commands = Object.values(COMMAND_MENU_COMMANDS); | ||||||
|  |  | ||||||
|   const actionCommands = actionMenuEntries |   const actionCommands: Command[] = actionMenuEntries | ||||||
|     ?.filter((actionMenuEntry) => actionMenuEntry.type === 'standard') |     ?.filter( | ||||||
|  |       (actionMenuEntry) => | ||||||
|  |         actionMenuEntry.type === ActionMenuEntryType.Standard, | ||||||
|  |     ) | ||||||
|     ?.map((actionMenuEntry) => ({ |     ?.map((actionMenuEntry) => ({ | ||||||
|       id: actionMenuEntry.key, |       id: actionMenuEntry.key, | ||||||
|       label: actionMenuEntry.label, |       label: actionMenuEntry.label, | ||||||
|       Icon: actionMenuEntry.Icon, |       Icon: actionMenuEntry.Icon, | ||||||
|       onCommandClick: actionMenuEntry.onClick, |       onCommandClick: actionMenuEntry.onClick, | ||||||
|       type: CommandType.StandardAction, |       type: CommandType.StandardAction, | ||||||
|  |       scope: | ||||||
|  |         actionMenuEntry.scope === ActionMenuEntryScope.RecordSelection | ||||||
|  |           ? CommandScope.RecordSelection | ||||||
|  |           : CommandScope.Global, | ||||||
|     })); |     })); | ||||||
|  |  | ||||||
|   const workflowRunCommands = actionMenuEntries |   const workflowRunCommands: Command[] = actionMenuEntries | ||||||
|     ?.filter((actionMenuEntry) => actionMenuEntry.type === 'workflow-run') |     ?.filter( | ||||||
|  |       (actionMenuEntry) => | ||||||
|  |         actionMenuEntry.type === ActionMenuEntryType.WorkflowRun, | ||||||
|  |     ) | ||||||
|     ?.map((actionMenuEntry) => ({ |     ?.map((actionMenuEntry) => ({ | ||||||
|       id: actionMenuEntry.key, |       id: actionMenuEntry.key, | ||||||
|       label: actionMenuEntry.label, |       label: actionMenuEntry.label, | ||||||
|       Icon: actionMenuEntry.Icon, |       Icon: actionMenuEntry.Icon, | ||||||
|       onCommandClick: actionMenuEntry.onClick, |       onCommandClick: actionMenuEntry.onClick, | ||||||
|       type: CommandType.WorkflowRun, |       type: CommandType.WorkflowRun, | ||||||
|  |       scope: | ||||||
|  |         actionMenuEntry.scope === ActionMenuEntryScope.RecordSelection | ||||||
|  |           ? CommandScope.RecordSelection | ||||||
|  |           : CommandScope.Global, | ||||||
|     })); |     })); | ||||||
|  |  | ||||||
|   return [...commands, ...actionCommands, ...workflowRunCommands]; |   return [...commands, ...actionCommands, ...workflowRunCommands]; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 bosiraphael
					bosiraphael