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

feat(dashboard): Highlight selected step with border #6869

Merged
merged 2 commits into from
Nov 6, 2024
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
11 changes: 8 additions & 3 deletions apps/dashboard/src/components/workflow-editor/base-node.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ export const NODE_WIDTH = 300;
export const NODE_HEIGHT = 86;

const nodeVariants = cva(
`relative border-neutral-alpha-200 bg-foreground-0 flex w-[300px] flex-col gap-1 border p-1 shadow-xs`,
`relative border-neutral-alpha-200 transition-colors aria-selected:border-primary bg-foreground-0 flex w-[300px] flex-col gap-1 border p-1 shadow-xs`,
{
variants: {
variant: {
Expand All @@ -108,6 +108,11 @@ const nodeVariants = cva(

export interface BaseNodeProps extends React.HTMLAttributes<HTMLDivElement>, VariantProps<typeof nodeVariants> {}

export const Node = ({ children, variant, className }: BaseNodeProps) => {
return <div className={nodeVariants({ variant, className })}>{children}</div>;
export const Node = (props: BaseNodeProps) => {
const { children, variant, className, ...rest } = props;
return (
<div className={nodeVariants({ variant, className })} {...rest}>
{children}
</div>
);
};
67 changes: 43 additions & 24 deletions apps/dashboard/src/components/workflow-editor/nodes.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import { Handle, Node as FlowNode, NodeProps, Position } from '@xyflow/react';
import { RiPlayCircleLine } from 'react-icons/ri';
import { Link } from 'react-router-dom';
import { Link, useParams } from 'react-router-dom';
import { STEP_TYPE_TO_COLOR } from '@/utils/color';
import { STEP_TYPE_TO_ICON } from '../icons/utils';
import { AddStepMenu } from './add-step-menu';
import { Node, NodeBody, NodeError, NodeHeader, NodeIcon, NodeName } from './base-node';
import { StepTypeEnum } from '@/utils/enums';
import { useWorkflowEditorContext } from './hooks';
import { buildRoute, ROUTES } from '@/utils/routes';
import { ComponentProps } from 'react';
import { cn } from '@/utils/ui';

export type NodeData = {
name?: string;
Expand Down Expand Up @@ -41,12 +43,22 @@ export const TriggerNode = (_props: NodeProps) => {
);
};

type StepNodeProps = ComponentProps<typeof Node> & { data: NodeData };
const StepNode = (props: StepNodeProps) => {
const { className, data, ...rest } = props;
const { stepSlug } = useParams<{
stepSlug: string;
}>();

return <Node aria-selected={stepSlug === data.stepSlug} className={cn('group', className)} {...rest} />;
};

export const EmailNode = ({ data }: NodeProps<NodeType>) => {
const Icon = STEP_TYPE_TO_ICON[StepTypeEnum.EMAIL];

return (
<Link to={`step/${data.stepSlug}`}>
<Node>
<StepNode data={data}>
<NodeHeader type={StepTypeEnum.EMAIL}>
<NodeIcon variant={STEP_TYPE_TO_COLOR[StepTypeEnum.EMAIL]}>
<Icon />
Expand All @@ -57,17 +69,18 @@ export const EmailNode = ({ data }: NodeProps<NodeType>) => {
{data.error && <NodeError>{data.error}</NodeError>}
<Handle isConnectable={false} className={handleClassName} type="target" position={Position.Top} id="a" />
<Handle isConnectable={false} className={handleClassName} type="source" position={Position.Bottom} id="b" />
</Node>
</StepNode>
</Link>
);
};

export const SmsNode = ({ data }: NodeProps<NodeType>) => {
export const SmsNode = (props: NodeProps<NodeType>) => {
const { data } = props;
const Icon = STEP_TYPE_TO_ICON[StepTypeEnum.SMS];

return (
<Link to={`step/${data.stepSlug}`}>
<Node>
<StepNode data={data}>
<NodeHeader type={StepTypeEnum.SMS}>
<NodeIcon variant={STEP_TYPE_TO_COLOR[StepTypeEnum.SMS]}>
<Icon />
Expand All @@ -78,17 +91,18 @@ export const SmsNode = ({ data }: NodeProps<NodeType>) => {
{data.error && <NodeError>{data.error}</NodeError>}
<Handle isConnectable={false} className={handleClassName} type="target" position={Position.Top} id="a" />
<Handle isConnectable={false} className={handleClassName} type="source" position={Position.Bottom} id="b" />
</Node>
</StepNode>
</Link>
);
};

export const InAppNode = ({ data }: NodeProps<NodeType>) => {
export const InAppNode = (props: NodeProps<NodeType>) => {
const { data } = props;
const Icon = STEP_TYPE_TO_ICON[StepTypeEnum.IN_APP];

return (
<Link to={buildRoute(ROUTES.CONFIGURE_STEP, { stepSlug: data.stepSlug ?? '' })}>
<Node>
<StepNode data={data}>
<NodeHeader type={StepTypeEnum.IN_APP}>
<NodeIcon variant={STEP_TYPE_TO_COLOR[StepTypeEnum.IN_APP]}>
<Icon />
Expand All @@ -99,17 +113,18 @@ export const InAppNode = ({ data }: NodeProps<NodeType>) => {
{data.error && <NodeError>{data.error}</NodeError>}
<Handle isConnectable={false} className={handleClassName} type="target" position={Position.Top} id="a" />
<Handle isConnectable={false} className={handleClassName} type="source" position={Position.Bottom} id="b" />
</Node>
</StepNode>
</Link>
);
};

export const PushNode = ({ data }: NodeProps<NodeType>) => {
export const PushNode = (props: NodeProps<NodeType>) => {
const { data } = props;
const Icon = STEP_TYPE_TO_ICON[StepTypeEnum.PUSH];

return (
<Link to={`step/${data.stepSlug}`}>
<Node>
<StepNode data={data}>
<NodeHeader type={StepTypeEnum.PUSH}>
<NodeIcon variant={STEP_TYPE_TO_COLOR[StepTypeEnum.PUSH]}>
<Icon />
Expand All @@ -120,17 +135,18 @@ export const PushNode = ({ data }: NodeProps<NodeType>) => {
{data.error && <NodeError>{data.error}</NodeError>}
<Handle isConnectable={false} className={handleClassName} type="target" position={Position.Top} id="a" />
<Handle isConnectable={false} className={handleClassName} type="source" position={Position.Bottom} id="b" />
</Node>
</StepNode>
</Link>
);
};

export const ChatNode = ({ data }: NodeProps<NodeType>) => {
export const ChatNode = (props: NodeProps<NodeType>) => {
const { data } = props;
const Icon = STEP_TYPE_TO_ICON[StepTypeEnum.CHAT];

return (
<Link to={`step/${data.stepSlug}`}>
<Node>
<StepNode data={data}>
<NodeHeader type={StepTypeEnum.CHAT}>
<NodeIcon variant={STEP_TYPE_TO_COLOR[StepTypeEnum.CHAT]}>
<Icon />
Expand All @@ -141,16 +157,17 @@ export const ChatNode = ({ data }: NodeProps<NodeType>) => {
{data.error && <NodeError>{data.error}</NodeError>}
<Handle isConnectable={false} className={handleClassName} type="target" position={Position.Top} id="a" />
<Handle isConnectable={false} className={handleClassName} type="source" position={Position.Bottom} id="b" />
</Node>
</StepNode>
</Link>
);
};

export const DelayNode = ({ data }: NodeProps<NodeType>) => {
export const DelayNode = (props: NodeProps<NodeType>) => {
const { data } = props;
const Icon = STEP_TYPE_TO_ICON[StepTypeEnum.DELAY];

return (
<Node>
<StepNode data={data}>
<NodeHeader type={StepTypeEnum.DELAY}>
<NodeIcon variant={STEP_TYPE_TO_COLOR[StepTypeEnum.DELAY]}>
<Icon />
Expand All @@ -160,15 +177,16 @@ export const DelayNode = ({ data }: NodeProps<NodeType>) => {
<NodeBody>{data.content || 'You have been invited to the Novu party on "commentSnippet"'}</NodeBody>
<Handle isConnectable={false} className={handleClassName} type="target" position={Position.Top} id="a" />
<Handle isConnectable={false} className={handleClassName} type="source" position={Position.Bottom} id="b" />
</Node>
</StepNode>
);
};

export const DigestNode = ({ data }: NodeProps<NodeType>) => {
export const DigestNode = (props: NodeProps<NodeType>) => {
const { data } = props;
const Icon = STEP_TYPE_TO_ICON[StepTypeEnum.DIGEST];

return (
<Node>
<StepNode data={data}>
<NodeHeader type={StepTypeEnum.DIGEST}>
<NodeIcon variant={STEP_TYPE_TO_COLOR[StepTypeEnum.DIGEST]}>
<Icon />
Expand All @@ -180,15 +198,16 @@ export const DigestNode = ({ data }: NodeProps<NodeType>) => {
</NodeBody>
<Handle isConnectable={false} className={handleClassName} type="target" position={Position.Top} id="a" />
<Handle isConnectable={false} className={handleClassName} type="source" position={Position.Bottom} id="b" />
</Node>
</StepNode>
);
};

export const CustomNode = ({ data }: NodeProps<NodeType>) => {
export const CustomNode = (props: NodeProps<NodeType>) => {
const { data } = props;
const Icon = STEP_TYPE_TO_ICON[StepTypeEnum.CUSTOM];

return (
<Node>
<StepNode data={data}>
<NodeHeader type={StepTypeEnum.CUSTOM}>
<NodeIcon variant={STEP_TYPE_TO_COLOR[StepTypeEnum.CUSTOM]}>
<Icon />
Expand All @@ -198,7 +217,7 @@ export const CustomNode = ({ data }: NodeProps<NodeType>) => {
<NodeBody>Executes the business logic in your bridge application</NodeBody>
<Handle isConnectable={false} className={handleClassName} type="target" position={Position.Top} id="a" />
<Handle isConnectable={false} className={handleClassName} type="source" position={Position.Bottom} id="b" />
</Node>
</StepNode>
);
};

Expand Down
Loading