Add item id field in parameters panel (#1883)

Co-authored-by: Muhammed Salih Altun <muhammedsalihaltun@gmail.com>
This commit is contained in:
Shuchang Zheng
2025-03-04 11:46:07 -05:00
committed by GitHub
parent 64ad052ab3
commit e2dcf5474c
9 changed files with 142 additions and 64 deletions

View File

@@ -152,6 +152,7 @@ function convertToParametersYAML(
key: parameter.key, key: parameter.key,
description: parameter.description || null, description: parameter.description || null,
bitwarden_collection_id: parameter.collectionId, bitwarden_collection_id: parameter.collectionId,
bitwarden_item_id: parameter.itemId,
url_parameter_key: parameter.urlParameterKey, url_parameter_key: parameter.urlParameterKey,
bitwarden_client_id_aws_secret_key: bitwarden_client_id_aws_secret_key:
BITWARDEN_CLIENT_ID_AWS_SECRET_KEY, BITWARDEN_CLIENT_ID_AWS_SECRET_KEY,

View File

@@ -131,6 +131,7 @@ function WorkflowEditor() {
key: parameter.key, key: parameter.key,
parameterType: WorkflowEditorParameterTypes.Credential, parameterType: WorkflowEditorParameterTypes.Credential,
collectionId: parameter.bitwarden_collection_id, collectionId: parameter.bitwarden_collection_id,
itemId: parameter.bitwarden_item_id,
urlParameterKey: parameter.url_parameter_key, urlParameterKey: parameter.url_parameter_key,
description: parameter.description, description: parameter.description,
}; };

View File

@@ -25,6 +25,7 @@ import { ScrollArea, ScrollAreaViewport } from "@/components/ui/scroll-area";
import CloudContext from "@/store/CloudContext"; import CloudContext from "@/store/CloudContext";
import { CredentialSelector } from "../../components/CredentialSelector"; import { CredentialSelector } from "../../components/CredentialSelector";
import { SwitchBar } from "@/components/SwitchBar"; import { SwitchBar } from "@/components/SwitchBar";
import { validateBitwardenLoginCredential } from "./util";
type Props = { type Props = {
type: WorkflowEditorParameterType; type: WorkflowEditorParameterType;
@@ -62,7 +63,9 @@ function WorkflowParameterAddPanel({ type, onClose, onSave }: Props) {
const [key, setKey] = useState(""); const [key, setKey] = useState("");
const [urlParameterKey, setUrlParameterKey] = useState(""); const [urlParameterKey, setUrlParameterKey] = useState("");
const [description, setDescription] = useState(""); const [description, setDescription] = useState("");
const [collectionId, setCollectionId] = useState(""); const [bitwardenCollectionId, setBitwardenCollectionId] = useState("");
const [bitwardenLoginCredentialItemId, setBitwardenLoginCredentialItemId] =
useState("");
const [parameterType, setParameterType] = const [parameterType, setParameterType] =
useState<WorkflowParameterValueType>("string"); useState<WorkflowParameterValueType>("string");
const [defaultValueState, setDefaultValueState] = useState<{ const [defaultValueState, setDefaultValueState] = useState<{
@@ -82,7 +85,8 @@ function WorkflowParameterAddPanel({ type, onClose, onSave }: Props) {
const [identityKey, setIdentityKey] = useState(""); const [identityKey, setIdentityKey] = useState("");
const [identityFields, setIdentityFields] = useState(""); const [identityFields, setIdentityFields] = useState("");
const [itemId, setItemId] = useState(""); const [sensitiveInformationItemId, setSensitiveInformationItemId] =
useState("");
const [credentialId, setCredentialId] = useState(""); const [credentialId, setCredentialId] = useState("");
@@ -217,8 +221,17 @@ function WorkflowParameterAddPanel({ type, onClose, onSave }: Props) {
<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 className="space-y-1">
<Label className="text-xs text-slate-300">Item ID</Label>
<Input
value={bitwardenLoginCredentialItemId}
onChange={(e) =>
setBitwardenLoginCredentialItemId(e.target.value)
}
/> />
</div> </div>
</> </>
@@ -253,8 +266,8 @@ function WorkflowParameterAddPanel({ type, onClose, onSave }: Props) {
<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>
</> </>
@@ -264,15 +277,17 @@ function WorkflowParameterAddPanel({ type, onClose, onSave }: Props) {
<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>
<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>
</> </>
@@ -333,12 +348,38 @@ function WorkflowParameterAddPanel({ type, onClose, onSave }: Props) {
: null, : null,
}); });
} }
if ( if (type === "credential" && credentialType === "bitwarden") {
(type === "credential" && credentialType === "bitwarden") || const errorMessage = validateBitwardenLoginCredential(
type === "secret" || bitwardenCollectionId,
type === "creditCardData" bitwardenLoginCredentialItemId,
) { urlParameterKey,
if (!collectionId) { );
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 === "secret" || type === "creditCardData") {
if (!bitwardenCollectionId) {
toast({ toast({
variant: "destructive", variant: "destructive",
title: "Failed to save parameter", title: "Failed to save parameter",
@@ -347,20 +388,11 @@ function WorkflowParameterAddPanel({ type, onClose, onSave }: Props) {
return; return;
} }
} }
if (type === "credential" && credentialType === "bitwarden") {
onSave({
key,
parameterType: "credential",
collectionId,
urlParameterKey,
description,
});
}
if (type === "secret") { if (type === "secret") {
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)
@@ -373,8 +405,8 @@ function WorkflowParameterAddPanel({ type, onClose, onSave }: Props) {
onSave({ onSave({
key, key,
parameterType: "creditCardData", parameterType: "creditCardData",
collectionId, collectionId: bitwardenCollectionId,
itemId, itemId: sensitiveInformationItemId,
description, description,
}); });
} }

View File

@@ -1,11 +1,9 @@
import { Cross2Icon } from "@radix-ui/react-icons"; import { SwitchBar } from "@/components/SwitchBar";
import { Label } from "@/components/ui/label"; import { Button } from "@/components/ui/button";
import { Checkbox } from "@/components/ui/checkbox";
import { Input } from "@/components/ui/input"; import { Input } from "@/components/ui/input";
import { useState, useContext } from "react"; import { Label } from "@/components/ui/label";
import { import { ScrollArea, ScrollAreaViewport } from "@/components/ui/scroll-area";
WorkflowEditorParameterType,
WorkflowParameterValueType,
} from "../../types/workflowTypes";
import { import {
Select, Select,
SelectContent, SelectContent,
@@ -14,21 +12,24 @@ import {
SelectTrigger, SelectTrigger,
SelectValue, SelectValue,
} from "@/components/ui/select"; } from "@/components/ui/select";
import { Button } from "@/components/ui/button";
import { Checkbox } from "@/components/ui/checkbox";
import { getDefaultValueForParameterType } from "../workflowEditorUtils";
import { WorkflowParameterInput } from "../../WorkflowParameterInput";
import { toast } from "@/components/ui/use-toast"; import { toast } from "@/components/ui/use-toast";
import { SourceParameterKeySelector } from "../../components/SourceParameterKeySelector";
import { ScrollArea, ScrollAreaViewport } from "@/components/ui/scroll-area";
import CloudContext from "@/store/CloudContext"; import CloudContext from "@/store/CloudContext";
import { Cross2Icon } from "@radix-ui/react-icons";
import { useContext, useState } from "react";
import { CredentialSelector } from "../../components/CredentialSelector"; import { CredentialSelector } from "../../components/CredentialSelector";
import { SwitchBar } from "@/components/SwitchBar"; import { SourceParameterKeySelector } from "../../components/SourceParameterKeySelector";
import {
WorkflowEditorParameterType,
WorkflowParameterValueType,
} from "../../types/workflowTypes";
import { WorkflowParameterInput } from "../../WorkflowParameterInput";
import { import {
parameterIsBitwardenCredential, parameterIsBitwardenCredential,
parameterIsSkyvernCredential, parameterIsSkyvernCredential,
ParametersState, ParametersState,
} from "../types"; } from "../types";
import { getDefaultValueForParameterType } from "../workflowEditorUtils";
import { validateBitwardenLoginCredential } from "./util";
type Props = { type Props = {
type: WorkflowEditorParameterType; type: WorkflowEditorParameterType;
@@ -80,7 +81,7 @@ function WorkflowParameterEditPanel({
isBitwardenCredential ? "bitwarden" : "skyvern", isBitwardenCredential ? "bitwarden" : "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 ?? "",
@@ -89,7 +90,7 @@ function WorkflowParameterEditPanel({
isBitwardenCredential || isBitwardenCredential ||
initialValues.parameterType === "secret" || initialValues.parameterType === "secret" ||
initialValues.parameterType === "creditCardData" initialValues.parameterType === "creditCardData"
? initialValues.collectionId ? initialValues.collectionId ?? ""
: "", : "",
); );
const [parameterType, setParameterType] = const [parameterType, setParameterType] =
@@ -142,6 +143,9 @@ function WorkflowParameterEditPanel({
isSkyvernCredential ? initialValues.credentialId : "", isSkyvernCredential ? initialValues.credentialId : "",
); );
const [bitwardenLoginCredentialItemId, setBitwardenLoginCredentialItemId] =
useState(isBitwardenCredential ? initialValues.itemId ?? "" : "");
return ( return (
<ScrollArea> <ScrollArea>
<ScrollAreaViewport className="max-h-[500px]"> <ScrollAreaViewport className="max-h-[500px]">
@@ -277,6 +281,15 @@ function WorkflowParameterEditPanel({
onChange={(e) => setCollectionId(e.target.value)} onChange={(e) => setCollectionId(e.target.value)}
/> />
</div> </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 === "context" && ( {type === "context" && (
@@ -389,11 +402,34 @@ function WorkflowParameterEditPanel({
: null, : null,
}); });
} }
if ( if (type === "credential" && credentialType === "bitwarden") {
(type === "credential" && credentialType === "bitwarden") || const errorMessage = validateBitwardenLoginCredential(
type === "secret" || collectionId,
type === "creditCardData" bitwardenLoginCredentialItemId,
) { urlParameterKey,
);
if (errorMessage) {
toast({
variant: "destructive",
title: "Failed to save parameter",
description: errorMessage,
});
return;
}
onSave({
key,
parameterType: "credential",
itemId:
bitwardenLoginCredentialItemId === ""
? null
: bitwardenLoginCredentialItemId,
urlParameterKey:
urlParameterKey === "" ? null : urlParameterKey,
collectionId: collectionId === "" ? null : collectionId,
description,
});
}
if (type === "secret" || type === "creditCardData") {
if (!collectionId) { if (!collectionId) {
toast({ toast({
variant: "destructive", variant: "destructive",
@@ -403,15 +439,6 @@ function WorkflowParameterEditPanel({
return; return;
} }
} }
if (type === "credential" && credentialType === "bitwarden") {
onSave({
key,
parameterType: "credential",
urlParameterKey,
collectionId,
description,
});
}
if (type === "secret") { if (type === "secret") {
onSave({ onSave({
key, key,

View File

@@ -0,0 +1,13 @@
export function validateBitwardenLoginCredential(
collectionId: string | null,
itemId: string | null,
urlParameterKey: string | null,
): string | null {
if (!collectionId && !itemId) {
return "Collection ID or Item ID is required";
}
if (collectionId && !urlParameterKey) {
return "URL Parameter Key is required when collection ID is used";
}
return null;
}

View File

@@ -4,8 +4,9 @@ export type BitwardenLoginCredential = {
key: string; key: string;
description?: string | null; description?: string | null;
parameterType: "credential"; parameterType: "credential";
collectionId: string; collectionId: string | null;
urlParameterKey: string; itemId: string | null;
urlParameterKey: string | null;
}; };
export type SkyvernCredential = { export type SkyvernCredential = {

View File

@@ -1505,6 +1505,7 @@ function convertParametersToParameterYAML(
...base, ...base,
parameter_type: WorkflowParameterTypes.Bitwarden_Login_Credential, parameter_type: WorkflowParameterTypes.Bitwarden_Login_Credential,
bitwarden_collection_id: parameter.bitwarden_collection_id, bitwarden_collection_id: parameter.bitwarden_collection_id,
bitwarden_item_id: parameter.bitwarden_item_id,
url_parameter_key: parameter.url_parameter_key, url_parameter_key: parameter.url_parameter_key,
bitwarden_client_id_aws_secret_key: bitwarden_client_id_aws_secret_key:
parameter.bitwarden_client_id_aws_secret_key, parameter.bitwarden_client_id_aws_secret_key,

View File

@@ -23,8 +23,9 @@ export type BitwardenLoginCredentialParameter = WorkflowParameterBase & {
bitwarden_client_id_aws_secret_key: string; bitwarden_client_id_aws_secret_key: string;
bitwarden_client_secret_aws_secret_key: string; bitwarden_client_secret_aws_secret_key: string;
bitwarden_master_password_aws_secret_key: string; bitwarden_master_password_aws_secret_key: string;
bitwarden_collection_id: string; bitwarden_collection_id: string | null;
url_parameter_key: string; bitwarden_item_id: string | null;
url_parameter_key: string | null;
created_at: string; created_at: string;
modified_at: string; modified_at: string;
deleted_at: string | null; deleted_at: string | null;

View File

@@ -40,8 +40,9 @@ export type WorkflowParameterYAML = ParameterYAMLBase & {
export type BitwardenLoginCredentialParameterYAML = ParameterYAMLBase & { export type BitwardenLoginCredentialParameterYAML = ParameterYAMLBase & {
parameter_type: "bitwarden_login_credential"; parameter_type: "bitwarden_login_credential";
bitwarden_collection_id: string; bitwarden_collection_id: string | null;
url_parameter_key: string; bitwarden_item_id: string | null;
url_parameter_key: string | null;
bitwarden_client_id_aws_secret_key: string; bitwarden_client_id_aws_secret_key: string;
bitwarden_client_secret_aws_secret_key: string; bitwarden_client_secret_aws_secret_key: string;
bitwarden_master_password_aws_secret_key: string; bitwarden_master_password_aws_secret_key: string;