Scaffold all company cards as widgets#15149
Conversation
| case WidgetType.TIMELINE: | ||
| return <TimelineWidget widget={widget} />; | ||
|
|
||
| case WidgetType.TASKS: | ||
| return <TaskWidget widget={widget} />; | ||
|
|
||
| case WidgetType.NOTES: | ||
| return <NoteWidget widget={widget} />; | ||
|
|
||
| case WidgetType.FILES: | ||
| return <FileWidget widget={widget} />; | ||
|
|
||
| case WidgetType.EMAILS: | ||
| return <EmailWidget widget={widget} />; | ||
|
|
||
| case WidgetType.CALENDAR: | ||
| return <CalendarWidget widget={widget} />; |
There was a problem hiding this comment.
At one point or another, we'll have to lazy-load the components
|
🚀 Preview Environment Ready! Your preview environment is available at: http://bore.pub:20032 This environment will automatically shut down when the PR is closed or after 5 hours. |
| const tabsToRenderInTabList = currentPageLayout.tabs.filter( | ||
| (tab) => tab.selfDisplayMode !== 'pinned-left', | ||
| ); | ||
| const pinnedLeftTab = currentPageLayout.tabs.find( | ||
| (tab) => tab.selfDisplayMode === 'pinned-left', | ||
| ); |
There was a problem hiding this comment.
selfDisplayMode: 'pinned-left' on tabs
| {isDefined(pinnedLeftTab) && ( | ||
| <ShowPageLeftContainer forceMobile={false}> | ||
| <SummaryCard | ||
| objectNameSingular={targetRecordIdentifier.targetObjectNameSingular} | ||
| objectRecordId={targetRecordIdentifier.id} | ||
| isInRightDrawer={isInRightDrawer} | ||
| /> | ||
|
|
||
| <PageLayoutGridLayout activeTabId={pinnedLeftTab.id} /> | ||
| </ShowPageLeftContainer> | ||
| )} |
There was a problem hiding this comment.
Hard-coded left panel; not fan of it.
packages/twenty-front/src/modules/page-layout/components/PageLayoutRendererContent.tsx
Show resolved
Hide resolved
| title: 'Fields', | ||
| position: 100, | ||
| layoutMode: 'vertical-list', | ||
| selfDisplayMode: 'pinned-left', |
There was a problem hiding this comment.
Why "selfDisplayMode" and not just displayMode? I didn't get the nuance
There was a problem hiding this comment.
Greptile Overview
Greptile Summary
This PR transforms company detail pages from a fixed card-based layout to a flexible widget-based system. The implementation creates dedicated widget components (TimelineWidget, TaskWidget, NoteWidget, FileWidget, EmailWidget, CalendarWidget) that wrap existing card components, expanding the widget type enum from 4 to 10 types. Each widget provides proper context handling through RightDrawerProvider and maintains existing functionality while enabling modular page layouts.
The architectural changes introduce a two-column layout similar to existing show pages, with a left sidebar containing a summary card and a pinned Fields widget, and a right container with tabbed content for other widgets. A database migration adds the new widget types to the PostgreSQL enum, and the default page layout configuration is updated to use specific widget types instead of generic VIEW widgets.
Important Files Changed
Changed Files
| Filename | Score | Overview |
|---|---|---|
packages/twenty-server/src/database/typeorm/core/migrations/common/1760628085765-addNewWidgetTypes.ts |
4/5 | Database migration adding 6 new widget types to PostgreSQL enum |
packages/twenty-server/src/engine/core-modules/page-layout/enums/widget-type.enum.ts |
5/5 | Backend enum expansion adding TIMELINE, TASKS, NOTES, FILES, EMAILS, CALENDAR |
packages/twenty-front/src/generated/graphql.ts |
5/5 | Generated GraphQL types reflecting new widget type enum values |
packages/twenty-front/src/modules/page-layout/constants/DefaultPageLayout.ts |
4/5 | Default layout configuration updated with specific widget types and pinned-left mode |
packages/twenty-front/src/modules/page-layout/components/PageLayoutRendererContent.tsx |
4/5 | Major refactor implementing two-column layout with left sidebar and tab filtering |
packages/twenty-front/src/modules/page-layout/widgets/components/WidgetContentRenderer.tsx |
5/5 | Widget renderer updated to support 6 new widget types with proper case handling |
packages/twenty-front/src/modules/page-layout/widgets/timeline/components/TimelineWidget.tsx |
5/5 | New timeline widget wrapper with proper context providers |
packages/twenty-front/src/modules/page-layout/widgets/tasks/components/TaskWidget.tsx |
5/5 | New task widget wrapper with context and styling |
packages/twenty-front/src/modules/page-layout/widgets/notes/components/NoteWidget.tsx |
4/5 | New notes widget wrapper following established patterns |
packages/twenty-front/src/modules/page-layout/widgets/files/components/FileWidget.tsx |
5/5 | New files widget wrapper with proper context handling |
packages/twenty-front/src/modules/page-layout/widgets/emails/components/EmailWidget.tsx |
4/5 | New email widget wrapper with right drawer provider |
packages/twenty-front/src/modules/page-layout/widgets/calendar/components/CalendarWidget.tsx |
4/5 | New calendar widget wrapper with context and styling |
packages/twenty-front/src/modules/page-layout/widgets/fields/components/FieldsWidget.tsx |
4/5 | Updated fields widget with width styling adjustment |
packages/twenty-front/src/modules/page-layout/components/PageLayoutGridLayout.tsx |
4/5 | Component refactored to accept explicit tabId prop instead of using global state |
packages/twenty-front/src/modules/page-layout/types/PageLayoutTab.ts |
5/5 | Type definition extended with optional selfDisplayMode property |
packages/twenty-front/src/modules/ui/layout/page/components/ShowPageContainer.tsx |
2/5 | Children type changed to ReactNode but contains React hooks rules violation |
packages/twenty-server/src/engine/core-modules/open-api/utils/components.utils.ts |
2/5 | OpenAPI schema updated inconsistently - new types missing from ForUpdate/ForResponse schemas |
packages/twenty-server/test/integration/constants/widget-configuration-test-data.constants.ts |
5/5 | Test configuration updated to support new widget types returning null config |
packages/twenty-front/src/modules/page-layout/components/__stories__/PageLayoutRenderer.stories.tsx |
4/5 | Storybook stories updated with proper LayoutRenderingProvider context |
Confidence score: 4/5
- This PR implements a well-structured widget architecture that maintains existing functionality while adding modularity
- Score reduced due to React hooks violations in ShowPageContainer, OpenAPI schema inconsistencies, and potential runtime issues with duplicate component rendering
- Pay close attention to ShowPageContainer.tsx and components.utils.ts for the identified issues that need correction before merging
Sequence Diagram
sequenceDiagram
participant User
participant PageLayoutRenderer
participant WidgetContentRenderer
participant CalendarWidget
participant EmailWidget
participant FileWidget
participant NoteWidget
participant TaskWidget
participant TimelineWidget
participant FieldsWidget
participant CalendarEventsCard
participant EmailsCard
participant FilesCard
participant NotesCard
participant TasksCard
participant TimelineCard
participant RecordFieldList
User->>PageLayoutRenderer: "Load page layout"
PageLayoutRenderer->>PageLayoutRenderer: "Get current page layout"
PageLayoutRenderer->>PageLayoutRenderer: "Filter tabs by display mode"
loop For each widget in active tab
PageLayoutRenderer->>WidgetContentRenderer: "Render widget"
alt Widget type is CALENDAR
WidgetContentRenderer->>CalendarWidget: "Create calendar widget"
CalendarWidget->>CalendarEventsCard: "Render calendar events"
CalendarEventsCard-->>CalendarWidget: "Return calendar content"
CalendarWidget-->>WidgetContentRenderer: "Return calendar widget"
else Widget type is EMAILS
WidgetContentRenderer->>EmailWidget: "Create email widget"
EmailWidget->>EmailsCard: "Render emails"
EmailsCard-->>EmailWidget: "Return email content"
EmailWidget-->>WidgetContentRenderer: "Return email widget"
else Widget type is FILES
WidgetContentRenderer->>FileWidget: "Create file widget"
FileWidget->>FilesCard: "Render files"
FilesCard-->>FileWidget: "Return file content"
FileWidget-->>WidgetContentRenderer: "Return file widget"
else Widget type is NOTES
WidgetContentRenderer->>NoteWidget: "Create note widget"
NoteWidget->>NotesCard: "Render notes"
NotesCard-->>NoteWidget: "Return note content"
NoteWidget-->>WidgetContentRenderer: "Return note widget"
else Widget type is TASKS
WidgetContentRenderer->>TaskWidget: "Create task widget"
TaskWidget->>TasksCard: "Render tasks"
TasksCard-->>TaskWidget: "Return task content"
TaskWidget-->>WidgetContentRenderer: "Return task widget"
else Widget type is TIMELINE
WidgetContentRenderer->>TimelineWidget: "Create timeline widget"
TimelineWidget->>TimelineCard: "Render timeline"
TimelineCard-->>TimelineWidget: "Return timeline content"
TimelineWidget-->>WidgetContentRenderer: "Return timeline widget"
else Widget type is FIELDS
WidgetContentRenderer->>FieldsWidget: "Create fields widget"
FieldsWidget->>RecordFieldList: "Render record fields"
RecordFieldList-->>FieldsWidget: "Return field list content"
FieldsWidget-->>WidgetContentRenderer: "Return fields widget"
end
WidgetContentRenderer-->>PageLayoutRenderer: "Return rendered widget"
end
PageLayoutRenderer-->>User: "Display page with all widgets"
Additional Comments (4)
-
packages/twenty-front/src/modules/ui/layout/page/components/ShowPageContainer.tsx, line 9 (link)logic: calling
useIsMobile()inside styled component definition violates rules of hooks - this will cause runtime errors -
packages/twenty-front/src/modules/ui/layout/page/components/ShowPageContainer.tsx, line 16 (link)logic: calling
useIsMobile()inside styled component definition violates rules of hooks - this will cause runtime errors -
packages/twenty-server/src/engine/core-modules/open-api/utils/components.utils.ts, line 1173-1175 (link)logic: Missing new widget types in ForUpdate schema. Should include TIMELINE, TASKS, NOTES, FILES, EMAILS, CALENDAR to match the main schema
-
packages/twenty-server/src/engine/core-modules/open-api/utils/components.utils.ts, line 1194-1196 (link)logic: Missing new widget types in ForResponse schema. Should include TIMELINE, TASKS, NOTES, FILES, EMAILS, CALENDAR to match the main schema
19 files reviewed, 11 comments
| widget: PageLayoutWidget; | ||
| }; | ||
|
|
||
| export const TaskWidget = ({ widget: _widget }: TaskWidgetProps) => { |
There was a problem hiding this comment.
style: The widget parameter is prefixed with underscore indicating it's intentionally unused, but consider if widget configuration might be needed for future functionality
Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/twenty-front/src/modules/page-layout/widgets/tasks/components/TaskWidget.tsx
Line: 17:17
Comment:
**style:** The widget parameter is prefixed with underscore indicating it's intentionally unused, but consider if widget configuration might be needed for future functionality
How can I resolve this? If you propose a fix, please make it concise.| widget: PageLayoutWidget; | ||
| }; | ||
|
|
||
| export const NoteWidget = ({ widget: _widget }: NoteWidgetProps) => { |
There was a problem hiding this comment.
style: Widget parameter is unused - consider removing underscore prefix once widget configuration is implemented
Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/twenty-front/src/modules/page-layout/widgets/notes/components/NoteWidget.tsx
Line: 17:17
Comment:
**style:** Widget parameter is unused - consider removing underscore prefix once widget configuration is implemented
How can I resolve this? If you propose a fix, please make it concise.
packages/twenty-front/src/modules/page-layout/widgets/notes/components/NoteWidget.tsx
Show resolved
Hide resolved
| height: 100%; | ||
| justify-content: start; | ||
| width: 100%; | ||
| height: 100%; |
There was a problem hiding this comment.
syntax: Duplicate height declaration - remove one of the height: 100% lines
Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/twenty-front/src/modules/page-layout/components/PageLayoutRendererContent.tsx
Line: 33:33
Comment:
**syntax:** Duplicate height declaration - remove one of the `height: 100%` lines
How can I resolve this? If you propose a fix, please make it concise.| isInRightDrawer={isInRightDrawer} | ||
| /> | ||
|
|
||
| <PageLayoutGridLayout tabId={pinnedLeftTab.id} /> |
There was a problem hiding this comment.
logic: Potential issue: PageLayoutGridLayout is rendered twice with different tabIds. Verify this doesn't cause conflicts or duplicate rendering.
Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/twenty-front/src/modules/page-layout/components/PageLayoutRendererContent.tsx
Line: 82:82
Comment:
**logic:** Potential issue: PageLayoutGridLayout is rendered twice with different tabIds. Verify this doesn't cause conflicts or duplicate rendering.
How can I resolve this? If you propose a fix, please make it concise.
This PR doesn't support mobile and side-panel modes. The fields tab will be displayed in these cases.
Demo
CleanShot.2025-10-17.at.17.14.12.mp4