From 26e2fe349fb638c37f009332037dc8dadf36a5c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Bosi?= <71827178+bosiraphael@users.noreply.github.com> Date: Mon, 24 Nov 2025 19:50:10 +0100 Subject: [PATCH] Fix page layout widget deletion (#16035) With the new side panel, we are able to delete a widget with the side panel still open. This caused the app to crash because we threw when the widget id wasn't defined. This PR fixes this by closing the side panel in the delete action and by returning null instead of throwing. ## Before https://github.com/user-attachments/assets/092bfe62-82dc-4d83-9967-1cc753ecf55e ## After https://github.com/user-attachments/assets/8bed6cc5-961b-4112-8cf5-e587865d14da --- .../constants/CommandMenuPagesConfig.tsx | 6 +-- ...=> CommandMenuPageLayoutChartSettings.tsx} | 13 +------ .../CommandMenuPageLayoutGraphFilter.tsx | 38 +++++++++---------- .../hooks/useDeletePageLayoutWidget.ts | 7 +++- 4 files changed, 30 insertions(+), 34 deletions(-) rename packages/twenty-front/src/modules/command-menu/pages/page-layout/components/{CommandMenuPageLayoutGraphTypeSelect.tsx => CommandMenuPageLayoutChartSettings.tsx} (85%) diff --git a/packages/twenty-front/src/modules/command-menu/constants/CommandMenuPagesConfig.tsx b/packages/twenty-front/src/modules/command-menu/constants/CommandMenuPagesConfig.tsx index ec5ff565a5..b4ad21c981 100644 --- a/packages/twenty-front/src/modules/command-menu/constants/CommandMenuPagesConfig.tsx +++ b/packages/twenty-front/src/modules/command-menu/constants/CommandMenuPagesConfig.tsx @@ -3,11 +3,11 @@ import { CommandMenuAIChatThreadsPage } from '@/command-menu/pages/AIChatThreads import { CommandMenuAskAIPage } from '@/command-menu/pages/ask-ai/components/CommandMenuAskAIPage'; import { CommandMenuCalendarEventPage } from '@/command-menu/pages/calendar-event/components/CommandMenuCalendarEventPage'; import { CommandMenuMessageThreadPage } from '@/command-menu/pages/message-thread/components/CommandMenuMessageThreadPage'; +import { CommandMenuPageLayoutChartSettings } from '@/command-menu/pages/page-layout/components/CommandMenuPageLayoutChartSettings'; import { CommandMenuPageLayoutGraphFilter } from '@/command-menu/pages/page-layout/components/CommandMenuPageLayoutGraphFilter'; -import { CommandMenuPageLayoutGraphTypeSelect } from '@/command-menu/pages/page-layout/components/CommandMenuPageLayoutGraphTypeSelect'; import { CommandMenuPageLayoutIframeSettings } from '@/command-menu/pages/page-layout/components/CommandMenuPageLayoutIframeSettings'; -import { CommandMenuPageLayoutWidgetTypeSelect } from '@/command-menu/pages/page-layout/components/CommandMenuPageLayoutWidgetTypeSelect'; import { CommandMenuPageLayoutTabSettings } from '@/command-menu/pages/page-layout/components/CommandMenuPageLayoutTabSettings'; +import { CommandMenuPageLayoutWidgetTypeSelect } from '@/command-menu/pages/page-layout/components/CommandMenuPageLayoutWidgetTypeSelect'; import { CommandMenuMergeRecordPage } from '@/command-menu/pages/record-page/components/CommandMenuMergeRecordPage'; import { CommandMenuRecordPage } from '@/command-menu/pages/record-page/components/CommandMenuRecordPage'; import { CommandMenuEditRichTextPage } from '@/command-menu/pages/rich-text-page/components/CommandMenuEditRichTextPage'; @@ -48,7 +48,7 @@ export const COMMAND_MENU_PAGES_CONFIG = new Map< ], [ CommandMenuPages.PageLayoutGraphTypeSelect, - , + , ], [ CommandMenuPages.PageLayoutGraphFilter, diff --git a/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/CommandMenuPageLayoutGraphTypeSelect.tsx b/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/CommandMenuPageLayoutChartSettings.tsx similarity index 85% rename from packages/twenty-front/src/modules/command-menu/pages/page-layout/components/CommandMenuPageLayoutGraphTypeSelect.tsx rename to packages/twenty-front/src/modules/command-menu/pages/page-layout/components/CommandMenuPageLayoutChartSettings.tsx index d187123cb6..04cd9b37ff 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/CommandMenuPageLayoutGraphTypeSelect.tsx +++ b/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/CommandMenuPageLayoutChartSettings.tsx @@ -14,7 +14,7 @@ const StyledContainer = styled.div` height: 100%; `; -export const CommandMenuPageLayoutGraphTypeSelect = () => { +export const CommandMenuPageLayoutChartSettings = () => { const { pageLayoutId } = usePageLayoutIdFromContextStoreTargetedRecord(); const draftPageLayout = useRecoilComponentValue( @@ -27,21 +27,12 @@ export const CommandMenuPageLayoutGraphTypeSelect = () => { pageLayoutId, ); - if (!isDefined(pageLayoutEditingWidgetId)) { - throw new Error('Widget ID must be present while editing the widget'); - } - const widgetInEditMode = draftPageLayout.tabs .flatMap((tab) => tab.widgets) .find((widget) => widget.id === pageLayoutEditingWidgetId); - if (!isDefined(widgetInEditMode)) { - throw new Error( - `Widget with ID ${pageLayoutEditingWidgetId} not found in page layout`, - ); - } - if ( + !isDefined(widgetInEditMode) || !isDefined(widgetInEditMode.configuration) || !('graphType' in widgetInEditMode.configuration) ) { diff --git a/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/CommandMenuPageLayoutGraphFilter.tsx b/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/CommandMenuPageLayoutGraphFilter.tsx index ff940b3b2c..353941563a 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/CommandMenuPageLayoutGraphFilter.tsx +++ b/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/CommandMenuPageLayoutGraphFilter.tsx @@ -1,10 +1,11 @@ import { ChartFiltersSettings } from '@/command-menu/pages/page-layout/components/ChartFiltersSettings'; import { usePageLayoutIdFromContextStoreTargetedRecord } from '@/command-menu/pages/page-layout/hooks/usePageLayoutFromContextStoreTargetedRecord'; import { isChartWidget } from '@/command-menu/pages/page-layout/utils/isChartWidget'; -import { useObjectMetadataItemById } from '@/object-metadata/hooks/useObjectMetadataItemById'; +import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; import { pageLayoutDraftComponentState } from '@/page-layout/states/pageLayoutDraftComponentState'; import { pageLayoutEditingWidgetIdComponentState } from '@/page-layout/states/pageLayoutEditingWidgetIdComponentState'; import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useRecoilValue } from 'recoil'; import { isDefined } from 'twenty-shared/utils'; export const CommandMenuPageLayoutGraphFilter = () => { @@ -24,28 +25,27 @@ export const CommandMenuPageLayoutGraphFilter = () => { .flatMap((tab) => tab.widgets) .find((widget) => widget.id === pageLayoutEditingWidgetId); - if (!isDefined(widgetInEditMode)) { - throw new Error( - `Widget with ID ${pageLayoutEditingWidgetId} not found in page layout`, - ); - } + const objectMetadataItems = useRecoilValue(objectMetadataItemsState); - if (!isDefined(widgetInEditMode?.objectMetadataId)) { - throw new Error('No data source in chart'); - } - - const { objectMetadataItem } = useObjectMetadataItemById({ - objectId: widgetInEditMode.objectMetadataId, - }); - - if (!isDefined(pageLayoutEditingWidgetId)) { - throw new Error('Widget ID must be present while editing the widget'); - } - - if (!isChartWidget(widgetInEditMode)) { + if ( + !isDefined(widgetInEditMode) || + !isDefined(widgetInEditMode.objectMetadataId) || + !isChartWidget(widgetInEditMode) + ) { return null; } + const objectMetadataItem = objectMetadataItems.find( + (objectMetadataItem) => + objectMetadataItem.id === widgetInEditMode?.objectMetadataId, + ); + + if (!isDefined(objectMetadataItem)) { + throw new Error( + `Object metadata item not found for id ${widgetInEditMode?.objectMetadataId}`, + ); + } + return ( <> { pageLayoutId, ); + const { closeCommandMenu } = useCommandMenu(); + const deletePageLayoutWidget = useRecoilCallback( ({ snapshot, set }) => (widgetId: string) => { + closeCommandMenu(); + const pageLayoutDraft = snapshot .getLoadable(pageLayoutDraftState) .getValue(); @@ -53,7 +58,7 @@ export const useDeletePageLayoutWidget = (pageLayoutIdFromProps?: string) => { })); } }, - [pageLayoutCurrentLayoutsState, pageLayoutDraftState], + [closeCommandMenu, pageLayoutCurrentLayoutsState, pageLayoutDraftState], ); return { deletePageLayoutWidget };