Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ᛘ Frontend logic for the IfNode #1095

Merged
merged 6 commits into from
Jul 19, 2023
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
25 changes: 19 additions & 6 deletions next/src/components/workflow/AbstractNode.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,16 @@ import type { HandleType, Position } from "reactflow";
import { Handle } from "reactflow";
import clsx from "clsx";

interface Handle {
position: Position;
type: HandleType;
className?: string;
id?: string;
text?: string;
}

interface NodeProps extends PropsWithChildren {
handles: [Position, HandleType][];
handles: Handle[];
selected: boolean;
status?: string;
}
Expand All @@ -24,14 +32,19 @@ function AbstractNode(props: NodeProps) {
)}
>
{props.children}
{props.handles.map(([position, type]) => (
{props.handles.map(({ position, type, text, className, id }, i) => (
<Handle
key={position}
key={`${i}-${id || ""}`}
{...(id ? { id } : {})} /* Only specify id if provided */
type={type}
position={position}
className="bg-black"
style={{ width: "0.5em", height: "0.5em" }}
/>
className={clsx(
"border-gradient !hover:border-white grid !h-fit !w-fit place-items-center !rounded-md !bg-black p-1 text-xs font-light",
className
)}
>
{text}
</Handle>
))}
</div>
);
Expand Down
4 changes: 2 additions & 2 deletions next/src/components/workflow/BasicNode.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ function BasicNode({ data, selected }: NodeProps<WorkflowNode>) {
selected={selected}
status={data.status}
handles={[
[Position.Top, "target"],
[Position.Bottom, "source"],
{ position: Position.Top, type: "target" },
{ position: Position.Bottom, type: "source" },
]}
>
<div className="flex items-center">
Expand Down
11 changes: 7 additions & 4 deletions next/src/components/workflow/Flowchart.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type { ComponentProps, MouseEvent} from "react";
import { type FC, useCallback } from "react";
import type { Connection, EdgeChange, FitViewOptions, NodeChange } from "reactflow";
import ReactFlow, {
Expand All @@ -11,12 +12,14 @@ import ReactFlow, {
} from "reactflow";

import "reactflow/dist/style.css";
import CustomNode from "./BasicNode";
import BasicNode from "./BasicNode";
import CustomEdge from "./BasicEdge";
import type { EdgesModel, NodesModel } from "../../types/workflow";
import IfNode from "./IfNode";

const nodeTypes = {
custom: CustomNode,
if: IfNode,
custom: BasicNode,
};

const edgeTypes = {
Expand All @@ -27,8 +30,8 @@ const fitViewOptions: FitViewOptions = {
padding: 0.2,
};

interface FlowChartProps extends React.ComponentProps<typeof ReactFlow> {
onSave?: (e: React.MouseEvent<HTMLButtonElement>) => Promise<void>;
interface FlowChartProps extends ComponentProps<typeof ReactFlow> {
onSave?: (e: MouseEvent<HTMLButtonElement>) => Promise<void>;
controls?: boolean;
minimap?: boolean;

Expand Down
44 changes: 44 additions & 0 deletions next/src/components/workflow/IfNode.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import React, { memo } from "react";
import { type NodeProps, Position } from "reactflow";
import type { WorkflowNode } from "../../types/workflow";
import { getNodeBlockDefinitions } from "../../services/workflow/node-block-definitions";
import AbstractNode from "./AbstractNode";

function IfNode(props: NodeProps<WorkflowNode>) {
const { data, selected } = props;
const definition = getNodeBlockDefinitions().find((d) => d.type === data.block.type);

return (
<AbstractNode
selected={selected}
status={data.status}
handles={[
{ position: Position.Top, type: "target" },
{
id: "true",
position: Position.Bottom,
type: "source",
text: "True",
className: "!left-[20%] !-bottom-4",
},

{
id: "false",
position: Position.Bottom,
text: "False",
className: "!left-[80%] !-bottom-4",
type: "source",
},
]}
>
<div className="flex items-center">
<div className="ml-2">
<div className="text-lg font-bold text-gray-100">{definition?.name}</div>
<div className="text-md text-sm font-thin">{definition?.description}</div>
</div>
</div>
</AbstractNode>
);
}

export default memo(IfNode);
7 changes: 4 additions & 3 deletions next/src/hooks/useWorkflow.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import type { Edge, Node } from "reactflow";
import { Dispatch, SetStateAction, useEffect, useState } from "react";
import type { Dispatch, SetStateAction} from "react";
import { useEffect, useState } from "react";
import { nanoid } from "nanoid";
import { useMutation, useQuery } from "@tanstack/react-query";
import type { NodeBlock, Workflow, WorkflowEdge, WorkflowNode } from "../types/workflow";
import { toReactFlowEdge, toReactFlowNode } from "../types/workflow";
import { getNodeType, toReactFlowEdge, toReactFlowNode } from "../types/workflow";
import WorkflowApi from "../services/workflow/workflowApi";
import useSocket from "./useSocket";
import { z } from "zod";
Expand Down Expand Up @@ -91,7 +92,7 @@ export const useWorkflow = (workflowId: string, session: Session | null) => {
...(nodes ?? []),
{
id: ref,
type: "custom",
type: getNodeType(block),
position: { x: 0, y: 0 },
data: {
id: undefined,
Expand Down
11 changes: 10 additions & 1 deletion next/src/services/workflow/node-block-definitions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,17 @@ const SlackWebhookBlockDefinition: NodeBlockDefinition = {
],
};

const IfBlockDefinition: NodeBlockDefinition = {
name: "If Block",
type: "IfBlock",
description: "Conditionally take a path",
image_url: "/tools/web.png",
input_fields: [],
output_fields: [],
};

export const getNodeBlockDefinitions = () => {
return [UrlStatusCheckBlockDefinition, SlackWebhookBlockDefinition];
return [UrlStatusCheckBlockDefinition, SlackWebhookBlockDefinition, IfBlockDefinition];
};

export const getNodeBlockDefinitionFromNode = (node: Node<WorkflowNode>) => {
Expand Down
16 changes: 9 additions & 7 deletions next/src/styles/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@ body {
}

.border-gradient {
/* Mark as important to override react flow styling */
background: linear-gradient(black, black) padding-box,
linear-gradient(to bottom, rgba(255, 255, 255, 0.35), rgba(255, 255, 255, 0.15)) border-box;
border: 1px solid transparent;
linear-gradient(to bottom, rgba(255, 255, 255, 0.35), rgba(255, 255, 255, 0.15)) border-box !important;
border: 1px solid transparent !important;
}

.radial-background-1 {
Expand Down Expand Up @@ -314,16 +315,17 @@ Not supports in Firefox and IE */
.animate-border-pulse {
animation: border-pulse-animation 2s infinite;
}

@keyframes moveBackground {
from {
background-position: 0 0;
background-position: 0 0;
}
to {
background-position: 100% 0;
background-position: 100% 0;
}
}
}

.bg-stars {
.bg-stars {
animation: moveBackground 30s linear infinite;
background: url("/stars.svg");
background-size: cover;
Expand All @@ -333,4 +335,4 @@ Not supports in Firefox and IE */
left: 0;
right: 0;
z-index: -1;
}
}
11 changes: 10 additions & 1 deletion next/src/types/workflow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export const toReactFlowNode = (node: WorkflowNode) =>
id: node.id ?? node.ref,
data: node,
position: { x: node.pos_x, y: node.pos_y },
type: "custom",
type: getNodeType(node.block),
} as Node<WorkflowNode>);

export const toReactFlowEdge = (edge: WorkflowEdge) =>
Expand All @@ -54,3 +54,12 @@ export const toReactFlowEdge = (edge: WorkflowEdge) =>
...edge,
},
} as Edge<WorkflowEdge>);

export const getNodeType = (block: NodeBlock) => {
switch (block.type) {
case "IfBlock":
return "if";
default:
return "custom";
}
};