Fix Side Panel v2 bugs (#10865)
Fixing: - Export as PDF on empty note - Command O (sub commands) not using the right contextStore - BelongsToOne Field input triggering an error on open if no existing relation record is pre-selected
This commit is contained in:
@ -2,7 +2,7 @@ import { RegisterRecordActionEffect } from '@/action-menu/actions/record-actions
|
|||||||
import { WorkflowRunRecordActionMenuEntrySetterEffect } from '@/action-menu/actions/record-actions/workflow-run-record-actions/components/WorkflowRunRecordActionMenuEntrySetter';
|
import { WorkflowRunRecordActionMenuEntrySetterEffect } from '@/action-menu/actions/record-actions/workflow-run-record-actions/components/WorkflowRunRecordActionMenuEntrySetter';
|
||||||
import { getActionConfig } from '@/action-menu/actions/utils/getActionConfig';
|
import { getActionConfig } from '@/action-menu/actions/utils/getActionConfig';
|
||||||
import { getActionViewType } from '@/action-menu/actions/utils/getActionViewType';
|
import { getActionViewType } from '@/action-menu/actions/utils/getActionViewType';
|
||||||
import { COMMAND_MENU_COMPONENT_INSTANCE_ID } from '@/command-menu/constants/CommandMenuComponentInstanceId';
|
import { MAIN_CONTEXT_STORE_INSTANCE_ID } from '@/context-store/constants/MainContextStoreInstanceId';
|
||||||
import { contextStoreCurrentObjectMetadataItemIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataItemIdComponentState';
|
import { contextStoreCurrentObjectMetadataItemIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataItemIdComponentState';
|
||||||
import { contextStoreCurrentViewTypeComponentState } from '@/context-store/states/contextStoreCurrentViewTypeComponentState';
|
import { contextStoreCurrentViewTypeComponentState } from '@/context-store/states/contextStoreCurrentViewTypeComponentState';
|
||||||
import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState';
|
import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState';
|
||||||
@ -14,18 +14,31 @@ import { isDefined } from 'twenty-shared';
|
|||||||
import { FeatureFlagKey } from '~/generated/graphql';
|
import { FeatureFlagKey } from '~/generated/graphql';
|
||||||
|
|
||||||
export const RecordActionMenuEntriesSetter = () => {
|
export const RecordActionMenuEntriesSetter = () => {
|
||||||
const contextStoreCurrentObjectMetadataItemId = useRecoilComponentValueV2(
|
const localContextStoreCurrentObjectMetadataItemId =
|
||||||
|
useRecoilComponentValueV2(
|
||||||
|
contextStoreCurrentObjectMetadataItemIdComponentState,
|
||||||
|
);
|
||||||
|
|
||||||
|
const mainContextStoreCurrentObjectMetadataItemId = useRecoilComponentValueV2(
|
||||||
contextStoreCurrentObjectMetadataItemIdComponentState,
|
contextStoreCurrentObjectMetadataItemIdComponentState,
|
||||||
COMMAND_MENU_COMPONENT_INSTANCE_ID,
|
MAIN_CONTEXT_STORE_INSTANCE_ID,
|
||||||
);
|
);
|
||||||
|
|
||||||
const objectMetadataItems = useRecoilValue(objectMetadataItemsState);
|
const objectMetadataItems = useRecoilValue(objectMetadataItemsState);
|
||||||
|
|
||||||
const objectMetadataItem = objectMetadataItems.find(
|
const localContextStoreObjectMetadataItem = objectMetadataItems.find(
|
||||||
(objectMetadataItem) =>
|
(objectMetadataItem) =>
|
||||||
objectMetadataItem.id === contextStoreCurrentObjectMetadataItemId,
|
objectMetadataItem.id === localContextStoreCurrentObjectMetadataItemId,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const mainContextStoreObjectMetadataItem = objectMetadataItems.find(
|
||||||
|
(objectMetadataItem) =>
|
||||||
|
objectMetadataItem.id === mainContextStoreCurrentObjectMetadataItemId,
|
||||||
|
);
|
||||||
|
|
||||||
|
const objectMetadataItem =
|
||||||
|
localContextStoreObjectMetadataItem ?? mainContextStoreObjectMetadataItem;
|
||||||
|
|
||||||
const contextStoreTargetedRecordsRule = useRecoilComponentValueV2(
|
const contextStoreTargetedRecordsRule = useRecoilComponentValueV2(
|
||||||
contextStoreTargetedRecordsRuleComponentState,
|
contextStoreTargetedRecordsRuleComponentState,
|
||||||
);
|
);
|
||||||
|
|||||||
@ -39,7 +39,7 @@ import {
|
|||||||
IconTrashX,
|
IconTrashX,
|
||||||
} from 'twenty-ui';
|
} from 'twenty-ui';
|
||||||
|
|
||||||
export const DEFAULT_ACTIONS_CONFIG_V2: Record<
|
export const DEFAULT_ACTIONS_CONFIG: Record<
|
||||||
string,
|
string,
|
||||||
ActionMenuEntry & {
|
ActionMenuEntry & {
|
||||||
useAction: ActionHook;
|
useAction: ActionHook;
|
||||||
@ -1,188 +0,0 @@
|
|||||||
import { useDeleteMultipleRecordsAction } from '@/action-menu/actions/record-actions/multiple-records/hooks/useDeleteMultipleRecordsAction';
|
|
||||||
import { useExportMultipleRecordsAction } from '@/action-menu/actions/record-actions/multiple-records/hooks/useExportMultipleRecordsAction';
|
|
||||||
import { useRestoreMultipleRecordsAction } from '@/action-menu/actions/record-actions/multiple-records/hooks/useRestoreMultipleRecordsAction';
|
|
||||||
import { MultipleRecordsActionKeys } from '@/action-menu/actions/record-actions/multiple-records/types/MultipleRecordsActionKeys';
|
|
||||||
import { useImportRecordsNoSelectionRecordAction } from '@/action-menu/actions/record-actions/no-selection/hooks/useImportRecordsNoSelectionRecordAction';
|
|
||||||
import { useSeeDeletedRecordsNoSelectionRecordAction } from '@/action-menu/actions/record-actions/no-selection/hooks/useSeeDeletedRecordsNoSelectionRecordAction';
|
|
||||||
import { NoSelectionRecordActionKeys } from '@/action-menu/actions/record-actions/no-selection/types/NoSelectionRecordActionsKey';
|
|
||||||
import { useAddToFavoritesSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/hooks/useAddToFavoritesSingleRecordAction';
|
|
||||||
import { useDeleteSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/hooks/useDeleteSingleRecordAction';
|
|
||||||
import { useRemoveFromFavoritesSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/hooks/useRemoveFromFavoritesSingleRecordAction';
|
|
||||||
import { useRestoreSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/hooks/useRestoreSingleRecordAction';
|
|
||||||
import { SingleRecordActionKeys } from '@/action-menu/actions/record-actions/single-record/types/SingleRecordActionsKey';
|
|
||||||
import { ActionHook } from '@/action-menu/actions/types/ActionHook';
|
|
||||||
import { ActionViewType } from '@/action-menu/actions/types/ActionViewType';
|
|
||||||
import {
|
|
||||||
ActionMenuEntry,
|
|
||||||
ActionMenuEntryScope,
|
|
||||||
ActionMenuEntryType,
|
|
||||||
} from '@/action-menu/types/ActionMenuEntry';
|
|
||||||
import { msg } from '@lingui/core/macro';
|
|
||||||
import {
|
|
||||||
IconDatabaseExport,
|
|
||||||
IconFileImport,
|
|
||||||
IconHeart,
|
|
||||||
IconHeartOff,
|
|
||||||
IconRefresh,
|
|
||||||
IconRotate2,
|
|
||||||
IconTrash,
|
|
||||||
} from 'twenty-ui';
|
|
||||||
|
|
||||||
export const DEFAULT_ACTIONS_CONFIG_V1: Record<
|
|
||||||
string,
|
|
||||||
ActionMenuEntry & {
|
|
||||||
useAction: ActionHook;
|
|
||||||
}
|
|
||||||
> = {
|
|
||||||
addToFavoritesSingleRecord: {
|
|
||||||
type: ActionMenuEntryType.Standard,
|
|
||||||
scope: ActionMenuEntryScope.RecordSelection,
|
|
||||||
key: SingleRecordActionKeys.ADD_TO_FAVORITES,
|
|
||||||
label: msg`Add to favorites`,
|
|
||||||
position: 0,
|
|
||||||
Icon: IconHeart,
|
|
||||||
availableOn: [
|
|
||||||
ActionViewType.SHOW_PAGE,
|
|
||||||
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
|
|
||||||
],
|
|
||||||
useAction: useAddToFavoritesSingleRecordAction,
|
|
||||||
},
|
|
||||||
removeFromFavoritesSingleRecord: {
|
|
||||||
type: ActionMenuEntryType.Standard,
|
|
||||||
scope: ActionMenuEntryScope.RecordSelection,
|
|
||||||
key: SingleRecordActionKeys.REMOVE_FROM_FAVORITES,
|
|
||||||
label: msg`Remove from favorites`,
|
|
||||||
position: 1,
|
|
||||||
Icon: IconHeartOff,
|
|
||||||
availableOn: [
|
|
||||||
ActionViewType.SHOW_PAGE,
|
|
||||||
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
|
|
||||||
],
|
|
||||||
useAction: useRemoveFromFavoritesSingleRecordAction,
|
|
||||||
},
|
|
||||||
deleteSingleRecord: {
|
|
||||||
type: ActionMenuEntryType.Standard,
|
|
||||||
scope: ActionMenuEntryScope.RecordSelection,
|
|
||||||
key: SingleRecordActionKeys.DELETE,
|
|
||||||
label: msg`Delete`,
|
|
||||||
position: 2,
|
|
||||||
Icon: IconTrash,
|
|
||||||
accent: 'danger',
|
|
||||||
isPinned: true,
|
|
||||||
availableOn: [
|
|
||||||
ActionViewType.SHOW_PAGE,
|
|
||||||
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
|
|
||||||
],
|
|
||||||
useAction: useDeleteSingleRecordAction,
|
|
||||||
},
|
|
||||||
deleteMultipleRecords: {
|
|
||||||
type: ActionMenuEntryType.Standard,
|
|
||||||
scope: ActionMenuEntryScope.RecordSelection,
|
|
||||||
key: MultipleRecordsActionKeys.DELETE,
|
|
||||||
label: msg`Delete records`,
|
|
||||||
shortLabel: msg`Delete`,
|
|
||||||
position: 3,
|
|
||||||
Icon: IconTrash,
|
|
||||||
accent: 'danger',
|
|
||||||
isPinned: true,
|
|
||||||
availableOn: [ActionViewType.INDEX_PAGE_BULK_SELECTION],
|
|
||||||
useAction: useDeleteMultipleRecordsAction,
|
|
||||||
},
|
|
||||||
exportSingleRecord: {
|
|
||||||
type: ActionMenuEntryType.Standard,
|
|
||||||
scope: ActionMenuEntryScope.RecordSelection,
|
|
||||||
key: SingleRecordActionKeys.EXPORT,
|
|
||||||
label: msg`Export record`,
|
|
||||||
shortLabel: msg`Export`,
|
|
||||||
position: 4,
|
|
||||||
Icon: IconDatabaseExport,
|
|
||||||
accent: 'default',
|
|
||||||
isPinned: false,
|
|
||||||
availableOn: [
|
|
||||||
ActionViewType.SHOW_PAGE,
|
|
||||||
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
|
|
||||||
],
|
|
||||||
useAction: useExportMultipleRecordsAction,
|
|
||||||
},
|
|
||||||
exportMultipleRecords: {
|
|
||||||
type: ActionMenuEntryType.Standard,
|
|
||||||
scope: ActionMenuEntryScope.RecordSelection,
|
|
||||||
key: MultipleRecordsActionKeys.EXPORT,
|
|
||||||
label: msg`Export records`,
|
|
||||||
shortLabel: msg`Export`,
|
|
||||||
position: 5,
|
|
||||||
Icon: IconDatabaseExport,
|
|
||||||
accent: 'default',
|
|
||||||
isPinned: false,
|
|
||||||
availableOn: [ActionViewType.INDEX_PAGE_BULK_SELECTION],
|
|
||||||
useAction: useExportMultipleRecordsAction,
|
|
||||||
},
|
|
||||||
exportView: {
|
|
||||||
type: ActionMenuEntryType.Standard,
|
|
||||||
scope: ActionMenuEntryScope.Object,
|
|
||||||
key: NoSelectionRecordActionKeys.EXPORT_VIEW,
|
|
||||||
label: msg`Export view`,
|
|
||||||
shortLabel: msg`Export`,
|
|
||||||
position: 6,
|
|
||||||
Icon: IconDatabaseExport,
|
|
||||||
accent: 'default',
|
|
||||||
isPinned: false,
|
|
||||||
availableOn: [ActionViewType.INDEX_PAGE_NO_SELECTION],
|
|
||||||
useAction: useExportMultipleRecordsAction,
|
|
||||||
},
|
|
||||||
restoreSingleRecord: {
|
|
||||||
type: ActionMenuEntryType.Standard,
|
|
||||||
scope: ActionMenuEntryScope.RecordSelection,
|
|
||||||
key: SingleRecordActionKeys.RESTORE,
|
|
||||||
label: msg`Restore record`,
|
|
||||||
shortLabel: msg`Restore`,
|
|
||||||
position: 7,
|
|
||||||
Icon: IconRefresh,
|
|
||||||
accent: 'default',
|
|
||||||
isPinned: true,
|
|
||||||
availableOn: [
|
|
||||||
ActionViewType.SHOW_PAGE,
|
|
||||||
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
|
|
||||||
],
|
|
||||||
useAction: useRestoreSingleRecordAction,
|
|
||||||
},
|
|
||||||
restoreMultipleRecords: {
|
|
||||||
type: ActionMenuEntryType.Standard,
|
|
||||||
scope: ActionMenuEntryScope.RecordSelection,
|
|
||||||
key: MultipleRecordsActionKeys.RESTORE,
|
|
||||||
label: msg`Restore records`,
|
|
||||||
shortLabel: msg`Restore`,
|
|
||||||
position: 8,
|
|
||||||
Icon: IconRefresh,
|
|
||||||
accent: 'default',
|
|
||||||
isPinned: true,
|
|
||||||
availableOn: [ActionViewType.INDEX_PAGE_BULK_SELECTION],
|
|
||||||
useAction: useRestoreMultipleRecordsAction,
|
|
||||||
},
|
|
||||||
seeDeletedRecords: {
|
|
||||||
type: ActionMenuEntryType.Standard,
|
|
||||||
scope: ActionMenuEntryScope.Object,
|
|
||||||
key: NoSelectionRecordActionKeys.SEE_DELETED_RECORDS,
|
|
||||||
label: msg`See deleted records`,
|
|
||||||
shortLabel: msg`Deleted records`,
|
|
||||||
position: 9,
|
|
||||||
Icon: IconRotate2,
|
|
||||||
accent: 'default',
|
|
||||||
isPinned: false,
|
|
||||||
availableOn: [ActionViewType.INDEX_PAGE_NO_SELECTION],
|
|
||||||
useAction: useSeeDeletedRecordsNoSelectionRecordAction,
|
|
||||||
},
|
|
||||||
importRecords: {
|
|
||||||
type: ActionMenuEntryType.Standard,
|
|
||||||
scope: ActionMenuEntryScope.Object,
|
|
||||||
key: NoSelectionRecordActionKeys.IMPORT_RECORDS,
|
|
||||||
label: msg`Import records`,
|
|
||||||
shortLabel: msg`Import`,
|
|
||||||
position: 10,
|
|
||||||
Icon: IconFileImport,
|
|
||||||
accent: 'default',
|
|
||||||
isPinned: false,
|
|
||||||
availableOn: [ActionViewType.INDEX_PAGE_NO_SELECTION],
|
|
||||||
useAction: useImportRecordsNoSelectionRecordAction,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
@ -3,6 +3,7 @@ import { ActionHookWithObjectMetadataItem } from '@/action-menu/actions/types/Ac
|
|||||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||||
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
|
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
|
||||||
import { BlockNoteEditor } from '@blocknote/core';
|
import { BlockNoteEditor } from '@blocknote/core';
|
||||||
|
import { isNonEmptyString } from '@sniptt/guards';
|
||||||
import { useRecoilValue } from 'recoil';
|
import { useRecoilValue } from 'recoil';
|
||||||
import { isDefined } from 'twenty-shared';
|
import { isDefined } from 'twenty-shared';
|
||||||
|
|
||||||
@ -20,10 +21,13 @@ export const useExportNoteAction: ActionHookWithObjectMetadataItem = ({
|
|||||||
objectMetadataItem?.nameSingular === CoreObjectNameSingular.Task;
|
objectMetadataItem?.nameSingular === CoreObjectNameSingular.Task;
|
||||||
|
|
||||||
const shouldBeRegistered =
|
const shouldBeRegistered =
|
||||||
isDefined(objectMetadataItem) && isDefined(selectedRecord) && isNoteOrTask;
|
isDefined(objectMetadataItem) &&
|
||||||
|
isDefined(selectedRecord) &&
|
||||||
|
isNoteOrTask &&
|
||||||
|
isNonEmptyString(selectedRecord.bodyV2?.blocknote);
|
||||||
|
|
||||||
const onClick = async () => {
|
const onClick = async () => {
|
||||||
if (!shouldBeRegistered || !selectedRecord?.body) {
|
if (!shouldBeRegistered || !selectedRecord.bodyV2.blocknote) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { DEFAULT_ACTIONS_CONFIG_V2 } from '@/action-menu/actions/record-actions/constants/DefaultActionsConfigV2';
|
import { DEFAULT_ACTIONS_CONFIG } from '@/action-menu/actions/record-actions/constants/DefaultActionsConfig';
|
||||||
import { WORKFLOW_ACTIONS_CONFIG } from '@/action-menu/actions/record-actions/constants/WorkflowActionsConfig';
|
import { WORKFLOW_ACTIONS_CONFIG } from '@/action-menu/actions/record-actions/constants/WorkflowActionsConfig';
|
||||||
import { WORKFLOW_RUNS_ACTIONS_CONFIG } from '@/action-menu/actions/record-actions/constants/WorkflowRunsActionsConfig';
|
import { WORKFLOW_RUNS_ACTIONS_CONFIG } from '@/action-menu/actions/record-actions/constants/WorkflowRunsActionsConfig';
|
||||||
import { WORKFLOW_VERSIONS_ACTIONS_CONFIG } from '@/action-menu/actions/record-actions/constants/WorkflowVersionsActionsConfig';
|
import { WORKFLOW_VERSIONS_ACTIONS_CONFIG } from '@/action-menu/actions/record-actions/constants/WorkflowVersionsActionsConfig';
|
||||||
@ -14,6 +14,6 @@ export const getActionConfig = (objectMetadataItem: ObjectMetadataItem) => {
|
|||||||
case CoreObjectNameSingular.WorkflowRun:
|
case CoreObjectNameSingular.WorkflowRun:
|
||||||
return WORKFLOW_RUNS_ACTIONS_CONFIG;
|
return WORKFLOW_RUNS_ACTIONS_CONFIG;
|
||||||
default:
|
default:
|
||||||
return DEFAULT_ACTIONS_CONFIG_V2;
|
return DEFAULT_ACTIONS_CONFIG;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@ -140,7 +140,7 @@ export const ObjectOptionsDropdownRecordGroupFieldsContent = () => {
|
|||||||
))}
|
))}
|
||||||
</DropdownMenuItemsContainer>
|
</DropdownMenuItemsContainer>
|
||||||
<DropdownMenuSeparator />
|
<DropdownMenuSeparator />
|
||||||
<DropdownMenuItemsContainer>
|
<DropdownMenuItemsContainer scrollable={false}>
|
||||||
<UndecoratedLink
|
<UndecoratedLink
|
||||||
to={newSelectFieldSettingsUrl}
|
to={newSelectFieldSettingsUrl}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
|||||||
@ -197,7 +197,9 @@ export const RecordDetailRelationSection = ({
|
|||||||
const handleOpenRelationPickerDropdown = () => {
|
const handleOpenRelationPickerDropdown = () => {
|
||||||
if (isToOneObject) {
|
if (isToOneObject) {
|
||||||
setSingleRecordPickerSearchFilter('');
|
setSingleRecordPickerSearchFilter('');
|
||||||
setSingleRecordPickerSelectedId(relationRecords[0].id);
|
if (relationRecords.length > 0) {
|
||||||
|
setSingleRecordPickerSelectedId(relationRecords[0].id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isToManyObjects) {
|
if (isToManyObjects) {
|
||||||
|
|||||||
@ -65,6 +65,8 @@ export const Default: Story = {
|
|||||||
play: async ({ canvasElement }) => {
|
play: async ({ canvasElement }) => {
|
||||||
const canvas = within(canvasElement);
|
const canvas = within(canvasElement);
|
||||||
await sleep(100);
|
await sleep(100);
|
||||||
await canvas.findByText('Code your function');
|
await canvas.findByText('Code your function', undefined, {
|
||||||
|
timeout: 3000,
|
||||||
|
});
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user