Don't show summary/fields on workflow record pages (#8804)
Hiding the left column on workflow pages This raises additional questions: how do we edit the title then? Probably need a significant refacto of PageHeader <img width="1094" alt="Screenshot 2024-11-29 at 10 01 08" src="https://github.com/user-attachments/assets/b98d55cb-5097-4e46-bac5-5570d9ca0ad8">
This commit is contained in:
@ -35,7 +35,7 @@ export const RecordShowContainer = ({
|
|||||||
objectRecordId,
|
objectRecordId,
|
||||||
});
|
});
|
||||||
|
|
||||||
const tabs = useRecordShowContainerTabs(
|
const { layout, tabs } = useRecordShowContainerTabs(
|
||||||
loading,
|
loading,
|
||||||
objectNameSingular as CoreObjectNameSingular,
|
objectNameSingular as CoreObjectNameSingular,
|
||||||
isInRightDrawer,
|
isInRightDrawer,
|
||||||
@ -61,6 +61,7 @@ export const RecordShowContainer = ({
|
|||||||
<ShowPageContainer>
|
<ShowPageContainer>
|
||||||
<ShowPageSubContainer
|
<ShowPageSubContainer
|
||||||
tabs={tabs}
|
tabs={tabs}
|
||||||
|
layout={layout}
|
||||||
targetableObject={{
|
targetableObject={{
|
||||||
id: objectRecordId,
|
id: objectRecordId,
|
||||||
targetObjectNameSingular: objectMetadataItem?.nameSingular,
|
targetObjectNameSingular: objectMetadataItem?.nameSingular,
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||||
import { CardType } from '@/object-record/record-show/types/CardType';
|
import { CardType } from '@/object-record/record-show/types/CardType';
|
||||||
import { RecordLayoutTab } from '@/ui/layout/tab/types/RecordLayoutTab';
|
import { RecordLayout } from '@/object-record/record-show/types/RecordLayout';
|
||||||
import {
|
import {
|
||||||
IconCheckbox,
|
IconCheckbox,
|
||||||
IconList,
|
IconList,
|
||||||
@ -9,7 +9,8 @@ import {
|
|||||||
IconTimelineEvent,
|
IconTimelineEvent,
|
||||||
} from 'twenty-ui';
|
} from 'twenty-ui';
|
||||||
|
|
||||||
export const BASE_RECORD_LAYOUT: Record<string, RecordLayoutTab> = {
|
export const BASE_RECORD_LAYOUT: RecordLayout = {
|
||||||
|
tabs: {
|
||||||
fields: {
|
fields: {
|
||||||
title: 'Fields',
|
title: 'Fields',
|
||||||
Icon: IconList,
|
Icon: IconList,
|
||||||
@ -80,4 +81,5 @@ export const BASE_RECORD_LAYOUT: Record<string, RecordLayoutTab> = {
|
|||||||
ifRelationsMissing: ['attachments'],
|
ifRelationsMissing: ['attachments'],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@ -23,7 +23,7 @@ export const useRecordShowContainerTabs = (
|
|||||||
targetObjectNameSingular: CoreObjectNameSingular,
|
targetObjectNameSingular: CoreObjectNameSingular,
|
||||||
isInRightDrawer: boolean,
|
isInRightDrawer: boolean,
|
||||||
objectMetadataItem: ObjectMetadataItem,
|
objectMetadataItem: ObjectMetadataItem,
|
||||||
): SingleTabProps[] => {
|
): { layout: RecordLayout; tabs: SingleTabProps[] } => {
|
||||||
const isMobile = useIsMobile();
|
const isMobile = useIsMobile();
|
||||||
const objectMetadataItems = useRecoilValue(objectMetadataItemsState);
|
const objectMetadataItems = useRecoilValue(objectMetadataItemsState);
|
||||||
|
|
||||||
@ -34,6 +34,7 @@ export const useRecordShowContainerTabs = (
|
|||||||
Record<CoreObjectNameSingular, RecordLayout>
|
Record<CoreObjectNameSingular, RecordLayout>
|
||||||
> = {
|
> = {
|
||||||
[CoreObjectNameSingular.Note]: {
|
[CoreObjectNameSingular.Note]: {
|
||||||
|
tabs: {
|
||||||
richText: {
|
richText: {
|
||||||
title: 'Note',
|
title: 'Note',
|
||||||
position: 0,
|
position: 0,
|
||||||
@ -51,7 +52,9 @@ export const useRecordShowContainerTabs = (
|
|||||||
tasks: null,
|
tasks: null,
|
||||||
notes: null,
|
notes: null,
|
||||||
},
|
},
|
||||||
|
},
|
||||||
[CoreObjectNameSingular.Task]: {
|
[CoreObjectNameSingular.Task]: {
|
||||||
|
tabs: {
|
||||||
richText: {
|
richText: {
|
||||||
title: 'Note',
|
title: 'Note',
|
||||||
position: 0,
|
position: 0,
|
||||||
@ -69,7 +72,9 @@ export const useRecordShowContainerTabs = (
|
|||||||
tasks: null,
|
tasks: null,
|
||||||
notes: null,
|
notes: null,
|
||||||
},
|
},
|
||||||
|
},
|
||||||
[CoreObjectNameSingular.Company]: {
|
[CoreObjectNameSingular.Company]: {
|
||||||
|
tabs: {
|
||||||
emails: {
|
emails: {
|
||||||
title: 'Emails',
|
title: 'Emails',
|
||||||
position: 600,
|
position: 600,
|
||||||
@ -99,7 +104,9 @@ export const useRecordShowContainerTabs = (
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
},
|
||||||
[CoreObjectNameSingular.Person]: {
|
[CoreObjectNameSingular.Person]: {
|
||||||
|
tabs: {
|
||||||
emails: {
|
emails: {
|
||||||
title: 'Emails',
|
title: 'Emails',
|
||||||
position: 600,
|
position: 600,
|
||||||
@ -129,7 +136,10 @@ export const useRecordShowContainerTabs = (
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
},
|
||||||
[CoreObjectNameSingular.Workflow]: {
|
[CoreObjectNameSingular.Workflow]: {
|
||||||
|
hideSummaryAndFields: true,
|
||||||
|
tabs: {
|
||||||
workflow: {
|
workflow: {
|
||||||
title: 'Flow',
|
title: 'Flow',
|
||||||
position: 0,
|
position: 0,
|
||||||
@ -145,8 +155,11 @@ export const useRecordShowContainerTabs = (
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
timeline: null,
|
timeline: null,
|
||||||
|
fields: null,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
[CoreObjectNameSingular.WorkflowVersion]: {
|
[CoreObjectNameSingular.WorkflowVersion]: {
|
||||||
|
tabs: {
|
||||||
workflowVersion: {
|
workflowVersion: {
|
||||||
title: 'Flow',
|
title: 'Flow',
|
||||||
position: 0,
|
position: 0,
|
||||||
@ -163,7 +176,9 @@ export const useRecordShowContainerTabs = (
|
|||||||
},
|
},
|
||||||
timeline: null,
|
timeline: null,
|
||||||
},
|
},
|
||||||
|
},
|
||||||
[CoreObjectNameSingular.WorkflowRun]: {
|
[CoreObjectNameSingular.WorkflowRun]: {
|
||||||
|
tabs: {
|
||||||
workflowRunOutput: {
|
workflowRunOutput: {
|
||||||
title: 'Output',
|
title: 'Output',
|
||||||
position: 0,
|
position: 0,
|
||||||
@ -194,15 +209,22 @@ export const useRecordShowContainerTabs = (
|
|||||||
},
|
},
|
||||||
timeline: null,
|
timeline: null,
|
||||||
},
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// Merge base layout with object-specific layout
|
// Merge base layout with object-specific layout
|
||||||
const tabDefinitions: RecordLayout = {
|
const recordLayout: RecordLayout = {
|
||||||
...BASE_RECORD_LAYOUT,
|
...BASE_RECORD_LAYOUT,
|
||||||
...(OBJECT_SPECIFIC_LAYOUTS[targetObjectNameSingular] || {}),
|
...(OBJECT_SPECIFIC_LAYOUTS[targetObjectNameSingular] || {}),
|
||||||
|
tabs: {
|
||||||
|
...BASE_RECORD_LAYOUT.tabs,
|
||||||
|
...(OBJECT_SPECIFIC_LAYOUTS[targetObjectNameSingular]?.tabs || {}),
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
return Object.entries(tabDefinitions)
|
return {
|
||||||
|
layout: recordLayout,
|
||||||
|
tabs: Object.entries(recordLayout.tabs)
|
||||||
.filter(
|
.filter(
|
||||||
(entry): entry is [string, NonNullable<RecordLayoutTab>] =>
|
(entry): entry is [string, NonNullable<RecordLayoutTab>] =>
|
||||||
entry[1] !== null && entry[1] !== undefined,
|
entry[1] !== null && entry[1] !== undefined,
|
||||||
@ -264,5 +286,6 @@ export const useRecordShowContainerTabs = (
|
|||||||
requiredObjectsInactive ||
|
requiredObjectsInactive ||
|
||||||
relationsDontExist,
|
relationsDontExist,
|
||||||
};
|
};
|
||||||
});
|
}),
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,3 +1,6 @@
|
|||||||
import { RecordLayoutTab } from '@/ui/layout/tab/types/RecordLayoutTab';
|
import { RecordLayoutTab } from '@/ui/layout/tab/types/RecordLayoutTab';
|
||||||
|
|
||||||
export type RecordLayout = Record<string, RecordLayoutTab | null>;
|
export type RecordLayout = {
|
||||||
|
hideSummaryAndFields?: boolean;
|
||||||
|
tabs: Record<string, RecordLayoutTab | null>;
|
||||||
|
};
|
||||||
|
|||||||
@ -0,0 +1,3 @@
|
|||||||
|
import { RecordLayout } from '@/object-record/record-show/types/RecordLayout';
|
||||||
|
|
||||||
|
export type RecordLayoutMap = Record<string, RecordLayout | null>;
|
||||||
@ -4,6 +4,7 @@ import { isNewViewableRecordLoadingState } from '@/object-record/record-right-dr
|
|||||||
import { CardComponents } from '@/object-record/record-show/components/CardComponents';
|
import { CardComponents } from '@/object-record/record-show/components/CardComponents';
|
||||||
import { FieldsCard } from '@/object-record/record-show/components/FieldsCard';
|
import { FieldsCard } from '@/object-record/record-show/components/FieldsCard';
|
||||||
import { SummaryCard } from '@/object-record/record-show/components/SummaryCard';
|
import { SummaryCard } from '@/object-record/record-show/components/SummaryCard';
|
||||||
|
import { RecordLayout } from '@/object-record/record-show/types/RecordLayout';
|
||||||
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
|
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
|
||||||
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||||
import { ShowPageLeftContainer } from '@/ui/layout/show-page/components/ShowPageLeftContainer';
|
import { ShowPageLeftContainer } from '@/ui/layout/show-page/components/ShowPageLeftContainer';
|
||||||
@ -23,12 +24,12 @@ const StyledShowPageRightContainer = styled.div<{ isMobile: boolean }>`
|
|||||||
overflow: auto;
|
overflow: auto;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const StyledTabListContainer = styled.div`
|
const StyledTabListContainer = styled.div<{ shouldDisplay: boolean }>`
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding-left: ${({ theme }) => theme.spacing(2)};
|
padding-left: ${({ theme }) => theme.spacing(2)};
|
||||||
border-bottom: ${({ theme }) => `1px solid ${theme.border.color.light}`};
|
border-bottom: ${({ theme }) => `1px solid ${theme.border.color.light}`};
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
display: flex;
|
display: ${({ shouldDisplay }) => (shouldDisplay ? 'flex' : 'none')};
|
||||||
gap: ${({ theme }) => theme.spacing(2)};
|
gap: ${({ theme }) => theme.spacing(2)};
|
||||||
height: 40px;
|
height: 40px;
|
||||||
`;
|
`;
|
||||||
@ -56,6 +57,7 @@ const StyledContentContainer = styled.div<{ isInRightDrawer: boolean }>`
|
|||||||
export const TAB_LIST_COMPONENT_ID = 'show-page-right-tab-list';
|
export const TAB_LIST_COMPONENT_ID = 'show-page-right-tab-list';
|
||||||
|
|
||||||
type ShowPageSubContainerProps = {
|
type ShowPageSubContainerProps = {
|
||||||
|
layout: RecordLayout;
|
||||||
tabs: SingleTabProps[];
|
tabs: SingleTabProps[];
|
||||||
targetableObject: Pick<
|
targetableObject: Pick<
|
||||||
ActivityTargetableObject,
|
ActivityTargetableObject,
|
||||||
@ -68,6 +70,7 @@ type ShowPageSubContainerProps = {
|
|||||||
|
|
||||||
export const ShowPageSubContainer = ({
|
export const ShowPageSubContainer = ({
|
||||||
tabs,
|
tabs,
|
||||||
|
layout,
|
||||||
targetableObject,
|
targetableObject,
|
||||||
loading,
|
loading,
|
||||||
isInRightDrawer = false,
|
isInRightDrawer = false,
|
||||||
@ -120,16 +123,18 @@ export const ShowPageSubContainer = ({
|
|||||||
recordStoreFamilyState(targetableObject.id),
|
recordStoreFamilyState(targetableObject.id),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const visibleTabs = tabs.filter((tab) => !tab.hide);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{!isMobile && !isInRightDrawer && (
|
{!layout.hideSummaryAndFields && !isMobile && !isInRightDrawer && (
|
||||||
<ShowPageLeftContainer forceMobile={isMobile}>
|
<ShowPageLeftContainer forceMobile={isMobile}>
|
||||||
{summaryCard}
|
{summaryCard}
|
||||||
{fieldsCard}
|
{fieldsCard}
|
||||||
</ShowPageLeftContainer>
|
</ShowPageLeftContainer>
|
||||||
)}
|
)}
|
||||||
<StyledShowPageRightContainer isMobile={isMobile}>
|
<StyledShowPageRightContainer isMobile={isMobile}>
|
||||||
<StyledTabListContainer>
|
<StyledTabListContainer shouldDisplay={visibleTabs.length > 1}>
|
||||||
<TabList
|
<TabList
|
||||||
behaveAsLinks={!isInRightDrawer}
|
behaveAsLinks={!isInRightDrawer}
|
||||||
loading={loading || isNewViewableRecordLoading}
|
loading={loading || isNewViewableRecordLoading}
|
||||||
|
|||||||
@ -46,7 +46,9 @@ export const TabList = ({
|
|||||||
className,
|
className,
|
||||||
behaveAsLinks = true,
|
behaveAsLinks = true,
|
||||||
}: TabListProps) => {
|
}: TabListProps) => {
|
||||||
const initialActiveTabId = tabs.find((tab) => !tab.hide)?.id || '';
|
const visibleTabs = tabs.filter((tab) => !tab.hide);
|
||||||
|
|
||||||
|
const initialActiveTabId = visibleTabs[0]?.id || '';
|
||||||
|
|
||||||
const { activeTabIdState, setActiveTabId } = useTabList(tabListInstanceId);
|
const { activeTabIdState, setActiveTabId } = useTabList(tabListInstanceId);
|
||||||
|
|
||||||
@ -56,6 +58,10 @@ export const TabList = ({
|
|||||||
setActiveTabId(initialActiveTabId);
|
setActiveTabId(initialActiveTabId);
|
||||||
}, [initialActiveTabId, setActiveTabId]);
|
}, [initialActiveTabId, setActiveTabId]);
|
||||||
|
|
||||||
|
if (visibleTabs.length <= 1) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TabListScope tabListScopeId={tabListInstanceId}>
|
<TabListScope tabListScopeId={tabListInstanceId}>
|
||||||
<TabListFromUrlOptionalEffect
|
<TabListFromUrlOptionalEffect
|
||||||
@ -64,9 +70,7 @@ export const TabList = ({
|
|||||||
/>
|
/>
|
||||||
<ScrollWrapper enableYScroll={false} contextProviderName="tabList">
|
<ScrollWrapper enableYScroll={false} contextProviderName="tabList">
|
||||||
<StyledContainer className={className}>
|
<StyledContainer className={className}>
|
||||||
{tabs
|
{visibleTabs.map((tab) => (
|
||||||
.filter((tab) => !tab.hide)
|
|
||||||
.map((tab) => (
|
|
||||||
<Tab
|
<Tab
|
||||||
id={tab.id}
|
id={tab.id}
|
||||||
key={tab.id}
|
key={tab.id}
|
||||||
|
|||||||
Reference in New Issue
Block a user