mirror of
https://github.com/lingble/twenty.git
synced 2025-11-01 21:27:58 +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