Visualize workflow run step output (#10730)
- Displays the output of the selected step in the `Output` tab - Access to the `Output` tab is prevented when the selected node is currently executed or was skipped - Display the status of the workflow run instead of the status of the workflow version at the top left corner of the workflow run visualizer - Fixed the icon's color for disabled tabs - Use text/primary color for the step's name even when the input is disabled ## Demo: Successful execution https://github.com/user-attachments/assets/02e492f3-1589-48e9-926e-7edb031d9210 ## Demo: Failed execution https://github.com/user-attachments/assets/73e5ec86-5f38-4306-aa9a-46b2e73950da Closes https://github.com/twentyhq/core-team-issues/issues/434
This commit is contained in:
committed by
GitHub
parent
0e1d742f3d
commit
b49ec864b1
@ -6,6 +6,7 @@ import { useWorkflowRun } from '@/workflow/hooks/useWorkflowRun';
|
||||
import { useWorkflowRunIdOrThrow } from '@/workflow/hooks/useWorkflowRunIdOrThrow';
|
||||
import { useWorkflowSelectedNodeOrThrow } from '@/workflow/workflow-diagram/hooks/useWorkflowSelectedNodeOrThrow';
|
||||
import { WorkflowRunStepInputDetail } from '@/workflow/workflow-steps/components/WorkflowRunStepInputDetail';
|
||||
import { WorkflowRunStepOutputDetail } from '@/workflow/workflow-steps/components/WorkflowRunStepOutputDetail';
|
||||
import { WorkflowStepDetail } from '@/workflow/workflow-steps/components/WorkflowStepDetail';
|
||||
import { WORKFLOW_RUN_STEP_SIDE_PANEL_TAB_LIST_COMPONENT_ID } from '@/workflow/workflow-steps/constants/WorkflowRunStepSidePanelTabListComponentId';
|
||||
import { getWorkflowRunStepExecutionStatus } from '@/workflow/workflow-steps/utils/getWorkflowRunStepExecutionStatus';
|
||||
@ -38,7 +39,7 @@ export const RightDrawerWorkflowRunViewStep = () => {
|
||||
})
|
||||
: undefined;
|
||||
|
||||
const isInputTabDisabled =
|
||||
const areInputAndOutputTabsDisabled =
|
||||
workflowSelectedNode === TRIGGER_STEP_ID ||
|
||||
stepExecutionStatus === 'running' ||
|
||||
stepExecutionStatus === 'not-executed';
|
||||
@ -49,9 +50,14 @@ export const RightDrawerWorkflowRunViewStep = () => {
|
||||
id: 'input',
|
||||
title: 'Input',
|
||||
Icon: IconLogin2,
|
||||
disabled: isInputTabDisabled,
|
||||
disabled: areInputAndOutputTabsDisabled,
|
||||
},
|
||||
{
|
||||
id: 'output',
|
||||
title: 'Output',
|
||||
Icon: IconLogout,
|
||||
disabled: areInputAndOutputTabsDisabled,
|
||||
},
|
||||
{ id: 'output', title: 'Output', Icon: IconLogout },
|
||||
];
|
||||
|
||||
if (!isDefined(workflowRun)) {
|
||||
@ -80,6 +86,10 @@ export const RightDrawerWorkflowRunViewStep = () => {
|
||||
{activeTabId === 'input' ? (
|
||||
<WorkflowRunStepInputDetail stepId={workflowSelectedNode} />
|
||||
) : null}
|
||||
|
||||
{activeTabId === 'output' ? (
|
||||
<WorkflowRunStepOutputDetail stepId={workflowSelectedNode} />
|
||||
) : null}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@ -0,0 +1,27 @@
|
||||
import { JsonTree } from '@/workflow/components/json-visualizer/components/JsonTree';
|
||||
import { useWorkflowRun } from '@/workflow/hooks/useWorkflowRun';
|
||||
import { useWorkflowRunIdOrThrow } from '@/workflow/hooks/useWorkflowRunIdOrThrow';
|
||||
import styled from '@emotion/styled';
|
||||
import { isDefined } from 'twenty-shared';
|
||||
|
||||
const StyledContainer = styled.div`
|
||||
padding-block: ${({ theme }) => theme.spacing(4)};
|
||||
padding-inline: ${({ theme }) => theme.spacing(3)};
|
||||
`;
|
||||
|
||||
export const WorkflowRunStepOutputDetail = ({ stepId }: { stepId: string }) => {
|
||||
const workflowRunId = useWorkflowRunIdOrThrow();
|
||||
const workflowRun = useWorkflowRun({ workflowRunId });
|
||||
|
||||
if (!isDefined(workflowRun?.output?.stepsOutput)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const stepOutput = workflowRun.output.stepsOutput[stepId];
|
||||
|
||||
return (
|
||||
<StyledContainer>
|
||||
<JsonTree value={stepOutput} />
|
||||
</StyledContainer>
|
||||
);
|
||||
};
|
||||
@ -26,6 +26,10 @@ const StyledHeaderTitle = styled.div`
|
||||
font-size: ${({ theme }) => theme.font.size.xl};
|
||||
width: 420px;
|
||||
overflow: hidden;
|
||||
|
||||
& > input:disabled {
|
||||
color: ${({ theme }) => theme.font.color.primary};
|
||||
}
|
||||
`;
|
||||
|
||||
const StyledHeaderType = styled.div`
|
||||
|
||||
@ -117,7 +117,6 @@ export const InputTabNotExecutedStep: Story = {
|
||||
return <Story />;
|
||||
},
|
||||
],
|
||||
|
||||
play: async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
@ -138,5 +137,52 @@ export const OutputTab: Story = {
|
||||
await waitFor(() => {
|
||||
expect(canvas.queryByText('Create Record')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
expect(await canvas.findByText('result')).toBeVisible();
|
||||
},
|
||||
};
|
||||
|
||||
export const OutputTabDisabledForTrigger: Story = {
|
||||
decorators: [
|
||||
(Story) => {
|
||||
const setWorkflowSelectedNode = useSetRecoilState(
|
||||
workflowSelectedNodeState,
|
||||
);
|
||||
|
||||
setWorkflowSelectedNode(TRIGGER_STEP_ID);
|
||||
|
||||
return <Story />;
|
||||
},
|
||||
],
|
||||
play: async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
const outputTab = await canvas.findByRole('button', { name: 'Output' });
|
||||
|
||||
expect(outputTab).toBeDisabled();
|
||||
},
|
||||
};
|
||||
|
||||
export const OutputTabNotExecutedStep: Story = {
|
||||
decorators: [
|
||||
(Story) => {
|
||||
const setWorkflowSelectedNode = useSetRecoilState(
|
||||
workflowSelectedNodeState,
|
||||
);
|
||||
|
||||
setWorkflowSelectedNode(
|
||||
oneFailedWorkflowRunQueryResult.workflowRun.output.flow.steps.at(-1)!
|
||||
.id,
|
||||
);
|
||||
|
||||
return <Story />;
|
||||
},
|
||||
],
|
||||
play: async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
const outputTab = await canvas.findByRole('button', { name: 'Output' });
|
||||
|
||||
expect(outputTab).toBeDisabled();
|
||||
},
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user