From 0750bcaefcf27a110e6a457d289a5f3983b1d7ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Bosi?= <71827178+bosiraphael@users.noreply.github.com> Date: Wed, 17 Sep 2025 17:58:26 +0200 Subject: [PATCH] Create edit dashboard action (#14564) Closes https://github.com/twentyhq/core-team-issues/issues/1435 Introduced a new pattern to force to register an action or not. Discussed this with @charlesBochet --- .../constants/DashboardActionsConfig.tsx | 74 +++++++++++++++++++ .../constants/WorkflowActionsConfig.tsx | 2 +- .../WorkflowVersionsActionsConfig.tsx | 2 +- ...=> NoSelectionWorkflowRecordActionKeys.ts} | 0 .../EditDashboardSingleRecordAction.tsx | 22 ++++++ .../types/DashboardSingleRecordActionKeys.ts | 3 + ...forceRegisteredActionsMapComponentState.ts | 10 +++ .../types/ShouldBeRegisteredFunctionParams.ts | 1 + .../actions/utils/getActionConfig.ts | 4 + .../action-menu/hooks/useRegisteredActions.ts | 12 ++- .../useShouldActionBeRegisteredParams.ts | 6 ++ .../components/DashboardContentRenderer.tsx | 33 +++++++++ .../components/DashboardRenderer.tsx | 4 +- .../hooks/useSetDashboardInEditMode.ts | 37 ++++++++++ .../PageLayoutInitializationQueryEffect.tsx | 5 +- .../components/PageLayoutRenderer.tsx | 8 +- .../page-layout/utils/isPageLayoutEmpty.ts | 7 ++ .../widgets/components/WidgetRenderer.tsx | 1 - 18 files changed, 223 insertions(+), 8 deletions(-) create mode 100644 packages/twenty-front/src/modules/action-menu/actions/record-actions/constants/DashboardActionsConfig.tsx rename packages/twenty-front/src/modules/action-menu/actions/record-actions/no-selection/workflow-actions/types/{NoSelectionWorkflowRecordActionsKeys.ts => NoSelectionWorkflowRecordActionKeys.ts} (100%) create mode 100644 packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/dashboard-actions/components/EditDashboardSingleRecordAction.tsx create mode 100644 packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/dashboard-actions/types/DashboardSingleRecordActionKeys.ts create mode 100644 packages/twenty-front/src/modules/action-menu/actions/states/forceRegisteredActionsMapComponentState.ts create mode 100644 packages/twenty-front/src/modules/dashboards/components/DashboardContentRenderer.tsx create mode 100644 packages/twenty-front/src/modules/dashboards/hooks/useSetDashboardInEditMode.ts create mode 100644 packages/twenty-front/src/modules/page-layout/utils/isPageLayoutEmpty.ts diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/constants/DashboardActionsConfig.tsx b/packages/twenty-front/src/modules/action-menu/actions/record-actions/constants/DashboardActionsConfig.tsx new file mode 100644 index 0000000000..6e0bf94a11 --- /dev/null +++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/constants/DashboardActionsConfig.tsx @@ -0,0 +1,74 @@ +import { EditDashboardSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/dashboard-actions/components/EditDashboardSingleRecordAction'; +import { DashboardSingleRecordActionKeys } from '@/action-menu/actions/record-actions/single-record/dashboard-actions/types/DashboardSingleRecordActionKeys'; +import { SingleRecordActionKeys } from '@/action-menu/actions/record-actions/single-record/types/SingleRecordActionsKey'; +import { inheritActionsFromDefaultConfig } from '@/action-menu/actions/record-actions/utils/inheritActionsFromDefaultConfig'; +import { ActionScope } from '@/action-menu/actions/types/ActionScope'; +import { ActionType } from '@/action-menu/actions/types/ActionType'; +import { ActionViewType } from '@/action-menu/actions/types/ActionViewType'; +import { msg } from '@lingui/core/macro'; +import { isDefined } from 'twenty-shared/utils'; +import { IconPencil } from 'twenty-ui/display'; + +export const DASHBOARD_ACTIONS_CONFIG = inheritActionsFromDefaultConfig({ + config: { + [DashboardSingleRecordActionKeys.EDIT_DASHBOARD]: { + key: DashboardSingleRecordActionKeys.EDIT_DASHBOARD, + label: msg`Edit Dashboard`, + shortLabel: msg`Edit`, + isPinned: true, + position: 1, + Icon: IconPencil, + type: ActionType.Standard, + scope: ActionScope.RecordSelection, + shouldBeRegistered: ({ selectedRecord }) => + isDefined(selectedRecord) && + !selectedRecord?.isRemote && + !isDefined(selectedRecord?.deletedAt) && + isDefined(selectedRecord?.pageLayoutId), + availableOn: [ActionViewType.SHOW_PAGE], + component: , + }, + }, + actionKeys: [ + SingleRecordActionKeys.ADD_TO_FAVORITES, + SingleRecordActionKeys.REMOVE_FROM_FAVORITES, + SingleRecordActionKeys.DELETE, + SingleRecordActionKeys.DESTROY, + SingleRecordActionKeys.RESTORE, + SingleRecordActionKeys.EXPORT_FROM_RECORD_SHOW, + SingleRecordActionKeys.NAVIGATE_TO_PREVIOUS_RECORD, + SingleRecordActionKeys.NAVIGATE_TO_NEXT_RECORD, + ], + propertiesToOverwrite: { + [SingleRecordActionKeys.ADD_TO_FAVORITES]: { + position: 2, + }, + [SingleRecordActionKeys.REMOVE_FROM_FAVORITES]: { + position: 3, + }, + [SingleRecordActionKeys.DELETE]: { + position: 4, + label: msg`Delete dashboard`, + }, + [SingleRecordActionKeys.EXPORT_FROM_RECORD_SHOW]: { + position: 5, + label: msg`Export dashboard`, + }, + [SingleRecordActionKeys.DESTROY]: { + position: 6, + label: msg`Permanently destroy dashboard`, + }, + [SingleRecordActionKeys.RESTORE]: { + position: 7, + label: msg`Restore dashboard`, + }, + [SingleRecordActionKeys.NAVIGATE_TO_PREVIOUS_RECORD]: { + position: 8, + label: msg`Navigate to previous dashboard`, + }, + [SingleRecordActionKeys.NAVIGATE_TO_NEXT_RECORD]: { + position: 9, + label: msg`Navigate to next dashboard`, + }, + }, +}); diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/constants/WorkflowActionsConfig.tsx b/packages/twenty-front/src/modules/action-menu/actions/record-actions/constants/WorkflowActionsConfig.tsx index 8058d50705..4660a12823 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/record-actions/constants/WorkflowActionsConfig.tsx +++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/constants/WorkflowActionsConfig.tsx @@ -1,7 +1,7 @@ import { ActionLink } from '@/action-menu/actions/components/ActionLink'; import { MultipleRecordsActionKeys } from '@/action-menu/actions/record-actions/multiple-records/types/MultipleRecordsActionKeys'; import { NoSelectionRecordActionKeys } from '@/action-menu/actions/record-actions/no-selection/types/NoSelectionRecordActionsKeys'; -import { NoSelectionWorkflowRecordActionKeys } from '@/action-menu/actions/record-actions/no-selection/workflow-actions/types/NoSelectionWorkflowRecordActionsKeys'; +import { NoSelectionWorkflowRecordActionKeys } from '@/action-menu/actions/record-actions/no-selection/workflow-actions/types/NoSelectionWorkflowRecordActionKeys'; import { SingleRecordActionKeys } from '@/action-menu/actions/record-actions/single-record/types/SingleRecordActionsKey'; import { ActivateWorkflowSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/workflow-actions/components/ActivateWorkflowSingleRecordAction'; import { DeactivateWorkflowSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/workflow-actions/components/DeactivateWorkflowSingleRecordAction'; diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/constants/WorkflowVersionsActionsConfig.tsx b/packages/twenty-front/src/modules/action-menu/actions/record-actions/constants/WorkflowVersionsActionsConfig.tsx index bdca663ad3..117614d9c6 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/record-actions/constants/WorkflowVersionsActionsConfig.tsx +++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/constants/WorkflowVersionsActionsConfig.tsx @@ -1,7 +1,7 @@ import { ActionLink } from '@/action-menu/actions/components/ActionLink'; import { MultipleRecordsActionKeys } from '@/action-menu/actions/record-actions/multiple-records/types/MultipleRecordsActionKeys'; import { NoSelectionRecordActionKeys } from '@/action-menu/actions/record-actions/no-selection/types/NoSelectionRecordActionsKeys'; -import { NoSelectionWorkflowRecordActionKeys } from '@/action-menu/actions/record-actions/no-selection/workflow-actions/types/NoSelectionWorkflowRecordActionsKeys'; +import { NoSelectionWorkflowRecordActionKeys } from '@/action-menu/actions/record-actions/no-selection/workflow-actions/types/NoSelectionWorkflowRecordActionKeys'; import { SingleRecordActionKeys } from '@/action-menu/actions/record-actions/single-record/types/SingleRecordActionsKey'; import { SeeRunsWorkflowVersionSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/workflow-version-actions/components/SeeRunsWorkflowVersionSingleRecordAction'; import { SeeVersionsWorkflowVersionSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/workflow-version-actions/components/SeeVersionsWorkflowVersionSingleRecordAction'; diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/no-selection/workflow-actions/types/NoSelectionWorkflowRecordActionsKeys.ts b/packages/twenty-front/src/modules/action-menu/actions/record-actions/no-selection/workflow-actions/types/NoSelectionWorkflowRecordActionKeys.ts similarity index 100% rename from packages/twenty-front/src/modules/action-menu/actions/record-actions/no-selection/workflow-actions/types/NoSelectionWorkflowRecordActionsKeys.ts rename to packages/twenty-front/src/modules/action-menu/actions/record-actions/no-selection/workflow-actions/types/NoSelectionWorkflowRecordActionKeys.ts diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/dashboard-actions/components/EditDashboardSingleRecordAction.tsx b/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/dashboard-actions/components/EditDashboardSingleRecordAction.tsx new file mode 100644 index 0000000000..6aada57384 --- /dev/null +++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/dashboard-actions/components/EditDashboardSingleRecordAction.tsx @@ -0,0 +1,22 @@ +import { Action } from '@/action-menu/actions/components/Action'; +import { useSelectedRecordIdOrThrow } from '@/action-menu/actions/record-actions/single-record/hooks/useSelectedRecordIdOrThrow'; +import { useSetIsDashboardInEditMode } from '@/dashboards/hooks/useSetDashboardInEditMode'; +import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; +import { useRecoilValue } from 'recoil'; + +export const EditDashboardSingleRecordAction = () => { + const recordId = useSelectedRecordIdOrThrow(); + + const selectedRecord = useRecoilValue(recordStoreFamilyState(recordId)); + + const pageLayoutId = selectedRecord?.pageLayoutId; + + const { setIsDashboardInEditMode } = + useSetIsDashboardInEditMode(pageLayoutId); + + const handleClick = () => { + setIsDashboardInEditMode(true); + }; + + return ; +}; diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/dashboard-actions/types/DashboardSingleRecordActionKeys.ts b/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/dashboard-actions/types/DashboardSingleRecordActionKeys.ts new file mode 100644 index 0000000000..3215b42c31 --- /dev/null +++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/dashboard-actions/types/DashboardSingleRecordActionKeys.ts @@ -0,0 +1,3 @@ +export enum DashboardSingleRecordActionKeys { + EDIT_DASHBOARD = 'edit-dashboard-single-record', +} diff --git a/packages/twenty-front/src/modules/action-menu/actions/states/forceRegisteredActionsMapComponentState.ts b/packages/twenty-front/src/modules/action-menu/actions/states/forceRegisteredActionsMapComponentState.ts new file mode 100644 index 0000000000..0eb30cdaec --- /dev/null +++ b/packages/twenty-front/src/modules/action-menu/actions/states/forceRegisteredActionsMapComponentState.ts @@ -0,0 +1,10 @@ +import { ActionMenuComponentInstanceContext } from '@/action-menu/states/contexts/ActionMenuComponentInstanceContext'; +import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; + +export const forceRegisteredActionsByKeyComponentState = createComponentState< + Record +>({ + key: 'forceRegisteredActionsByKeyComponentState', + defaultValue: {}, + componentInstanceContext: ActionMenuComponentInstanceContext, +}); diff --git a/packages/twenty-front/src/modules/action-menu/actions/types/ShouldBeRegisteredFunctionParams.ts b/packages/twenty-front/src/modules/action-menu/actions/types/ShouldBeRegisteredFunctionParams.ts index 4f4aa8fd49..0ff0a125dc 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/types/ShouldBeRegisteredFunctionParams.ts +++ b/packages/twenty-front/src/modules/action-menu/actions/types/ShouldBeRegisteredFunctionParams.ts @@ -25,4 +25,5 @@ export type ShouldBeRegisteredFunctionParams = { getTargetObjectWritePermission: ( objectMetadataItemNameSingular: string, ) => boolean; + forceRegisteredActionsByKey: Record; }; diff --git a/packages/twenty-front/src/modules/action-menu/actions/utils/getActionConfig.ts b/packages/twenty-front/src/modules/action-menu/actions/utils/getActionConfig.ts index 0c27c6968a..dca13c49b4 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/utils/getActionConfig.ts +++ b/packages/twenty-front/src/modules/action-menu/actions/utils/getActionConfig.ts @@ -1,3 +1,4 @@ +import { DASHBOARD_ACTIONS_CONFIG } from '@/action-menu/actions/record-actions/constants/DashboardActionsConfig'; import { DEFAULT_RECORD_ACTIONS_CONFIG } from '@/action-menu/actions/record-actions/constants/DefaultRecordActionsConfig'; 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'; @@ -17,6 +18,9 @@ export const getActionConfig = ({ } switch (objectMetadataItem.nameSingular) { + case CoreObjectNameSingular.Dashboard: { + return DASHBOARD_ACTIONS_CONFIG; + } case CoreObjectNameSingular.Workflow: { return WORKFLOW_ACTIONS_CONFIG; } diff --git a/packages/twenty-front/src/modules/action-menu/hooks/useRegisteredActions.ts b/packages/twenty-front/src/modules/action-menu/hooks/useRegisteredActions.ts index 5322c5a67d..854ad45050 100644 --- a/packages/twenty-front/src/modules/action-menu/hooks/useRegisteredActions.ts +++ b/packages/twenty-front/src/modules/action-menu/hooks/useRegisteredActions.ts @@ -14,7 +14,8 @@ import { useIcons } from 'twenty-ui/display'; export const useRegisteredActions = ( shouldBeRegisteredParams: ShouldBeRegisteredFunctionParams, ) => { - const { objectMetadataItem } = shouldBeRegisteredParams; + const { objectMetadataItem, forceRegisteredActionsByKey } = + shouldBeRegisteredParams; const { getIcon } = useIcons(); @@ -67,6 +68,15 @@ export const useRegisteredActions = ( ) { return false; } + const forcedShouldBeRegistered = forceRegisteredActionsByKey[action.key]; + + if (isDefined(forcedShouldBeRegistered)) { + return ( + forcedShouldBeRegistered && + action.shouldBeRegistered(shouldBeRegisteredParams) + ); + } + return action.shouldBeRegistered(shouldBeRegisteredParams); }) .sort((a, b) => a.position - b.position); diff --git a/packages/twenty-front/src/modules/action-menu/hooks/useShouldActionBeRegisteredParams.ts b/packages/twenty-front/src/modules/action-menu/hooks/useShouldActionBeRegisteredParams.ts index 6ecb29f9d3..b407cbc0ff 100644 --- a/packages/twenty-front/src/modules/action-menu/hooks/useShouldActionBeRegisteredParams.ts +++ b/packages/twenty-front/src/modules/action-menu/hooks/useShouldActionBeRegisteredParams.ts @@ -1,3 +1,4 @@ +import { forceRegisteredActionsByKeyComponentState } from '@/action-menu/actions/states/forceRegisteredActionsMapComponentState'; import { type ShouldBeRegisteredFunctionParams } from '@/action-menu/actions/types/ShouldBeRegisteredFunctionParams'; import { getActionViewType } from '@/action-menu/actions/utils/getActionViewType'; import { ActionMenuContext } from '@/action-menu/contexts/ActionMenuContext'; @@ -100,6 +101,10 @@ export const useShouldActionBeRegisteredParams = ({ [], ); + const forceRegisteredActionsByKey = useRecoilComponentValue( + forceRegisteredActionsByKeyComponentState, + ); + return { objectMetadataItem, isFavorite, @@ -113,5 +118,6 @@ export const useShouldActionBeRegisteredParams = ({ viewType: viewType ?? undefined, getTargetObjectReadPermission: getObjectReadPermission, getTargetObjectWritePermission: getObjectWritePermission, + forceRegisteredActionsByKey, }; }; diff --git a/packages/twenty-front/src/modules/dashboards/components/DashboardContentRenderer.tsx b/packages/twenty-front/src/modules/dashboards/components/DashboardContentRenderer.tsx new file mode 100644 index 0000000000..9f137856e3 --- /dev/null +++ b/packages/twenty-front/src/modules/dashboards/components/DashboardContentRenderer.tsx @@ -0,0 +1,33 @@ +import { type Dashboard } from '@/dashboards/components/types/Dashboard'; +import { useSetIsDashboardInEditMode } from '@/dashboards/hooks/useSetDashboardInEditMode'; +import { PageLayoutRenderer } from '@/page-layout/components/PageLayoutRenderer'; +import { type PageLayoutWithData } from '@/page-layout/types/pageLayoutTypes'; +import { isPageLayoutEmpty } from '@/page-layout/utils/isPageLayoutEmpty'; + +type DashboardContentRendererProps = { + dashboard: Dashboard; +}; + +export const DashboardContentRenderer = ({ + dashboard, +}: DashboardContentRendererProps) => { + const pageLayoutId = dashboard.pageLayoutId; + + const { setIsDashboardInEditMode } = + useSetIsDashboardInEditMode(pageLayoutId); + + const onInitialized = (pageLayout: PageLayoutWithData) => { + if (isPageLayoutEmpty(pageLayout)) { + setIsDashboardInEditMode(true); + } else { + setIsDashboardInEditMode(false); + } + }; + + return ( + + ); +}; diff --git a/packages/twenty-front/src/modules/dashboards/components/DashboardRenderer.tsx b/packages/twenty-front/src/modules/dashboards/components/DashboardRenderer.tsx index e75d43fea8..c38be75ba2 100644 --- a/packages/twenty-front/src/modules/dashboards/components/DashboardRenderer.tsx +++ b/packages/twenty-front/src/modules/dashboards/components/DashboardRenderer.tsx @@ -1,7 +1,7 @@ +import { DashboardContentRenderer } from '@/dashboards/components/DashboardContentRenderer'; import { type Dashboard } from '@/dashboards/components/types/Dashboard'; import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; import { useFindOneRecord } from '@/object-record/hooks/useFindOneRecord'; -import { PageLayoutRenderer } from '@/page-layout/components/PageLayoutRenderer'; import { isDefined } from 'twenty-shared/utils'; type DashboardRendererProps = { @@ -18,5 +18,5 @@ export const DashboardRenderer = ({ recordId }: DashboardRendererProps) => { return null; } - return ; + return ; }; diff --git a/packages/twenty-front/src/modules/dashboards/hooks/useSetDashboardInEditMode.ts b/packages/twenty-front/src/modules/dashboards/hooks/useSetDashboardInEditMode.ts new file mode 100644 index 0000000000..343418a271 --- /dev/null +++ b/packages/twenty-front/src/modules/dashboards/hooks/useSetDashboardInEditMode.ts @@ -0,0 +1,37 @@ +import { DashboardSingleRecordActionKeys } from '@/action-menu/actions/record-actions/single-record/dashboard-actions/types/DashboardSingleRecordActionKeys'; +import { forceRegisteredActionsByKeyComponentState } from '@/action-menu/actions/states/forceRegisteredActionsMapComponentState'; +import { PageLayoutComponentInstanceContext } from '@/page-layout/states/contexts/PageLayoutComponentInstanceContext'; +import { isPageLayoutInEditModeComponentState } from '@/page-layout/states/isPageLayoutInEditModeComponentState'; +import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; +import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; +import { useRecoilCallback } from 'recoil'; + +export const useSetIsDashboardInEditMode = (pageLayoutIdFromProps: string) => { + const pageLayoutId = useAvailableComponentInstanceIdOrThrow( + PageLayoutComponentInstanceContext, + pageLayoutIdFromProps, + ); + + const isPageLayoutInEditModeState = useRecoilComponentCallbackState( + isPageLayoutInEditModeComponentState, + pageLayoutId, + ); + + const forceRegisteredActionsByKeyState = useRecoilComponentCallbackState( + forceRegisteredActionsByKeyComponentState, + ); + + const setIsDashboardInEditMode = useRecoilCallback( + ({ set }) => + (value: boolean) => { + set(isPageLayoutInEditModeState, value); + set(forceRegisteredActionsByKeyState, (prev) => ({ + ...prev, + [DashboardSingleRecordActionKeys.EDIT_DASHBOARD]: !value, + })); + }, + [forceRegisteredActionsByKeyState, isPageLayoutInEditModeState], + ); + + return { setIsDashboardInEditMode }; +}; diff --git a/packages/twenty-front/src/modules/page-layout/components/PageLayoutInitializationQueryEffect.tsx b/packages/twenty-front/src/modules/page-layout/components/PageLayoutInitializationQueryEffect.tsx index ab06cded0f..7bc9839586 100644 --- a/packages/twenty-front/src/modules/page-layout/components/PageLayoutInitializationQueryEffect.tsx +++ b/packages/twenty-front/src/modules/page-layout/components/PageLayoutInitializationQueryEffect.tsx @@ -14,10 +14,12 @@ import { isDeeplyEqual } from '~/utils/isDeeplyEqual'; type PageLayoutInitializationQueryEffectProps = { pageLayoutId: string; + onInitialized: (pageLayout: PageLayoutWithData) => void; }; export const PageLayoutInitializationQueryEffect = ({ pageLayoutId, + onInitialized, }: PageLayoutInitializationQueryEffectProps) => { const [isInitialized, setIsInitialized] = useState(false); @@ -88,9 +90,10 @@ export const PageLayoutInitializationQueryEffect = ({ useEffect(() => { if (!isInitialized && isDefined(pageLayout)) { initializePageLayout(pageLayout); + onInitialized?.(pageLayout); setIsInitialized(true); } - }, [initializePageLayout, isInitialized, pageLayout]); + }, [initializePageLayout, isInitialized, pageLayout, onInitialized]); return null; }; diff --git a/packages/twenty-front/src/modules/page-layout/components/PageLayoutRenderer.tsx b/packages/twenty-front/src/modules/page-layout/components/PageLayoutRenderer.tsx index 53cc48364a..323e16d64c 100644 --- a/packages/twenty-front/src/modules/page-layout/components/PageLayoutRenderer.tsx +++ b/packages/twenty-front/src/modules/page-layout/components/PageLayoutRenderer.tsx @@ -2,6 +2,7 @@ import { PageLayoutInitializationQueryEffect } from '@/page-layout/components/Pa import { PageLayoutRendererContent } from '@/page-layout/components/PageLayoutRendererContent'; import { PageLayoutComponentInstanceContext } from '@/page-layout/states/contexts/PageLayoutComponentInstanceContext'; +import { type PageLayoutWithData } from '@/page-layout/types/pageLayoutTypes'; import { getTabListInstanceIdFromPageLayoutId } from '@/page-layout/utils/getTabListInstanceIdFromPageLayoutId'; import { TabListComponentInstanceContext } from '@/ui/layout/tab-list/states/contexts/TabListComponentInstanceContext'; import 'react-grid-layout/css/styles.css'; @@ -9,10 +10,12 @@ import 'react-resizable/css/styles.css'; type PageLayoutRendererProps = { pageLayoutId: string; + onInitialized: (pageLayout: PageLayoutWithData) => void; }; export const PageLayoutRenderer = ({ pageLayoutId, + onInitialized, }: PageLayoutRendererProps) => { return ( - + diff --git a/packages/twenty-front/src/modules/page-layout/utils/isPageLayoutEmpty.ts b/packages/twenty-front/src/modules/page-layout/utils/isPageLayoutEmpty.ts new file mode 100644 index 0000000000..92d2cfde12 --- /dev/null +++ b/packages/twenty-front/src/modules/page-layout/utils/isPageLayoutEmpty.ts @@ -0,0 +1,7 @@ +import { type PageLayoutWithData } from '~/modules/page-layout/types/pageLayoutTypes'; + +export const isPageLayoutEmpty = (pageLayout: PageLayoutWithData): boolean => { + return ( + pageLayout.tabs.length === 1 && pageLayout.tabs[0].widgets.length === 0 + ); +}; diff --git a/packages/twenty-front/src/modules/page-layout/widgets/components/WidgetRenderer.tsx b/packages/twenty-front/src/modules/page-layout/widgets/components/WidgetRenderer.tsx index 868dd2f4db..07db62e635 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/components/WidgetRenderer.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/components/WidgetRenderer.tsx @@ -26,7 +26,6 @@ export const WidgetRenderer = ({ widget }: WidgetRendererProps) => { const isPageLayoutInEditMode = useRecoilComponentValue( isPageLayoutInEditModeComponentState, - widget.id, ); return (