Track HiveGrid Cloud planning reference
This commit is contained in:
1 parent
b3d5ea6764
commit
e341c5938a
5784 files changed
+1104929
-3
No files matched your search
+99
@@ -0,0 +1,99 @@
|
||||
import { Position, Handle, type NodeProps } from "@xyflow/react";
|
||||
import { t as i18nT } from "i18next";
|
||||
import { WorkflowBlockDto } from "../../dtos/WorkflowBlockDto";
|
||||
import { getWorkflowBlockCategoryLabel, getWorkflowBlockName, WorkflowBlockTypes } from "../../dtos/WorkflowBlockTypes";
|
||||
import WorkflowContext from "../../context/WorkflowContext";
|
||||
import { useContext, useMemo } from "react";
|
||||
import WorkflowBlockUtils from "../../helpers/WorkflowBlockUtils";
|
||||
import { WorkflowDto } from "../../dtos/WorkflowDto";
|
||||
import clsx from "clsx";
|
||||
import { useParams } from "react-router";
|
||||
|
||||
export default function BlockEditorNode({ id, data }: NodeProps) {
|
||||
const params = useParams();
|
||||
const { onNodeDelete, isNodeSelected, incomingBlockIds } = useContext(WorkflowContext);
|
||||
const block = data.block as WorkflowBlockDto;
|
||||
const workflow = data.workflow as WorkflowDto;
|
||||
const workflowBlock = WorkflowBlockTypes.find((x) => x.value === block.type);
|
||||
|
||||
const errors = useMemo(
|
||||
() => (workflow && block ? WorkflowBlockUtils.getBlockErrors({ workflow, block, validationContext: { incomingBlockIds } }) : []),
|
||||
[block, incomingBlockIds, workflow]
|
||||
);
|
||||
|
||||
if (!workflow) {
|
||||
return <div>{i18nT("workflows.blocks.node.unknownWorkflow")}</div>;
|
||||
}
|
||||
if (!workflowBlock) {
|
||||
return <div>{i18nT("workflows.blocks.node.unknownBlockType", { value: block.type })}</div>;
|
||||
}
|
||||
const workflowBlockName = getWorkflowBlockName(workflowBlock, i18nT);
|
||||
const workflowBlockCategory = getWorkflowBlockCategoryLabel(workflowBlock.category, i18nT);
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
data-ui-id="ui.workflows.builder.node"
|
||||
data-workflow-node-id={block.id}
|
||||
data-workflow-node-kind="block"
|
||||
className={clsx(
|
||||
"relative flex h-[80px] w-[250px] flex-col justify-center rounded-md border p-2 text-left focus:ring-1 focus:ring-blue-600 focus:ring-offset-2",
|
||||
isNodeSelected(id) ? "bg-blue-50 ring-1 ring-blue-600 ring-offset-2" : "bg-background",
|
||||
errors.length ? "border-red-300" : "border-border"
|
||||
)}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === "Delete" || e.key === "Backspace") {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
onNodeDelete(block.id);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<div className="w-full space-y-2">
|
||||
<div className="flex justify-between space-x-2">
|
||||
<div className="flex items-center space-x-2 truncate">
|
||||
<workflowBlock.icon className="text-muted-foreground h-4 w-4 shrink-0" />
|
||||
<div className="text-foreground/80 truncate text-sm font-medium">{workflowBlockName}</div>
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
className={clsx(
|
||||
"rounded-md border px-2 py-1 text-xs",
|
||||
workflowBlock.type === "trigger" ? "border-yellow-200 bg-yellow-50 text-yellow-800" : "border-border text-muted-foreground bg-secondary"
|
||||
)}
|
||||
>
|
||||
{workflowBlock.type === "trigger" ? <span>{i18nT("workflows.blocks.types.trigger")}</span> : <span>{workflowBlockCategory}</span>}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="border-border border-t" />
|
||||
{errors.length > 0 ? (
|
||||
<div>
|
||||
<div className="line-clamp-1 text-xs text-red-500">{errors.join(", ")}</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className=" text-muted-foreground line-clamp-1 text-xs">
|
||||
{workflowBlock.appliesToAllTenants && !params.tenant && <span className="text-xs text-blue-500">({i18nT("workflows.blocks.node.allAccounts")}) </span>}
|
||||
{block.description || block.input.event || i18nT("workflows.blocks.node.noDescription")}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{workflowBlock.type === "action" && (
|
||||
<Handle type="target" position={Position.Top} id="in" style={{ opacity: 0, width: "100%", height: "100%", top: 0 }} />
|
||||
)}
|
||||
<Handle
|
||||
type="source"
|
||||
position={Position.Bottom}
|
||||
id="out"
|
||||
style={{
|
||||
bottom: "-7px",
|
||||
left: "calc(50%)",
|
||||
width: "15px",
|
||||
height: "15px",
|
||||
background: "#fff",
|
||||
border: "1px solid #2563eb",
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</button>
|
||||
);
|
||||
}
|
||||
+92
@@ -0,0 +1,92 @@
|
||||
import { Position, Handle, type NodeProps } from "@xyflow/react";
|
||||
import { t as i18nT } from "i18next";
|
||||
import { WorkflowBlockDto } from "../../dtos/WorkflowBlockDto";
|
||||
import { getWorkflowBlockCategoryLabel, getWorkflowBlockName, WorkflowBlockTypes } from "../../dtos/WorkflowBlockTypes";
|
||||
import WorkflowContext from "../../context/WorkflowContext";
|
||||
import { useContext, useMemo } from "react";
|
||||
import WorkflowBlockUtils from "../../helpers/WorkflowBlockUtils";
|
||||
import { WorkflowDto } from "../../dtos/WorkflowDto";
|
||||
import clsx from "clsx";
|
||||
import { WorkflowBlockExecutionDto } from "../../dtos/WorkflowBlockExecutionDto";
|
||||
|
||||
export default function BlockExecutionNode({ id, data }: NodeProps) {
|
||||
const { isNodeSelected, incomingBlockIds } = useContext(WorkflowContext);
|
||||
const block = data.block as WorkflowBlockDto;
|
||||
const workflow = data.workflow as WorkflowDto;
|
||||
const workflowBlockExecution = data.workflowBlockExecution as WorkflowBlockExecutionDto | null;
|
||||
const workflowBlock = WorkflowBlockTypes.find((x) => x.value === block.type);
|
||||
|
||||
const errors = useMemo(
|
||||
() => (workflow && block ? WorkflowBlockUtils.getBlockErrors({ workflow, block, validationContext: { incomingBlockIds } }) : []),
|
||||
[block, incomingBlockIds, workflow]
|
||||
);
|
||||
|
||||
if (!workflow) {
|
||||
return <div>{i18nT("workflows.blocks.node.unknownWorkflow")}</div>;
|
||||
}
|
||||
if (!workflowBlock) {
|
||||
return <div>{i18nT("workflows.blocks.node.unknownBlockType", { value: block.type })}</div>;
|
||||
}
|
||||
const workflowBlockName = getWorkflowBlockName(workflowBlock, i18nT);
|
||||
const workflowBlockCategory = getWorkflowBlockCategoryLabel(workflowBlock.category, i18nT);
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
data-ui-id="ui.workflows.builder.node"
|
||||
data-workflow-node-id={block.id}
|
||||
className={clsx(
|
||||
"relative flex h-[80px] w-[250px] flex-col justify-center rounded-md border p-2 text-left focus:ring-1 focus:ring-offset-2",
|
||||
isNodeSelected(id) ? "ring-1 ring-offset-2" : "",
|
||||
!workflowBlockExecution && "bg-background border-border focus:ring-blue-600",
|
||||
workflowBlockExecution?.status === "success" && "border-teal-300 bg-teal-50 ring-teal-600 focus:ring-teal-600",
|
||||
workflowBlockExecution?.status === "error" && "border-red-300 bg-red-50 ring-red-600 focus:ring-red-600"
|
||||
)}
|
||||
>
|
||||
<div className="w-full space-y-2">
|
||||
<div className="flex justify-between space-x-2">
|
||||
<div className="flex items-center space-x-2 truncate">
|
||||
<workflowBlock.icon className="text-muted-foreground h-4 w-4 shrink-0" />
|
||||
<div className="text-foreground/80 truncate text-sm font-medium">{workflowBlockName}</div>
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
className={clsx(
|
||||
"rounded-md border px-2 py-1 text-xs",
|
||||
workflowBlock.type === "trigger" ? "border-yellow-200 bg-yellow-50 text-yellow-800" : "border-border text-muted-foreground bg-secondary"
|
||||
)}
|
||||
>
|
||||
{workflowBlock.type === "trigger" ? <span>{i18nT("workflows.blocks.types.trigger")}</span> : <span>{workflowBlockCategory}</span>}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="border-border border-t" />
|
||||
{errors.length > 0 ? (
|
||||
<div>
|
||||
<div className="line-clamp-1 text-xs text-red-500">{errors.join(", ")}</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className=" text-muted-foreground line-clamp-1 text-xs">{block.description || block.input.event || i18nT("workflows.blocks.node.noDescription")}</div>
|
||||
)}
|
||||
|
||||
{workflowBlock.type === "action" && (
|
||||
<Handle type="target" position={Position.Top} id="in" style={{ opacity: 0, width: "100%", height: "100%", top: 0 }} isConnectable={false} />
|
||||
)}
|
||||
|
||||
<Handle
|
||||
type="source"
|
||||
position={Position.Bottom}
|
||||
isConnectable={false}
|
||||
id="out"
|
||||
style={{
|
||||
bottom: "-7px",
|
||||
left: "calc(50%)",
|
||||
width: "15px",
|
||||
height: "15px",
|
||||
background: "#fff",
|
||||
border: "1px solid #2563eb",
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</button>
|
||||
);
|
||||
}
|
||||
+173
@@ -0,0 +1,173 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { t as i18nT } from "i18next";
|
||||
import ButtonPrimary from "~/components/ui/buttons/ButtonPrimary";
|
||||
import ButtonSecondary from "~/components/ui/buttons/ButtonSecondary";
|
||||
import { WorkflowConditionOperators, WorkflowConditionsDto, WorkflowConditionsGroupDto } from "~/modules/workflowEngine/dtos/WorkflowConditionDtos";
|
||||
import WorkflowConditionUtils from "~/modules/workflowEngine/helpers/WorkflowConditionUtils";
|
||||
import WorkflowVariableTextInput from "../../variables/WorkflowVariableTextInput";
|
||||
import { WorkflowDto } from "~/modules/workflowEngine/dtos/WorkflowDto";
|
||||
import { WorkflowBlockDto } from "~/modules/workflowEngine/dtos/WorkflowBlockDto";
|
||||
import { TrashIcon } from "~/components/ui/icons/vendor";
|
||||
|
||||
function ConditionsGroupInput({
|
||||
workflow,
|
||||
block,
|
||||
type,
|
||||
conditionsGroup,
|
||||
onSave,
|
||||
onCancel,
|
||||
}: {
|
||||
workflow: WorkflowDto;
|
||||
block: WorkflowBlockDto;
|
||||
type: "if" | "switch";
|
||||
conditionsGroup: WorkflowConditionsGroupDto;
|
||||
onSave: (conditionsGroup: WorkflowConditionsGroupDto) => void;
|
||||
onCancel: () => void;
|
||||
}) {
|
||||
const [conditions, setConditions] = useState<WorkflowConditionsDto[]>(
|
||||
conditionsGroup.conditions.length > 0
|
||||
? conditionsGroup.conditions
|
||||
: [
|
||||
{
|
||||
index: 0,
|
||||
variable: "",
|
||||
operator: "isNotEmpty",
|
||||
value: "",
|
||||
},
|
||||
]
|
||||
);
|
||||
const [errors, setErrors] = useState<{ condition: WorkflowConditionsDto; errors: string[] }[]>([]);
|
||||
const [conditionGroupType, setConditionGroupType] = useState<"AND" | "OR">(conditionsGroup.type);
|
||||
|
||||
useEffect(() => {
|
||||
setErrors(WorkflowConditionUtils.getConditionsErrors(conditions));
|
||||
}, [conditions]);
|
||||
|
||||
function updateConditionInGroup(idx: number, updatedCondition: WorkflowConditionsDto) {
|
||||
const operator = WorkflowConditionUtils.getOperator(updatedCondition.operator);
|
||||
if (!operator?.requiresValue) {
|
||||
updatedCondition.value = "";
|
||||
}
|
||||
setConditions(conditions.map((condition, i) => (i === idx ? updatedCondition : condition)));
|
||||
}
|
||||
function removeConditionFromGroup(idx: number) {
|
||||
setConditions(conditions.filter((_condition, i) => i !== idx));
|
||||
}
|
||||
function addConditionToGroup() {
|
||||
const newCondition: WorkflowConditionsDto = {
|
||||
index: conditions.length,
|
||||
variable: "",
|
||||
operator: "isNotEmpty",
|
||||
value: "",
|
||||
};
|
||||
setConditions([...conditions, newCondition]);
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
{conditions.length === 0 ? (
|
||||
<div className=" border-border bg-secondary/90 flex flex-col items-center justify-center rounded-md border p-2 text-center">
|
||||
<div className="text-muted-foreground text-sm font-medium">{i18nT("workflows.conditions.empty")}</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="space-y-1">
|
||||
<div className="flex h-10 items-center justify-between space-x-2">
|
||||
{/* <div className="font-medium">{conditionsGroup.name}</div> */}
|
||||
<div className="font-medium">{i18nT("workflows.conditions.count", { count: conditions.length })}</div>
|
||||
{conditions.length > 1 && (
|
||||
<select
|
||||
aria-label={i18nT("workflows.conditions.logic.label")}
|
||||
value={conditionGroupType}
|
||||
onChange={(e) => setConditionGroupType(e.target.value as "AND" | "OR")}
|
||||
className="border-border bg-secondary hover:bg-secondary/90 col-span-2 rounded-lg border px-2 py-2 pr-10 text-sm focus:outline-hidden"
|
||||
>
|
||||
<option value="AND">{i18nT("workflows.conditions.logic.and")}</option>
|
||||
<option value="OR">{i18nT("workflows.conditions.logic.or")}</option>
|
||||
</select>
|
||||
)}
|
||||
</div>
|
||||
<div className="space-y-1 pb-2">
|
||||
{conditions.map((condition, idx) => (
|
||||
<div key={idx} className="group relative">
|
||||
<button
|
||||
type="button"
|
||||
aria-label={i18nT("workflows.conditions.deleteCondition")}
|
||||
onClick={() => removeConditionFromGroup(idx)}
|
||||
className="text-muted-foreground absolute right-2 top-2.5 hidden rounded-md hover:text-red-500 focus:outline-hidden focus:ring-2 focus:ring-gray-500 focus:ring-offset-2 group-focus-within:block group-hover:block"
|
||||
>
|
||||
<TrashIcon className="h-4 w-4" />
|
||||
</button>
|
||||
<div className="grid grid-cols-1 gap-1 sm:grid-cols-10">
|
||||
<WorkflowVariableTextInput
|
||||
workflow={workflow}
|
||||
block={block}
|
||||
className="sm:col-span-4"
|
||||
name="variable"
|
||||
placeholder={i18nT("workflows.conditions.variable")}
|
||||
value={condition.variable}
|
||||
onChange={(e) => updateConditionInGroup(idx, { ...condition, variable: e })}
|
||||
/>
|
||||
<select
|
||||
aria-label={i18nT("workflows.conditions.operator")}
|
||||
className="border-border bg-secondary hover:bg-secondary/90 w-full rounded-lg border px-2 py-2 text-sm focus:outline-hidden sm:col-span-2"
|
||||
value={condition.operator}
|
||||
onChange={(e) => updateConditionInGroup(idx, { ...condition, operator: e.target.value as any })}
|
||||
>
|
||||
{WorkflowConditionOperators.map((operator) => {
|
||||
return (
|
||||
<option key={operator.value} value={operator.value}>
|
||||
{i18nT(operator.translationKey)}
|
||||
</option>
|
||||
);
|
||||
})}
|
||||
</select>
|
||||
{/* <input
|
||||
className="col-span-4 bg-secondary border border-border hover:bg-secondary/90 rounded-lg w-full px-2 py-2 text-sm focus:outline-hidden"
|
||||
type="text"
|
||||
placeholder={i18nT("workflows.conditions.value")}
|
||||
value={condition.value}
|
||||
onChange={(e) => updateConditionInGroup(idx, { ...condition, value: e.target.value })}
|
||||
/> */}
|
||||
{WorkflowConditionUtils.getOperator(condition.operator)?.requiresValue && (
|
||||
<WorkflowVariableTextInput
|
||||
workflow={workflow}
|
||||
block={block}
|
||||
className="sm:col-span-4"
|
||||
name="value"
|
||||
placeholder={i18nT("workflows.conditions.value")}
|
||||
value={condition.value}
|
||||
onChange={(e) => updateConditionInGroup(idx, { ...condition, value: e })}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="border-border border-t">
|
||||
<div className="flex justify-between space-x-2 pt-2">
|
||||
<div>
|
||||
{/* <ButtonSecondary onClick={onCancel} className="mr-2">
|
||||
Cancel
|
||||
</ButtonSecondary> */}
|
||||
<ButtonSecondary
|
||||
onClick={() => addConditionToGroup()}
|
||||
// className="bg-secondary hover:bg-secondary/90 border border-border px-2 py-1 rounded-md text-muted-foreground text-xs"
|
||||
>
|
||||
{i18nT("workflows.conditions.add")}
|
||||
</ButtonSecondary>
|
||||
</div>
|
||||
<div className="flex items-center space-x-1">
|
||||
<ButtonPrimary disabled={errors.length > 0} onClick={() => onSave({ ...conditionsGroup, conditions, type: conditionGroupType })}>
|
||||
{i18nT("shared.save")}
|
||||
</ButtonPrimary>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default ConditionsGroupInput;
|
||||
+150
@@ -0,0 +1,150 @@
|
||||
import { useState } from "react";
|
||||
import { t as i18nT } from "i18next";
|
||||
import SlideOverWideEmpty from "~/components/ui/slideOvers/SlideOverWideEmpty";
|
||||
import { WorkflowConditionsGroupDto } from "~/modules/workflowEngine/dtos/WorkflowConditionDtos";
|
||||
import ConditionsGroupInput from "./ConditionsGroupInput";
|
||||
import { WorkflowBlockDto } from "~/modules/workflowEngine/dtos/WorkflowBlockDto";
|
||||
import { WorkflowDto } from "~/modules/workflowEngine/dtos/WorkflowDto";
|
||||
import WorkflowConditionUtils from "~/modules/workflowEngine/helpers/WorkflowConditionUtils";
|
||||
import clsx from "clsx";
|
||||
import { TrashIcon } from "~/components/ui/icons/vendor";
|
||||
|
||||
export default function ConditionsGroupsInfo({
|
||||
workflow,
|
||||
block,
|
||||
type,
|
||||
onUpdateConditionsGroups,
|
||||
}: {
|
||||
workflow: WorkflowDto;
|
||||
block: WorkflowBlockDto;
|
||||
type: "if" | "switch";
|
||||
onUpdateConditionsGroups: (conditionsGroups: WorkflowConditionsGroupDto[]) => void;
|
||||
}) {
|
||||
const [selectedConditionsGroup, setSelectedConditionsGroup] = useState<WorkflowConditionsGroupDto | null>(null);
|
||||
const [addingNewGroup, setAddingNewGroup] = useState(false);
|
||||
|
||||
function onSaveGroup(conditionsGroup: WorkflowConditionsGroupDto) {
|
||||
if (conditionsGroup.index === block.conditionGroups.length) {
|
||||
onUpdateConditionsGroups([...block.conditionGroups, conditionsGroup]);
|
||||
} else {
|
||||
onUpdateConditionsGroups(block.conditionGroups.map((group) => (group.index === conditionsGroup.index ? conditionsGroup : group)));
|
||||
}
|
||||
setSelectedConditionsGroup(null);
|
||||
setAddingNewGroup(false);
|
||||
}
|
||||
function onDeleteGroup(idx: number) {
|
||||
const newConditionsGroups = block.conditionGroups.filter((_group, i) => i !== idx);
|
||||
onUpdateConditionsGroups(newConditionsGroups);
|
||||
}
|
||||
return (
|
||||
<div className="space-y-1">
|
||||
{block.conditionGroups.map((group) => {
|
||||
return (
|
||||
<div key={group.index} className="space-y-0.5">
|
||||
{type === "switch" && (
|
||||
<div className="text-muted-foreground text-xs font-medium uppercase">{i18nT("workflows.conditions.caseNumber", { index: group.index + 1 })}</div>
|
||||
)}
|
||||
{/* role=button instead of <button>: this row contains a nested delete <button>, so it cannot be a button element. */}
|
||||
<div
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
onClick={() => setSelectedConditionsGroup(group)}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === "Enter" || e.key === " ") {
|
||||
e.preventDefault();
|
||||
setSelectedConditionsGroup(group);
|
||||
}
|
||||
}}
|
||||
className={clsx(
|
||||
"border-border group relative cursor-pointer rounded-lg border border-dashed px-2 py-2 text-sm hover:border-dotted focus:outline-hidden",
|
||||
group.conditions.length === 0
|
||||
? "border-red-300 bg-red-50 text-red-800 hover:border-red-800 hover:bg-red-100"
|
||||
: "border-border bg-background hover:bg-secondary/90 hover:border-border"
|
||||
)}
|
||||
>
|
||||
{type === "switch" && (
|
||||
<button
|
||||
type="button"
|
||||
aria-label={i18nT("workflows.conditions.deleteCase", { index: group.index + 1 })}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
onDeleteGroup(group.index);
|
||||
}}
|
||||
className="text-muted-foreground absolute right-2 top-2.5 hidden rounded-md hover:text-red-500 focus:outline-hidden focus:ring-2 focus:ring-gray-500 focus:ring-offset-2 group-focus-within:block group-hover:block"
|
||||
>
|
||||
<TrashIcon className="h-4 w-4" />
|
||||
</button>
|
||||
)}
|
||||
<div className="space-y-0.5">
|
||||
{group.conditions.length === 0 ? (
|
||||
<div>
|
||||
<div className="font-medium">{i18nT("workflows.conditions.empty")}</div>
|
||||
</div>
|
||||
) : group.conditions.length === 1 ? (
|
||||
<div className=" border-border bg-secondary/90 flex flex-col items-center justify-center rounded-md border p-2 text-center">
|
||||
<div key={group.index} className="flex items-center space-x-2">
|
||||
<div className="font-medium">{WorkflowConditionUtils.getConditionString(group.conditions[0], i18nT)}</div>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div>
|
||||
<div className="font-medium">{i18nT("workflows.conditions.count", { count: group.conditions.length })}</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
{type === "switch" && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setAddingNewGroup(true)}
|
||||
className="border-border text-muted-foreground bg-secondary hover:bg-secondary/90 rounded-md border px-2 py-1 text-xs"
|
||||
>
|
||||
{i18nT("workflows.conditions.addCase")}
|
||||
</button>
|
||||
)}
|
||||
|
||||
<SlideOverWideEmpty
|
||||
className="sm:max-w-2xl"
|
||||
title={!selectedConditionsGroup ? "" : type === "if" ? i18nT("workflows.conditions.ifTitle") : i18nT("workflows.conditions.caseTitle", { index: selectedConditionsGroup.index + 1 })}
|
||||
open={!!selectedConditionsGroup}
|
||||
onClose={() => setSelectedConditionsGroup(null)}
|
||||
>
|
||||
{selectedConditionsGroup && (
|
||||
<ConditionsGroupInput
|
||||
workflow={workflow}
|
||||
block={block}
|
||||
type={type}
|
||||
conditionsGroup={selectedConditionsGroup}
|
||||
onCancel={() => setSelectedConditionsGroup(null)}
|
||||
onSave={onSaveGroup}
|
||||
/>
|
||||
)}
|
||||
</SlideOverWideEmpty>
|
||||
|
||||
<SlideOverWideEmpty
|
||||
className="sm:max-w-2xl"
|
||||
title={i18nT("workflows.conditions.addCaseTitle", { index: block.conditionGroups.length + 1 })}
|
||||
open={addingNewGroup}
|
||||
onClose={() => setAddingNewGroup(false)}
|
||||
>
|
||||
{addingNewGroup && (
|
||||
<ConditionsGroupInput
|
||||
workflow={workflow}
|
||||
block={block}
|
||||
type={type}
|
||||
conditionsGroup={{
|
||||
index: block.conditionGroups.length,
|
||||
type: "AND",
|
||||
conditions: [],
|
||||
}}
|
||||
onCancel={() => setAddingNewGroup(false)}
|
||||
onSave={onSaveGroup}
|
||||
/>
|
||||
)}
|
||||
</SlideOverWideEmpty>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
import { ArrowLeftRightIcon } from "~/components/ui/icons/vendor";
|
||||
|
||||
export default function ConditionalIcon({ className }: { className?: string }) {
|
||||
return <ArrowLeftRightIcon className={className} />;
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
export default function DoNothingIcon({ className }: { className?: string }) {
|
||||
return (
|
||||
<svg className={className} fill="currentColor" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" width="50" height="50" viewBox="0 0 50 50">
|
||||
<path d="M 32 9 L 32 21.851563 L 11 8.152344 L 11 41.847656 L 32 28.148438 L 32 41 L 40 41 L 40 9 Z"></path>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
export default function HttpRequestIcon({ className }: { className?: string }) {
|
||||
return (
|
||||
<svg className={className} fill="currentColor" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" width="50" height="50" viewBox="0 0 50 50">
|
||||
<path d="M 3 6 C 2.449219 6 2 6.449219 2 7 L 2 43 C 2 43.554688 2.449219 44 3 44 L 47 44 C 47.554688 44 48 43.554688 48 43 L 48 7 C 48 6.449219 47.554688 6 47 6 Z M 14.5 16 C 14.9375 16 15.339844 16.300781 15.46875 16.71875 L 19.96875 31.34375 C 19.996094 31.441406 20 31.523438 20 31.625 L 20 32 C 20 32.554688 19.550781 33 19 33 C 18.449219 33 18 32.554688 18 32 L 18 31.78125 L 17.15625 29 L 11.84375 29 L 11 31.78125 L 11 32 C 11 32.554688 10.550781 33 10 33 C 9.449219 33 9 32.554688 9 32 L 9 31.625 C 9 31.523438 9.003906 31.441406 9.03125 31.34375 L 13.53125 16.71875 C 13.660156 16.300781 14.0625 16 14.5 16 Z M 24 16 L 28 16 C 30.207031 16 32 17.792969 32 20 L 32 23 C 32 25.207031 30.207031 27 28 27 L 25 27 L 25 32 C 25 32.554688 24.550781 33 24 33 C 23.449219 33 23 32.554688 23 32 L 23 17 C 23 16.449219 23.449219 16 24 16 Z M 35.5 16 L 38.5 16 C 39.054688 16 39.5 16.449219 39.5 17 C 39.5 17.550781 39.054688 18 38.5 18 L 38 18 L 38 31 L 38.5 31 C 39.054688 31 39.5 31.445313 39.5 32 C 39.5 32.554688 39.054688 33 38.5 33 L 35.5 33 C 34.945313 33 34.5 32.554688 34.5 32 C 34.5 31.445313 34.945313 31 35.5 31 L 36 31 L 36 18 L 35.5 18 C 34.945313 18 34.5 17.550781 34.5 17 C 34.5 16.449219 34.945313 16 35.5 16 Z M 25 18 L 25 25 L 28 25 C 29.101563 25 30 24.101563 30 23 L 30 20 C 30 18.898438 29.101563 18 28 18 Z M 14.5 20.40625 L 12.46875 27 L 16.53125 27 Z"></path>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
export default function LogIcon({ className }: { className?: string }) {
|
||||
return (
|
||||
<svg className={className} fill="currentColor" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" width="64" height="64" viewBox="0 0 64 64">
|
||||
<path d="M 11 6 L 11 58 L 53 58 L 53 24.154297 C 53 22.117297 52.280703 20.144938 50.970703 18.585938 L 42.109375 8.0429688 C 41.021375 6.7479688 39.416609 6 37.724609 6 L 11 6 z M 15 10 L 36.695312 10 C 39.985312 10 41 11.365078 41 12.580078 C 41 14.365078 39 17 39 17 C 47.724993 21.129645 48.835785 21.437688 48.974609 24 L 15 24 L 15 10 z M 30.927734 27.791016 C 33.318734 27.791016 35.044922 29.770094 35.044922 32.996094 C 35.044922 36.222094 33.360672 38.228516 31.013672 38.228516 C 28.622672 38.228516 26.8125 36.291094 26.8125 32.996094 C 26.8125 29.770094 28.565734 27.791016 30.927734 27.791016 z M 41.285156 27.791016 C 42.855156 27.791016 43.959609 28.342172 44.849609 29.826172 L 43.109375 30.986328 C 42.727375 30.236328 41.922156 29.714844 41.285156 29.714844 C 39.800156 29.714844 39.050781 30.818094 39.050781 32.996094 C 39.050781 34.948094 39.928156 36.361328 41.285156 36.361328 C 42.290156 36.361328 42.981672 35.740047 43.138672 34.623047 L 41.257812 34.623047 L 41.257812 32.8125 L 45.259766 32.8125 L 45.259766 33.632812 C 45.259766 35.981812 43.563156 38.228516 41.285156 38.228516 C 38.824156 38.228516 37.169922 35.966094 37.169922 32.996094 C 37.169922 29.800094 38.626156 27.791016 41.285156 27.791016 z M 19.527344 27.931641 L 21.351562 27.931641 L 21.351562 36.291016 L 25.425781 36.291016 L 25.425781 38.087891 L 19.527344 38.087891 L 19.527344 27.931641 z M 30.927734 29.585938 C 29.570734 29.585938 28.609375 30.717141 28.609375 32.994141 C 28.609375 35.271141 29.640734 36.404297 30.927734 36.404297 C 32.242734 36.404297 33.248047 35.271141 33.248047 32.994141 C 33.248047 30.717141 32.412734 29.585937 30.927734 29.585938 z M 15 42 L 49 42 L 49 54 L 15 54 L 15 42 z"></path>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
import { type NodeProps } from "@xyflow/react";
|
||||
import { t as i18nT } from "i18next";
|
||||
|
||||
export default function SetTriggerNode({ id }: NodeProps) {
|
||||
return (
|
||||
<div
|
||||
data-ui-id="ui.workflows.builder.node"
|
||||
data-workflow-node-id={id}
|
||||
data-workflow-node-kind="set-trigger"
|
||||
className="border-border h-20 w-64 rounded-md border border-dashed bg-slate-100 ring-1 ring-blue-600 ring-offset-2"
|
||||
>
|
||||
<div className="flex h-full flex-col justify-center space-y-1">
|
||||
<div className="text-muted-foreground text-center text-xs">{i18nT("workflows.builder.setTriggerPrompt")}</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
export default function TriggerManualIcon({ className }: { className?: string }) {
|
||||
return (
|
||||
<svg className={className} fill="currentColor" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" width="50" height="50" viewBox="0 0 50 50">
|
||||
<path d="M 19.5 2 C 15.363281 2 12 5.363281 12 9.5 C 12 11.945313 13.183594 14.128906 15 15.5 L 15 12.65625 C 14.371094 11.761719 14 10.671875 14 9.5 C 14 6.464844 16.46875 4 19.5 4 C 22.53125 4 25 6.46875 25 9.5 C 25 10.671875 24.628906 11.761719 24 12.65625 L 24 15.5 C 25.816406 14.128906 27 11.945313 27 9.5 C 27 5.363281 23.636719 2 19.5 2 Z M 19.5 7.03125 C 18.535156 7.03125 17 7.695313 17 9.4375 L 17 34.0625 L 10.96875 28.03125 C 9.601563 26.664063 7.398438 26.664063 6.03125 28.03125 C 4.664063 29.398438 4.664063 31.601563 6.03125 32.96875 L 17 44 C 17.683594 44.683594 21.113281 48 25.78125 48 C 25.816406 48.003906 34 48 34 48 C 38.425781 48 43 44.632813 43 39 L 43 24.59375 C 43 23.21875 42.253906 22 40.53125 22 C 38.808594 22 38.03125 23.1875 38.03125 24.53125 L 38.03125 27 C 38.03125 27.550781 37.585938 28 37.03125 28 C 36.476563 28 36 27.550781 36 27 L 36 22.46875 C 36.019531 21.261719 35.28125 20 33.53125 20 C 31.78125 20 31 21.355469 31 22.5 L 31 25 C 31 25.550781 30.554688 26 30 26 C 29.449219 26 28.96875 25.550781 28.96875 25 L 29 21.5 C 29 20.488281 28.210938 19 26.5 19 C 24.789063 19 24 20.488281 24 21.5 L 24 25 C 24 25.550781 23.550781 26 23 26 C 22.449219 26 22 25.550781 22 25 L 22 9.5625 C 22 7.722656 20.507813 7.03125 19.5 7.03125 Z"></path>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user