Delete workflow step (#7373)
- Allows the deletion of triggers and steps in workflows. If the workflow can not be edited right now, we create a new draft version. - The workflow right drawer can now render nothing. It's necessary to behave that way because a deleted step will still be displayed for a short amount of time in the drawer. The drawer will be filled with blank content when it disappears. https://github.com/user-attachments/assets/abd5184e-d3db-4fe7-8870-ccc78ff23d41 Closes #7057
This commit is contained in:
committed by
GitHub
parent
3a0c32a88d
commit
35361093bf
@ -7,7 +7,7 @@ import { useUpdateWorkflowVersionTrigger } from '@/workflow/hooks/useUpdateWorkf
|
||||
import { workflowSelectedNodeState } from '@/workflow/states/workflowSelectedNodeState';
|
||||
import { WorkflowWithCurrentVersion } from '@/workflow/types/Workflow';
|
||||
import { assertUnreachable } from '@/workflow/utils/assertUnreachable';
|
||||
import { findStepPositionOrThrow } from '@/workflow/utils/findStepPositionOrThrow';
|
||||
import { findStepPosition } from '@/workflow/utils/findStepPosition';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { isDefined } from 'twenty-ui';
|
||||
|
||||
@ -43,10 +43,13 @@ const getStepDefinitionOrThrow = ({
|
||||
);
|
||||
}
|
||||
|
||||
const selectedNodePosition = findStepPositionOrThrow({
|
||||
const selectedNodePosition = findStepPosition({
|
||||
steps: currentVersion.steps,
|
||||
stepId: stepId,
|
||||
});
|
||||
if (!isDefined(selectedNodePosition)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return {
|
||||
type: 'action',
|
||||
@ -76,6 +79,9 @@ export const RightDrawerWorkflowEditStepContent = ({
|
||||
stepId: workflowSelectedNode,
|
||||
workflow,
|
||||
});
|
||||
if (!isDefined(stepDefinition)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
switch (stepDefinition.type) {
|
||||
case 'trigger': {
|
||||
|
||||
@ -2,6 +2,7 @@ import { WorkflowDiagramStepNodeData } from '@/workflow/types/WorkflowDiagram';
|
||||
import styled from '@emotion/styled';
|
||||
import { Handle, Position } from '@xyflow/react';
|
||||
import React from 'react';
|
||||
import { isDefined } from 'twenty-ui';
|
||||
import { capitalize } from '~/utils/string/capitalize';
|
||||
|
||||
type Variant = 'placeholder';
|
||||
@ -76,16 +77,24 @@ export const StyledTargetHandle = styled(Handle)`
|
||||
visibility: hidden;
|
||||
`;
|
||||
|
||||
const StyledRightFloatingElementContainer = styled.div`
|
||||
position: absolute;
|
||||
transform: translateX(100%);
|
||||
right: ${({ theme }) => theme.spacing(-2)};
|
||||
`;
|
||||
|
||||
export const WorkflowDiagramBaseStepNode = ({
|
||||
nodeType,
|
||||
label,
|
||||
variant,
|
||||
Icon,
|
||||
RightFloatingElement,
|
||||
}: {
|
||||
nodeType: WorkflowDiagramStepNodeData['nodeType'];
|
||||
label: string;
|
||||
variant?: Variant;
|
||||
Icon?: React.ReactNode;
|
||||
RightFloatingElement?: React.ReactNode;
|
||||
}) => {
|
||||
return (
|
||||
<StyledStepNodeContainer>
|
||||
@ -101,6 +110,12 @@ export const WorkflowDiagramBaseStepNode = ({
|
||||
|
||||
{label}
|
||||
</StyledStepNodeLabel>
|
||||
|
||||
{isDefined(RightFloatingElement) ? (
|
||||
<StyledRightFloatingElementContainer>
|
||||
{RightFloatingElement}
|
||||
</StyledRightFloatingElementContainer>
|
||||
) : null}
|
||||
</StyledStepNodeInnerContainer>
|
||||
|
||||
<StyledSourceHandle type="source" position={Position.Bottom} />
|
||||
|
||||
@ -1,9 +1,15 @@
|
||||
import { FloatingIconButton } from '@/ui/input/button/components/FloatingIconButton';
|
||||
import { WorkflowDiagramBaseStepNode } from '@/workflow/components/WorkflowDiagramBaseStepNode';
|
||||
import { useDeleteOneStep } from '@/workflow/hooks/useDeleteOneStep';
|
||||
import { useWorkflowWithCurrentVersion } from '@/workflow/hooks/useWorkflowWithCurrentVersion';
|
||||
import { workflowIdState } from '@/workflow/states/workflowIdState';
|
||||
import { WorkflowDiagramStepNodeData } from '@/workflow/types/WorkflowDiagram';
|
||||
import { assertUnreachable } from '@/workflow/utils/assertUnreachable';
|
||||
import { assertWorkflowWithCurrentVersionIsDefined } from '@/workflow/utils/assertWorkflowWithCurrentVersionIsDefined';
|
||||
import { useTheme } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
import { IconCode, IconMail, IconPlaylistAdd } from 'twenty-ui';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { IconCode, IconMail, IconPlaylistAdd, IconTrash } from 'twenty-ui';
|
||||
|
||||
const StyledStepNodeLabelIconContainer = styled.div`
|
||||
align-items: center;
|
||||
@ -15,12 +21,26 @@ const StyledStepNodeLabelIconContainer = styled.div`
|
||||
`;
|
||||
|
||||
export const WorkflowDiagramStepNode = ({
|
||||
id,
|
||||
data,
|
||||
selected,
|
||||
}: {
|
||||
id: string;
|
||||
data: WorkflowDiagramStepNodeData;
|
||||
selected?: boolean;
|
||||
}) => {
|
||||
const theme = useTheme();
|
||||
|
||||
const workflowId = useRecoilValue(workflowIdState);
|
||||
|
||||
const workflowWithCurrentVersion = useWorkflowWithCurrentVersion(workflowId);
|
||||
assertWorkflowWithCurrentVersionIsDefined(workflowWithCurrentVersion);
|
||||
|
||||
const { deleteOneStep } = useDeleteOneStep({
|
||||
workflow: workflowWithCurrentVersion,
|
||||
stepId: id,
|
||||
});
|
||||
|
||||
const renderStepIcon = () => {
|
||||
switch (data.nodeType) {
|
||||
case 'trigger': {
|
||||
@ -67,6 +87,16 @@ export const WorkflowDiagramStepNode = ({
|
||||
nodeType={data.nodeType}
|
||||
label={data.label}
|
||||
Icon={renderStepIcon()}
|
||||
RightFloatingElement={
|
||||
selected ? (
|
||||
<FloatingIconButton
|
||||
Icon={IconTrash}
|
||||
onClick={() => {
|
||||
return deleteOneStep();
|
||||
}}
|
||||
/>
|
||||
) : undefined
|
||||
}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user