Companies show page as record page (#15132)
Example showing two widgets positioned in a vertical list: https://github.com/user-attachments/assets/cf3e9793-7d80-4cab-b708-aad9f2bca7d8
This commit is contained in:
committed by
GitHub
parent
b2247a7a3d
commit
1b6c9e851f
@@ -1250,6 +1250,7 @@ export enum FeatureFlagKey {
|
||||
IS_PAGE_LAYOUT_ENABLED = 'IS_PAGE_LAYOUT_ENABLED',
|
||||
IS_POSTGRESQL_INTEGRATION_ENABLED = 'IS_POSTGRESQL_INTEGRATION_ENABLED',
|
||||
IS_PUBLIC_DOMAIN_ENABLED = 'IS_PUBLIC_DOMAIN_ENABLED',
|
||||
IS_RECORD_PAGE_LAYOUT_ENABLED = 'IS_RECORD_PAGE_LAYOUT_ENABLED',
|
||||
IS_RELATION_CONNECT_ENABLED = 'IS_RELATION_CONNECT_ENABLED',
|
||||
IS_STRIPE_INTEGRATION_ENABLED = 'IS_STRIPE_INTEGRATION_ENABLED',
|
||||
IS_UNIQUE_INDEXES_ENABLED = 'IS_UNIQUE_INDEXES_ENABLED',
|
||||
|
||||
@@ -1214,6 +1214,7 @@ export enum FeatureFlagKey {
|
||||
IS_PAGE_LAYOUT_ENABLED = 'IS_PAGE_LAYOUT_ENABLED',
|
||||
IS_POSTGRESQL_INTEGRATION_ENABLED = 'IS_POSTGRESQL_INTEGRATION_ENABLED',
|
||||
IS_PUBLIC_DOMAIN_ENABLED = 'IS_PUBLIC_DOMAIN_ENABLED',
|
||||
IS_RECORD_PAGE_LAYOUT_ENABLED = 'IS_RECORD_PAGE_LAYOUT_ENABLED',
|
||||
IS_RELATION_CONNECT_ENABLED = 'IS_RELATION_CONNECT_ENABLED',
|
||||
IS_STRIPE_INTEGRATION_ENABLED = 'IS_STRIPE_INTEGRATION_ENABLED',
|
||||
IS_UNIQUE_INDEXES_ENABLED = 'IS_UNIQUE_INDEXES_ENABLED',
|
||||
|
||||
+10
-2
@@ -4,7 +4,8 @@ import { RecordShowContainer } from '@/object-record/record-show/components/Reco
|
||||
import { RecordShowEffect } from '@/object-record/record-show/components/RecordShowEffect';
|
||||
import { LayoutRenderingProvider } from '@/ui/layout/contexts/LayoutRenderingContext';
|
||||
import { type TargetRecordIdentifier } from '@/ui/layout/contexts/TargetRecordIdentifier';
|
||||
import { PageLayoutType } from '~/generated/graphql';
|
||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||
import { FeatureFlagKey, PageLayoutType } from '~/generated/graphql';
|
||||
|
||||
export const PageLayoutDispatcher = ({
|
||||
targetRecordIdentifier,
|
||||
@@ -13,9 +14,16 @@ export const PageLayoutDispatcher = ({
|
||||
targetRecordIdentifier: TargetRecordIdentifier;
|
||||
isInRightDrawer?: boolean;
|
||||
}) => {
|
||||
const isRecordPageEnabled = useIsFeatureEnabled(
|
||||
FeatureFlagKey.IS_RECORD_PAGE_LAYOUT_ENABLED,
|
||||
);
|
||||
|
||||
if (
|
||||
targetRecordIdentifier.targetObjectNameSingular ===
|
||||
CoreObjectNameSingular.Dashboard
|
||||
CoreObjectNameSingular.Dashboard ||
|
||||
(targetRecordIdentifier.targetObjectNameSingular ===
|
||||
CoreObjectNameSingular.Company &&
|
||||
isRecordPageEnabled)
|
||||
) {
|
||||
return (
|
||||
<PageLayoutRecordPageRenderer
|
||||
|
||||
@@ -16,6 +16,7 @@ import { WidgetRenderer } from '@/page-layout/widgets/components/WidgetRenderer'
|
||||
import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTabIdComponentState';
|
||||
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
||||
import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState';
|
||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||
import styled from '@emotion/styled';
|
||||
import { useRef } from 'react';
|
||||
import {
|
||||
@@ -24,6 +25,7 @@ import {
|
||||
type ResponsiveProps,
|
||||
} from 'react-grid-layout';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { FeatureFlagKey } from '~/generated/graphql';
|
||||
|
||||
const StyledGridContainer = styled.div`
|
||||
background: ${({ theme }) => theme.background.primary};
|
||||
@@ -55,7 +57,17 @@ const ResponsiveGridLayout = WidthProvider(
|
||||
Responsive,
|
||||
) as React.ComponentType<ExtendedResponsiveProps>;
|
||||
|
||||
const StyledVerticalListContainer = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: ${({ theme }) => theme.spacing(2)};
|
||||
`;
|
||||
|
||||
export const PageLayoutGridLayout = () => {
|
||||
const isRecordPageEnabled = useIsFeatureEnabled(
|
||||
FeatureFlagKey.IS_RECORD_PAGE_LAYOUT_ENABLED,
|
||||
);
|
||||
|
||||
const setPageLayoutCurrentBreakpoint = useSetRecoilComponentState(
|
||||
pageLayoutCurrentBreakpointComponentState,
|
||||
);
|
||||
@@ -76,20 +88,38 @@ export const PageLayoutGridLayout = () => {
|
||||
|
||||
const { currentPageLayout } = useCurrentPageLayout();
|
||||
|
||||
if (!isDefined(activeTabId) || !isDefined(currentPageLayout)) {
|
||||
const activeTab = currentPageLayout?.tabs.find(
|
||||
(tab) => tab.id === activeTabId,
|
||||
);
|
||||
|
||||
if (
|
||||
!isDefined(activeTabId) ||
|
||||
!isDefined(currentPageLayout) ||
|
||||
!isDefined(activeTab)
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const activeTabWidgets = currentPageLayout.tabs.find(
|
||||
(tab) => tab.id === activeTabId,
|
||||
)?.widgets;
|
||||
const activeTabWidgets = activeTab.widgets;
|
||||
|
||||
const isLayoutEmpty =
|
||||
!isDefined(activeTabWidgets) || activeTabWidgets.length === 0;
|
||||
|
||||
const layouts = isLayoutEmpty
|
||||
? EMPTY_LAYOUT
|
||||
: pageLayoutCurrentLayouts[activeTabId] || EMPTY_LAYOUT;
|
||||
: (pageLayoutCurrentLayouts[activeTabId] ?? EMPTY_LAYOUT);
|
||||
|
||||
const Widgets = isLayoutEmpty ? (
|
||||
<div key="empty-placeholder" data-select-disable="true">
|
||||
<WidgetPlaceholder />
|
||||
</div>
|
||||
) : (
|
||||
activeTabWidgets?.map((widget) => (
|
||||
<div key={widget.id} data-select-disable="true">
|
||||
<WidgetRenderer widget={widget} />
|
||||
</div>
|
||||
))
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -102,43 +132,42 @@ export const PageLayoutGridLayout = () => {
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
<ResponsiveGridLayout
|
||||
className="layout"
|
||||
layouts={layouts}
|
||||
breakpoints={PAGE_LAYOUT_CONFIG.breakpoints}
|
||||
cols={PAGE_LAYOUT_CONFIG.columns}
|
||||
rowHeight={55}
|
||||
maxCols={12}
|
||||
containerPadding={[0, 0]}
|
||||
margin={[8, 8]}
|
||||
isDraggable={isPageLayoutInEditMode}
|
||||
isResizable={isPageLayoutInEditMode}
|
||||
draggableHandle=".drag-handle"
|
||||
compactType="vertical"
|
||||
preventCollision={false}
|
||||
resizeHandle={
|
||||
isPageLayoutInEditMode ? <PageLayoutGridResizeHandle /> : undefined
|
||||
}
|
||||
resizeHandles={['se']}
|
||||
onLayoutChange={handleLayoutChange}
|
||||
onBreakpointChange={(newBreakpoint) =>
|
||||
setPageLayoutCurrentBreakpoint(
|
||||
newBreakpoint as PageLayoutBreakpoint,
|
||||
)
|
||||
}
|
||||
>
|
||||
{isLayoutEmpty ? (
|
||||
<div key="empty-placeholder" data-select-disable="true">
|
||||
<WidgetPlaceholder />
|
||||
</div>
|
||||
) : (
|
||||
activeTabWidgets?.map((widget) => (
|
||||
<div key={widget.id} data-select-disable="true">
|
||||
<WidgetRenderer widget={widget} />
|
||||
</div>
|
||||
))
|
||||
)}
|
||||
</ResponsiveGridLayout>
|
||||
|
||||
{isRecordPageEnabled &&
|
||||
!isPageLayoutInEditMode &&
|
||||
activeTab.layoutMode === 'vertical-list' ? (
|
||||
<StyledVerticalListContainer>{Widgets}</StyledVerticalListContainer>
|
||||
) : (
|
||||
<ResponsiveGridLayout
|
||||
className="layout"
|
||||
layouts={layouts}
|
||||
breakpoints={PAGE_LAYOUT_CONFIG.breakpoints}
|
||||
cols={PAGE_LAYOUT_CONFIG.columns}
|
||||
rowHeight={55}
|
||||
maxCols={12}
|
||||
containerPadding={[0, 0]}
|
||||
margin={[8, 8]}
|
||||
isDraggable={isPageLayoutInEditMode}
|
||||
isResizable={isPageLayoutInEditMode}
|
||||
draggableHandle=".drag-handle"
|
||||
compactType="vertical"
|
||||
preventCollision={false}
|
||||
resizeHandle={
|
||||
isPageLayoutInEditMode ? (
|
||||
<PageLayoutGridResizeHandle />
|
||||
) : undefined
|
||||
}
|
||||
resizeHandles={['se']}
|
||||
onLayoutChange={handleLayoutChange}
|
||||
onBreakpointChange={(newBreakpoint) =>
|
||||
setPageLayoutCurrentBreakpoint(
|
||||
newBreakpoint as PageLayoutBreakpoint,
|
||||
)
|
||||
}
|
||||
>
|
||||
{Widgets}
|
||||
</ResponsiveGridLayout>
|
||||
)}
|
||||
</StyledGridContainer>
|
||||
</>
|
||||
);
|
||||
|
||||
+10
-3
@@ -1,4 +1,6 @@
|
||||
import { FIND_ONE_PAGE_LAYOUT } from '@/dashboards/graphql/queries/findOnePageLayout';
|
||||
import { DEFAULT_PAGE_LAYOUT } from '@/page-layout/constants/DefaultPageLayout';
|
||||
import { DEFAULT_PAGE_LAYOUT_ID } from '@/page-layout/constants/DefaultPageLayoutId';
|
||||
import { pageLayoutCurrentLayoutsComponentState } from '@/page-layout/states/pageLayoutCurrentLayoutsComponentState';
|
||||
import { pageLayoutDraftComponentState } from '@/page-layout/states/pageLayoutDraftComponentState';
|
||||
import { pageLayoutPersistedComponentState } from '@/page-layout/states/pageLayoutPersistedComponentState';
|
||||
@@ -24,15 +26,20 @@ export const PageLayoutInitializationQueryEffect = ({
|
||||
}: PageLayoutInitializationQueryEffectProps) => {
|
||||
const [isInitialized, setIsInitialized] = useState(false);
|
||||
|
||||
const isDefaultLayout = pageLayoutId === DEFAULT_PAGE_LAYOUT_ID;
|
||||
|
||||
const { data } = useQuery(FIND_ONE_PAGE_LAYOUT, {
|
||||
variables: {
|
||||
id: pageLayoutId,
|
||||
},
|
||||
skip: isDefaultLayout,
|
||||
});
|
||||
|
||||
const pageLayout: PageLayout | undefined = data?.getPageLayout
|
||||
? transformPageLayout(data.getPageLayout)
|
||||
: undefined;
|
||||
const pageLayout: PageLayout | undefined = isDefaultLayout
|
||||
? DEFAULT_PAGE_LAYOUT
|
||||
: data?.getPageLayout
|
||||
? transformPageLayout(data.getPageLayout)
|
||||
: undefined;
|
||||
|
||||
const pageLayoutPersistedComponentCallbackState =
|
||||
useRecoilComponentCallbackState(pageLayoutPersistedComponentState);
|
||||
|
||||
@@ -0,0 +1,252 @@
|
||||
import { DEFAULT_PAGE_LAYOUT_ID } from '@/page-layout/constants/DefaultPageLayoutId';
|
||||
import { type PageLayout } from '@/page-layout/types/PageLayout';
|
||||
import { PageLayoutType, WidgetType } from '~/generated/graphql';
|
||||
|
||||
/**
|
||||
* Default mock PageLayout used when pageLayoutId equals DEFAULT_PAGE_LAYOUT_ID.
|
||||
* This combines base record layout tabs (fields, timeline, tasks, notes, files)
|
||||
* with company-specific tabs (emails, calendar).
|
||||
*/
|
||||
export const DEFAULT_PAGE_LAYOUT: PageLayout = {
|
||||
__typename: 'PageLayout',
|
||||
id: DEFAULT_PAGE_LAYOUT_ID,
|
||||
name: 'Default Record Layout',
|
||||
type: PageLayoutType.RECORD_PAGE,
|
||||
objectMetadataId: null,
|
||||
createdAt: new Date().toISOString(),
|
||||
updatedAt: new Date().toISOString(),
|
||||
deletedAt: null,
|
||||
tabs: [
|
||||
// Fields tab (position 100)
|
||||
{
|
||||
__typename: 'PageLayoutTab',
|
||||
id: 'default-tab-fields',
|
||||
title: 'Fields',
|
||||
position: 100,
|
||||
layoutMode: 'vertical-list',
|
||||
pageLayoutId: DEFAULT_PAGE_LAYOUT_ID,
|
||||
createdAt: new Date().toISOString(),
|
||||
updatedAt: new Date().toISOString(),
|
||||
deletedAt: null,
|
||||
widgets: [
|
||||
{
|
||||
__typename: 'PageLayoutWidget',
|
||||
id: 'default-widget-fields',
|
||||
pageLayoutTabId: 'default-tab-fields',
|
||||
title: 'Fields',
|
||||
type: WidgetType.FIELDS,
|
||||
objectMetadataId: null,
|
||||
gridPosition: {
|
||||
__typename: 'GridPosition',
|
||||
row: 0,
|
||||
column: 0,
|
||||
rowSpan: 12,
|
||||
columnSpan: 12,
|
||||
},
|
||||
configuration: null,
|
||||
createdAt: new Date().toISOString(),
|
||||
updatedAt: new Date().toISOString(),
|
||||
deletedAt: null,
|
||||
},
|
||||
],
|
||||
},
|
||||
// Timeline tab (position 200)
|
||||
{
|
||||
__typename: 'PageLayoutTab',
|
||||
id: 'default-tab-timeline',
|
||||
title: 'Timeline',
|
||||
position: 200,
|
||||
layoutMode: 'vertical-list',
|
||||
pageLayoutId: DEFAULT_PAGE_LAYOUT_ID,
|
||||
createdAt: new Date().toISOString(),
|
||||
updatedAt: new Date().toISOString(),
|
||||
deletedAt: null,
|
||||
widgets: [
|
||||
{
|
||||
__typename: 'PageLayoutWidget',
|
||||
id: 'default-widget-timeline',
|
||||
pageLayoutTabId: 'default-tab-timeline',
|
||||
title: 'Timeline',
|
||||
type: WidgetType.VIEW,
|
||||
objectMetadataId: null,
|
||||
gridPosition: {
|
||||
__typename: 'GridPosition',
|
||||
row: 0,
|
||||
column: 0,
|
||||
rowSpan: 6,
|
||||
columnSpan: 12,
|
||||
},
|
||||
configuration: null,
|
||||
createdAt: new Date().toISOString(),
|
||||
updatedAt: new Date().toISOString(),
|
||||
deletedAt: null,
|
||||
},
|
||||
],
|
||||
},
|
||||
// Tasks tab (position 300)
|
||||
{
|
||||
__typename: 'PageLayoutTab',
|
||||
id: 'default-tab-tasks',
|
||||
title: 'Tasks',
|
||||
position: 300,
|
||||
layoutMode: 'vertical-list',
|
||||
pageLayoutId: DEFAULT_PAGE_LAYOUT_ID,
|
||||
createdAt: new Date().toISOString(),
|
||||
updatedAt: new Date().toISOString(),
|
||||
deletedAt: null,
|
||||
widgets: [
|
||||
{
|
||||
__typename: 'PageLayoutWidget',
|
||||
id: 'default-widget-tasks',
|
||||
pageLayoutTabId: 'default-tab-tasks',
|
||||
title: 'Tasks',
|
||||
type: WidgetType.VIEW,
|
||||
objectMetadataId: null,
|
||||
gridPosition: {
|
||||
__typename: 'GridPosition',
|
||||
row: 0,
|
||||
column: 0,
|
||||
rowSpan: 6,
|
||||
columnSpan: 12,
|
||||
},
|
||||
configuration: null,
|
||||
createdAt: new Date().toISOString(),
|
||||
updatedAt: new Date().toISOString(),
|
||||
deletedAt: null,
|
||||
},
|
||||
],
|
||||
},
|
||||
// Notes tab (position 400)
|
||||
{
|
||||
__typename: 'PageLayoutTab',
|
||||
id: 'default-tab-notes',
|
||||
title: 'Notes',
|
||||
position: 400,
|
||||
layoutMode: 'vertical-list',
|
||||
pageLayoutId: DEFAULT_PAGE_LAYOUT_ID,
|
||||
createdAt: new Date().toISOString(),
|
||||
updatedAt: new Date().toISOString(),
|
||||
deletedAt: null,
|
||||
widgets: [
|
||||
{
|
||||
__typename: 'PageLayoutWidget',
|
||||
id: 'default-widget-notes',
|
||||
pageLayoutTabId: 'default-tab-notes',
|
||||
title: 'Notes',
|
||||
type: WidgetType.VIEW,
|
||||
objectMetadataId: null,
|
||||
gridPosition: {
|
||||
__typename: 'GridPosition',
|
||||
row: 0,
|
||||
column: 0,
|
||||
rowSpan: 6,
|
||||
columnSpan: 12,
|
||||
},
|
||||
configuration: null,
|
||||
createdAt: new Date().toISOString(),
|
||||
updatedAt: new Date().toISOString(),
|
||||
deletedAt: null,
|
||||
},
|
||||
],
|
||||
},
|
||||
// Files tab (position 500)
|
||||
{
|
||||
__typename: 'PageLayoutTab',
|
||||
id: 'default-tab-files',
|
||||
title: 'Files',
|
||||
position: 500,
|
||||
layoutMode: 'vertical-list',
|
||||
pageLayoutId: DEFAULT_PAGE_LAYOUT_ID,
|
||||
createdAt: new Date().toISOString(),
|
||||
updatedAt: new Date().toISOString(),
|
||||
deletedAt: null,
|
||||
widgets: [
|
||||
{
|
||||
__typename: 'PageLayoutWidget',
|
||||
id: 'default-widget-files',
|
||||
pageLayoutTabId: 'default-tab-files',
|
||||
title: 'Files',
|
||||
type: WidgetType.VIEW,
|
||||
objectMetadataId: null,
|
||||
gridPosition: {
|
||||
__typename: 'GridPosition',
|
||||
row: 0,
|
||||
column: 0,
|
||||
rowSpan: 6,
|
||||
columnSpan: 12,
|
||||
},
|
||||
configuration: null,
|
||||
createdAt: new Date().toISOString(),
|
||||
updatedAt: new Date().toISOString(),
|
||||
deletedAt: null,
|
||||
},
|
||||
],
|
||||
},
|
||||
// Emails tab (position 600) - Company specific
|
||||
{
|
||||
__typename: 'PageLayoutTab',
|
||||
id: 'default-tab-emails',
|
||||
title: 'Emails',
|
||||
position: 600,
|
||||
layoutMode: 'vertical-list',
|
||||
pageLayoutId: DEFAULT_PAGE_LAYOUT_ID,
|
||||
createdAt: new Date().toISOString(),
|
||||
updatedAt: new Date().toISOString(),
|
||||
deletedAt: null,
|
||||
widgets: [
|
||||
{
|
||||
__typename: 'PageLayoutWidget',
|
||||
id: 'default-widget-emails',
|
||||
pageLayoutTabId: 'default-tab-emails',
|
||||
title: 'Emails',
|
||||
type: WidgetType.VIEW,
|
||||
objectMetadataId: null,
|
||||
gridPosition: {
|
||||
__typename: 'GridPosition',
|
||||
row: 0,
|
||||
column: 0,
|
||||
rowSpan: 6,
|
||||
columnSpan: 12,
|
||||
},
|
||||
configuration: null,
|
||||
createdAt: new Date().toISOString(),
|
||||
updatedAt: new Date().toISOString(),
|
||||
deletedAt: null,
|
||||
},
|
||||
],
|
||||
},
|
||||
// Calendar tab (position 700) - Company specific
|
||||
{
|
||||
__typename: 'PageLayoutTab',
|
||||
id: 'default-tab-calendar',
|
||||
title: 'Calendar',
|
||||
position: 700,
|
||||
layoutMode: 'vertical-list',
|
||||
pageLayoutId: DEFAULT_PAGE_LAYOUT_ID,
|
||||
createdAt: new Date().toISOString(),
|
||||
updatedAt: new Date().toISOString(),
|
||||
deletedAt: null,
|
||||
widgets: [
|
||||
{
|
||||
__typename: 'PageLayoutWidget',
|
||||
id: 'default-widget-calendar',
|
||||
pageLayoutTabId: 'default-tab-calendar',
|
||||
title: 'Calendar',
|
||||
type: WidgetType.VIEW,
|
||||
objectMetadataId: null,
|
||||
gridPosition: {
|
||||
__typename: 'GridPosition',
|
||||
row: 0,
|
||||
column: 0,
|
||||
rowSpan: 6,
|
||||
columnSpan: 12,
|
||||
},
|
||||
configuration: null,
|
||||
createdAt: new Date().toISOString(),
|
||||
updatedAt: new Date().toISOString(),
|
||||
deletedAt: null,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
@@ -0,0 +1 @@
|
||||
export const DEFAULT_PAGE_LAYOUT_ID = 'DEFAULT_LAYOUT_ID';
|
||||
@@ -1,5 +1,6 @@
|
||||
import { useFindOneRecord } from '@/object-record/hooks/useFindOneRecord';
|
||||
import { type ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||
import { DEFAULT_PAGE_LAYOUT_ID } from '@/page-layout/constants/DefaultPageLayoutId';
|
||||
import { type TargetRecordIdentifier } from '@/ui/layout/contexts/TargetRecordIdentifier';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
@@ -28,6 +29,6 @@ export const useRecordPageLayoutId = ({
|
||||
|
||||
// TODO: implement a default layout
|
||||
return {
|
||||
pageLayoutId: 'DEFAULT_LAYOUT_ID',
|
||||
pageLayoutId: DEFAULT_PAGE_LAYOUT_ID,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -5,4 +5,8 @@ import {
|
||||
|
||||
export type PageLayoutTab = Omit<PageLayoutTabGenerated, 'widgets'> & {
|
||||
widgets: PageLayoutWidget[];
|
||||
/**
|
||||
* Only available behind IS_RECORD_PAGE_LAYOUT_ENABLED for now.
|
||||
*/
|
||||
layoutMode?: 'grid' | 'vertical-list';
|
||||
};
|
||||
|
||||
+4
@@ -1,3 +1,4 @@
|
||||
import { FieldsWidget } from '@/page-layout/widgets/fields/components/FieldsWidget';
|
||||
import { GraphWidgetRenderer } from '@/page-layout/widgets/graph/components/GraphWidgetRenderer';
|
||||
import { IframeWidget } from '@/page-layout/widgets/iframe/components/IframeWidget';
|
||||
import { type PageLayoutWidget, WidgetType } from '~/generated/graphql';
|
||||
@@ -16,6 +17,9 @@ export const WidgetContentRenderer = ({
|
||||
case WidgetType.IFRAME:
|
||||
return <IframeWidget widget={widget} />;
|
||||
|
||||
case WidgetType.FIELDS:
|
||||
return <FieldsWidget widget={widget} />;
|
||||
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
import { RecordFieldList } from '@/object-record/record-field-list/components/RecordFieldList';
|
||||
import { useLayoutRenderingContext } from '@/ui/layout/contexts/LayoutRenderingContext';
|
||||
import { useTargetRecord } from '@/ui/layout/contexts/useTargetRecord';
|
||||
import { RightDrawerProvider } from '@/ui/layout/right-drawer/contexts/RightDrawerContext';
|
||||
import styled from '@emotion/styled';
|
||||
import { type PageLayoutWidget } from '~/generated/graphql';
|
||||
|
||||
const StyledContainer = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
`;
|
||||
|
||||
type FieldsWidgetProps = {
|
||||
widget: PageLayoutWidget;
|
||||
};
|
||||
|
||||
export const FieldsWidget = ({ widget: _widget }: FieldsWidgetProps) => {
|
||||
const targetRecord = useTargetRecord();
|
||||
const { isInRightDrawer } = useLayoutRenderingContext();
|
||||
|
||||
return (
|
||||
<RightDrawerProvider value={{ isInRightDrawer }}>
|
||||
<StyledContainer>
|
||||
<RecordFieldList
|
||||
instanceId={`fields-widget-${targetRecord.id}-${isInRightDrawer ? 'right-drawer' : ''}`}
|
||||
objectNameSingular={targetRecord.targetObjectNameSingular}
|
||||
objectRecordId={targetRecord.id}
|
||||
// TODO: pick the value from the widget configuration
|
||||
showDuplicatesSection={true}
|
||||
/>
|
||||
</StyledContainer>
|
||||
</RightDrawerProvider>
|
||||
);
|
||||
};
|
||||
+1
@@ -13,6 +13,7 @@ export enum FeatureFlagKey {
|
||||
IS_CORE_VIEW_ENABLED = 'IS_CORE_VIEW_ENABLED',
|
||||
IS_WORKSPACE_MIGRATION_V2_ENABLED = 'IS_WORKSPACE_MIGRATION_V2_ENABLED',
|
||||
IS_PAGE_LAYOUT_ENABLED = 'IS_PAGE_LAYOUT_ENABLED',
|
||||
IS_RECORD_PAGE_LAYOUT_ENABLED = 'IS_RECORD_PAGE_LAYOUT_ENABLED',
|
||||
IS_MESSAGE_FOLDER_CONTROL_ENABLED = 'IS_MESSAGE_FOLDER_CONTROL_ENABLED',
|
||||
IS_WORKFLOW_ITERATOR_ENABLED = 'IS_WORKFLOW_ITERATOR_ENABLED',
|
||||
IS_CALENDAR_VIEW_ENABLED = 'IS_CALENDAR_VIEW_ENABLED',
|
||||
|
||||
+9
@@ -136,6 +136,7 @@ describe('WorkspaceEntityManager', () => {
|
||||
IS_CORE_VIEW_ENABLED: false,
|
||||
IS_WORKSPACE_MIGRATION_V2_ENABLED: false,
|
||||
IS_PAGE_LAYOUT_ENABLED: false,
|
||||
IS_RECORD_PAGE_LAYOUT_ENABLED: false,
|
||||
IS_MESSAGE_FOLDER_CONTROL_ENABLED: false,
|
||||
IS_WORKFLOW_ITERATOR_ENABLED: false,
|
||||
IS_CALENDAR_VIEW_ENABLED: false,
|
||||
@@ -168,6 +169,14 @@ describe('WorkspaceEntityManager', () => {
|
||||
IS_CORE_VIEW_ENABLED: false,
|
||||
IS_WORKSPACE_MIGRATION_V2_ENABLED: false,
|
||||
IS_PAGE_LAYOUT_ENABLED: false,
|
||||
IS_RECORD_PAGE_LAYOUT_ENABLED: false,
|
||||
IS_MESSAGE_FOLDER_CONTROL_ENABLED: false,
|
||||
IS_CALENDAR_VIEW_ENABLED: false,
|
||||
IS_GROUP_BY_ENABLED: false,
|
||||
IS_PUBLIC_DOMAIN_ENABLED: false,
|
||||
IS_EMAILING_DOMAIN_ENABLED: false,
|
||||
IS_DYNAMIC_SEARCH_FIELDS_ENABLED: false,
|
||||
IS_COMMON_API_ENABLED: false,
|
||||
IS_WORKFLOW_ITERATOR_ENABLED: false,
|
||||
},
|
||||
permissionsPerRoleId: {},
|
||||
|
||||
+5
@@ -71,6 +71,11 @@ export const seedFeatureFlags = async (
|
||||
workspaceId: workspaceId,
|
||||
value: true,
|
||||
},
|
||||
{
|
||||
key: FeatureFlagKey.IS_RECORD_PAGE_LAYOUT_ENABLED,
|
||||
workspaceId: workspaceId,
|
||||
value: false,
|
||||
},
|
||||
{
|
||||
key: FeatureFlagKey.IS_WORKFLOW_ITERATOR_ENABLED,
|
||||
workspaceId: workspaceId,
|
||||
|
||||
Reference in New Issue
Block a user