Create a right drawer for viewing steps in workflow runs (#10366)
- Improve the type-safety of the objects mapping the id of a right drawer or side panel view to a React component - Improve the types of the `useTabList` hook to type the available tab identifiers strictly - Create a specialized `WorkflowRunDiagramCanvas` component to render a `WorkflowRunDiagramCanvasEffect` component that opens `RightDrawerPages.WorkflowRunStepView` when a step is selected - Create a new side panel view specifically for workflow run step details - Create tab list in the new side panel; all the tabs are `Node`, `Input` and `Output` - Create a hook `useWorkflowSelectedNodeOrThrow` not to duplicate throwing mechanisms Closes https://github.com/twentyhq/core-team-issues/issues/432 ## Demo https://github.com/user-attachments/assets/8d5df7dc-0b99-49a2-9a54-d3eaee80a8e6
This commit is contained in:
committed by
GitHub
parent
694553608b
commit
f74e4bedc4
@ -9,8 +9,8 @@ import { isRightDrawerMinimizedState } from '@/ui/layout/right-drawer/states/isR
|
||||
|
||||
import { RightDrawerContainer } from '@/ui/layout/right-drawer/components/RightDrawerContainer';
|
||||
import { RightDrawerTopBar } from '@/ui/layout/right-drawer/components/RightDrawerTopBar';
|
||||
import { ComponentByRightDrawerPage } from '@/ui/layout/right-drawer/types/ComponentByRightDrawerPage';
|
||||
import { RightDrawerWorkflowEditStep } from '@/workflow/workflow-steps/components/RightDrawerWorkflowEditStep';
|
||||
import { RightDrawerWorkflowRunViewStep } from '@/workflow/workflow-steps/components/RightDrawerWorkflowRunViewStep';
|
||||
import { RightDrawerWorkflowViewStep } from '@/workflow/workflow-steps/components/RightDrawerWorkflowViewStep';
|
||||
import { RightDrawerWorkflowSelectAction } from '@/workflow/workflow-steps/workflow-actions/components/RightDrawerWorkflowSelectAction';
|
||||
import { RightDrawerWorkflowSelectTriggerType } from '@/workflow/workflow-trigger/components/RightDrawerWorkflowSelectTriggerType';
|
||||
@ -28,7 +28,7 @@ const StyledRightDrawerBody = styled.div`
|
||||
position: relative;
|
||||
`;
|
||||
|
||||
const RIGHT_DRAWER_PAGES_CONFIG: ComponentByRightDrawerPage = {
|
||||
const RIGHT_DRAWER_PAGES_CONFIG = {
|
||||
[RightDrawerPages.ViewEmailThread]: <RightDrawerEmailThread />,
|
||||
[RightDrawerPages.ViewCalendarEvent]: <RightDrawerCalendarEvent />,
|
||||
[RightDrawerPages.ViewRecord]: <RightDrawerRecord />,
|
||||
@ -41,7 +41,8 @@ const RIGHT_DRAWER_PAGES_CONFIG: ComponentByRightDrawerPage = {
|
||||
),
|
||||
[RightDrawerPages.WorkflowStepEdit]: <RightDrawerWorkflowEditStep />,
|
||||
[RightDrawerPages.WorkflowStepView]: <RightDrawerWorkflowViewStep />,
|
||||
};
|
||||
[RightDrawerPages.WorkflowRunStepView]: <RightDrawerWorkflowRunViewStep />,
|
||||
} satisfies Record<RightDrawerPages, JSX.Element>;
|
||||
|
||||
export const RightDrawerRouter = () => {
|
||||
const [rightDrawerPage] = useRecoilState(rightDrawerPageState);
|
||||
|
||||
@ -9,4 +9,5 @@ export const RIGHT_DRAWER_PAGE_ICONS = {
|
||||
[RightDrawerPages.WorkflowStepSelectAction]: 'IconSparkles',
|
||||
[RightDrawerPages.WorkflowStepEdit]: 'IconSparkles',
|
||||
[RightDrawerPages.WorkflowStepView]: 'IconSparkles',
|
||||
};
|
||||
[RightDrawerPages.WorkflowRunStepView]: 'IconSparkles',
|
||||
} satisfies Record<RightDrawerPages, string>;
|
||||
|
||||
@ -9,4 +9,5 @@ export const RIGHT_DRAWER_PAGE_TITLES = {
|
||||
[RightDrawerPages.WorkflowStepSelectAction]: 'Workflow',
|
||||
[RightDrawerPages.WorkflowStepEdit]: 'Workflow',
|
||||
[RightDrawerPages.WorkflowStepView]: 'Workflow',
|
||||
};
|
||||
[RightDrawerPages.WorkflowRunStepView]: 'Workflow',
|
||||
} satisfies Record<RightDrawerPages, string>;
|
||||
|
||||
@ -1,5 +0,0 @@
|
||||
import { RightDrawerPages } from '@/ui/layout/right-drawer/types/RightDrawerPages';
|
||||
|
||||
export type ComponentByRightDrawerPage = {
|
||||
[componentName in RightDrawerPages]?: JSX.Element;
|
||||
};
|
||||
@ -7,4 +7,5 @@ export enum RightDrawerPages {
|
||||
WorkflowStepSelectAction = 'workflow-step-select-action',
|
||||
WorkflowStepView = 'workflow-step-view',
|
||||
WorkflowStepEdit = 'workflow-step-edit',
|
||||
WorkflowRunStepView = 'workflow-run-step-view',
|
||||
}
|
||||
|
||||
@ -4,24 +4,25 @@ import { RightDrawerPages } from '@/ui/layout/right-drawer/types/RightDrawerPage
|
||||
export const mapRightDrawerPageToCommandMenuPage = (
|
||||
rightDrawerPage: RightDrawerPages,
|
||||
) => {
|
||||
switch (rightDrawerPage) {
|
||||
case RightDrawerPages.ViewRecord:
|
||||
return CommandMenuPages.ViewRecord;
|
||||
case RightDrawerPages.ViewEmailThread:
|
||||
return CommandMenuPages.ViewEmailThread;
|
||||
case RightDrawerPages.ViewCalendarEvent:
|
||||
return CommandMenuPages.ViewCalendarEvent;
|
||||
case RightDrawerPages.Copilot:
|
||||
return CommandMenuPages.Copilot;
|
||||
case RightDrawerPages.WorkflowStepSelectTriggerType:
|
||||
return CommandMenuPages.WorkflowStepSelectTriggerType;
|
||||
case RightDrawerPages.WorkflowStepSelectAction:
|
||||
return CommandMenuPages.WorkflowStepSelectAction;
|
||||
case RightDrawerPages.WorkflowStepView:
|
||||
return CommandMenuPages.WorkflowStepView;
|
||||
case RightDrawerPages.WorkflowStepEdit:
|
||||
return CommandMenuPages.WorkflowStepEdit;
|
||||
default:
|
||||
return CommandMenuPages.Root;
|
||||
}
|
||||
const rightDrawerPagesToCommandMenuPages: Record<
|
||||
RightDrawerPages,
|
||||
CommandMenuPages
|
||||
> = {
|
||||
[RightDrawerPages.ViewRecord]: CommandMenuPages.ViewRecord,
|
||||
[RightDrawerPages.ViewEmailThread]: CommandMenuPages.ViewEmailThread,
|
||||
[RightDrawerPages.ViewCalendarEvent]: CommandMenuPages.ViewCalendarEvent,
|
||||
[RightDrawerPages.Copilot]: CommandMenuPages.Copilot,
|
||||
[RightDrawerPages.WorkflowStepSelectTriggerType]:
|
||||
CommandMenuPages.WorkflowStepSelectTriggerType,
|
||||
[RightDrawerPages.WorkflowStepSelectAction]:
|
||||
CommandMenuPages.WorkflowStepSelectAction,
|
||||
[RightDrawerPages.WorkflowStepView]: CommandMenuPages.WorkflowStepView,
|
||||
[RightDrawerPages.WorkflowRunStepView]:
|
||||
CommandMenuPages.WorkflowRunStepView,
|
||||
[RightDrawerPages.WorkflowStepEdit]: CommandMenuPages.WorkflowStepEdit,
|
||||
};
|
||||
|
||||
return (
|
||||
rightDrawerPagesToCommandMenuPages[rightDrawerPage] ?? CommandMenuPages.Root
|
||||
);
|
||||
};
|
||||
|
||||
@ -9,6 +9,7 @@ import { recordStoreFamilyState } from '@/object-record/record-store/states/reco
|
||||
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||
import { RightDrawerFooter } from '@/ui/layout/right-drawer/components/RightDrawerFooter';
|
||||
import { ShowPageLeftContainer } from '@/ui/layout/show-page/components/ShowPageLeftContainer';
|
||||
import { ShowPageSubContainerTabListContainer } from '@/ui/layout/show-page/components/ShowPageSubContainerTabListContainer';
|
||||
import { SingleTabProps, TabList } from '@/ui/layout/tab/components/TabList';
|
||||
import { useTabList } from '@/ui/layout/tab/hooks/useTabList';
|
||||
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
|
||||
@ -26,14 +27,8 @@ const StyledShowPageRightContainer = styled.div<{ isMobile: boolean }>`
|
||||
`;
|
||||
|
||||
const StyledTabListContainer = styled.div<{ shouldDisplay: boolean }>`
|
||||
align-items: center;
|
||||
padding-left: ${({ theme }) => theme.spacing(2)};
|
||||
border-bottom: ${({ theme }) => `1px solid ${theme.border.color.light}`};
|
||||
box-sizing: border-box;
|
||||
display: ${({ shouldDisplay }) => (shouldDisplay ? 'flex' : 'none')};
|
||||
gap: ${({ theme }) => theme.spacing(2)};
|
||||
height: 40px;
|
||||
`;
|
||||
`.withComponent(ShowPageSubContainerTabListContainer);
|
||||
|
||||
const StyledContentContainer = styled.div<{ isInRightDrawer: boolean }>`
|
||||
flex: 1;
|
||||
|
||||
@ -0,0 +1,13 @@
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
const StyledTabListContainer = styled.div`
|
||||
align-items: center;
|
||||
padding-left: ${({ theme }) => theme.spacing(2)};
|
||||
border-bottom: ${({ theme }) => `1px solid ${theme.border.color.light}`};
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
gap: ${({ theme }) => theme.spacing(2)};
|
||||
height: 40px;
|
||||
`;
|
||||
|
||||
export { StyledTabListContainer as ShowPageSubContainerTabListContainer };
|
||||
@ -9,10 +9,10 @@ import { useEffect } from 'react';
|
||||
import { IconComponent } from 'twenty-ui';
|
||||
import { Tab } from './Tab';
|
||||
|
||||
export type SingleTabProps = {
|
||||
export type SingleTabProps<T extends string = string> = {
|
||||
title: string;
|
||||
Icon?: IconComponent;
|
||||
id: string;
|
||||
id: T;
|
||||
hide?: boolean;
|
||||
disabled?: boolean;
|
||||
pill?: string | React.ReactElement;
|
||||
|
||||
@ -1,13 +1,15 @@
|
||||
import { useRecoilState } from 'recoil';
|
||||
import { RecoilState, useRecoilState } from 'recoil';
|
||||
|
||||
import { useTabListStates } from '@/ui/layout/tab/hooks/internal/useTabListStates';
|
||||
|
||||
export const useTabList = (tabListId?: string) => {
|
||||
export const useTabList = <T extends string>(tabListId?: string) => {
|
||||
const { activeTabIdState } = useTabListStates({
|
||||
tabListScopeId: tabListId,
|
||||
});
|
||||
|
||||
const [activeTabId, setActiveTabId] = useRecoilState(activeTabIdState);
|
||||
const [activeTabId, setActiveTabId] = useRecoilState(
|
||||
activeTabIdState as RecoilState<T | null>,
|
||||
);
|
||||
|
||||
return {
|
||||
activeTabId,
|
||||
|
||||
Reference in New Issue
Block a user