Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion packages/react-ui/public/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,9 @@
"Go to Step": "Go to Step",
"Copy": "Copy",
"Paste after selection": "Paste after selection",
"Paste Inside Loop": "Paste Inside Loop",
"Paste inside Loop": "Paste inside Loop",
"Paste inside first branch": "Paste inside first branch",
"Paste inside default branch": "Paste inside default branch",
"Paste After": "Paste After",
"Replace": "Replace",
"Duplicate": "Duplicate",
Expand Down
10 changes: 9 additions & 1 deletion packages/react-ui/src/app/features/builder/builder-hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -422,7 +422,8 @@ export type UndoHistoryRelevantFlowOperationRequest = Extract<
| FlowOperationType.UPDATE_TRIGGER
| FlowOperationType.UPDATE_ACTION
| FlowOperationType.DUPLICATE_ACTION
| FlowOperationType.ADD_ACTION;
| FlowOperationType.ADD_ACTION
| FlowOperationType.PASTE_ACTIONS;
}
>;

Expand All @@ -439,6 +440,13 @@ const updateFlowVersion = (
) => void,
) => {
const newFlowVersion = flowHelper.apply(state.flowVersion, operation);
if (
operation.type === FlowOperationType.DELETE_ACTION &&
operation.request.name === state.selectedStep
) {
set({ selectedStep: undefined });
}
Comment on lines +443 to +448
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clear deleted selectedStep from the builder store


const updateRequest = async () => {
set({ saving: true });
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,25 @@ import {
useCanvasContext,
WorkflowNode,
} from '@openops/components/ui';
import { ActionType, FlagId, flowHelper } from '@openops/shared';
import {
Action,
ActionType,
FlagId,
flowHelper,
isNil,
StepLocationRelativeToParent,
} from '@openops/shared';

import { flagsHooks } from '@/app/common/hooks/flags-hooks';
import { useReactFlow } from '@xyflow/react';
import { useBuilderStateContext } from '../../builder-hooks';
import { usePaste } from '../../hooks/use-paste';
import { CanvasShortcuts, ShortcutWrapper } from './canvas-shortcuts';
import { CanvasContextMenuProps } from './context-menu-wrapper';

export const CanvasContextMenuContent = ({
contextMenuType,
actionToPaste,
}: CanvasContextMenuProps) => {
const showCopyPaste =
flagsHooks.useFlag<boolean>(FlagId.COPY_PASTE_ACTIONS_ENABLED).data ||
Expand All @@ -35,84 +44,150 @@ export const CanvasContextMenuContent = ({
return acc;
}, [] as string[]);

const [flowVersion, readonly] = useBuilderStateContext((state) => [
state.flowVersion,
state.readonly,
]);
const [flowVersion, readonly, selectedStep] = useBuilderStateContext(
(state) => [state.flowVersion, state.readonly, state.selectedStep],
);

const { copySelectedArea } = useCanvasContext();
const { copySelectedArea, copyAction } = useCanvasContext();

const disabled = selectedNodes.length === 0;
const isSingleSelectedNode = selectedNodes.length === 1;

const doSelectedNodesIncludeTrigger = selectedNodes.some(
(node: string) => node === flowVersion.trigger.name,
);

// https://linear.app/openops/issue/OPS-854/add-paste-logic
const disabledPaste = true;
const disabledPaste = isNil(actionToPaste);
const firstSelectedStep = flowHelper.getStep(flowVersion, selectedNodes[0]);
const showPasteAfterLastStep =
!readonly && contextMenuType === ContextMenuType.CANVAS;
const showPasteAsFirstLoopAction =
selectedNodes.length === 1 &&
isSingleSelectedNode &&
firstSelectedStep?.type === ActionType.LOOP_ON_ITEMS &&
!readonly &&
contextMenuType === ContextMenuType.STEP;

const showPasteAfterCurrentStep =
selectedNodes.length === 1 &&
(isSingleSelectedNode || selectedStep) &&
!readonly &&
contextMenuType === ContextMenuType.STEP;

const showPasteInConditionBranch =
contextMenuType === ContextMenuType.STEP &&
firstSelectedStep?.type === ActionType.BRANCH;

const showPasteInSplitBranch =
contextMenuType === ContextMenuType.STEP &&
firstSelectedStep?.type === ActionType.SPLIT;

const showCopy =
showCopyPaste &&
!doSelectedNodesIncludeTrigger &&
contextMenuType === ContextMenuType.STEP;

const { onPaste } = usePaste();

return (
<>
{showCopy && (
<ContextMenuItem disabled={disabled} onClick={copySelectedArea}>
<ContextMenuItem
disabled={disabled}
onClick={() => {
if (selectedStep) {
const step = flowHelper.getStep(flowVersion, selectedStep);
copyAction(step as Action);
Comment thread
cezudas marked this conversation as resolved.
return;
}

copySelectedArea();
}}
>
<ShortcutWrapper shortcut={CanvasShortcuts['Copy']}>
<Copy className="w-4 h-4"></Copy> {t('Copy')}
</ShortcutWrapper>
</ContextMenuItem>
)}

<>
{showPasteAfterLastStep && showCopyPaste && (
{showPasteAfterLastStep && (
<ContextMenuItem
disabled={disabledPaste}
onClick={() => {
// // https://linear.app/openops/issue/OPS-854/add-paste-logic
}}
onClick={() =>
onPaste(
actionToPaste as Action,
StepLocationRelativeToParent.AFTER,
selectedStep,
)
}
className="flex items-center gap-2"
>
<ClipboardPlus className="w-4 h-4"></ClipboardPlus>{' '}
{t('Paste after selection')}
</ContextMenuItem>
)}
{showPasteAsFirstLoopAction && (
<ContextMenuItem
disabled={disabledPaste}
onClick={() =>
onPaste(
actionToPaste as Action,
StepLocationRelativeToParent.INSIDE_LOOP,
selectedStep,
)
}
className="flex items-center gap-2"
>
<ClipboardPaste className="w-4 h-4"></ClipboardPaste>
{t('Paste inside Loop')}
</ContextMenuItem>
)}
{showPasteInConditionBranch && (
<ContextMenuItem
disabled={disabledPaste}
onClick={() =>
onPaste(
actionToPaste as Action,
StepLocationRelativeToParent.INSIDE_TRUE_BRANCH,
selectedStep,
)
}
className="flex items-center gap-2"
>
<ClipboardPaste className="w-4 h-4"></ClipboardPaste>
{t('Paste inside first branch')}
</ContextMenuItem>
)}
{showPasteInSplitBranch && (
<ContextMenuItem
disabled={disabledPaste}
onClick={() => {
// https://linear.app/openops/issue/OPS-854/add-paste-logic
const branchNodeId = firstSelectedStep.settings.options[0].id;
return onPaste(
actionToPaste as Action,
StepLocationRelativeToParent.INSIDE_SPLIT,
selectedStep,
branchNodeId,
);
}}
className="flex items-center gap-2"
>
<ClipboardPaste className="w-4 h-4"></ClipboardPaste>{' '}
{t('Paste Inside Loop')}
<ClipboardPaste className="w-4 h-4"></ClipboardPaste>
{t('Paste inside default branch')}
</ContextMenuItem>
)}
{showPasteAfterCurrentStep && (
<ContextMenuItem
disabled={disabledPaste}
onClick={() => {
// https://linear.app/openops/issue/OPS-854/add-paste-logic
}}
onClick={() =>
onPaste(
actionToPaste as Action,
StepLocationRelativeToParent.AFTER,
selectedStep,
)
}
className="flex items-center gap-2"
>
<ClipboardPlus className="w-4 h-4"></ClipboardPlus>{' '}
<ClipboardPlus className="w-4 h-4"></ClipboardPlus>
{t('Paste After')}
</ContextMenuItem>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,16 @@ import {
toast,
UNSAVED_CHANGES_TOAST,
useCanvasContext,
usePasteActionsInClipboard,
WorkflowNode,
} from '@openops/components/ui';
import { Action, FlagId, FlowOperationType } from '@openops/shared';
import {
Action,
ActionType,
FlagId,
FlowOperationType,
StepLocationRelativeToParent,
} from '@openops/shared';

import { t } from 'i18next';
import {
Expand All @@ -24,6 +31,7 @@ import {
import { memo } from 'react';
import { useBuilderStateContext } from '../../builder-hooks';
import { useApplyOperationAndPushToHistory } from '../../flow-version-undo-redo/hooks/apply-operation-and-push-to-history';
import { usePaste } from '../../hooks/use-paste';
import { StepActionWrapper } from '../nodes/step-action-wrapper';

type Props = {
Expand All @@ -48,6 +56,9 @@ const CanvasContextMenu = memo(
const applyOperationAndPushToHistory = useApplyOperationAndPushToHistory();

const { copyAction } = useCanvasContext();
const { onPaste } = usePaste();
const { actionToPaste, fetchClipboardOperations } =
usePasteActionsInClipboard();

const [selectStepByName, removeStepSelection, setAllowCanvasPanning] =
useBuilderStateContext((state) => [
Expand Down Expand Up @@ -90,8 +101,12 @@ const CanvasContextMenu = memo(
return (
<DropdownMenu
open={openStepActionsMenu}
onOpenChange={(open) => {
onOpenChange={async (open) => {
await fetchClipboardOperations();
setOpenStepActionsMenu(open);
if (open && data.step) {
selectStepByName(data.step.name);
}
}}
modal={true}
>
Expand Down Expand Up @@ -163,13 +178,90 @@ const CanvasContextMenu = memo(
</DropdownMenuItem>
)}

{isAction && showCopyPaste && (
{isAction &&
showCopyPaste &&
actionToPaste &&
data.step?.type === ActionType.LOOP_ON_ITEMS && (
<DropdownMenuItem
onSelect={(e) => {
e.preventDefault();
if (data.step) {
onPaste(
actionToPaste as Action,
StepLocationRelativeToParent.INSIDE_LOOP,
data.step.name,
);
}
}}
>
<StepActionWrapper>
<Copy className="mr-2 h-4 w-4" />
<span className=""> {t('Paste inside Loop')}</span>
</StepActionWrapper>
</DropdownMenuItem>
)}

{isAction &&
showCopyPaste &&
actionToPaste &&
data.step?.type === ActionType.BRANCH && (
<DropdownMenuItem
onSelect={(e) => {
e.preventDefault();
if (data.step) {
onPaste(
actionToPaste as Action,
StepLocationRelativeToParent.INSIDE_TRUE_BRANCH,
data.step.name,
);
}
}}
>
<StepActionWrapper>
<Copy className="mr-2 h-4 w-4" />
<span className=""> {t('Paste inside first branch')}</span>
</StepActionWrapper>
</DropdownMenuItem>
)}

{isAction &&
showCopyPaste &&
actionToPaste &&
data.step?.type === ActionType.SPLIT && (
<DropdownMenuItem
onSelect={(e) => {
e.preventDefault();
if (data.step) {
const branchNodeId = data.step.settings.options[0].id;
onPaste(
actionToPaste as Action,
StepLocationRelativeToParent.INSIDE_SPLIT,
data.step.name,
branchNodeId,
);
}
}}
>
<StepActionWrapper>
<Copy className="mr-2 h-4 w-4" />
<span className="">{t('Paste inside default branch')}</span>
</StepActionWrapper>
</DropdownMenuItem>
)}

{isAction && showCopyPaste && actionToPaste && (
<>
<DropdownMenuSeparator />
<DropdownMenuItem
onSelect={(e) => {
e.preventDefault();
// https://linear.app/openops/issue/OPS-854/add-paste-logic
if (data.step) {
onPaste(
actionToPaste as Action,
StepLocationRelativeToParent.AFTER,
data.step.name,
);
}
}}
>
<StepActionWrapper>
Expand Down
Loading
Loading