Refactoring: merge WorkflowParameterEditPanel and WorkflowParameterAddPanel (#3750)

This commit is contained in:
Stanislav Novosad
2025-10-23 11:02:41 -06:00
committed by GitHub
parent a2cef7985d
commit 117b2469e4
4 changed files with 69 additions and 669 deletions

View File

@@ -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 };

View File

@@ -37,7 +37,7 @@ type Props = {
type: WorkflowEditorParameterType; type: WorkflowEditorParameterType;
onClose: () => void; onClose: () => void;
onSave: (value: ParametersState[number]) => void; onSave: (value: ParametersState[number]) => void;
initialValues: ParametersState[number]; initialValues?: ParametersState[number];
}; };
const workflowParameterTypeOptions = [ const workflowParameterTypeOptions = [
@@ -50,20 +50,21 @@ const workflowParameterTypeOptions = [
{ label: "JSON", value: WorkflowParameterValueType.JSON }, { label: "JSON", value: WorkflowParameterValueType.JSON },
]; ];
function header(type: WorkflowEditorParameterType) { function header(type: WorkflowEditorParameterType, isEdit: boolean) {
const prefix = isEdit ? "Edit" : "Add";
if (type === "workflow") { if (type === "workflow") {
return "Edit Input Parameter"; return `${prefix} Input Parameter`;
} }
if (type === "credential") { if (type === "credential") {
return "Edit Credential Parameter"; return `${prefix} Credential Parameter`;
} }
if (type === "secret") { if (type === "secret") {
return "Edit Secret Parameter"; return `${prefix} Secret Parameter`;
} }
if (type === "creditCardData") { if (type === "creditCardData") {
return "Edit Credit Card Parameter"; return `${prefix} Credit Card Parameter`;
} }
return "Edit Context Parameter"; return `${prefix} Context Parameter`;
} }
function WorkflowParameterEditPanel({ function WorkflowParameterEditPanel({
@@ -72,20 +73,22 @@ function WorkflowParameterEditPanel({
onSave, onSave,
initialValues, initialValues,
}: Props) { }: Props) {
const reservedKeys = ["current_item", "current_value", "current_index"];
const isCloud = useContext(CloudContext); 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 hasWhitespace = /\s/.test(key);
const isBitwardenCredential = const isBitwardenCredential =
initialValues.parameterType === "credential" && initialValues?.parameterType === "credential" &&
parameterIsBitwardenCredential(initialValues); parameterIsBitwardenCredential(initialValues);
const isSkyvernCredential = const isSkyvernCredential =
initialValues.parameterType === "credential" && initialValues?.parameterType === "credential" &&
parameterIsSkyvernCredential(initialValues); parameterIsSkyvernCredential(initialValues);
const isOnePasswordCredential = const isOnePasswordCredential =
initialValues.parameterType === "onepassword" && initialValues?.parameterType === "onepassword" &&
parameterIsOnePasswordCredential(initialValues); parameterIsOnePasswordCredential(initialValues);
const isAzureVaultCredential = const isAzureVaultCredential =
initialValues.parameterType === "credential" && initialValues?.parameterType === "credential" &&
parameterIsAzureVaultCredential(initialValues); parameterIsAzureVaultCredential(initialValues);
const [credentialType, setCredentialType] = useState< const [credentialType, setCredentialType] = useState<
"bitwarden" | "skyvern" | "onepassword" | "azurevault" "bitwarden" | "skyvern" | "onepassword" | "azurevault"
@@ -99,21 +102,21 @@ function WorkflowParameterEditPanel({
: "skyvern", : "skyvern",
); );
const [urlParameterKey, setUrlParameterKey] = useState( const [urlParameterKey, setUrlParameterKey] = useState(
isBitwardenCredential ? initialValues.urlParameterKey ?? "" : "", isBitwardenCredential ? initialValues?.urlParameterKey ?? "" : "",
); );
const [description, setDescription] = useState( const [description, setDescription] = useState(
initialValues.description ?? "", initialValues?.description ?? "",
); );
const [collectionId, setCollectionId] = useState( const [bitwardenCollectionId, setBitwardenCollectionId] = useState(
isBitwardenCredential || isBitwardenCredential ||
initialValues.parameterType === "secret" || initialValues?.parameterType === "secret" ||
initialValues.parameterType === "creditCardData" initialValues?.parameterType === "creditCardData"
? initialValues.collectionId ?? "" ? initialValues?.collectionId ?? ""
: "", : "",
); );
const [parameterType, setParameterType] = const [parameterType, setParameterType] =
useState<WorkflowParameterValueType>( useState<WorkflowParameterValueType>(
initialValues.parameterType === "workflow" initialValues?.parameterType === "workflow"
? initialValues.dataType ? initialValues.dataType
: "string", : "string",
); );
@@ -122,7 +125,7 @@ function WorkflowParameterEditPanel({
hasDefaultValue: boolean; hasDefaultValue: boolean;
defaultValue: unknown; defaultValue: unknown;
}>( }>(
initialValues.parameterType === "workflow" initialValues?.parameterType === "workflow"
? { ? {
hasDefaultValue: initialValues.defaultValue !== null, hasDefaultValue: initialValues.defaultValue !== null,
defaultValue: initialValues.defaultValue ?? null, defaultValue: initialValues.defaultValue ?? null,
@@ -136,23 +139,23 @@ function WorkflowParameterEditPanel({
const [sourceParameterKey, setSourceParameterKey] = useState< const [sourceParameterKey, setSourceParameterKey] = useState<
string | undefined string | undefined
>( >(
initialValues.parameterType === "context" initialValues?.parameterType === "context"
? initialValues.sourceParameterKey ? initialValues.sourceParameterKey
: undefined, : undefined,
); );
const [identityKey, setIdentityKey] = useState( const [identityKey, setIdentityKey] = useState(
initialValues.parameterType === "secret" ? initialValues.identityKey : "", initialValues?.parameterType === "secret" ? initialValues.identityKey : "",
); );
const [identityFields, setIdentityFields] = useState( const [identityFields, setIdentityFields] = useState(
initialValues.parameterType === "secret" initialValues?.parameterType === "secret"
? initialValues.identityFields.join(", ") ? initialValues.identityFields.join(", ")
: "", : "",
); );
const [itemId, setItemId] = useState( const [sensitiveInformationItemId, setSensitiveInformationItemId] = useState(
initialValues.parameterType === "creditCardData" initialValues?.parameterType === "creditCardData"
? initialValues.itemId ? initialValues.itemId
: "", : "",
); );
@@ -160,7 +163,7 @@ function WorkflowParameterEditPanel({
const [credentialId, setCredentialId] = useState( const [credentialId, setCredentialId] = useState(
isSkyvernCredential ? initialValues.credentialId : "", isSkyvernCredential ? initialValues.credentialId : "",
); );
const [vaultId, setVaultId] = useState( const [opVaultId, setOpVaultId] = useState(
isOnePasswordCredential ? initialValues.vaultId : "", isOnePasswordCredential ? initialValues.vaultId : "",
); );
const [opItemId, setOpItemId] = useState( const [opItemId, setOpItemId] = useState(
@@ -168,7 +171,7 @@ function WorkflowParameterEditPanel({
); );
const [bitwardenLoginCredentialItemId, setBitwardenLoginCredentialItemId] = const [bitwardenLoginCredentialItemId, setBitwardenLoginCredentialItemId] =
useState(isBitwardenCredential ? initialValues.itemId ?? "" : ""); useState(isBitwardenCredential ? initialValues?.itemId ?? "" : "");
const [azureVaultName, setAzureVaultName] = useState( const [azureVaultName, setAzureVaultName] = useState(
isAzureVaultCredential ? initialValues.vaultName : "", isAzureVaultCredential ? initialValues.vaultName : "",
@@ -188,7 +191,7 @@ function WorkflowParameterEditPanel({
<ScrollAreaViewport className="max-h-[500px]"> <ScrollAreaViewport className="max-h-[500px]">
<div className="space-y-4 p-1 px-4"> <div className="space-y-4 p-1 px-4">
<header className="flex items-center justify-between"> <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} /> <Cross2Icon className="h-6 w-6 cursor-pointer" onClick={onClose} />
</header> </header>
<div className="space-y-1"> <div className="space-y-1">
@@ -274,7 +277,7 @@ function WorkflowParameterEditPanel({
setDefaultValueState((state) => { setDefaultValueState((state) => {
return { return {
...state, ...state,
defaultValue: value, defaultValue: value.s3uri,
}; };
}); });
return; return;
@@ -340,8 +343,8 @@ function WorkflowParameterEditPanel({
<div className="space-y-1"> <div className="space-y-1">
<Label className="text-xs text-slate-300">Collection ID</Label> <Label className="text-xs text-slate-300">Collection ID</Label>
<Input <Input
value={collectionId} value={bitwardenCollectionId}
onChange={(e) => setCollectionId(e.target.value)} onChange={(e) => setBitwardenCollectionId(e.target.value)}
/> />
</div> </div>
<div className="space-y-1"> <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." /> <HelpTooltip content="You can find the Vault ID and Item ID in the URL when viewing the item in 1Password on the web." />
</div> </div>
<Input <Input
value={vaultId} value={opVaultId}
onChange={(e) => setVaultId(e.target.value)} onChange={(e) => setOpVaultId(e.target.value)}
/> />
</div> </div>
<div className="space-y-1"> <div className="space-y-1">
@@ -451,8 +454,8 @@ function WorkflowParameterEditPanel({
<div className="space-y-1"> <div className="space-y-1">
<Label className="text-xs text-slate-300">Collection ID</Label> <Label className="text-xs text-slate-300">Collection ID</Label>
<Input <Input
value={collectionId} value={bitwardenCollectionId}
onChange={(e) => setCollectionId(e.target.value)} onChange={(e) => setBitwardenCollectionId(e.target.value)}
/> />
</div> </div>
</> </>
@@ -462,15 +465,17 @@ function WorkflowParameterEditPanel({
<div className="space-y-1"> <div className="space-y-1">
<Label className="text-xs text-slate-300">Collection ID</Label> <Label className="text-xs text-slate-300">Collection ID</Label>
<Input <Input
value={collectionId} value={bitwardenCollectionId}
onChange={(e) => setCollectionId(e.target.value)} onChange={(e) => setBitwardenCollectionId(e.target.value)}
/> />
</div> </div>
<div className="space-y-1"> <div className="space-y-1">
<Label className="text-xs text-slate-300">Item ID</Label> <Label className="text-xs text-slate-300">Item ID</Label>
<Input <Input
value={itemId} value={sensitiveInformationItemId}
onChange={(e) => setItemId(e.target.value)} onChange={(e) =>
setSensitiveInformationItemId(e.target.value)
}
/> />
</div> </div>
</> </>
@@ -509,6 +514,14 @@ function WorkflowParameterEditPanel({
}); });
return; 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 (type === "workflow") {
if ( if (
parameterType === "json" && parameterType === "json" &&
@@ -542,7 +555,7 @@ function WorkflowParameterEditPanel({
} }
if (type === "credential" && credentialType === "bitwarden") { if (type === "credential" && credentialType === "bitwarden") {
const errorMessage = validateBitwardenLoginCredential( const errorMessage = validateBitwardenLoginCredential(
collectionId, bitwardenCollectionId,
bitwardenLoginCredentialItemId, bitwardenLoginCredentialItemId,
urlParameterKey, urlParameterKey,
); );
@@ -563,12 +576,15 @@ function WorkflowParameterEditPanel({
: bitwardenLoginCredentialItemId, : bitwardenLoginCredentialItemId,
urlParameterKey: urlParameterKey:
urlParameterKey === "" ? null : urlParameterKey, urlParameterKey === "" ? null : urlParameterKey,
collectionId: collectionId === "" ? null : collectionId, collectionId:
bitwardenCollectionId === ""
? null
: bitwardenCollectionId,
description, description,
}); });
} }
if (type === "credential" && credentialType === "onepassword") { if (type === "credential" && credentialType === "onepassword") {
if (vaultId.trim() === "" || opItemId.trim() === "") { if (opVaultId.trim() === "" || opItemId.trim() === "") {
toast({ toast({
variant: "destructive", variant: "destructive",
title: "Failed to save parameter", title: "Failed to save parameter",
@@ -579,7 +595,7 @@ function WorkflowParameterEditPanel({
onSave({ onSave({
key, key,
parameterType: "onepassword", parameterType: "onepassword",
vaultId, vaultId: opVaultId,
itemId: opItemId, itemId: opItemId,
description, description,
}); });
@@ -610,7 +626,7 @@ function WorkflowParameterEditPanel({
}); });
} }
if (type === "secret" || type === "creditCardData") { if (type === "secret" || type === "creditCardData") {
if (!collectionId) { if (!bitwardenCollectionId) {
toast({ toast({
variant: "destructive", variant: "destructive",
title: "Failed to save parameter", title: "Failed to save parameter",
@@ -623,7 +639,7 @@ function WorkflowParameterEditPanel({
onSave({ onSave({
key, key,
parameterType: "secret", parameterType: "secret",
collectionId, collectionId: bitwardenCollectionId,
identityFields: identityFields identityFields: identityFields
.split(",") .split(",")
.filter((s) => s.length > 0) .filter((s) => s.length > 0)
@@ -636,8 +652,8 @@ function WorkflowParameterEditPanel({
onSave({ onSave({
key, key,
parameterType: "creditCardData", parameterType: "creditCardData",
collectionId, collectionId: bitwardenCollectionId,
itemId, itemId: sensitiveInformationItemId,
description, description,
}); });
} }

View File

@@ -1,5 +1,4 @@
import { useState } from "react"; import { useState } from "react";
import { WorkflowParameterAddPanel } from "./WorkflowParameterAddPanel";
import { ParametersState } from "../types"; import { ParametersState } from "../types";
import { WorkflowParameterEditPanel } from "./WorkflowParameterEditPanel"; import { WorkflowParameterEditPanel } from "./WorkflowParameterEditPanel";
import { MixerVerticalIcon, PlusIcon } from "@radix-ui/react-icons"; import { MixerVerticalIcon, PlusIcon } from "@radix-ui/react-icons";
@@ -242,7 +241,7 @@ function WorkflowParametersPanel({ onMouseDownCapture }: Props) {
> >
{operationPanelState.operation === "add" && ( {operationPanelState.operation === "add" && (
<div className="w-80 rounded-xl border border-slate-700 bg-slate-950 p-5 px-2 shadow-xl"> <div className="w-80 rounded-xl border border-slate-700 bg-slate-950 p-5 px-2 shadow-xl">
<WorkflowParameterAddPanel <WorkflowParameterEditPanel
type={operationPanelState.type} type={operationPanelState.type}
onSave={(parameter) => { onSave={(parameter) => {
setWorkflowParameters([...workflowParameters, parameter]); setWorkflowParameters([...workflowParameters, parameter]);

View File

@@ -1,6 +1,6 @@
import { defineConfig } from 'vitest/config' import { defineConfig } from "vitest/config";
import react from '@vitejs/plugin-react-swc' import react from "@vitejs/plugin-react-swc";
import path from 'path' import path from "path";
export default defineConfig({ export default defineConfig({
plugins: [react()], plugins: [react()],
@@ -9,7 +9,7 @@ export default defineConfig({
}, },
resolve: { resolve: {
alias: { alias: {
'@': path.resolve(__dirname, './src'), "@": path.resolve(__dirname, "./src"),
}, },
}, },
}) });