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,75 +9,77 @@ import {
|
|||||||
IconTimelineEvent,
|
IconTimelineEvent,
|
||||||
} from 'twenty-ui';
|
} from 'twenty-ui';
|
||||||
|
|
||||||
export const BASE_RECORD_LAYOUT: Record<string, RecordLayoutTab> = {
|
export const BASE_RECORD_LAYOUT: RecordLayout = {
|
||||||
fields: {
|
tabs: {
|
||||||
title: 'Fields',
|
fields: {
|
||||||
Icon: IconList,
|
title: 'Fields',
|
||||||
position: 100,
|
Icon: IconList,
|
||||||
cards: [{ type: CardType.FieldCard }],
|
position: 100,
|
||||||
hide: {
|
cards: [{ type: CardType.FieldCard }],
|
||||||
ifMobile: false,
|
hide: {
|
||||||
ifDesktop: true,
|
ifMobile: false,
|
||||||
ifInRightDrawer: false,
|
ifDesktop: true,
|
||||||
ifFeaturesDisabled: [],
|
ifInRightDrawer: false,
|
||||||
ifRequiredObjectsInactive: [],
|
ifFeaturesDisabled: [],
|
||||||
ifRelationsMissing: [],
|
ifRequiredObjectsInactive: [],
|
||||||
|
ifRelationsMissing: [],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
timeline: {
|
||||||
timeline: {
|
title: 'Timeline',
|
||||||
title: 'Timeline',
|
Icon: IconTimelineEvent,
|
||||||
Icon: IconTimelineEvent,
|
position: 200,
|
||||||
position: 200,
|
cards: [{ type: CardType.TimelineCard }],
|
||||||
cards: [{ type: CardType.TimelineCard }],
|
hide: {
|
||||||
hide: {
|
ifMobile: false,
|
||||||
ifMobile: false,
|
ifDesktop: false,
|
||||||
ifDesktop: false,
|
ifInRightDrawer: true,
|
||||||
ifInRightDrawer: true,
|
ifFeaturesDisabled: [],
|
||||||
ifFeaturesDisabled: [],
|
ifRequiredObjectsInactive: [],
|
||||||
ifRequiredObjectsInactive: [],
|
ifRelationsMissing: [],
|
||||||
ifRelationsMissing: [],
|
},
|
||||||
},
|
},
|
||||||
},
|
tasks: {
|
||||||
tasks: {
|
title: 'Tasks',
|
||||||
title: 'Tasks',
|
Icon: IconCheckbox,
|
||||||
Icon: IconCheckbox,
|
position: 300,
|
||||||
position: 300,
|
cards: [{ type: CardType.TaskCard }],
|
||||||
cards: [{ type: CardType.TaskCard }],
|
hide: {
|
||||||
hide: {
|
ifMobile: false,
|
||||||
ifMobile: false,
|
ifDesktop: false,
|
||||||
ifDesktop: false,
|
ifInRightDrawer: false,
|
||||||
ifInRightDrawer: false,
|
ifFeaturesDisabled: [],
|
||||||
ifFeaturesDisabled: [],
|
ifRequiredObjectsInactive: [CoreObjectNameSingular.Task],
|
||||||
ifRequiredObjectsInactive: [CoreObjectNameSingular.Task],
|
ifRelationsMissing: ['taskTargets'],
|
||||||
ifRelationsMissing: ['taskTargets'],
|
},
|
||||||
},
|
},
|
||||||
},
|
notes: {
|
||||||
notes: {
|
title: 'Notes',
|
||||||
title: 'Notes',
|
Icon: IconNotes,
|
||||||
Icon: IconNotes,
|
position: 400,
|
||||||
position: 400,
|
cards: [{ type: CardType.NoteCard }],
|
||||||
cards: [{ type: CardType.NoteCard }],
|
hide: {
|
||||||
hide: {
|
ifMobile: false,
|
||||||
ifMobile: false,
|
ifDesktop: false,
|
||||||
ifDesktop: false,
|
ifInRightDrawer: false,
|
||||||
ifInRightDrawer: false,
|
ifFeaturesDisabled: [],
|
||||||
ifFeaturesDisabled: [],
|
ifRequiredObjectsInactive: [CoreObjectNameSingular.Note],
|
||||||
ifRequiredObjectsInactive: [CoreObjectNameSingular.Note],
|
ifRelationsMissing: ['noteTargets'],
|
||||||
ifRelationsMissing: ['noteTargets'],
|
},
|
||||||
},
|
},
|
||||||
},
|
files: {
|
||||||
files: {
|
title: 'Files',
|
||||||
title: 'Files',
|
Icon: IconPaperclip,
|
||||||
Icon: IconPaperclip,
|
position: 500,
|
||||||
position: 500,
|
cards: [{ type: CardType.FileCard }],
|
||||||
cards: [{ type: CardType.FileCard }],
|
hide: {
|
||||||
hide: {
|
ifMobile: false,
|
||||||
ifMobile: false,
|
ifDesktop: false,
|
||||||
ifDesktop: false,
|
ifInRightDrawer: false,
|
||||||
ifInRightDrawer: false,
|
ifFeaturesDisabled: [],
|
||||||
ifFeaturesDisabled: [],
|
ifRequiredObjectsInactive: [CoreObjectNameSingular.Attachment],
|
||||||
ifRequiredObjectsInactive: [CoreObjectNameSingular.Attachment],
|
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,235 +34,258 @@ export const useRecordShowContainerTabs = (
|
|||||||
Record<CoreObjectNameSingular, RecordLayout>
|
Record<CoreObjectNameSingular, RecordLayout>
|
||||||
> = {
|
> = {
|
||||||
[CoreObjectNameSingular.Note]: {
|
[CoreObjectNameSingular.Note]: {
|
||||||
richText: {
|
tabs: {
|
||||||
title: 'Note',
|
richText: {
|
||||||
position: 0,
|
title: 'Note',
|
||||||
Icon: IconNotes,
|
position: 0,
|
||||||
cards: [{ type: CardType.RichTextCard }],
|
Icon: IconNotes,
|
||||||
hide: {
|
cards: [{ type: CardType.RichTextCard }],
|
||||||
ifMobile: false,
|
hide: {
|
||||||
ifDesktop: false,
|
ifMobile: false,
|
||||||
ifInRightDrawer: false,
|
ifDesktop: false,
|
||||||
ifFeaturesDisabled: [],
|
ifInRightDrawer: false,
|
||||||
ifRequiredObjectsInactive: [],
|
ifFeaturesDisabled: [],
|
||||||
ifRelationsMissing: [],
|
ifRequiredObjectsInactive: [],
|
||||||
|
ifRelationsMissing: [],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
tasks: null,
|
||||||
|
notes: null,
|
||||||
},
|
},
|
||||||
tasks: null,
|
|
||||||
notes: null,
|
|
||||||
},
|
},
|
||||||
[CoreObjectNameSingular.Task]: {
|
[CoreObjectNameSingular.Task]: {
|
||||||
richText: {
|
tabs: {
|
||||||
title: 'Note',
|
richText: {
|
||||||
position: 0,
|
title: 'Note',
|
||||||
Icon: IconNotes,
|
position: 0,
|
||||||
cards: [{ type: CardType.RichTextCard }],
|
Icon: IconNotes,
|
||||||
hide: {
|
cards: [{ type: CardType.RichTextCard }],
|
||||||
ifMobile: false,
|
hide: {
|
||||||
ifDesktop: false,
|
ifMobile: false,
|
||||||
ifInRightDrawer: false,
|
ifDesktop: false,
|
||||||
ifFeaturesDisabled: [],
|
ifInRightDrawer: false,
|
||||||
ifRequiredObjectsInactive: [],
|
ifFeaturesDisabled: [],
|
||||||
ifRelationsMissing: [],
|
ifRequiredObjectsInactive: [],
|
||||||
|
ifRelationsMissing: [],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
tasks: null,
|
||||||
|
notes: null,
|
||||||
},
|
},
|
||||||
tasks: null,
|
|
||||||
notes: null,
|
|
||||||
},
|
},
|
||||||
[CoreObjectNameSingular.Company]: {
|
[CoreObjectNameSingular.Company]: {
|
||||||
emails: {
|
tabs: {
|
||||||
title: 'Emails',
|
emails: {
|
||||||
position: 600,
|
title: 'Emails',
|
||||||
Icon: IconMail,
|
position: 600,
|
||||||
cards: [{ type: CardType.EmailCard }],
|
Icon: IconMail,
|
||||||
hide: {
|
cards: [{ type: CardType.EmailCard }],
|
||||||
ifMobile: false,
|
hide: {
|
||||||
ifDesktop: false,
|
ifMobile: false,
|
||||||
ifInRightDrawer: false,
|
ifDesktop: false,
|
||||||
ifFeaturesDisabled: [],
|
ifInRightDrawer: false,
|
||||||
ifRequiredObjectsInactive: [],
|
ifFeaturesDisabled: [],
|
||||||
ifRelationsMissing: [],
|
ifRequiredObjectsInactive: [],
|
||||||
|
ifRelationsMissing: [],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
calendar: {
|
||||||
calendar: {
|
title: 'Calendar',
|
||||||
title: 'Calendar',
|
position: 700,
|
||||||
position: 700,
|
Icon: IconCalendarEvent,
|
||||||
Icon: IconCalendarEvent,
|
cards: [{ type: CardType.CalendarCard }],
|
||||||
cards: [{ type: CardType.CalendarCard }],
|
hide: {
|
||||||
hide: {
|
ifMobile: false,
|
||||||
ifMobile: false,
|
ifDesktop: false,
|
||||||
ifDesktop: false,
|
ifInRightDrawer: false,
|
||||||
ifInRightDrawer: false,
|
ifFeaturesDisabled: [],
|
||||||
ifFeaturesDisabled: [],
|
ifRequiredObjectsInactive: [],
|
||||||
ifRequiredObjectsInactive: [],
|
ifRelationsMissing: [],
|
||||||
ifRelationsMissing: [],
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
[CoreObjectNameSingular.Person]: {
|
[CoreObjectNameSingular.Person]: {
|
||||||
emails: {
|
tabs: {
|
||||||
title: 'Emails',
|
emails: {
|
||||||
position: 600,
|
title: 'Emails',
|
||||||
Icon: IconMail,
|
position: 600,
|
||||||
cards: [{ type: CardType.EmailCard }],
|
Icon: IconMail,
|
||||||
hide: {
|
cards: [{ type: CardType.EmailCard }],
|
||||||
ifMobile: false,
|
hide: {
|
||||||
ifDesktop: false,
|
ifMobile: false,
|
||||||
ifInRightDrawer: false,
|
ifDesktop: false,
|
||||||
ifFeaturesDisabled: [],
|
ifInRightDrawer: false,
|
||||||
ifRequiredObjectsInactive: [],
|
ifFeaturesDisabled: [],
|
||||||
ifRelationsMissing: [],
|
ifRequiredObjectsInactive: [],
|
||||||
|
ifRelationsMissing: [],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
calendar: {
|
||||||
calendar: {
|
title: 'Calendar',
|
||||||
title: 'Calendar',
|
position: 700,
|
||||||
position: 700,
|
Icon: IconCalendarEvent,
|
||||||
Icon: IconCalendarEvent,
|
cards: [{ type: CardType.CalendarCard }],
|
||||||
cards: [{ type: CardType.CalendarCard }],
|
hide: {
|
||||||
hide: {
|
ifMobile: false,
|
||||||
ifMobile: false,
|
ifDesktop: false,
|
||||||
ifDesktop: false,
|
ifInRightDrawer: false,
|
||||||
ifInRightDrawer: false,
|
ifFeaturesDisabled: [],
|
||||||
ifFeaturesDisabled: [],
|
ifRequiredObjectsInactive: [],
|
||||||
ifRequiredObjectsInactive: [],
|
ifRelationsMissing: [],
|
||||||
ifRelationsMissing: [],
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
[CoreObjectNameSingular.Workflow]: {
|
[CoreObjectNameSingular.Workflow]: {
|
||||||
workflow: {
|
hideSummaryAndFields: true,
|
||||||
title: 'Flow',
|
tabs: {
|
||||||
position: 0,
|
workflow: {
|
||||||
Icon: IconSettings,
|
title: 'Flow',
|
||||||
cards: [{ type: CardType.WorkflowCard }],
|
position: 0,
|
||||||
hide: {
|
Icon: IconSettings,
|
||||||
ifMobile: false,
|
cards: [{ type: CardType.WorkflowCard }],
|
||||||
ifDesktop: false,
|
hide: {
|
||||||
ifInRightDrawer: false,
|
ifMobile: false,
|
||||||
ifFeaturesDisabled: ['IS_WORKFLOW_ENABLED'],
|
ifDesktop: false,
|
||||||
ifRequiredObjectsInactive: [],
|
ifInRightDrawer: false,
|
||||||
ifRelationsMissing: [],
|
ifFeaturesDisabled: ['IS_WORKFLOW_ENABLED'],
|
||||||
|
ifRequiredObjectsInactive: [],
|
||||||
|
ifRelationsMissing: [],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
timeline: null,
|
||||||
|
fields: null,
|
||||||
},
|
},
|
||||||
timeline: null,
|
|
||||||
},
|
},
|
||||||
[CoreObjectNameSingular.WorkflowVersion]: {
|
[CoreObjectNameSingular.WorkflowVersion]: {
|
||||||
workflowVersion: {
|
tabs: {
|
||||||
title: 'Flow',
|
workflowVersion: {
|
||||||
position: 0,
|
title: 'Flow',
|
||||||
Icon: IconSettings,
|
position: 0,
|
||||||
cards: [{ type: CardType.WorkflowVersionCard }],
|
Icon: IconSettings,
|
||||||
hide: {
|
cards: [{ type: CardType.WorkflowVersionCard }],
|
||||||
ifMobile: false,
|
hide: {
|
||||||
ifDesktop: false,
|
ifMobile: false,
|
||||||
ifInRightDrawer: false,
|
ifDesktop: false,
|
||||||
ifFeaturesDisabled: ['IS_WORKFLOW_ENABLED'],
|
ifInRightDrawer: false,
|
||||||
ifRequiredObjectsInactive: [],
|
ifFeaturesDisabled: ['IS_WORKFLOW_ENABLED'],
|
||||||
ifRelationsMissing: [],
|
ifRequiredObjectsInactive: [],
|
||||||
|
ifRelationsMissing: [],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
timeline: null,
|
||||||
},
|
},
|
||||||
timeline: null,
|
|
||||||
},
|
},
|
||||||
[CoreObjectNameSingular.WorkflowRun]: {
|
[CoreObjectNameSingular.WorkflowRun]: {
|
||||||
workflowRunOutput: {
|
tabs: {
|
||||||
title: 'Output',
|
workflowRunOutput: {
|
||||||
position: 0,
|
title: 'Output',
|
||||||
Icon: IconPrinter,
|
position: 0,
|
||||||
cards: [{ type: CardType.WorkflowRunOutputCard }],
|
Icon: IconPrinter,
|
||||||
hide: {
|
cards: [{ type: CardType.WorkflowRunOutputCard }],
|
||||||
ifMobile: false,
|
hide: {
|
||||||
ifDesktop: false,
|
ifMobile: false,
|
||||||
ifInRightDrawer: false,
|
ifDesktop: false,
|
||||||
ifFeaturesDisabled: ['IS_WORKFLOW_ENABLED'],
|
ifInRightDrawer: false,
|
||||||
ifRequiredObjectsInactive: [],
|
ifFeaturesDisabled: ['IS_WORKFLOW_ENABLED'],
|
||||||
ifRelationsMissing: [],
|
ifRequiredObjectsInactive: [],
|
||||||
|
ifRelationsMissing: [],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
workflowRunFlow: {
|
||||||
workflowRunFlow: {
|
title: 'Flow',
|
||||||
title: 'Flow',
|
position: 0,
|
||||||
position: 0,
|
Icon: IconSettings,
|
||||||
Icon: IconSettings,
|
cards: [{ type: CardType.WorkflowRunCard }],
|
||||||
cards: [{ type: CardType.WorkflowRunCard }],
|
hide: {
|
||||||
hide: {
|
ifMobile: false,
|
||||||
ifMobile: false,
|
ifDesktop: false,
|
||||||
ifDesktop: false,
|
ifInRightDrawer: false,
|
||||||
ifInRightDrawer: false,
|
ifFeaturesDisabled: ['IS_WORKFLOW_ENABLED'],
|
||||||
ifFeaturesDisabled: ['IS_WORKFLOW_ENABLED'],
|
ifRequiredObjectsInactive: [],
|
||||||
ifRequiredObjectsInactive: [],
|
ifRelationsMissing: [],
|
||||||
ifRelationsMissing: [],
|
},
|
||||||
},
|
},
|
||||||
|
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 {
|
||||||
.filter(
|
layout: recordLayout,
|
||||||
(entry): entry is [string, NonNullable<RecordLayoutTab>] =>
|
tabs: Object.entries(recordLayout.tabs)
|
||||||
entry[1] !== null && entry[1] !== undefined,
|
.filter(
|
||||||
)
|
(entry): entry is [string, NonNullable<RecordLayoutTab>] =>
|
||||||
.sort(([, a], [, b]) => a.position - b.position)
|
entry[1] !== null && entry[1] !== undefined,
|
||||||
.map(([key, { title, Icon, hide, cards }]) => {
|
)
|
||||||
// Special handling for fields tab
|
.sort(([, a], [, b]) => a.position - b.position)
|
||||||
if (key === 'fields') {
|
.map(([key, { title, Icon, hide, cards }]) => {
|
||||||
|
// Special handling for fields tab
|
||||||
|
if (key === 'fields') {
|
||||||
|
return {
|
||||||
|
id: key,
|
||||||
|
title,
|
||||||
|
Icon,
|
||||||
|
cards,
|
||||||
|
hide: !(isMobile || isInRightDrawer),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const baseHide =
|
||||||
|
(hide.ifMobile && isMobile) ||
|
||||||
|
(hide.ifDesktop && !isMobile) ||
|
||||||
|
(hide.ifInRightDrawer && isInRightDrawer);
|
||||||
|
|
||||||
|
const featureNotEnabled =
|
||||||
|
hide.ifFeaturesDisabled.length > 0 &&
|
||||||
|
!hide.ifFeaturesDisabled.every((flagKey) => {
|
||||||
|
return !!currentWorkspace?.featureFlags?.find(
|
||||||
|
(flag: FeatureFlag) => flag.key === flagKey && flag.value,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
const requiredObjectsInactive =
|
||||||
|
hide.ifRequiredObjectsInactive.length > 0 &&
|
||||||
|
!hide.ifRequiredObjectsInactive.every((obj) =>
|
||||||
|
objectMetadataItems.some(
|
||||||
|
(item) => item.nameSingular === obj && item.isActive,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
const relationsDontExist =
|
||||||
|
hide.ifRelationsMissing.length > 0 &&
|
||||||
|
!hide.ifRelationsMissing.every((rel) =>
|
||||||
|
objectMetadataItem.fields.some(
|
||||||
|
(field) =>
|
||||||
|
field.type === FieldMetadataType.Relation &&
|
||||||
|
field.name === rel &&
|
||||||
|
field.isActive,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: key,
|
id: key,
|
||||||
title,
|
title,
|
||||||
Icon,
|
Icon,
|
||||||
cards,
|
cards,
|
||||||
hide: !(isMobile || isInRightDrawer),
|
hide:
|
||||||
|
loading ||
|
||||||
|
baseHide ||
|
||||||
|
featureNotEnabled ||
|
||||||
|
requiredObjectsInactive ||
|
||||||
|
relationsDontExist,
|
||||||
};
|
};
|
||||||
}
|
}),
|
||||||
|
};
|
||||||
const baseHide =
|
|
||||||
(hide.ifMobile && isMobile) ||
|
|
||||||
(hide.ifDesktop && !isMobile) ||
|
|
||||||
(hide.ifInRightDrawer && isInRightDrawer);
|
|
||||||
|
|
||||||
const featureNotEnabled =
|
|
||||||
hide.ifFeaturesDisabled.length > 0 &&
|
|
||||||
!hide.ifFeaturesDisabled.every((flagKey) => {
|
|
||||||
return !!currentWorkspace?.featureFlags?.find(
|
|
||||||
(flag: FeatureFlag) => flag.key === flagKey && flag.value,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
const requiredObjectsInactive =
|
|
||||||
hide.ifRequiredObjectsInactive.length > 0 &&
|
|
||||||
!hide.ifRequiredObjectsInactive.every((obj) =>
|
|
||||||
objectMetadataItems.some(
|
|
||||||
(item) => item.nameSingular === obj && item.isActive,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
const relationsDontExist =
|
|
||||||
hide.ifRelationsMissing.length > 0 &&
|
|
||||||
!hide.ifRelationsMissing.every((rel) =>
|
|
||||||
objectMetadataItem.fields.some(
|
|
||||||
(field) =>
|
|
||||||
field.type === FieldMetadataType.Relation &&
|
|
||||||
field.name === rel &&
|
|
||||||
field.isActive,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
return {
|
|
||||||
id: key,
|
|
||||||
title,
|
|
||||||
Icon,
|
|
||||||
cards,
|
|
||||||
hide:
|
|
||||||
loading ||
|
|
||||||
baseHide ||
|
|
||||||
featureNotEnabled ||
|
|
||||||
requiredObjectsInactive ||
|
|
||||||
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,26 +70,24 @@ 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)
|
<Tab
|
||||||
.map((tab) => (
|
id={tab.id}
|
||||||
<Tab
|
key={tab.id}
|
||||||
id={tab.id}
|
title={tab.title}
|
||||||
key={tab.id}
|
Icon={tab.Icon}
|
||||||
title={tab.title}
|
logo={tab.logo}
|
||||||
Icon={tab.Icon}
|
active={tab.id === activeTabId}
|
||||||
logo={tab.logo}
|
disabled={tab.disabled ?? loading}
|
||||||
active={tab.id === activeTabId}
|
pill={tab.pill}
|
||||||
disabled={tab.disabled ?? loading}
|
to={behaveAsLinks ? `#${tab.id}` : undefined}
|
||||||
pill={tab.pill}
|
onClick={() => {
|
||||||
to={behaveAsLinks ? `#${tab.id}` : undefined}
|
if (!behaveAsLinks) {
|
||||||
onClick={() => {
|
setActiveTabId(tab.id);
|
||||||
if (!behaveAsLinks) {
|
}
|
||||||
setActiveTabId(tab.id);
|
}}
|
||||||
}
|
/>
|
||||||
}}
|
))}
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</StyledContainer>
|
</StyledContainer>
|
||||||
</ScrollWrapper>
|
</ScrollWrapper>
|
||||||
</TabListScope>
|
</TabListScope>
|
||||||
|
|||||||
Reference in New Issue
Block a user