Skip to content

Commit

Permalink
Merge branch 'activepieces:main' into apitraffic/main
Browse files Browse the repository at this point in the history
  • Loading branch information
jasonfill authored Jan 14, 2025
2 parents d4450a6 + 5cea8eb commit f6b6aee
Show file tree
Hide file tree
Showing 11 changed files with 261 additions and 152 deletions.
4 changes: 2 additions & 2 deletions packages/engine/src/lib/handler/context/engine-constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,10 @@ export class EngineConstants {
public readonly resumePayload?: ResumePayload,
) {
if (!publicApiUrl.endsWith('/api/')) {
throw new Error('Public URL must end with a slash')
throw new Error('Public URL must end with a slash, got: ' + publicApiUrl)
}
if (!internalApiUrl.endsWith('/')) {
throw new Error('Internal API URL must end with a slash')
throw new Error('Internal API URL must end with a slash, got: ' + internalApiUrl)
}
}

Expand Down
2 changes: 1 addition & 1 deletion packages/engine/test/handler/test-helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export const generateMockEngineConstants = (params?: Partial<EngineConstants>):
params?.flowVersionId ?? 'flowVersionId',
params?.flowVersionState ?? FlowVersionState.DRAFT,
params?.flowRunId ?? 'flowRunId',
params?.publicUrl ?? 'http://127.0.0.1:3000',
params?.publicApiUrl ?? 'http://127.0.0.1:4200/api/',
params?.internalApiUrl ?? 'http://127.0.0.1:3000/',
params?.retryConstants ?? {
maxAttempts: 2,
Expand Down
86 changes: 77 additions & 9 deletions packages/react-ui/src/app/builder/builder-hooks.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
import { useMutation } from '@tanstack/react-query';
import { createContext, useContext, useCallback, useState } from 'react';
import { useReactFlow } from '@xyflow/react';
import {
createContext,
useContext,
useCallback,
useState,
useEffect,
useRef,
} from 'react';
import { usePrevious } from 'react-use';
import { create, useStore } from 'zustand';

import { INTERNAL_ERROR_TOAST, toast } from '@/components/ui/use-toast';
Expand All @@ -19,6 +28,7 @@ import {
isNil,
StepLocationRelativeToParent,
Action,
isFlowStateTerminal,
} from '@activepieces/shared';

import { flowRunUtils } from '../../features/flow-runs/lib/flow-run-utils';
Expand All @@ -37,6 +47,7 @@ import {
CanvasShortcutsProps,
} from './flow-canvas/context-menu/canvas-context-menu';
import { STEP_CONTEXT_MENU_ATTRIBUTE } from './flow-canvas/utils/consts';
import { flowCanvasUtils } from './flow-canvas/utils/flow-canvas-utils';

const flowUpdatesQueue = new PromiseQueue();

Expand Down Expand Up @@ -77,7 +88,6 @@ export type BuilderState = {
selectedStep: string | null;
canExitRun: boolean;
activeDraggingStep: string | null;
allowCanvasPanning: boolean;
saving: boolean;
/** change this value to trigger the step form to set its values from the step */
refreshStepFormSettingsToggle: boolean;
Expand All @@ -98,7 +108,6 @@ export type BuilderState = {
removeStepSelection: () => void;
selectStepByName: (stepName: string) => void;
startSaving: () => void;
setAllowCanvasPanning: (allowCanvasPanning: boolean) => void;
setActiveDraggingStep: (stepName: string | null) => void;
setFlow: (flow: PopulatedFlow) => void;
setSampleData: (stepName: string, payload: unknown) => void;
Expand Down Expand Up @@ -187,7 +196,6 @@ export const createBuilderStore = (initialState: BuilderInitialState) =>
selectedStep: initiallySelectedStep,
canExitRun: initialState.canExitRun,
activeDraggingStep: null,
allowCanvasPanning: true,
rightSidebar:
initiallySelectedStep &&
(initiallySelectedStep !== 'trigger' ||
Expand All @@ -202,10 +210,7 @@ export const createBuilderStore = (initialState: BuilderInitialState) =>
rightSidebar: RightSideBarType.NONE,
selectedBranchIndex: null,
}),
setAllowCanvasPanning: (allowCanvasPanning: boolean) =>
set({
allowCanvasPanning,
}),

setActiveDraggingStep: (stepName: string | null) =>
set({
activeDraggingStep: stepName,
Expand Down Expand Up @@ -535,7 +540,7 @@ export const useHandleKeyPressOnCanvas = () => {
state.readonly,
]);

return useCallback(
const handleKeyDown = useCallback(
(e: KeyboardEvent) => {
if (
e.target instanceof HTMLElement &&
Expand Down Expand Up @@ -614,6 +619,11 @@ export const useHandleKeyPressOnCanvas = () => {
readonly,
],
);

useEffect(() => {
document.addEventListener('keydown', handleKeyDown);
return () => document.removeEventListener('keydown', handleKeyDown);
}, [handleKeyDown]);
};

export const useSwitchToDraft = () => {
Expand Down Expand Up @@ -658,3 +668,61 @@ export const usePasteActionsInClipboard = () => {
};
return { actionsToPaste, fetchClipboardOperations };
};

export const useFocusedFailedStep = () => {
const currentRun = useBuilderStateContext((state) => state.run);
const previousRun = usePrevious(currentRun);
const { fitView } = useReactFlow();
if (
(currentRun &&
previousRun?.id !== currentRun.id &&
isFlowStateTerminal(currentRun.status)) ||
(currentRun &&
previousRun &&
!isFlowStateTerminal(previousRun.status) &&
isFlowStateTerminal(currentRun.status))
) {
const failedStep = currentRun.steps
? flowRunUtils.findFailedStepInOutput(currentRun.steps)
: null;
if (failedStep) {
setTimeout(() => {
fitView(flowCanvasUtils.createFocusStepInGraphParams(failedStep));
});
}
}
};

export const useResizeCanvas = (
containerRef: React.RefObject<HTMLDivElement>,
setHasCanvasBeenInitialised: (hasCanvasBeenInitialised: boolean) => void,
) => {
const containerSizeRef = useRef({
width: 0,
height: 0,
});
const { getViewport, setViewport } = useReactFlow();

useEffect(() => {
if (!containerRef.current) return;
const resizeObserver = new ResizeObserver((entries) => {
const { width, height } = entries[0].contentRect;
setHasCanvasBeenInitialised(true);
const { x, y, zoom } = getViewport();
if (containerRef.current && width !== containerSizeRef.current.width) {
const newX = x + (width - containerSizeRef.current.width) / 2;
// Update the viewport to keep content centered without affecting zoom
setViewport({ x: newX, y, zoom });
}
// Adjust x/y values based on the new size and keep the same zoom level
containerSizeRef.current = {
width,
height,
};
});
resizeObserver.observe(containerRef.current);
return () => {
resizeObserver.disconnect();
};
}, [setViewport, getViewport]);
};
67 changes: 38 additions & 29 deletions packages/react-ui/src/app/builder/flow-canvas/flow-drag-layer.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import {
CollisionDetection,
DndContext,
DragEndEvent,
DragOverlay,
Expand All @@ -10,7 +9,9 @@ import {
useSensor,
useSensors,
} from '@dnd-kit/core';
import { useViewport } from '@xyflow/react';
import { t } from 'i18next';
import { useCallback, useState } from 'react';

import { UNSAVED_CHANGES_TOAST, useToast } from '@/components/ui/use-toast';
import {
Expand All @@ -24,66 +25,74 @@ import { useBuilderStateContext } from '../builder-hooks';
import StepDragOverlay from './step-drag-overlay';
import { ApButtonData } from './utils/types';

// https://github.com/clauderic/dnd-kit/pull/334#issuecomment-1965708784
const fixCursorSnapOffset: CollisionDetection = (args) => {
// Bail out if keyboard activated
if (!args.pointerCoordinates) {
return rectIntersection(args);
}
const { x, y } = args.pointerCoordinates;
const { width, height } = args.collisionRect;
const updated = {
...args,
// The collision rectangle is broken when using snapCenterToCursor. Reset
// the collision rectangle based on pointer location and overlay size.
collisionRect: {
width,
height,
bottom: y + height / 2,
left: x - width / 2,
right: x + width / 2,
top: y - height / 2,
},
};
return rectIntersection(updated);
};

const FlowDragLayer = ({
children,
lefSideBarContainerWidth,
cursorPosition,
}: {
children: React.ReactNode;
lefSideBarContainerWidth: number;
cursorPosition: { x: number; y: number };
}) => {
const { toast } = useToast();
const viewport = useViewport();
const [previousViewPort, setPreviousViewPort] = useState(viewport);
const [
setActiveDraggingStep,
applyOperation,
flowVersion,
activeDraggingStep,
setAllowCanvasPanning,
] = useBuilderStateContext((state) => [
state.setActiveDraggingStep,
state.applyOperation,
state.flowVersion,
state.activeDraggingStep,
state.setAllowCanvasPanning,
]);

const fixCursorSnapOffset = useCallback(
(args: Parameters<typeof rectIntersection>[0]) => {
// Bail out if keyboard activated
if (!args.pointerCoordinates) {
return rectIntersection(args);
}
const { x, y } = args.pointerCoordinates;
const { width, height } = args.collisionRect;
const deltaViewport = {
x: previousViewPort.x - viewport.x,
y: previousViewPort.y - viewport.y,
};
const updated = {
...args,
// The collision rectangle is broken when using snapCenterToCursor. Reset
// the collision rectangle based on pointer location and overlay size.
collisionRect: {
width,
height,
bottom: y + height / 2 + deltaViewport.y,
left: x - width / 2 + deltaViewport.x,
right: x + width / 2 + deltaViewport.x,
top: y - height / 2 + deltaViewport.y,
},
};
return rectIntersection(updated);
},
[viewport.x, viewport.y, previousViewPort.x, previousViewPort.y],
);
const draggedStep = activeDraggingStep
? flowStructureUtil.getStep(activeDraggingStep, flowVersion.trigger)
: undefined;

const handleDragStart = (e: DragStartEvent) => {
setActiveDraggingStep(e.active.id.toString());
setPreviousViewPort(viewport);
};

const handleDragCancel = () => {
setActiveDraggingStep(null);
};

const handleDragEnd = (e: DragEndEvent) => {
setActiveDraggingStep(null);
setAllowCanvasPanning(true);
if (
e.over &&
e.over.data.current &&
Expand Down Expand Up @@ -140,7 +149,6 @@ const FlowDragLayer = ({
}),
useSensor(TouchSensor),
);

return (
<>
<DndContext
Expand All @@ -156,6 +164,7 @@ const FlowDragLayer = ({

{draggedStep && (
<StepDragOverlay
cursorPosition={cursorPosition}
lefSideBarContainerWidth={lefSideBarContainerWidth}
step={draggedStep}
></StepDragOverlay>
Expand Down
Loading

0 comments on commit f6b6aee

Please sign in to comment.