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
+96
@@ -0,0 +1,96 @@
|
||||
import React, { useState } from "react";
|
||||
import WorkflowVariableTextInput from "~/modules/workflowEngine/components/variables/WorkflowVariableTextInput";
|
||||
import { WorkflowDto } from "~/modules/workflowEngine/dtos/WorkflowDto";
|
||||
import { WorkflowBlockDto } from "~/modules/workflowEngine/dtos/WorkflowBlockDto";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { TrashIcon } from "~/components/ui/icons/vendor";
|
||||
|
||||
export default function WorkflowKeyValueInputs({
|
||||
workflow,
|
||||
block,
|
||||
initialData,
|
||||
onChange,
|
||||
}: {
|
||||
workflow: WorkflowDto;
|
||||
block: WorkflowBlockDto;
|
||||
initialData: {
|
||||
[key: string]: string;
|
||||
};
|
||||
onChange: (data: any) => void;
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
const initialPairs = Object.keys(initialData).map((key) => ({
|
||||
id: crypto.randomUUID(),
|
||||
key,
|
||||
value: initialData[key],
|
||||
}));
|
||||
|
||||
const [pairs, setPairs] = useState(initialPairs);
|
||||
|
||||
const handleAddPair = () => {
|
||||
setPairs([...pairs, { id: crypto.randomUUID(), key: "", value: "" }]);
|
||||
};
|
||||
|
||||
const handleKeyChange = (id: string, newKey: string) => {
|
||||
const updatedPairs = pairs.map((pair) => (pair.id === id ? { ...pair, key: newKey } : pair));
|
||||
setPairs(updatedPairs);
|
||||
triggerOnChange(updatedPairs);
|
||||
};
|
||||
|
||||
const handleValueChange = (id: string, newValue: string) => {
|
||||
const updatedPairs = pairs.map((pair) => (pair.id === id ? { ...pair, value: newValue } : pair));
|
||||
setPairs(updatedPairs);
|
||||
triggerOnChange(updatedPairs);
|
||||
};
|
||||
|
||||
const triggerOnChange = (updatedPairs: { id: string; key: string; value: string }[]) => {
|
||||
const newData = updatedPairs.reduce((acc: any, { key, value }) => ({ ...acc, [key]: value }), {});
|
||||
onChange(newData);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="border-border bg-secondary space-y-1 rounded-md border p-2">
|
||||
{pairs.map(({ id, key, value }) => (
|
||||
<div key={id} className="group relative grid grid-cols-1 gap-1 truncate sm:grid-cols-12">
|
||||
<button
|
||||
type="button"
|
||||
aria-label={t("workflows.variables.removePair")}
|
||||
onClick={() => {
|
||||
const updatedPairs = pairs.filter((pair) => pair.id !== id);
|
||||
setPairs(updatedPairs);
|
||||
triggerOnChange(updatedPairs);
|
||||
}}
|
||||
className="absolute right-1 top-1.5 hidden rounded-md p-1 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="p-0.5 sm:col-span-6">
|
||||
<WorkflowVariableTextInput
|
||||
workflow={workflow}
|
||||
block={block}
|
||||
name="key"
|
||||
label={t("workflows.variables.key")}
|
||||
value={key}
|
||||
onChange={(e) => handleKeyChange(id, e)}
|
||||
placeholder={t("workflows.variables.key")}
|
||||
/>
|
||||
</div>
|
||||
<div className="p-0.5 sm:col-span-6">
|
||||
<WorkflowVariableTextInput
|
||||
workflow={workflow}
|
||||
block={block}
|
||||
name="value"
|
||||
label={t("workflows.variables.value")}
|
||||
value={value}
|
||||
onChange={(e) => handleValueChange(id, e)}
|
||||
placeholder={t("workflows.variables.value")}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
<button type="button" onClick={handleAddPair} className="border-border text-muted-foreground bg-secondary hover:bg-secondary/90 rounded-md border px-2 py-1 text-xs">
|
||||
{t("shared.add")}
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
+107
@@ -0,0 +1,107 @@
|
||||
import { Fragment, useEffect, useState } from "react";
|
||||
import SlideOverWideEmpty from "~/components/ui/slideOvers/SlideOverWideEmpty";
|
||||
import WorkflowUtils from "../../helpers/WorkflowUtils";
|
||||
import { WorkflowDto } from "../../dtos/WorkflowDto";
|
||||
import { WorkflowBlockDto } from "../../dtos/WorkflowBlockDto";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { VariableIcon } from "~/components/ui/icons/vendor";
|
||||
|
||||
export default function WorkflowVariableButton({
|
||||
workflow,
|
||||
block,
|
||||
onSelected,
|
||||
}: {
|
||||
workflow: WorkflowDto;
|
||||
block: WorkflowBlockDto;
|
||||
onSelected: (variable: { name: string }) => void;
|
||||
}) {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<button
|
||||
type="button"
|
||||
aria-label={t("workflows.variables.insert")}
|
||||
onClick={() => setIsOpen(true)}
|
||||
className="border-border text-muted-foreground hover:text-foreground hover:bg-background bg-secondary rounded-md border p-1 text-xs font-medium focus:outline-hidden focus:ring-2 focus:ring-gray-500 focus:ring-offset-2"
|
||||
>
|
||||
<VariableIcon className="h-4 w-4" />
|
||||
</button>
|
||||
<SlideOverWideEmpty className="sm:max-w-sm" title={t("workflows.variables.title")} open={isOpen} onClose={() => setIsOpen(false)}>
|
||||
<VariableList
|
||||
workflow={workflow}
|
||||
block={block}
|
||||
onSelected={(variable) => {
|
||||
onSelected(variable);
|
||||
setIsOpen(false);
|
||||
}}
|
||||
/>
|
||||
</SlideOverWideEmpty>
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
function VariableList({ workflow, block, onSelected }: { workflow: WorkflowDto; block: WorkflowBlockDto; onSelected: (variable: { name: string }) => void }) {
|
||||
const [groups, setGroups] = useState<{ name: string; variables: { name: string; label: string }[] }[]>([]);
|
||||
const { t } = useTranslation();
|
||||
useEffect(() => {
|
||||
const variables = WorkflowUtils.getVariables({ workflow, currentBlock: block });
|
||||
const groups = variables.reduce<{ name: string; variables: { name: string; label: string }[] }[]>((acc, variable) => {
|
||||
const group = acc.find((x) => x.name === variable.group);
|
||||
if (group) {
|
||||
group.variables.push(variable);
|
||||
} else {
|
||||
acc.push({ name: variable.group, variables: [variable] });
|
||||
}
|
||||
return acc;
|
||||
}, []);
|
||||
if (workflow.$credentials && workflow.$credentials.length > 0) {
|
||||
groups.unshift({
|
||||
name: t("workflows.variables.credentials"),
|
||||
variables: workflow.$credentials.map((f) => ({
|
||||
name: `{{$credentials.${f}}}`,
|
||||
label: f,
|
||||
})),
|
||||
});
|
||||
}
|
||||
let globalVariables = workflow.$variables ?? [];
|
||||
const variableBlocks = workflow.blocks.filter((x) => x.type === "variable");
|
||||
variableBlocks.forEach((variableBlock) => {
|
||||
globalVariables.push(variableBlock.input.variableName);
|
||||
});
|
||||
if (globalVariables.length > 0) {
|
||||
groups.unshift({
|
||||
name: t("workflows.variables.global"),
|
||||
variables: globalVariables.map((f) => ({
|
||||
name: `{{$vars.${f}}}`,
|
||||
label: f,
|
||||
})),
|
||||
});
|
||||
}
|
||||
setGroups(groups);
|
||||
}, [workflow, block, t]);
|
||||
return (
|
||||
<div className="space-y-2">
|
||||
{groups.map((group, idx) => {
|
||||
return (
|
||||
<div key={idx} className="space-y-1">
|
||||
<div className="font-medium">{group.name}</div>
|
||||
<div className="space-y-1">
|
||||
{group.variables.map((variable) => (
|
||||
<button
|
||||
type="button"
|
||||
key={variable.name}
|
||||
className="hover:bg-secondary border-border bg-background flex w-full items-center space-x-2 truncate rounded-md border px-2 py-2 text-sm"
|
||||
onClick={() => onSelected(variable)}
|
||||
>
|
||||
<div>{variable.label}</div>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
import { useRef } from "react";
|
||||
import { WorkflowDto } from "../../dtos/WorkflowDto";
|
||||
import { WorkflowBlockDto } from "../../dtos/WorkflowBlockDto";
|
||||
import WorkflowVariableButton from "./WorkflowVariableButton";
|
||||
import clsx from "clsx";
|
||||
|
||||
export default function WorkflowVariableTextInput({
|
||||
name,
|
||||
placeholder,
|
||||
label,
|
||||
workflow,
|
||||
block,
|
||||
value,
|
||||
onChange,
|
||||
className,
|
||||
}: {
|
||||
name: string;
|
||||
placeholder: string | undefined;
|
||||
label?: string;
|
||||
workflow: WorkflowDto;
|
||||
block: WorkflowBlockDto;
|
||||
value: string;
|
||||
onChange: (value: string) => void;
|
||||
className?: string;
|
||||
}) {
|
||||
const refString = useRef<HTMLInputElement>(null);
|
||||
|
||||
function onSelected(variable: { name: string }) {
|
||||
if (!refString.current) {
|
||||
return;
|
||||
}
|
||||
var start = refString.current.selectionStart || 0;
|
||||
var end = refString.current.selectionEnd || 0;
|
||||
var text = refString.current.value;
|
||||
var before = text.substring(0, start);
|
||||
var after = text.substring(end, text.length);
|
||||
onChange(before + variable.name + after);
|
||||
}
|
||||
return (
|
||||
<div className={clsx("relative rounded-md shadow-2xs", className)}>
|
||||
<input
|
||||
ref={refString}
|
||||
name={name}
|
||||
id={name}
|
||||
className="border-border bg-secondary hover:bg-secondary/90 w-full rounded-lg border px-2 py-2 pr-10 text-sm focus:outline-hidden"
|
||||
value={value}
|
||||
onClick={(e: React.MouseEvent<HTMLInputElement>) => {
|
||||
// @ts-ignore
|
||||
e.target.select();
|
||||
}}
|
||||
placeholder={placeholder}
|
||||
aria-label={label ?? placeholder ?? name}
|
||||
onChange={(e) => onChange(e.target.value)}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === "Enter") {
|
||||
e.currentTarget.blur();
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<div className="absolute inset-y-0 right-0 flex py-1.5 pr-1.5 ">
|
||||
<WorkflowVariableButton workflow={workflow} block={block} onSelected={onSelected} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user