Refactoring: merge WorkflowParameterEditPanel and WorkflowParameterAddPanel (#3750)
This commit is contained in:
committed by
GitHub
parent
a2cef7985d
commit
117b2469e4
@@ -1,615 +0,0 @@
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Checkbox } from "@/components/ui/checkbox";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { ScrollArea, ScrollAreaViewport } from "@/components/ui/scroll-area";
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectGroup,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
import { toast } from "@/components/ui/use-toast";
|
||||
import CloudContext from "@/store/CloudContext";
|
||||
import { Cross2Icon } from "@radix-ui/react-icons";
|
||||
import { useContext, useState } from "react";
|
||||
import { CredentialParameterSourceSelector } from "../../components/CredentialParameterSourceSelector";
|
||||
import { SourceParameterKeySelector } from "../../components/SourceParameterKeySelector";
|
||||
import {
|
||||
WorkflowEditorParameterType,
|
||||
WorkflowParameterValueType,
|
||||
} from "../../types/workflowTypes";
|
||||
import { WorkflowParameterInput } from "../../WorkflowParameterInput";
|
||||
import { ParametersState } from "../types";
|
||||
import { getDefaultValueForParameterType } from "../workflowEditorUtils";
|
||||
import { validateBitwardenLoginCredential } from "./util";
|
||||
import { HelpTooltip } from "@/components/HelpTooltip";
|
||||
|
||||
type Props = {
|
||||
type: WorkflowEditorParameterType;
|
||||
onClose: () => void;
|
||||
onSave: (value: ParametersState[number]) => void;
|
||||
};
|
||||
|
||||
const workflowParameterTypeOptions = [
|
||||
{ label: "string", value: WorkflowParameterValueType.String },
|
||||
{ label: "float", value: WorkflowParameterValueType.Float },
|
||||
{ label: "integer", value: WorkflowParameterValueType.Integer },
|
||||
{ label: "boolean", value: WorkflowParameterValueType.Boolean },
|
||||
{ label: "file", value: WorkflowParameterValueType.FileURL },
|
||||
{ label: "JSON", value: WorkflowParameterValueType.JSON },
|
||||
];
|
||||
|
||||
function header(type: WorkflowEditorParameterType) {
|
||||
if (type === "workflow") {
|
||||
return "Add Input Parameter";
|
||||
}
|
||||
if (type === "credential") {
|
||||
return "Add Credential Parameter";
|
||||
}
|
||||
if (type === "secret") {
|
||||
return "Add Secret Parameter";
|
||||
}
|
||||
if (type === "creditCardData") {
|
||||
return "Add Credit Card Parameter";
|
||||
}
|
||||
return "Add Context Parameter";
|
||||
}
|
||||
|
||||
function WorkflowParameterAddPanel({ type, onClose, onSave }: Props) {
|
||||
const reservedKeys = ["current_item", "current_value", "current_index"];
|
||||
const isCloud = useContext(CloudContext);
|
||||
const [key, setKey] = useState("");
|
||||
const hasWhitespace = /\s/.test(key);
|
||||
const [urlParameterKey, setUrlParameterKey] = useState("");
|
||||
const [description, setDescription] = useState("");
|
||||
const [bitwardenCollectionId, setBitwardenCollectionId] = useState("");
|
||||
const [bitwardenLoginCredentialItemId, setBitwardenLoginCredentialItemId] =
|
||||
useState("");
|
||||
const [parameterType, setParameterType] =
|
||||
useState<WorkflowParameterValueType>("string");
|
||||
const [defaultValueState, setDefaultValueState] = useState<{
|
||||
hasDefaultValue: boolean;
|
||||
defaultValue: unknown;
|
||||
}>({
|
||||
hasDefaultValue: false,
|
||||
defaultValue: null,
|
||||
});
|
||||
const [sourceParameterKey, setSourceParameterKey] = useState<
|
||||
string | undefined
|
||||
>(undefined);
|
||||
|
||||
const [credentialType, setCredentialType] = useState<
|
||||
"bitwarden" | "skyvern" | "onepassword" | "azurevault"
|
||||
>("skyvern");
|
||||
const [vaultId, setVaultId] = useState("");
|
||||
const [itemId, setItemId] = useState("");
|
||||
|
||||
const [identityKey, setIdentityKey] = useState("");
|
||||
const [identityFields, setIdentityFields] = useState("");
|
||||
const [sensitiveInformationItemId, setSensitiveInformationItemId] =
|
||||
useState("");
|
||||
|
||||
const [credentialId, setCredentialId] = useState("");
|
||||
|
||||
const [azureVaultName, setAzureVaultName] = useState("");
|
||||
const [azureUsernameKey, setAzureUsernameKey] = useState("");
|
||||
const [azurePasswordKey, setAzurePasswordKey] = useState("");
|
||||
const [azureTotpSecretKey, setAzureTotpKey] = useState("");
|
||||
|
||||
return (
|
||||
<ScrollArea>
|
||||
<ScrollAreaViewport className="max-h-[500px]">
|
||||
<div className="space-y-4 p-1 px-4">
|
||||
<header className="flex items-center justify-between">
|
||||
<span>{header(type)}</span>
|
||||
<Cross2Icon className="h-6 w-6 cursor-pointer" onClick={onClose} />
|
||||
</header>
|
||||
<div className="space-y-1">
|
||||
<Label className="text-xs text-slate-300">Key</Label>
|
||||
<Input value={key} onChange={(e) => setKey(e.target.value)} />
|
||||
{hasWhitespace && (
|
||||
<p className="text-xs text-destructive">
|
||||
Spaces are not allowed, consider using _
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<Label className="text-xs text-slate-300">Description</Label>
|
||||
<Input
|
||||
value={description}
|
||||
onChange={(e) => setDescription(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
{type === "workflow" && (
|
||||
<>
|
||||
<div className="space-y-1">
|
||||
<Label className="text-xs">Value Type</Label>
|
||||
<Select
|
||||
value={parameterType}
|
||||
onValueChange={(value) => {
|
||||
setParameterType(value as WorkflowParameterValueType);
|
||||
setDefaultValueState((state) => {
|
||||
return {
|
||||
...state,
|
||||
defaultValue: getDefaultValueForParameterType(
|
||||
value as WorkflowParameterValueType,
|
||||
),
|
||||
};
|
||||
});
|
||||
}}
|
||||
>
|
||||
<SelectTrigger className="w-full">
|
||||
<SelectValue placeholder="Select a type" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
{workflowParameterTypeOptions.map((option) => (
|
||||
<SelectItem key={option.value} value={option.value}>
|
||||
{option.label}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<div className="space-y-4">
|
||||
<div className="flex items-center gap-2">
|
||||
<Checkbox
|
||||
checked={defaultValueState.hasDefaultValue}
|
||||
onCheckedChange={(checked) => {
|
||||
if (!checked) {
|
||||
setDefaultValueState({
|
||||
hasDefaultValue: false,
|
||||
defaultValue: null,
|
||||
});
|
||||
return;
|
||||
}
|
||||
setDefaultValueState({
|
||||
hasDefaultValue: true,
|
||||
defaultValue:
|
||||
getDefaultValueForParameterType(parameterType),
|
||||
});
|
||||
}}
|
||||
/>
|
||||
<Label className="text-xs text-slate-300">
|
||||
Use Default Value
|
||||
</Label>
|
||||
</div>
|
||||
{defaultValueState.hasDefaultValue && (
|
||||
<WorkflowParameterInput
|
||||
onChange={(value) => {
|
||||
if (
|
||||
parameterType === "file_url" &&
|
||||
typeof value === "object" &&
|
||||
value &&
|
||||
"s3uri" in value
|
||||
) {
|
||||
setDefaultValueState((state) => {
|
||||
return {
|
||||
...state,
|
||||
defaultValue: value.s3uri,
|
||||
};
|
||||
});
|
||||
return;
|
||||
}
|
||||
setDefaultValueState((state) => {
|
||||
return {
|
||||
...state,
|
||||
defaultValue: value,
|
||||
};
|
||||
});
|
||||
}}
|
||||
type={parameterType}
|
||||
value={defaultValueState.defaultValue}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{type === "credential" && (
|
||||
<>
|
||||
<div className="space-y-1">
|
||||
<Label className="text-xs text-slate-300">
|
||||
Credential Type
|
||||
</Label>
|
||||
<Select
|
||||
value={credentialType}
|
||||
onValueChange={(value) => {
|
||||
setCredentialType(
|
||||
value as
|
||||
| "bitwarden"
|
||||
| "skyvern"
|
||||
| "onepassword"
|
||||
| "azurevault",
|
||||
);
|
||||
}}
|
||||
>
|
||||
<SelectTrigger className="w-full">
|
||||
<SelectValue placeholder="Select a type" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectItem value="skyvern">Skyvern</SelectItem>
|
||||
<SelectItem value="bitwarden">Bitwarden</SelectItem>
|
||||
<SelectItem value="onepassword">1Password</SelectItem>
|
||||
<SelectItem value="azurevault">Azure Vault</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{type === "credential" && credentialType === "bitwarden" && (
|
||||
<>
|
||||
<div className="space-y-1">
|
||||
<Label className="text-xs text-slate-300">
|
||||
URL Parameter Key
|
||||
</Label>
|
||||
<Input
|
||||
value={urlParameterKey}
|
||||
onChange={(e) => setUrlParameterKey(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<Label className="text-xs text-slate-300">Collection ID</Label>
|
||||
<Input
|
||||
value={bitwardenCollectionId}
|
||||
onChange={(e) => setBitwardenCollectionId(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<Label className="text-xs text-slate-300">Item ID</Label>
|
||||
<Input
|
||||
value={bitwardenLoginCredentialItemId}
|
||||
onChange={(e) =>
|
||||
setBitwardenLoginCredentialItemId(e.target.value)
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{type === "credential" && credentialType === "onepassword" && (
|
||||
<>
|
||||
<div className="space-y-1">
|
||||
<div className="flex gap-2">
|
||||
<Label className="text-xs text-slate-300">Vault ID</Label>
|
||||
<HelpTooltip content="You can find the Vault ID and Item ID in the URL when viewing the item in 1Password on the web." />
|
||||
</div>
|
||||
<Input
|
||||
value={vaultId}
|
||||
onChange={(e) => setVaultId(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<div className="flex gap-2">
|
||||
<Label className="text-xs text-slate-300">Item ID</Label>
|
||||
<HelpTooltip content="Supports all 1Password item types: Logins, Passwords, Credit Cards, Secure Notes, and more." />
|
||||
</div>
|
||||
<Input
|
||||
value={itemId}
|
||||
onChange={(e) => setItemId(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<div className="rounded-md bg-slate-800 p-2">
|
||||
<div className="space-y-1 text-xs text-slate-400">
|
||||
* Credit Cards: Due to a 1Password limitation, add the
|
||||
expiration date as a separate text field named "Expire Date"
|
||||
in the format MM/YYYY (e.g. 09/2027).
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{type === "credential" && credentialType === "azurevault" && (
|
||||
<>
|
||||
<div className="space-y-1">
|
||||
<Label className="text-xs text-slate-300">Vault Name</Label>
|
||||
<Input
|
||||
value={azureVaultName}
|
||||
onChange={(e) => setAzureVaultName(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<Label className="text-xs text-slate-300">Username Key</Label>
|
||||
<Input
|
||||
autoComplete="off"
|
||||
value={azureUsernameKey}
|
||||
onChange={(e) => setAzureUsernameKey(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<Label className="text-xs text-slate-300">Password Key</Label>
|
||||
<Input
|
||||
value={azurePasswordKey}
|
||||
onChange={(e) => setAzurePasswordKey(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<Label className="text-xs text-slate-300">
|
||||
TOTP Secret Key
|
||||
</Label>
|
||||
<Input
|
||||
value={azureTotpSecretKey}
|
||||
onChange={(e) => setAzureTotpKey(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{type === "context" && (
|
||||
<div className="space-y-1">
|
||||
<Label className="text-xs text-slate-300">Source Parameter</Label>
|
||||
<SourceParameterKeySelector
|
||||
value={sourceParameterKey}
|
||||
onChange={setSourceParameterKey}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{type === "secret" && (
|
||||
<>
|
||||
<div className="space-y-1">
|
||||
<Label className="text-xs text-slate-300">Identity Key</Label>
|
||||
<Input
|
||||
value={identityKey}
|
||||
onChange={(e) => setIdentityKey(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<Label className="text-xs text-slate-300">
|
||||
Identity Fields
|
||||
</Label>
|
||||
<Input
|
||||
value={identityFields}
|
||||
onChange={(e) => setIdentityFields(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<Label className="text-xs text-slate-300">Collection ID</Label>
|
||||
<Input
|
||||
value={bitwardenCollectionId}
|
||||
onChange={(e) => setBitwardenCollectionId(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{type === "creditCardData" && (
|
||||
<>
|
||||
<div className="space-y-1">
|
||||
<Label className="text-xs text-slate-300">Collection ID</Label>
|
||||
<Input
|
||||
value={bitwardenCollectionId}
|
||||
onChange={(e) => setBitwardenCollectionId(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<Label className="text-xs text-slate-300">Item ID</Label>
|
||||
<Input
|
||||
value={sensitiveInformationItemId}
|
||||
onChange={(e) =>
|
||||
setSensitiveInformationItemId(e.target.value)
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{
|
||||
// temporarily cloud only
|
||||
type === "credential" &&
|
||||
credentialType === "skyvern" &&
|
||||
isCloud && (
|
||||
<div className="space-y-1">
|
||||
<Label className="text-xs text-slate-300">Credential</Label>
|
||||
<CredentialParameterSourceSelector
|
||||
value={credentialId}
|
||||
onChange={(value) => setCredentialId(value)}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
<div className="flex justify-end">
|
||||
<Button
|
||||
onClick={() => {
|
||||
if (!key) {
|
||||
toast({
|
||||
variant: "destructive",
|
||||
title: "Failed to add parameter",
|
||||
description: "Key is required",
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (hasWhitespace) {
|
||||
toast({
|
||||
variant: "destructive",
|
||||
title: "Failed to add parameter",
|
||||
description: "Key cannot contain whitespaces",
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (reservedKeys.includes(key)) {
|
||||
toast({
|
||||
variant: "destructive",
|
||||
title: "Failed to add parameter",
|
||||
description: `${key} is reserved, please use another key`,
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (type === "workflow") {
|
||||
if (
|
||||
parameterType === "json" &&
|
||||
typeof defaultValueState.defaultValue === "string"
|
||||
) {
|
||||
try {
|
||||
JSON.parse(defaultValueState.defaultValue);
|
||||
} catch (e) {
|
||||
toast({
|
||||
variant: "destructive",
|
||||
title: "Failed to add parameter",
|
||||
description: "Invalid JSON for default value",
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
const defaultValue =
|
||||
parameterType === "json" &&
|
||||
typeof defaultValueState.defaultValue === "string"
|
||||
? JSON.parse(defaultValueState.defaultValue)
|
||||
: defaultValueState.defaultValue;
|
||||
onSave({
|
||||
key,
|
||||
parameterType: "workflow",
|
||||
dataType: parameterType,
|
||||
description,
|
||||
defaultValue: defaultValueState.hasDefaultValue
|
||||
? defaultValue
|
||||
: null,
|
||||
});
|
||||
}
|
||||
if (type === "credential" && credentialType === "bitwarden") {
|
||||
const errorMessage = validateBitwardenLoginCredential(
|
||||
bitwardenCollectionId,
|
||||
bitwardenLoginCredentialItemId,
|
||||
urlParameterKey,
|
||||
);
|
||||
if (errorMessage) {
|
||||
toast({
|
||||
variant: "destructive",
|
||||
title: "Failed to save parameter",
|
||||
description: errorMessage,
|
||||
});
|
||||
return;
|
||||
}
|
||||
onSave({
|
||||
key,
|
||||
parameterType: "credential",
|
||||
collectionId:
|
||||
bitwardenCollectionId === ""
|
||||
? null
|
||||
: bitwardenCollectionId,
|
||||
itemId:
|
||||
bitwardenLoginCredentialItemId === ""
|
||||
? null
|
||||
: bitwardenLoginCredentialItemId,
|
||||
urlParameterKey:
|
||||
urlParameterKey === "" ? null : urlParameterKey,
|
||||
description,
|
||||
});
|
||||
}
|
||||
if (type === "credential" && credentialType === "onepassword") {
|
||||
if (vaultId.trim() === "" || itemId.trim() === "") {
|
||||
toast({
|
||||
variant: "destructive",
|
||||
title: "Failed to add parameter",
|
||||
description: "Vault ID and Item ID are required",
|
||||
});
|
||||
return;
|
||||
}
|
||||
onSave({
|
||||
key,
|
||||
parameterType: "onepassword",
|
||||
vaultId,
|
||||
itemId,
|
||||
description,
|
||||
});
|
||||
}
|
||||
if (type === "credential" && credentialType === "azurevault") {
|
||||
if (
|
||||
azureVaultName.trim() === "" ||
|
||||
azureUsernameKey.trim() === "" ||
|
||||
azurePasswordKey.trim() === ""
|
||||
) {
|
||||
toast({
|
||||
variant: "destructive",
|
||||
title: "Failed to add parameter",
|
||||
description:
|
||||
"Azure Vault Name, Username Key and Password Key are required",
|
||||
});
|
||||
return;
|
||||
}
|
||||
onSave({
|
||||
key,
|
||||
parameterType: "credential",
|
||||
vaultName: azureVaultName,
|
||||
usernameKey: azureUsernameKey,
|
||||
passwordKey: azurePasswordKey,
|
||||
totpSecretKey:
|
||||
azureTotpSecretKey === "" ? null : azureTotpSecretKey,
|
||||
description: description,
|
||||
});
|
||||
}
|
||||
if (type === "secret" || type === "creditCardData") {
|
||||
if (!bitwardenCollectionId) {
|
||||
toast({
|
||||
variant: "destructive",
|
||||
title: "Failed to save parameter",
|
||||
description: "Collection ID is required",
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (type === "secret") {
|
||||
onSave({
|
||||
key,
|
||||
parameterType: "secret",
|
||||
collectionId: bitwardenCollectionId,
|
||||
identityFields: identityFields
|
||||
.split(",")
|
||||
.filter((s) => s.length > 0)
|
||||
.map((field) => field.trim()),
|
||||
identityKey,
|
||||
description,
|
||||
});
|
||||
}
|
||||
if (type === "creditCardData") {
|
||||
onSave({
|
||||
key,
|
||||
parameterType: "creditCardData",
|
||||
collectionId: bitwardenCollectionId,
|
||||
itemId: sensitiveInformationItemId,
|
||||
description,
|
||||
});
|
||||
}
|
||||
if (type === "context") {
|
||||
if (!sourceParameterKey) {
|
||||
toast({
|
||||
variant: "destructive",
|
||||
title: "Failed to add parameter",
|
||||
description: "Source parameter key is required",
|
||||
});
|
||||
return;
|
||||
}
|
||||
onSave({
|
||||
key,
|
||||
parameterType: "context",
|
||||
sourceParameterKey,
|
||||
description,
|
||||
});
|
||||
}
|
||||
if (type === "credential" && credentialType === "skyvern") {
|
||||
if (!credentialId) {
|
||||
toast({
|
||||
variant: "destructive",
|
||||
title: "Failed to add parameter",
|
||||
description: "Credential is required",
|
||||
});
|
||||
return;
|
||||
}
|
||||
onSave({
|
||||
key,
|
||||
parameterType: "credential",
|
||||
credentialId,
|
||||
description,
|
||||
});
|
||||
}
|
||||
}}
|
||||
>
|
||||
Save
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</ScrollAreaViewport>
|
||||
</ScrollArea>
|
||||
);
|
||||
}
|
||||
|
||||
export { WorkflowParameterAddPanel };
|
||||
@@ -37,7 +37,7 @@ type Props = {
|
||||
type: WorkflowEditorParameterType;
|
||||
onClose: () => void;
|
||||
onSave: (value: ParametersState[number]) => void;
|
||||
initialValues: ParametersState[number];
|
||||
initialValues?: ParametersState[number];
|
||||
};
|
||||
|
||||
const workflowParameterTypeOptions = [
|
||||
@@ -50,20 +50,21 @@ const workflowParameterTypeOptions = [
|
||||
{ label: "JSON", value: WorkflowParameterValueType.JSON },
|
||||
];
|
||||
|
||||
function header(type: WorkflowEditorParameterType) {
|
||||
function header(type: WorkflowEditorParameterType, isEdit: boolean) {
|
||||
const prefix = isEdit ? "Edit" : "Add";
|
||||
if (type === "workflow") {
|
||||
return "Edit Input Parameter";
|
||||
return `${prefix} Input Parameter`;
|
||||
}
|
||||
if (type === "credential") {
|
||||
return "Edit Credential Parameter";
|
||||
return `${prefix} Credential Parameter`;
|
||||
}
|
||||
if (type === "secret") {
|
||||
return "Edit Secret Parameter";
|
||||
return `${prefix} Secret Parameter`;
|
||||
}
|
||||
if (type === "creditCardData") {
|
||||
return "Edit Credit Card Parameter";
|
||||
return `${prefix} Credit Card Parameter`;
|
||||
}
|
||||
return "Edit Context Parameter";
|
||||
return `${prefix} Context Parameter`;
|
||||
}
|
||||
|
||||
function WorkflowParameterEditPanel({
|
||||
@@ -72,20 +73,22 @@ function WorkflowParameterEditPanel({
|
||||
onSave,
|
||||
initialValues,
|
||||
}: Props) {
|
||||
const reservedKeys = ["current_item", "current_value", "current_index"];
|
||||
const isCloud = useContext(CloudContext);
|
||||
const [key, setKey] = useState(initialValues.key);
|
||||
const isEditMode = !!initialValues;
|
||||
const [key, setKey] = useState(initialValues?.key ?? "");
|
||||
const hasWhitespace = /\s/.test(key);
|
||||
const isBitwardenCredential =
|
||||
initialValues.parameterType === "credential" &&
|
||||
initialValues?.parameterType === "credential" &&
|
||||
parameterIsBitwardenCredential(initialValues);
|
||||
const isSkyvernCredential =
|
||||
initialValues.parameterType === "credential" &&
|
||||
initialValues?.parameterType === "credential" &&
|
||||
parameterIsSkyvernCredential(initialValues);
|
||||
const isOnePasswordCredential =
|
||||
initialValues.parameterType === "onepassword" &&
|
||||
initialValues?.parameterType === "onepassword" &&
|
||||
parameterIsOnePasswordCredential(initialValues);
|
||||
const isAzureVaultCredential =
|
||||
initialValues.parameterType === "credential" &&
|
||||
initialValues?.parameterType === "credential" &&
|
||||
parameterIsAzureVaultCredential(initialValues);
|
||||
const [credentialType, setCredentialType] = useState<
|
||||
"bitwarden" | "skyvern" | "onepassword" | "azurevault"
|
||||
@@ -99,21 +102,21 @@ function WorkflowParameterEditPanel({
|
||||
: "skyvern",
|
||||
);
|
||||
const [urlParameterKey, setUrlParameterKey] = useState(
|
||||
isBitwardenCredential ? initialValues.urlParameterKey ?? "" : "",
|
||||
isBitwardenCredential ? initialValues?.urlParameterKey ?? "" : "",
|
||||
);
|
||||
const [description, setDescription] = useState(
|
||||
initialValues.description ?? "",
|
||||
initialValues?.description ?? "",
|
||||
);
|
||||
const [collectionId, setCollectionId] = useState(
|
||||
const [bitwardenCollectionId, setBitwardenCollectionId] = useState(
|
||||
isBitwardenCredential ||
|
||||
initialValues.parameterType === "secret" ||
|
||||
initialValues.parameterType === "creditCardData"
|
||||
? initialValues.collectionId ?? ""
|
||||
initialValues?.parameterType === "secret" ||
|
||||
initialValues?.parameterType === "creditCardData"
|
||||
? initialValues?.collectionId ?? ""
|
||||
: "",
|
||||
);
|
||||
const [parameterType, setParameterType] =
|
||||
useState<WorkflowParameterValueType>(
|
||||
initialValues.parameterType === "workflow"
|
||||
initialValues?.parameterType === "workflow"
|
||||
? initialValues.dataType
|
||||
: "string",
|
||||
);
|
||||
@@ -122,7 +125,7 @@ function WorkflowParameterEditPanel({
|
||||
hasDefaultValue: boolean;
|
||||
defaultValue: unknown;
|
||||
}>(
|
||||
initialValues.parameterType === "workflow"
|
||||
initialValues?.parameterType === "workflow"
|
||||
? {
|
||||
hasDefaultValue: initialValues.defaultValue !== null,
|
||||
defaultValue: initialValues.defaultValue ?? null,
|
||||
@@ -136,23 +139,23 @@ function WorkflowParameterEditPanel({
|
||||
const [sourceParameterKey, setSourceParameterKey] = useState<
|
||||
string | undefined
|
||||
>(
|
||||
initialValues.parameterType === "context"
|
||||
initialValues?.parameterType === "context"
|
||||
? initialValues.sourceParameterKey
|
||||
: undefined,
|
||||
);
|
||||
|
||||
const [identityKey, setIdentityKey] = useState(
|
||||
initialValues.parameterType === "secret" ? initialValues.identityKey : "",
|
||||
initialValues?.parameterType === "secret" ? initialValues.identityKey : "",
|
||||
);
|
||||
|
||||
const [identityFields, setIdentityFields] = useState(
|
||||
initialValues.parameterType === "secret"
|
||||
initialValues?.parameterType === "secret"
|
||||
? initialValues.identityFields.join(", ")
|
||||
: "",
|
||||
);
|
||||
|
||||
const [itemId, setItemId] = useState(
|
||||
initialValues.parameterType === "creditCardData"
|
||||
const [sensitiveInformationItemId, setSensitiveInformationItemId] = useState(
|
||||
initialValues?.parameterType === "creditCardData"
|
||||
? initialValues.itemId
|
||||
: "",
|
||||
);
|
||||
@@ -160,7 +163,7 @@ function WorkflowParameterEditPanel({
|
||||
const [credentialId, setCredentialId] = useState(
|
||||
isSkyvernCredential ? initialValues.credentialId : "",
|
||||
);
|
||||
const [vaultId, setVaultId] = useState(
|
||||
const [opVaultId, setOpVaultId] = useState(
|
||||
isOnePasswordCredential ? initialValues.vaultId : "",
|
||||
);
|
||||
const [opItemId, setOpItemId] = useState(
|
||||
@@ -168,7 +171,7 @@ function WorkflowParameterEditPanel({
|
||||
);
|
||||
|
||||
const [bitwardenLoginCredentialItemId, setBitwardenLoginCredentialItemId] =
|
||||
useState(isBitwardenCredential ? initialValues.itemId ?? "" : "");
|
||||
useState(isBitwardenCredential ? initialValues?.itemId ?? "" : "");
|
||||
|
||||
const [azureVaultName, setAzureVaultName] = useState(
|
||||
isAzureVaultCredential ? initialValues.vaultName : "",
|
||||
@@ -188,7 +191,7 @@ function WorkflowParameterEditPanel({
|
||||
<ScrollAreaViewport className="max-h-[500px]">
|
||||
<div className="space-y-4 p-1 px-4">
|
||||
<header className="flex items-center justify-between">
|
||||
<span>{header(type)}</span>
|
||||
<span>{header(type, isEditMode)}</span>
|
||||
<Cross2Icon className="h-6 w-6 cursor-pointer" onClick={onClose} />
|
||||
</header>
|
||||
<div className="space-y-1">
|
||||
@@ -274,7 +277,7 @@ function WorkflowParameterEditPanel({
|
||||
setDefaultValueState((state) => {
|
||||
return {
|
||||
...state,
|
||||
defaultValue: value,
|
||||
defaultValue: value.s3uri,
|
||||
};
|
||||
});
|
||||
return;
|
||||
@@ -340,8 +343,8 @@ function WorkflowParameterEditPanel({
|
||||
<div className="space-y-1">
|
||||
<Label className="text-xs text-slate-300">Collection ID</Label>
|
||||
<Input
|
||||
value={collectionId}
|
||||
onChange={(e) => setCollectionId(e.target.value)}
|
||||
value={bitwardenCollectionId}
|
||||
onChange={(e) => setBitwardenCollectionId(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
@@ -363,8 +366,8 @@ function WorkflowParameterEditPanel({
|
||||
<HelpTooltip content="You can find the Vault ID and Item ID in the URL when viewing the item in 1Password on the web." />
|
||||
</div>
|
||||
<Input
|
||||
value={vaultId}
|
||||
onChange={(e) => setVaultId(e.target.value)}
|
||||
value={opVaultId}
|
||||
onChange={(e) => setOpVaultId(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
@@ -451,8 +454,8 @@ function WorkflowParameterEditPanel({
|
||||
<div className="space-y-1">
|
||||
<Label className="text-xs text-slate-300">Collection ID</Label>
|
||||
<Input
|
||||
value={collectionId}
|
||||
onChange={(e) => setCollectionId(e.target.value)}
|
||||
value={bitwardenCollectionId}
|
||||
onChange={(e) => setBitwardenCollectionId(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
@@ -462,15 +465,17 @@ function WorkflowParameterEditPanel({
|
||||
<div className="space-y-1">
|
||||
<Label className="text-xs text-slate-300">Collection ID</Label>
|
||||
<Input
|
||||
value={collectionId}
|
||||
onChange={(e) => setCollectionId(e.target.value)}
|
||||
value={bitwardenCollectionId}
|
||||
onChange={(e) => setBitwardenCollectionId(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<Label className="text-xs text-slate-300">Item ID</Label>
|
||||
<Input
|
||||
value={itemId}
|
||||
onChange={(e) => setItemId(e.target.value)}
|
||||
value={sensitiveInformationItemId}
|
||||
onChange={(e) =>
|
||||
setSensitiveInformationItemId(e.target.value)
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
@@ -509,6 +514,14 @@ function WorkflowParameterEditPanel({
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (!isEditMode && reservedKeys.includes(key)) {
|
||||
toast({
|
||||
variant: "destructive",
|
||||
title: "Failed to add parameter",
|
||||
description: `${key} is reserved, please use another key`,
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (type === "workflow") {
|
||||
if (
|
||||
parameterType === "json" &&
|
||||
@@ -542,7 +555,7 @@ function WorkflowParameterEditPanel({
|
||||
}
|
||||
if (type === "credential" && credentialType === "bitwarden") {
|
||||
const errorMessage = validateBitwardenLoginCredential(
|
||||
collectionId,
|
||||
bitwardenCollectionId,
|
||||
bitwardenLoginCredentialItemId,
|
||||
urlParameterKey,
|
||||
);
|
||||
@@ -563,12 +576,15 @@ function WorkflowParameterEditPanel({
|
||||
: bitwardenLoginCredentialItemId,
|
||||
urlParameterKey:
|
||||
urlParameterKey === "" ? null : urlParameterKey,
|
||||
collectionId: collectionId === "" ? null : collectionId,
|
||||
collectionId:
|
||||
bitwardenCollectionId === ""
|
||||
? null
|
||||
: bitwardenCollectionId,
|
||||
description,
|
||||
});
|
||||
}
|
||||
if (type === "credential" && credentialType === "onepassword") {
|
||||
if (vaultId.trim() === "" || opItemId.trim() === "") {
|
||||
if (opVaultId.trim() === "" || opItemId.trim() === "") {
|
||||
toast({
|
||||
variant: "destructive",
|
||||
title: "Failed to save parameter",
|
||||
@@ -579,7 +595,7 @@ function WorkflowParameterEditPanel({
|
||||
onSave({
|
||||
key,
|
||||
parameterType: "onepassword",
|
||||
vaultId,
|
||||
vaultId: opVaultId,
|
||||
itemId: opItemId,
|
||||
description,
|
||||
});
|
||||
@@ -610,7 +626,7 @@ function WorkflowParameterEditPanel({
|
||||
});
|
||||
}
|
||||
if (type === "secret" || type === "creditCardData") {
|
||||
if (!collectionId) {
|
||||
if (!bitwardenCollectionId) {
|
||||
toast({
|
||||
variant: "destructive",
|
||||
title: "Failed to save parameter",
|
||||
@@ -623,7 +639,7 @@ function WorkflowParameterEditPanel({
|
||||
onSave({
|
||||
key,
|
||||
parameterType: "secret",
|
||||
collectionId,
|
||||
collectionId: bitwardenCollectionId,
|
||||
identityFields: identityFields
|
||||
.split(",")
|
||||
.filter((s) => s.length > 0)
|
||||
@@ -636,8 +652,8 @@ function WorkflowParameterEditPanel({
|
||||
onSave({
|
||||
key,
|
||||
parameterType: "creditCardData",
|
||||
collectionId,
|
||||
itemId,
|
||||
collectionId: bitwardenCollectionId,
|
||||
itemId: sensitiveInformationItemId,
|
||||
description,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { useState } from "react";
|
||||
import { WorkflowParameterAddPanel } from "./WorkflowParameterAddPanel";
|
||||
import { ParametersState } from "../types";
|
||||
import { WorkflowParameterEditPanel } from "./WorkflowParameterEditPanel";
|
||||
import { MixerVerticalIcon, PlusIcon } from "@radix-ui/react-icons";
|
||||
@@ -242,7 +241,7 @@ function WorkflowParametersPanel({ onMouseDownCapture }: Props) {
|
||||
>
|
||||
{operationPanelState.operation === "add" && (
|
||||
<div className="w-80 rounded-xl border border-slate-700 bg-slate-950 p-5 px-2 shadow-xl">
|
||||
<WorkflowParameterAddPanel
|
||||
<WorkflowParameterEditPanel
|
||||
type={operationPanelState.type}
|
||||
onSave={(parameter) => {
|
||||
setWorkflowParameters([...workflowParameters, parameter]);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { defineConfig } from 'vitest/config'
|
||||
import react from '@vitejs/plugin-react-swc'
|
||||
import path from 'path'
|
||||
import { defineConfig } from "vitest/config";
|
||||
import react from "@vitejs/plugin-react-swc";
|
||||
import path from "path";
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [react()],
|
||||
@@ -9,7 +9,7 @@ export default defineConfig({
|
||||
},
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': path.resolve(__dirname, './src'),
|
||||
"@": path.resolve(__dirname, "./src"),
|
||||
},
|
||||
},
|
||||
})
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user