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,
description: parameter.description || null,
bitwarden_collection_id: parameter.collectionId,
bitwarden_item_id: parameter.itemId,
url_parameter_key: parameter.urlParameterKey,
bitwarden_client_id_aws_secret_key:
BITWARDEN_CLIENT_ID_AWS_SECRET_KEY,

View File

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

View File

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

View File

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

View File

@@ -1505,6 +1505,7 @@ function convertParametersToParameterYAML(
...base,
parameter_type: WorkflowParameterTypes.Bitwarden_Login_Credential,
bitwarden_collection_id: parameter.bitwarden_collection_id,
bitwarden_item_id: parameter.bitwarden_item_id,
url_parameter_key: parameter.url_parameter_key,
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_secret_aws_secret_key: string;
bitwarden_master_password_aws_secret_key: string;
bitwarden_collection_id: string;
url_parameter_key: string;
bitwarden_collection_id: string | null;
bitwarden_item_id: string | null;
url_parameter_key: string | null;
created_at: string;
modified_at: string;
deleted_at: string | null;

View File

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