[feat]:Added the ability to create a view from Command Menu (#13335)

Fixes - #13307 

**Description** 
This PR adds the feature to create view from the command menu

**Key Changes**
- Added the command in the DEAFULT_RECORD_ACTION_CONFIG
- Created a component which is used in the action when the command is
clicked

**Files Changed**
-
packages/twenty-front/src/modules/action-menu/actions/record-actions/constants/DefaultRecordActionsConfig.tsx
-
packages/twenty-front/src/modules/action-menu/actions/record-actions/no-selection/components/SeeDeletedRecordsNoSelectionRecordAction.tsx
-
packages/twenty-front/src/modules/action-menu/actions/record-actions/no-selection/types/NoSelectionRecordActionsKeys.ts
-
packages/twenty-front/src/modules/views/view-picker/components/ViewPickerListContent.tsx


**Demo Video**


https://github.com/user-attachments/assets/8e3dc3dd-7f85-4da5-8c4a-6721abb29aff

---------

Co-authored-by: bosiraphael <raphael.bosi@gmail.com>
This commit is contained in:
Priyansh Verma
2025-07-22 17:39:59 +05:30
committed by GitHub
parent 9d61337396
commit 20f285d246
3 changed files with 77 additions and 14 deletions

View File

@ -5,6 +5,7 @@ import { ExportMultipleRecordsAction } from '@/action-menu/actions/record-action
import { RestoreMultipleRecordsAction } from '@/action-menu/actions/record-actions/multiple-records/components/RestoreMultipleRecordsAction';
import { MultipleRecordsActionKeys } from '@/action-menu/actions/record-actions/multiple-records/types/MultipleRecordsActionKeys';
import { CreateNewTableRecordNoSelectionRecordAction } from '@/action-menu/actions/record-actions/no-selection/components/CreateNewTableRecordNoSelectionRecordAction';
import { CreateNewViewNoSelectionRecord } from '@/action-menu/actions/record-actions/no-selection/components/CreateNewViewNoSelectionRecord';
import { HideDeletedRecordsNoSelectionRecordAction } from '@/action-menu/actions/record-actions/no-selection/components/HideDeletedRecordsNoSelectionRecordAction';
import { ImportRecordsNoSelectionRecordAction } from '@/action-menu/actions/record-actions/no-selection/components/ImportRecordsNoSelectionRecordAction';
import { SeeDeletedRecordsNoSelectionRecordAction } from '@/action-menu/actions/record-actions/no-selection/components/SeeDeletedRecordsNoSelectionRecordAction';
@ -41,6 +42,7 @@ import {
IconFileImport,
IconHeart,
IconHeartOff,
IconLayout,
IconPlus,
IconRefresh,
IconRotate2,
@ -276,13 +278,28 @@ export const DEFAULT_RECORD_ACTIONS_CONFIG: Record<
availableOn: [ActionViewType.INDEX_PAGE_NO_SELECTION],
component: <SeeDeletedRecordsNoSelectionRecordAction />,
},
[NoSelectionRecordActionKeys.CREATE_NEW_VIEW]: {
type: ActionType.Standard,
scope: ActionScope.Object,
key: NoSelectionRecordActionKeys.CREATE_NEW_VIEW,
label: msg`Create View`,
shortLabel: msg`Create View`,
position: 11,
Icon: IconLayout,
accent: 'default',
isPinned: false,
shouldBeRegistered: ({ isSoftDeleteFilterActive }) =>
!isSoftDeleteFilterActive,
availableOn: [ActionViewType.INDEX_PAGE_NO_SELECTION],
component: <CreateNewViewNoSelectionRecord />,
},
[NoSelectionRecordActionKeys.HIDE_DELETED_RECORDS]: {
type: ActionType.Standard,
scope: ActionScope.Object,
key: NoSelectionRecordActionKeys.HIDE_DELETED_RECORDS,
label: msg`Hide deleted records`,
shortLabel: msg`Hide deleted`,
position: 11,
position: 12,
Icon: IconEyeOff,
accent: 'default',
isPinned: false,
@ -297,7 +314,7 @@ export const DEFAULT_RECORD_ACTIONS_CONFIG: Record<
key: SingleRecordActionKeys.DESTROY,
label: msg`Permanently destroy record`,
shortLabel: msg`Destroy`,
position: 12,
position: 13,
Icon: IconTrashX,
accent: 'danger',
isPinned: true,
@ -316,7 +333,7 @@ export const DEFAULT_RECORD_ACTIONS_CONFIG: Record<
scope: ActionScope.RecordSelection,
key: SingleRecordActionKeys.NAVIGATE_TO_PREVIOUS_RECORD,
label: msg`Navigate to previous record`,
position: 13,
position: 14,
isPinned: true,
Icon: IconChevronUp,
shouldBeRegistered: ({ isInRightDrawer }) => !isInRightDrawer,
@ -328,7 +345,7 @@ export const DEFAULT_RECORD_ACTIONS_CONFIG: Record<
scope: ActionScope.RecordSelection,
key: SingleRecordActionKeys.NAVIGATE_TO_NEXT_RECORD,
label: msg`Navigate to next record`,
position: 14,
position: 15,
isPinned: true,
Icon: IconChevronDown,
shouldBeRegistered: ({ isInRightDrawer }) => !isInRightDrawer,
@ -341,7 +358,7 @@ export const DEFAULT_RECORD_ACTIONS_CONFIG: Record<
key: MultipleRecordsActionKeys.DESTROY,
label: msg`Permanently destroy records`,
shortLabel: msg`Destroy`,
position: 15,
position: 16,
Icon: IconTrashX,
accent: 'danger',
isPinned: true,
@ -366,7 +383,7 @@ export const DEFAULT_RECORD_ACTIONS_CONFIG: Record<
key: SingleRecordActionKeys.RESTORE,
label: msg`Restore record`,
shortLabel: msg`Restore`,
position: 16,
position: 17,
Icon: IconRefresh,
accent: 'default',
isPinned: true,
@ -394,7 +411,7 @@ export const DEFAULT_RECORD_ACTIONS_CONFIG: Record<
key: MultipleRecordsActionKeys.RESTORE,
label: msg`Restore records`,
shortLabel: msg`Restore`,
position: 17,
position: 18,
Icon: IconRefresh,
accent: 'default',
isPinned: true,
@ -419,7 +436,7 @@ export const DEFAULT_RECORD_ACTIONS_CONFIG: Record<
key: NoSelectionRecordActionKeys.GO_TO_WORKFLOWS,
label: msg`Go to workflows`,
shortLabel: msg`See workflows`,
position: 18,
position: 19,
Icon: IconSettingsAutomation,
accent: 'default',
isPinned: false,
@ -451,7 +468,7 @@ export const DEFAULT_RECORD_ACTIONS_CONFIG: Record<
key: NoSelectionRecordActionKeys.GO_TO_PEOPLE,
label: msg`Go to People`,
shortLabel: msg`People`,
position: 19,
position: 20,
Icon: IconUser,
isPinned: false,
availableOn: [
@ -482,7 +499,7 @@ export const DEFAULT_RECORD_ACTIONS_CONFIG: Record<
key: NoSelectionRecordActionKeys.GO_TO_COMPANIES,
label: msg`Go to Companies`,
shortLabel: msg`Companies`,
position: 20,
position: 21,
Icon: IconBuildingSkyscraper,
isPinned: false,
availableOn: [
@ -513,7 +530,7 @@ export const DEFAULT_RECORD_ACTIONS_CONFIG: Record<
key: NoSelectionRecordActionKeys.GO_TO_OPPORTUNITIES,
label: msg`Go to Opportunities`,
shortLabel: msg`Opportunities`,
position: 21,
position: 22,
Icon: IconTargetArrow,
isPinned: false,
availableOn: [
@ -546,7 +563,7 @@ export const DEFAULT_RECORD_ACTIONS_CONFIG: Record<
key: NoSelectionRecordActionKeys.GO_TO_SETTINGS,
label: msg`Go to Settings`,
shortLabel: msg`Settings`,
position: 22,
position: 23,
Icon: IconSettings,
isPinned: false,
availableOn: [
@ -572,7 +589,7 @@ export const DEFAULT_RECORD_ACTIONS_CONFIG: Record<
key: NoSelectionRecordActionKeys.GO_TO_TASKS,
label: msg`Go to Tasks`,
shortLabel: msg`Tasks`,
position: 23,
position: 24,
Icon: IconCheckbox,
isPinned: false,
availableOn: [
@ -603,7 +620,7 @@ export const DEFAULT_RECORD_ACTIONS_CONFIG: Record<
key: NoSelectionRecordActionKeys.GO_TO_NOTES,
label: msg`Go to Notes`,
shortLabel: msg`Notes`,
position: 24,
position: 25,
Icon: IconCheckbox,
isPinned: false,
availableOn: [

View File

@ -0,0 +1,45 @@
import { Action } from '@/action-menu/actions/components/Action';
import { useContextStoreObjectMetadataItemOrThrow } from '@/context-store/hooks/useContextStoreObjectMetadataItemOrThrow';
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
import { getRecordIndexIdFromObjectNamePluralAndViewId } from '@/object-record/utils/getRecordIndexIdFromObjectNamePluralAndViewId';
import { useOpenDropdown } from '@/ui/layout/dropdown/hooks/useOpenDropdown';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
import { useViewPickerMode } from '@/views/view-picker/hooks/useViewPickerMode';
import { viewPickerReferenceViewIdComponentState } from '@/views/view-picker/states/viewPickerReferenceViewIdComponentState';
import { VIEW_PICKER_DROPDOWN_ID } from '@/views/view-picker/constants/ViewPickerDropdownId';
export const CreateNewViewNoSelectionRecord = () => {
const { objectMetadataItem } = useContextStoreObjectMetadataItemOrThrow();
const { openDropdown } = useOpenDropdown();
const currentViewId = useRecoilComponentValueV2(
contextStoreCurrentViewIdComponentState,
);
if (!currentViewId) {
throw new Error('Current view ID is not defined');
}
const recordIndexId = getRecordIndexIdFromObjectNamePluralAndViewId(
objectMetadataItem.namePlural,
currentViewId,
);
const setViewPickerReferenceViewId = useSetRecoilComponentStateV2(
viewPickerReferenceViewIdComponentState,
recordIndexId,
);
const { setViewPickerMode } = useViewPickerMode(recordIndexId);
const handleAddViewButtonClick = () => {
setViewPickerReferenceViewId(currentViewId);
setViewPickerMode('create-empty');
openDropdown({
dropdownComponentInstanceIdFromProps: VIEW_PICKER_DROPDOWN_ID,
});
};
return <Action onClick={handleAddViewButtonClick} />;
};

View File

@ -11,4 +11,5 @@ export enum NoSelectionRecordActionKeys {
GO_TO_SETTINGS = 'go-to-settings',
GO_TO_TASKS = 'go-to-tasks',
GO_TO_NOTES = 'go-to-notes',
CREATE_NEW_VIEW = 'create-view',
}