From fced148724576e1ec9e46cc68cca9f6ad7a199b5 Mon Sep 17 00:00:00 2001
From: nitin <142569587+ehconitin@users.noreply.github.com>
Date: Thu, 9 Oct 2025 17:06:53 +0530
Subject: [PATCH] Fix widget header shrink and make widget placeholder to
change state on click (#14999)
closes closes https://github.com/twentyhq/core-team-issues/issues/1609
---
.../components/PageLayoutGridLayout.tsx | 13 +----
.../widgets/components/WidgetHeader.tsx | 2 +
.../widgets/components/WidgetPlaceholder.tsx | 47 +++++++++++++++----
.../__stories__/WidgetPlaceholder.stories.tsx | 41 +++++++++-------
4 files changed, 66 insertions(+), 37 deletions(-)
diff --git a/packages/twenty-front/src/modules/page-layout/components/PageLayoutGridLayout.tsx b/packages/twenty-front/src/modules/page-layout/components/PageLayoutGridLayout.tsx
index ccc98aefa9..5382e897ed 100644
--- a/packages/twenty-front/src/modules/page-layout/components/PageLayoutGridLayout.tsx
+++ b/packages/twenty-front/src/modules/page-layout/components/PageLayoutGridLayout.tsx
@@ -1,5 +1,3 @@
-import { useNavigatePageLayoutCommandMenu } from '@/command-menu/pages/page-layout/hooks/useNavigatePageLayoutCommandMenu';
-import { CommandMenuPages } from '@/command-menu/types/CommandMenuPages';
import { PageLayoutGridLayoutDragSelector } from '@/page-layout/components/PageLayoutGridLayoutDragSelector';
import { PageLayoutGridOverlay } from '@/page-layout/components/PageLayoutGridOverlay';
import { EMPTY_LAYOUT } from '@/page-layout/constants/EmptyLayout';
@@ -75,8 +73,6 @@ export const PageLayoutGridLayout = () => {
const activeTabId = useRecoilComponentValue(activeTabIdComponentState);
- const { navigatePageLayoutCommandMenu } = useNavigatePageLayoutCommandMenu();
-
const { currentPageLayout } = useCurrentPageLayout();
if (!isDefined(activeTabId) || !isDefined(currentPageLayout)) {
@@ -128,14 +124,7 @@ export const PageLayoutGridLayout = () => {
>
{isLayoutEmpty ? (
- {
- navigatePageLayoutCommandMenu({
- commandMenuPage:
- CommandMenuPages.PageLayoutWidgetTypeSelect,
- });
- }}
- />
+
) : (
activeTabWidgets?.map((widget) => (
diff --git a/packages/twenty-front/src/modules/page-layout/widgets/components/WidgetHeader.tsx b/packages/twenty-front/src/modules/page-layout/widgets/components/WidgetHeader.tsx
index 035e8ccf25..627b072966 100644
--- a/packages/twenty-front/src/modules/page-layout/widgets/components/WidgetHeader.tsx
+++ b/packages/twenty-front/src/modules/page-layout/widgets/components/WidgetHeader.tsx
@@ -6,6 +6,8 @@ const StyledHeader = styled.div`
align-items: center;
display: flex;
gap: ${({ theme }) => theme.spacing(2)};
+ height: ${({ theme }) => theme.spacing(6)};
+ flex-shrink: 0;
`;
const StyledDragHandleButton = styled(IconButton)`
diff --git a/packages/twenty-front/src/modules/page-layout/widgets/components/WidgetPlaceholder.tsx b/packages/twenty-front/src/modules/page-layout/widgets/components/WidgetPlaceholder.tsx
index 1ebe2a77df..2f2346bc85 100644
--- a/packages/twenty-front/src/modules/page-layout/widgets/components/WidgetPlaceholder.tsx
+++ b/packages/twenty-front/src/modules/page-layout/widgets/components/WidgetPlaceholder.tsx
@@ -1,5 +1,14 @@
+import { useNavigatePageLayoutCommandMenu } from '@/command-menu/pages/page-layout/hooks/useNavigatePageLayoutCommandMenu';
+import { CommandMenuPages } from '@/command-menu/types/CommandMenuPages';
+import { useSetIsDashboardInEditMode } from '@/dashboards/hooks/useSetDashboardInEditMode';
+import { PageLayoutComponentInstanceContext } from '@/page-layout/states/contexts/PageLayoutComponentInstanceContext';
+import { isPageLayoutInEditModeComponentState } from '@/page-layout/states/isPageLayoutInEditModeComponentState';
import { WidgetContainer } from '@/page-layout/widgets/components/WidgetContainer';
import { WidgetHeader } from '@/page-layout/widgets/components/WidgetHeader';
+import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
+import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
+import { t } from '@lingui/core/macro';
+import { Trans } from '@lingui/react/macro';
import {
AnimatedPlaceholder,
AnimatedPlaceholderEmptyContainer,
@@ -9,14 +18,36 @@ import {
EMPTY_PLACEHOLDER_TRANSITION_PROPS,
} from 'twenty-ui/layout';
-type WidgetPlaceholderProps = {
- onClick: () => void;
-};
+export const WidgetPlaceholder = () => {
+ const pageLayoutId = useAvailableComponentInstanceIdOrThrow(
+ PageLayoutComponentInstanceContext,
+ );
+
+ const isPageLayoutInEditMode = useRecoilComponentValue(
+ isPageLayoutInEditModeComponentState,
+ );
+
+ const { setIsDashboardInEditMode } =
+ useSetIsDashboardInEditMode(pageLayoutId);
+
+ const { navigatePageLayoutCommandMenu } = useNavigatePageLayoutCommandMenu();
+
+ const handleClick = () => {
+ if (!isPageLayoutInEditMode) {
+ setIsDashboardInEditMode(true);
+ }
+ navigatePageLayoutCommandMenu({
+ commandMenuPage: CommandMenuPages.PageLayoutWidgetTypeSelect,
+ });
+ };
-export const WidgetPlaceholder = ({ onClick }: WidgetPlaceholderProps) => {
return (
-
-
+
+
{
- No widgets yet
+ No widgets yet
- Click to add your first widget
+ Click to add your first widget
diff --git a/packages/twenty-front/src/modules/page-layout/widgets/components/__stories__/WidgetPlaceholder.stories.tsx b/packages/twenty-front/src/modules/page-layout/widgets/components/__stories__/WidgetPlaceholder.stories.tsx
index 7ca3242803..9474cf7224 100644
--- a/packages/twenty-front/src/modules/page-layout/widgets/components/__stories__/WidgetPlaceholder.stories.tsx
+++ b/packages/twenty-front/src/modules/page-layout/widgets/components/__stories__/WidgetPlaceholder.stories.tsx
@@ -1,48 +1,55 @@
+import { isAppWaitingForFreshObjectMetadataState } from '@/object-metadata/states/isAppWaitingForFreshObjectMetadataState';
+import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
import { PageLayoutTestWrapper } from '@/page-layout/hooks/__tests__/PageLayoutTestWrapper';
import { WidgetPlaceholder } from '@/page-layout/widgets/components/WidgetPlaceholder';
import { type Meta, type StoryObj } from '@storybook/react';
+import { type MutableSnapshot } from 'recoil';
import { ComponentDecorator } from 'twenty-ui/testing';
+import { I18nFrontDecorator } from '~/testing/decorators/I18nFrontDecorator';
+import { generatedMockObjectMetadataItems } from '~/testing/utils/generatedMockObjectMetadataItems';
const meta: Meta = {
title: 'Modules/PageLayout/Widgets/WidgetPlaceholder',
component: WidgetPlaceholder,
decorators: [
- (Story) => (
-
-
-
- ),
+ (Story) => {
+ const initializeState = (snapshot: MutableSnapshot) => {
+ snapshot.set(
+ objectMetadataItemsState,
+ generatedMockObjectMetadataItems,
+ );
+ snapshot.set(isAppWaitingForFreshObjectMetadataState, false);
+ };
+
+ return (
+
+
+
+ );
+ },
ComponentDecorator,
+ I18nFrontDecorator,
],
parameters: {
layout: 'centered',
docs: {
description: {
component:
- 'A placeholder widget that appears when no widgets are present. Shows an empty state with a call-to-action to add the first widget.',
+ 'A self-contained placeholder widget that appears when no widgets are present. Automatically enables edit mode when clicked and opens the widget type selection command menu.',
},
},
},
- argTypes: {
- onClick: {
- action: 'onClick',
- description:
- 'Callback function triggered when the placeholder is clicked',
- },
- },
};
export default meta;
type Story = StoryObj;
export const Default: Story = {
- args: {
- onClick: () => {},
- },
parameters: {
docs: {
description: {
- story: 'Default widget placeholder state.',
+ story:
+ 'Default widget placeholder state. Click to trigger the add widget flow.',
},
},
},