Merge credential parameters in the UI (#1853)

This commit is contained in:
Shuchang Zheng
2025-02-27 11:47:24 -08:00
committed by GitHub
parent ab2212c6fb
commit 5c5464b187
10 changed files with 172 additions and 129 deletions

View File

@@ -38,7 +38,6 @@ import {
WorkflowApiResponse,
WorkflowEditorParameterTypes,
WorkflowParameterTypes,
WorkflowParameterValueType,
WorkflowSettings,
} from "../types/workflowTypes";
import {
@@ -83,6 +82,7 @@ import {
nodeAdderNode,
startNode,
} from "./workflowEditorUtils";
import { parameterIsBitwardenCredential, ParametersState } from "./types";
function convertToParametersYAML(
parameters: ParametersState,
@@ -145,76 +145,33 @@ function convertToParametersYAML(
bitwarden_master_password_aws_secret_key:
BITWARDEN_MASTER_PASSWORD_AWS_SECRET_KEY,
};
} else if (
parameter.parameterType === WorkflowEditorParameterTypes.Credential
) {
return {
parameter_type: WorkflowParameterTypes.Credential,
key: parameter.key,
description: parameter.description || null,
credential_id: parameter.credentialId,
};
} else {
return {
parameter_type: WorkflowParameterTypes.Bitwarden_Login_Credential,
key: parameter.key,
description: parameter.description || null,
bitwarden_collection_id: parameter.collectionId,
url_parameter_key: parameter.urlParameterKey,
bitwarden_client_id_aws_secret_key: BITWARDEN_CLIENT_ID_AWS_SECRET_KEY,
bitwarden_client_secret_aws_secret_key:
BITWARDEN_CLIENT_SECRET_AWS_SECRET_KEY,
bitwarden_master_password_aws_secret_key:
BITWARDEN_MASTER_PASSWORD_AWS_SECRET_KEY,
};
if (parameterIsBitwardenCredential(parameter)) {
return {
parameter_type: WorkflowParameterTypes.Bitwarden_Login_Credential,
key: parameter.key,
description: parameter.description || null,
bitwarden_collection_id: parameter.collectionId,
url_parameter_key: parameter.urlParameterKey,
bitwarden_client_id_aws_secret_key:
BITWARDEN_CLIENT_ID_AWS_SECRET_KEY,
bitwarden_client_secret_aws_secret_key:
BITWARDEN_CLIENT_SECRET_AWS_SECRET_KEY,
bitwarden_master_password_aws_secret_key:
BITWARDEN_MASTER_PASSWORD_AWS_SECRET_KEY,
};
} else {
return {
parameter_type: WorkflowParameterTypes.Credential,
key: parameter.key,
description: parameter.description || null,
credential_id: parameter.credentialId,
};
}
}
});
}
export type ParametersState = Array<
| {
key: string;
parameterType: "workflow";
dataType: WorkflowParameterValueType;
description?: string | null;
defaultValue: unknown;
}
| {
key: string;
parameterType: "bitwardenLoginCredential";
collectionId: string;
urlParameterKey: string;
description?: string | null;
}
| {
key: string;
parameterType: "context";
sourceParameterKey: string;
description?: string | null;
}
| {
key: string;
parameterType: "secret";
identityKey: string;
identityFields: Array<string>;
collectionId: string;
description?: string | null;
}
| {
key: string;
parameterType: "creditCardData";
itemId: string;
collectionId: string;
description?: string | null;
}
| {
key: string;
parameterType: "credential";
credentialId: string;
description?: string | null;
}
>;
type Props = {
initialTitle: string;
initialNodes: Array<AppNode>;

View File

@@ -129,8 +129,7 @@ function WorkflowEditor() {
} else {
return {
key: parameter.key,
parameterType:
WorkflowEditorParameterTypes.BitwardenLoginCredential,
parameterType: WorkflowEditorParameterTypes.Credential,
collectionId: parameter.bitwarden_collection_id,
urlParameterKey: parameter.url_parameter_key,
description: parameter.description,

View File

@@ -1,5 +1,5 @@
import { createContext } from "react";
import { ParametersState } from "./FlowRenderer";
import { ParametersState } from "./types";
type WorkflowParametersState = [
ParametersState,

View File

@@ -16,9 +16,7 @@ type Props = {
function CredentialParameterSelector({ value, onChange }: Props) {
const [workflowParameters] = useWorkflowParametersState();
const credentialParameters = workflowParameters.filter(
(parameter) =>
parameter.parameterType === "credential" ||
parameter.parameterType === "bitwardenLoginCredential",
(parameter) => parameter.parameterType === "credential",
);
const noneItemValue = useId();

View File

@@ -15,7 +15,7 @@ import {
SelectValue,
} from "@/components/ui/select";
import { Button } from "@/components/ui/button";
import { ParametersState } from "../FlowRenderer";
import { ParametersState } from "../types";
import { WorkflowParameterInput } from "../../WorkflowParameterInput";
import { Checkbox } from "@/components/ui/checkbox";
import { getDefaultValueForParameterType } from "../workflowEditorUtils";
@@ -24,6 +24,7 @@ import { SourceParameterKeySelector } from "../../components/SourceParameterKeyS
import { ScrollArea, ScrollAreaViewport } from "@/components/ui/scroll-area";
import CloudContext from "@/store/CloudContext";
import { CredentialSelector } from "../../components/CredentialSelector";
import { SwitchBar } from "@/components/SwitchBar";
type Props = {
type: WorkflowEditorParameterType;
@@ -47,9 +48,6 @@ function header(type: WorkflowEditorParameterType) {
if (type === "credential") {
return "Add Credential Parameter";
}
if (type === "bitwardenLoginCredential") {
return "Add Bitwarden Login Credential Parameter";
}
if (type === "secret") {
return "Add Secret Parameter";
}
@@ -78,6 +76,10 @@ function WorkflowParameterAddPanel({ type, onClose, onSave }: Props) {
string | undefined
>(undefined);
const [credentialType, setCredentialType] = useState<"bitwarden" | "skyvern">(
"skyvern",
);
const [identityKey, setIdentityKey] = useState("");
const [identityFields, setIdentityFields] = useState("");
const [itemId, setItemId] = useState("");
@@ -189,7 +191,19 @@ function WorkflowParameterAddPanel({ type, onClose, onSave }: Props) {
</div>
</>
)}
{type === "bitwardenLoginCredential" && (
{type === "credential" && (
<SwitchBar
value={credentialType}
onChange={(value) => {
setCredentialType(value as "bitwarden" | "skyvern");
}}
options={[
{ label: "Skyvern", value: "skyvern" },
{ label: "Bitwarden", value: "bitwarden" },
]}
/>
)}
{type === "credential" && credentialType === "bitwarden" && (
<>
<div className="space-y-1">
<Label className="text-xs text-slate-300">
@@ -265,15 +279,17 @@ function WorkflowParameterAddPanel({ type, onClose, onSave }: Props) {
)}
{
// temporarily cloud only
type === "credential" && isCloud && (
<div className="space-y-1">
<Label className="text-xs text-slate-300">Credential</Label>
<CredentialSelector
value={credentialId}
onChange={(value) => setCredentialId(value)}
/>
</div>
)
type === "credential" &&
credentialType === "skyvern" &&
isCloud && (
<div className="space-y-1">
<Label className="text-xs text-slate-300">Credential</Label>
<CredentialSelector
value={credentialId}
onChange={(value) => setCredentialId(value)}
/>
</div>
)
}
<div className="flex justify-end">
<Button
@@ -318,7 +334,7 @@ function WorkflowParameterAddPanel({ type, onClose, onSave }: Props) {
});
}
if (
type === "bitwardenLoginCredential" ||
(type === "credential" && credentialType === "bitwarden") ||
type === "secret" ||
type === "creditCardData"
) {
@@ -331,10 +347,10 @@ function WorkflowParameterAddPanel({ type, onClose, onSave }: Props) {
return;
}
}
if (type === "bitwardenLoginCredential") {
if (type === "credential" && credentialType === "bitwarden") {
onSave({
key,
parameterType: "bitwardenLoginCredential",
parameterType: "credential",
collectionId,
urlParameterKey,
description,
@@ -378,7 +394,7 @@ function WorkflowParameterAddPanel({ type, onClose, onSave }: Props) {
description,
});
}
if (type === "credential") {
if (type === "credential" && credentialType === "skyvern") {
if (!credentialId) {
toast({
variant: "destructive",

View File

@@ -15,7 +15,6 @@ import {
SelectValue,
} from "@/components/ui/select";
import { Button } from "@/components/ui/button";
import { ParametersState } from "../FlowRenderer";
import { Checkbox } from "@/components/ui/checkbox";
import { getDefaultValueForParameterType } from "../workflowEditorUtils";
import { WorkflowParameterInput } from "../../WorkflowParameterInput";
@@ -24,6 +23,12 @@ import { SourceParameterKeySelector } from "../../components/SourceParameterKeyS
import { ScrollArea, ScrollAreaViewport } from "@/components/ui/scroll-area";
import CloudContext from "@/store/CloudContext";
import { CredentialSelector } from "../../components/CredentialSelector";
import { SwitchBar } from "@/components/SwitchBar";
import {
parameterIsBitwardenCredential,
parameterIsSkyvernCredential,
ParametersState,
} from "../types";
type Props = {
type: WorkflowEditorParameterType;
@@ -51,9 +56,6 @@ function header(type: WorkflowEditorParameterType) {
if (type === "secret") {
return "Edit Secret Parameter";
}
if (type === "bitwardenLoginCredential") {
return "Edit Bitwarden Login Credential Parameter";
}
if (type === "creditCardData") {
return "Edit Credit Card Data Parameter";
}
@@ -68,16 +70,23 @@ function WorkflowParameterEditPanel({
}: Props) {
const isCloud = useContext(CloudContext);
const [key, setKey] = useState(initialValues.key);
const isBitwardenCredential =
initialValues.parameterType === "credential" &&
parameterIsBitwardenCredential(initialValues);
const isSkyvernCredential =
initialValues.parameterType === "credential" &&
parameterIsSkyvernCredential(initialValues);
const [credentialType, setCredentialType] = useState<"bitwarden" | "skyvern">(
isBitwardenCredential ? "bitwarden" : "skyvern",
);
const [urlParameterKey, setUrlParameterKey] = useState(
initialValues.parameterType === "bitwardenLoginCredential"
? initialValues.urlParameterKey
: "",
isBitwardenCredential ? initialValues.urlParameterKey : "",
);
const [description, setDescription] = useState(
initialValues.description ?? "",
);
const [collectionId, setCollectionId] = useState(
initialValues.parameterType === "bitwardenLoginCredential" ||
isBitwardenCredential ||
initialValues.parameterType === "secret" ||
initialValues.parameterType === "creditCardData"
? initialValues.collectionId
@@ -130,9 +139,7 @@ function WorkflowParameterEditPanel({
);
const [credentialId, setCredentialId] = useState(
initialValues.parameterType === "credential"
? initialValues.credentialId
: "",
isSkyvernCredential ? initialValues.credentialId : "",
);
return (
@@ -240,7 +247,19 @@ function WorkflowParameterEditPanel({
</div>
</>
)}
{type === "bitwardenLoginCredential" && (
{type === "credential" && (
<SwitchBar
value={credentialType}
onChange={(value) => {
setCredentialType(value as "bitwarden" | "skyvern");
}}
options={[
{ label: "Skyvern", value: "skyvern" },
{ label: "Bitwarden", value: "bitwarden" },
]}
/>
)}
{type === "credential" && credentialType === "bitwarden" && (
<>
<div className="space-y-1">
<Label className="text-xs text-slate-300">
@@ -316,15 +335,17 @@ function WorkflowParameterEditPanel({
)}
{
// temporarily cloud only
type === "credential" && isCloud && (
<div className="space-y-1">
<Label className="text-xs text-slate-300">Credential</Label>
<CredentialSelector
value={credentialId}
onChange={(value) => setCredentialId(value)}
/>
</div>
)
type === "credential" &&
credentialType === "skyvern" &&
isCloud && (
<div className="space-y-1">
<Label className="text-xs text-slate-300">Credential</Label>
<CredentialSelector
value={credentialId}
onChange={(value) => setCredentialId(value)}
/>
</div>
)
}
<div className="flex justify-end">
<Button
@@ -369,7 +390,7 @@ function WorkflowParameterEditPanel({
});
}
if (
type === "bitwardenLoginCredential" ||
(type === "credential" && credentialType === "bitwarden") ||
type === "secret" ||
type === "creditCardData"
) {
@@ -382,10 +403,10 @@ function WorkflowParameterEditPanel({
return;
}
}
if (type === "bitwardenLoginCredential") {
if (type === "credential" && credentialType === "bitwarden") {
onSave({
key,
parameterType: "bitwardenLoginCredential",
parameterType: "credential",
urlParameterKey,
collectionId,
description,
@@ -429,7 +450,7 @@ function WorkflowParameterEditPanel({
description,
});
}
if (type === "credential") {
if (type === "credential" && credentialType === "skyvern") {
if (!credentialId) {
toast({
variant: "destructive",

View File

@@ -1,7 +1,7 @@
import { useState } from "react";
import { useWorkflowParametersState } from "../useWorkflowParametersState";
import { WorkflowParameterAddPanel } from "./WorkflowParameterAddPanel";
import { ParametersState } from "../FlowRenderer";
import { ParametersState } from "../types";
import { WorkflowParameterEditPanel } from "./WorkflowParameterEditPanel";
import { MixerVerticalIcon, PlusIcon } from "@radix-ui/react-icons";
import { Button } from "@/components/ui/button";
@@ -96,17 +96,6 @@ function WorkflowParametersPanel() {
>
Credential Parameter
</DropdownMenuItem>
<DropdownMenuItem
onClick={() => {
setOperationPanelState({
active: true,
operation: "add",
type: WorkflowEditorParameterTypes.BitwardenLoginCredential,
});
}}
>
Bitwarden Login Credential Parameter
</DropdownMenuItem>
<DropdownMenuItem
onClick={() => {
setOperationPanelState({

View File

@@ -0,0 +1,64 @@
import { WorkflowParameterValueType } from "../types/workflowTypes";
export type BitwardenLoginCredential = {
key: string;
description?: string | null;
parameterType: "credential";
collectionId: string;
urlParameterKey: string;
};
export type SkyvernCredential = {
key: string;
description?: string | null;
parameterType: "credential";
credentialId: string;
};
export function parameterIsBitwardenCredential(
parameter: CredentialParameterState,
): parameter is BitwardenLoginCredential {
return "collectionId" in parameter;
}
export function parameterIsSkyvernCredential(
parameter: CredentialParameterState,
): parameter is SkyvernCredential {
return "credentialId" in parameter;
}
export type CredentialParameterState =
| BitwardenLoginCredential
| SkyvernCredential;
export type ParametersState = Array<
| {
key: string;
parameterType: "workflow";
dataType: WorkflowParameterValueType;
description?: string | null;
defaultValue: unknown;
}
| {
key: string;
parameterType: "context";
sourceParameterKey: string;
description?: string | null;
}
| {
key: string;
parameterType: "secret";
identityKey: string;
identityFields: Array<string>;
collectionId: string;
description?: string | null;
}
| {
key: string;
parameterType: "creditCardData";
itemId: string;
collectionId: string;
description?: string | null;
}
| CredentialParameterState
>;

View File

@@ -48,7 +48,7 @@ import {
SMTP_USERNAME_AWS_KEY,
SMTP_USERNAME_PARAMETER_KEY,
} from "./constants";
import { ParametersState } from "./FlowRenderer";
import { ParametersState } from "./types";
import { AppNode, isWorkflowBlockNode, WorkflowBlockNode } from "./nodes";
import { codeBlockNodeDefaultData } from "./nodes/CodeBlockNode/types";
import { downloadNodeDefaultData } from "./nodes/DownloadNode/types";

View File

@@ -213,7 +213,6 @@ export type WorkflowBlockType =
export const WorkflowEditorParameterTypes = {
Workflow: "workflow",
BitwardenLoginCredential: "bitwardenLoginCredential",
Credential: "credential",
Secret: "secret",
Context: "context",