mirror of
https://github.com/Skyvern-AI/skyvern.git
synced 2025-09-02 02:30:07 +00:00
Credentials UI (#1828)
This commit is contained in:
parent
39ab9c0603
commit
c5a2438e7f
13 changed files with 337 additions and 27 deletions
|
@ -296,3 +296,19 @@ export type Createv2TaskRequest = {
|
||||||
webhook_callback_url?: string | null;
|
webhook_callback_url?: string | null;
|
||||||
proxy_location?: ProxyLocation | null;
|
proxy_location?: ProxyLocation | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type PasswordCredentialApiResponse = {
|
||||||
|
username: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type CreditCardCredentialApiResponse = {
|
||||||
|
last_four: string;
|
||||||
|
brand: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type CredentialApiResponse = {
|
||||||
|
credential_id: string;
|
||||||
|
credential: PasswordCredentialApiResponse | CreditCardCredentialApiResponse;
|
||||||
|
credential_type: "password" | "credit_card";
|
||||||
|
name: string;
|
||||||
|
};
|
||||||
|
|
50
skyvern-frontend/src/components/DropdownWithOptions.tsx
Normal file
50
skyvern-frontend/src/components/DropdownWithOptions.tsx
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
import {
|
||||||
|
Select,
|
||||||
|
SelectContent,
|
||||||
|
SelectItem,
|
||||||
|
SelectTrigger,
|
||||||
|
SelectValue,
|
||||||
|
} from "./ui/select";
|
||||||
|
|
||||||
|
type Item = {
|
||||||
|
label: string;
|
||||||
|
value: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
options: Item[];
|
||||||
|
value: string;
|
||||||
|
onChange: (selected: string) => void;
|
||||||
|
placeholder?: string;
|
||||||
|
className?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
function DropdownWithOptions({
|
||||||
|
options,
|
||||||
|
value,
|
||||||
|
onChange,
|
||||||
|
placeholder,
|
||||||
|
className,
|
||||||
|
}: Props) {
|
||||||
|
return (
|
||||||
|
<Select
|
||||||
|
value={value}
|
||||||
|
onValueChange={(value) => {
|
||||||
|
onChange(value);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<SelectTrigger className={className}>
|
||||||
|
<SelectValue placeholder={placeholder} />
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent className="max-h-48">
|
||||||
|
{options.map((option) => (
|
||||||
|
<SelectItem key={option.value} value={option.value}>
|
||||||
|
{option.label}
|
||||||
|
</SelectItem>
|
||||||
|
))}
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export { DropdownWithOptions };
|
26
skyvern-frontend/src/components/icons/KeyIcon.tsx
Normal file
26
skyvern-frontend/src/components/icons/KeyIcon.tsx
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
type Props = {
|
||||||
|
className?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
function KeyIcon({ className }: Props) {
|
||||||
|
return (
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="24"
|
||||||
|
height="24"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
className={className}
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M17 8.99994C17 8.48812 16.8047 7.9763 16.4142 7.58579C16.0237 7.19526 15.5118 7 15 7M15 15C18.3137 15 21 12.3137 21 9C21 5.68629 18.3137 3 15 3C11.6863 3 9 5.68629 9 9C9 9.27368 9.01832 9.54308 9.05381 9.80704C9.11218 10.2412 9.14136 10.4583 9.12172 10.5956C9.10125 10.7387 9.0752 10.8157 9.00469 10.9419C8.937 11.063 8.81771 11.1823 8.57913 11.4209L3.46863 16.5314C3.29568 16.7043 3.2092 16.7908 3.14736 16.8917C3.09253 16.9812 3.05213 17.0787 3.02763 17.1808C3 17.2959 3 17.4182 3 17.6627V19.4C3 19.9601 3 20.2401 3.10899 20.454C3.20487 20.6422 3.35785 20.7951 3.54601 20.891C3.75992 21 4.03995 21 4.6 21H7V19H9V17H11L12.5791 15.4209C12.8177 15.1823 12.937 15.063 13.0581 14.9953C13.1843 14.9248 13.2613 14.8987 13.4044 14.8783C13.5417 14.8586 13.7588 14.8878 14.193 14.9462C14.4569 14.9817 14.7263 15 15 15Z"
|
||||||
|
stroke="currentColor"
|
||||||
|
strokeWidth="2"
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export { KeyIcon };
|
|
@ -0,0 +1,66 @@
|
||||||
|
import { getClient } from "@/api/AxiosClient";
|
||||||
|
import { CredentialApiResponse } from "@/api/types";
|
||||||
|
import {
|
||||||
|
Select,
|
||||||
|
SelectContent,
|
||||||
|
SelectItem,
|
||||||
|
SelectTrigger,
|
||||||
|
SelectValue,
|
||||||
|
} from "@/components/ui/select";
|
||||||
|
import { Skeleton } from "@/components/ui/skeleton";
|
||||||
|
import { useCredentialGetter } from "@/hooks/useCredentialGetter";
|
||||||
|
import { useQuery } from "@tanstack/react-query";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
value: string;
|
||||||
|
onChange: (value: string) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
function CredentialSelector({ value, onChange }: Props) {
|
||||||
|
const credentialGetter = useCredentialGetter();
|
||||||
|
|
||||||
|
const { data: credentials, isFetching } = useQuery<
|
||||||
|
Array<CredentialApiResponse>
|
||||||
|
>({
|
||||||
|
queryKey: ["credentials"],
|
||||||
|
queryFn: async () => {
|
||||||
|
const client = await getClient(credentialGetter);
|
||||||
|
return await client.get("/credentials").then((res) => res.data);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (isFetching) {
|
||||||
|
return <Skeleton className="h-10 w-full" />;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!credentials) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Select value={value} onValueChange={onChange}>
|
||||||
|
<SelectTrigger>
|
||||||
|
<SelectValue placeholder="Select a credential" />
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent>
|
||||||
|
{credentials.map((credential) => (
|
||||||
|
<SelectItem
|
||||||
|
key={credential.credential_id}
|
||||||
|
value={credential.credential_id}
|
||||||
|
>
|
||||||
|
<div className="space-y-2">
|
||||||
|
<p className="text-sm font-medium">{credential.name}</p>
|
||||||
|
<p className="text-xs text-slate-400">
|
||||||
|
{credential.credential_type === "password"
|
||||||
|
? "Password"
|
||||||
|
: "Credit Card"}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</SelectItem>
|
||||||
|
))}
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export { CredentialSelector };
|
|
@ -47,6 +47,7 @@ import {
|
||||||
BitwardenSensitiveInformationParameterYAML,
|
BitwardenSensitiveInformationParameterYAML,
|
||||||
BlockYAML,
|
BlockYAML,
|
||||||
ContextParameterYAML,
|
ContextParameterYAML,
|
||||||
|
CredentialParameterYAML,
|
||||||
ParameterYAML,
|
ParameterYAML,
|
||||||
WorkflowCreateYAMLRequest,
|
WorkflowCreateYAMLRequest,
|
||||||
WorkflowParameterYAML,
|
WorkflowParameterYAML,
|
||||||
|
@ -91,6 +92,7 @@ function convertToParametersYAML(
|
||||||
| ContextParameterYAML
|
| ContextParameterYAML
|
||||||
| BitwardenSensitiveInformationParameterYAML
|
| BitwardenSensitiveInformationParameterYAML
|
||||||
| BitwardenCreditCardDataParameterYAML
|
| BitwardenCreditCardDataParameterYAML
|
||||||
|
| CredentialParameterYAML
|
||||||
> {
|
> {
|
||||||
return parameters.map((parameter) => {
|
return parameters.map((parameter) => {
|
||||||
if (parameter.parameterType === WorkflowEditorParameterTypes.Workflow) {
|
if (parameter.parameterType === WorkflowEditorParameterTypes.Workflow) {
|
||||||
|
@ -143,6 +145,15 @@ function convertToParametersYAML(
|
||||||
bitwarden_master_password_aws_secret_key:
|
bitwarden_master_password_aws_secret_key:
|
||||||
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 {
|
} else {
|
||||||
return {
|
return {
|
||||||
parameter_type: WorkflowParameterTypes.Bitwarden_Login_Credential,
|
parameter_type: WorkflowParameterTypes.Bitwarden_Login_Credential,
|
||||||
|
@ -170,7 +181,7 @@ export type ParametersState = Array<
|
||||||
}
|
}
|
||||||
| {
|
| {
|
||||||
key: string;
|
key: string;
|
||||||
parameterType: "credential";
|
parameterType: "bitwardenLoginCredential";
|
||||||
collectionId: string;
|
collectionId: string;
|
||||||
urlParameterKey: string;
|
urlParameterKey: string;
|
||||||
description?: string | null;
|
description?: string | null;
|
||||||
|
@ -196,6 +207,12 @@ export type ParametersState = Array<
|
||||||
collectionId: string;
|
collectionId: string;
|
||||||
description?: string | null;
|
description?: string | null;
|
||||||
}
|
}
|
||||||
|
| {
|
||||||
|
key: string;
|
||||||
|
parameterType: "credential";
|
||||||
|
credentialId: string;
|
||||||
|
description?: string | null;
|
||||||
|
}
|
||||||
>;
|
>;
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
|
|
@ -75,27 +75,32 @@ function WorkflowEditor() {
|
||||||
initialParameters={workflow.workflow_definition.parameters
|
initialParameters={workflow.workflow_definition.parameters
|
||||||
.filter((parameter) => isDisplayedInWorkflowEditor(parameter))
|
.filter((parameter) => isDisplayedInWorkflowEditor(parameter))
|
||||||
.map((parameter) => {
|
.map((parameter) => {
|
||||||
if (parameter.parameter_type === "workflow") {
|
if (
|
||||||
|
parameter.parameter_type === WorkflowParameterTypes.Workflow
|
||||||
|
) {
|
||||||
return {
|
return {
|
||||||
key: parameter.key,
|
key: parameter.key,
|
||||||
parameterType: "workflow",
|
parameterType: WorkflowEditorParameterTypes.Workflow,
|
||||||
dataType: parameter.workflow_parameter_type,
|
dataType: parameter.workflow_parameter_type,
|
||||||
defaultValue: parameter.default_value,
|
defaultValue: parameter.default_value,
|
||||||
description: parameter.description,
|
description: parameter.description,
|
||||||
};
|
};
|
||||||
} else if (parameter.parameter_type === "context") {
|
} else if (
|
||||||
|
parameter.parameter_type === WorkflowParameterTypes.Context
|
||||||
|
) {
|
||||||
return {
|
return {
|
||||||
key: parameter.key,
|
key: parameter.key,
|
||||||
parameterType: "context",
|
parameterType: WorkflowEditorParameterTypes.Context,
|
||||||
sourceParameterKey: parameter.source.key,
|
sourceParameterKey: parameter.source.key,
|
||||||
description: parameter.description,
|
description: parameter.description,
|
||||||
};
|
};
|
||||||
} else if (
|
} else if (
|
||||||
parameter.parameter_type === "bitwarden_sensitive_information"
|
parameter.parameter_type ===
|
||||||
|
WorkflowParameterTypes.Bitwarden_Sensitive_Information
|
||||||
) {
|
) {
|
||||||
return {
|
return {
|
||||||
key: parameter.key,
|
key: parameter.key,
|
||||||
parameterType: "secret",
|
parameterType: WorkflowEditorParameterTypes.Secret,
|
||||||
collectionId: parameter.bitwarden_collection_id,
|
collectionId: parameter.bitwarden_collection_id,
|
||||||
identityKey: parameter.bitwarden_identity_key,
|
identityKey: parameter.bitwarden_identity_key,
|
||||||
identityFields: parameter.bitwarden_identity_fields,
|
identityFields: parameter.bitwarden_identity_fields,
|
||||||
|
@ -112,10 +117,20 @@ function WorkflowEditor() {
|
||||||
itemId: parameter.bitwarden_item_id,
|
itemId: parameter.bitwarden_item_id,
|
||||||
description: parameter.description,
|
description: parameter.description,
|
||||||
};
|
};
|
||||||
|
} else if (
|
||||||
|
parameter.parameter_type === WorkflowParameterTypes.Credential
|
||||||
|
) {
|
||||||
|
return {
|
||||||
|
key: parameter.key,
|
||||||
|
parameterType: WorkflowEditorParameterTypes.Credential,
|
||||||
|
credentialId: parameter.credential_id,
|
||||||
|
description: parameter.description,
|
||||||
|
};
|
||||||
} else {
|
} else {
|
||||||
return {
|
return {
|
||||||
key: parameter.key,
|
key: parameter.key,
|
||||||
parameterType: "credential",
|
parameterType:
|
||||||
|
WorkflowEditorParameterTypes.BitwardenLoginCredential,
|
||||||
collectionId: parameter.bitwarden_collection_id,
|
collectionId: parameter.bitwarden_collection_id,
|
||||||
urlParameterKey: parameter.url_parameter_key,
|
urlParameterKey: parameter.url_parameter_key,
|
||||||
description: parameter.description,
|
description: parameter.description,
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { Cross2Icon } from "@radix-ui/react-icons";
|
import { Cross2Icon } from "@radix-ui/react-icons";
|
||||||
import { Label } from "@/components/ui/label";
|
import { Label } from "@/components/ui/label";
|
||||||
import { Input } from "@/components/ui/input";
|
import { Input } from "@/components/ui/input";
|
||||||
import { useState } from "react";
|
import { useContext, useState } from "react";
|
||||||
import {
|
import {
|
||||||
WorkflowEditorParameterType,
|
WorkflowEditorParameterType,
|
||||||
WorkflowParameterValueType,
|
WorkflowParameterValueType,
|
||||||
|
@ -22,6 +22,8 @@ import { getDefaultValueForParameterType } from "../workflowEditorUtils";
|
||||||
import { toast } from "@/components/ui/use-toast";
|
import { toast } from "@/components/ui/use-toast";
|
||||||
import { SourceParameterKeySelector } from "../../components/SourceParameterKeySelector";
|
import { SourceParameterKeySelector } from "../../components/SourceParameterKeySelector";
|
||||||
import { ScrollArea, ScrollAreaViewport } from "@/components/ui/scroll-area";
|
import { ScrollArea, ScrollAreaViewport } from "@/components/ui/scroll-area";
|
||||||
|
import CloudContext from "@/store/CloudContext";
|
||||||
|
import { CredentialSelector } from "../../components/CredentialSelector";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
type: WorkflowEditorParameterType;
|
type: WorkflowEditorParameterType;
|
||||||
|
@ -45,6 +47,9 @@ function header(type: WorkflowEditorParameterType) {
|
||||||
if (type === "credential") {
|
if (type === "credential") {
|
||||||
return "Add Credential Parameter";
|
return "Add Credential Parameter";
|
||||||
}
|
}
|
||||||
|
if (type === "bitwardenLoginCredential") {
|
||||||
|
return "Add Bitwarden Login Credential Parameter";
|
||||||
|
}
|
||||||
if (type === "secret") {
|
if (type === "secret") {
|
||||||
return "Add Secret Parameter";
|
return "Add Secret Parameter";
|
||||||
}
|
}
|
||||||
|
@ -55,6 +60,7 @@ function header(type: WorkflowEditorParameterType) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function WorkflowParameterAddPanel({ type, onClose, onSave }: Props) {
|
function WorkflowParameterAddPanel({ type, onClose, onSave }: Props) {
|
||||||
|
const isCloud = useContext(CloudContext);
|
||||||
const [key, setKey] = useState("");
|
const [key, setKey] = useState("");
|
||||||
const [urlParameterKey, setUrlParameterKey] = useState("");
|
const [urlParameterKey, setUrlParameterKey] = useState("");
|
||||||
const [description, setDescription] = useState("");
|
const [description, setDescription] = useState("");
|
||||||
|
@ -76,6 +82,8 @@ function WorkflowParameterAddPanel({ type, onClose, onSave }: Props) {
|
||||||
const [identityFields, setIdentityFields] = useState("");
|
const [identityFields, setIdentityFields] = useState("");
|
||||||
const [itemId, setItemId] = useState("");
|
const [itemId, setItemId] = useState("");
|
||||||
|
|
||||||
|
const [credentialId, setCredentialId] = useState("");
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ScrollArea>
|
<ScrollArea>
|
||||||
<ScrollAreaViewport className="max-h-[500px]">
|
<ScrollAreaViewport className="max-h-[500px]">
|
||||||
|
@ -181,7 +189,7 @@ function WorkflowParameterAddPanel({ type, onClose, onSave }: Props) {
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{type === "credential" && (
|
{type === "bitwardenLoginCredential" && (
|
||||||
<>
|
<>
|
||||||
<div className="space-y-1">
|
<div className="space-y-1">
|
||||||
<Label className="text-xs text-slate-300">
|
<Label className="text-xs text-slate-300">
|
||||||
|
@ -255,6 +263,18 @@ function WorkflowParameterAddPanel({ type, onClose, onSave }: Props) {
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
{
|
||||||
|
// 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>
|
||||||
|
)
|
||||||
|
}
|
||||||
<div className="flex justify-end">
|
<div className="flex justify-end">
|
||||||
<Button
|
<Button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
@ -290,7 +310,7 @@ function WorkflowParameterAddPanel({ type, onClose, onSave }: Props) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
type === "credential" ||
|
type === "bitwardenLoginCredential" ||
|
||||||
type === "secret" ||
|
type === "secret" ||
|
||||||
type === "creditCardData"
|
type === "creditCardData"
|
||||||
) {
|
) {
|
||||||
|
@ -303,10 +323,10 @@ function WorkflowParameterAddPanel({ type, onClose, onSave }: Props) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (type === "credential") {
|
if (type === "bitwardenLoginCredential") {
|
||||||
onSave({
|
onSave({
|
||||||
key,
|
key,
|
||||||
parameterType: "credential",
|
parameterType: "bitwardenLoginCredential",
|
||||||
collectionId,
|
collectionId,
|
||||||
urlParameterKey,
|
urlParameterKey,
|
||||||
description,
|
description,
|
||||||
|
@ -346,7 +366,23 @@ function WorkflowParameterAddPanel({ type, onClose, onSave }: Props) {
|
||||||
onSave({
|
onSave({
|
||||||
key,
|
key,
|
||||||
parameterType: "context",
|
parameterType: "context",
|
||||||
sourceParameterKey: sourceParameterKey,
|
sourceParameterKey,
|
||||||
|
description,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (type === "credential") {
|
||||||
|
if (!credentialId) {
|
||||||
|
toast({
|
||||||
|
variant: "destructive",
|
||||||
|
title: "Failed to add parameter",
|
||||||
|
description: "Credential is required",
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
onSave({
|
||||||
|
key,
|
||||||
|
parameterType: "credential",
|
||||||
|
credentialId,
|
||||||
description,
|
description,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { Cross2Icon } from "@radix-ui/react-icons";
|
import { Cross2Icon } from "@radix-ui/react-icons";
|
||||||
import { Label } from "@/components/ui/label";
|
import { Label } from "@/components/ui/label";
|
||||||
import { Input } from "@/components/ui/input";
|
import { Input } from "@/components/ui/input";
|
||||||
import { useState } from "react";
|
import { useState, useContext } from "react";
|
||||||
import {
|
import {
|
||||||
WorkflowEditorParameterType,
|
WorkflowEditorParameterType,
|
||||||
WorkflowParameterValueType,
|
WorkflowParameterValueType,
|
||||||
|
@ -22,6 +22,8 @@ import { WorkflowParameterInput } from "../../WorkflowParameterInput";
|
||||||
import { toast } from "@/components/ui/use-toast";
|
import { toast } from "@/components/ui/use-toast";
|
||||||
import { SourceParameterKeySelector } from "../../components/SourceParameterKeySelector";
|
import { SourceParameterKeySelector } from "../../components/SourceParameterKeySelector";
|
||||||
import { ScrollArea, ScrollAreaViewport } from "@/components/ui/scroll-area";
|
import { ScrollArea, ScrollAreaViewport } from "@/components/ui/scroll-area";
|
||||||
|
import CloudContext from "@/store/CloudContext";
|
||||||
|
import { CredentialSelector } from "../../components/CredentialSelector";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
type: WorkflowEditorParameterType;
|
type: WorkflowEditorParameterType;
|
||||||
|
@ -49,6 +51,9 @@ function header(type: WorkflowEditorParameterType) {
|
||||||
if (type === "secret") {
|
if (type === "secret") {
|
||||||
return "Edit Secret Parameter";
|
return "Edit Secret Parameter";
|
||||||
}
|
}
|
||||||
|
if (type === "bitwardenLoginCredential") {
|
||||||
|
return "Edit Bitwarden Login Credential Parameter";
|
||||||
|
}
|
||||||
if (type === "creditCardData") {
|
if (type === "creditCardData") {
|
||||||
return "Edit Credit Card Data Parameter";
|
return "Edit Credit Card Data Parameter";
|
||||||
}
|
}
|
||||||
|
@ -61,9 +66,10 @@ function WorkflowParameterEditPanel({
|
||||||
onSave,
|
onSave,
|
||||||
initialValues,
|
initialValues,
|
||||||
}: Props) {
|
}: Props) {
|
||||||
|
const isCloud = useContext(CloudContext);
|
||||||
const [key, setKey] = useState(initialValues.key);
|
const [key, setKey] = useState(initialValues.key);
|
||||||
const [urlParameterKey, setUrlParameterKey] = useState(
|
const [urlParameterKey, setUrlParameterKey] = useState(
|
||||||
initialValues.parameterType === "credential"
|
initialValues.parameterType === "bitwardenLoginCredential"
|
||||||
? initialValues.urlParameterKey
|
? initialValues.urlParameterKey
|
||||||
: "",
|
: "",
|
||||||
);
|
);
|
||||||
|
@ -71,7 +77,7 @@ function WorkflowParameterEditPanel({
|
||||||
initialValues.description ?? "",
|
initialValues.description ?? "",
|
||||||
);
|
);
|
||||||
const [collectionId, setCollectionId] = useState(
|
const [collectionId, setCollectionId] = useState(
|
||||||
initialValues.parameterType === "credential" ||
|
initialValues.parameterType === "bitwardenLoginCredential" ||
|
||||||
initialValues.parameterType === "secret" ||
|
initialValues.parameterType === "secret" ||
|
||||||
initialValues.parameterType === "creditCardData"
|
initialValues.parameterType === "creditCardData"
|
||||||
? initialValues.collectionId
|
? initialValues.collectionId
|
||||||
|
@ -123,6 +129,12 @@ function WorkflowParameterEditPanel({
|
||||||
: "",
|
: "",
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const [credentialId, setCredentialId] = useState(
|
||||||
|
initialValues.parameterType === "credential"
|
||||||
|
? initialValues.credentialId
|
||||||
|
: "",
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ScrollArea>
|
<ScrollArea>
|
||||||
<ScrollAreaViewport className="max-h-[500px]">
|
<ScrollAreaViewport className="max-h-[500px]">
|
||||||
|
@ -228,7 +240,7 @@ function WorkflowParameterEditPanel({
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{type === "credential" && (
|
{type === "bitwardenLoginCredential" && (
|
||||||
<>
|
<>
|
||||||
<div className="space-y-1">
|
<div className="space-y-1">
|
||||||
<Label className="text-xs text-slate-300">
|
<Label className="text-xs text-slate-300">
|
||||||
|
@ -302,6 +314,18 @@ function WorkflowParameterEditPanel({
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
{
|
||||||
|
// 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>
|
||||||
|
)
|
||||||
|
}
|
||||||
<div className="flex justify-end">
|
<div className="flex justify-end">
|
||||||
<Button
|
<Button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
@ -337,7 +361,7 @@ function WorkflowParameterEditPanel({
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
type === "credential" ||
|
type === "bitwardenLoginCredential" ||
|
||||||
type === "secret" ||
|
type === "secret" ||
|
||||||
type === "creditCardData"
|
type === "creditCardData"
|
||||||
) {
|
) {
|
||||||
|
@ -350,10 +374,10 @@ function WorkflowParameterEditPanel({
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (type === "credential") {
|
if (type === "bitwardenLoginCredential") {
|
||||||
onSave({
|
onSave({
|
||||||
key,
|
key,
|
||||||
parameterType: "credential",
|
parameterType: "bitwardenLoginCredential",
|
||||||
urlParameterKey,
|
urlParameterKey,
|
||||||
collectionId,
|
collectionId,
|
||||||
description,
|
description,
|
||||||
|
@ -397,6 +421,22 @@ function WorkflowParameterEditPanel({
|
||||||
description,
|
description,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if (type === "credential") {
|
||||||
|
if (!credentialId) {
|
||||||
|
toast({
|
||||||
|
variant: "destructive",
|
||||||
|
title: "Failed to save parameter",
|
||||||
|
description: "Credential is required",
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
onSave({
|
||||||
|
key,
|
||||||
|
parameterType: "credential",
|
||||||
|
credentialId,
|
||||||
|
description,
|
||||||
|
});
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Save
|
Save
|
||||||
|
|
|
@ -79,7 +79,7 @@ function WorkflowParametersPanel() {
|
||||||
setOperationPanelState({
|
setOperationPanelState({
|
||||||
active: true,
|
active: true,
|
||||||
operation: "add",
|
operation: "add",
|
||||||
type: "workflow",
|
type: WorkflowEditorParameterTypes.Workflow,
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
@ -90,7 +90,7 @@ function WorkflowParametersPanel() {
|
||||||
setOperationPanelState({
|
setOperationPanelState({
|
||||||
active: true,
|
active: true,
|
||||||
operation: "add",
|
operation: "add",
|
||||||
type: "credential",
|
type: WorkflowEditorParameterTypes.Credential,
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
@ -101,7 +101,18 @@ function WorkflowParametersPanel() {
|
||||||
setOperationPanelState({
|
setOperationPanelState({
|
||||||
active: true,
|
active: true,
|
||||||
operation: "add",
|
operation: "add",
|
||||||
type: "secret",
|
type: WorkflowEditorParameterTypes.BitwardenLoginCredential,
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Bitwarden Login Credential Parameter
|
||||||
|
</DropdownMenuItem>
|
||||||
|
<DropdownMenuItem
|
||||||
|
onClick={() => {
|
||||||
|
setOperationPanelState({
|
||||||
|
active: true,
|
||||||
|
operation: "add",
|
||||||
|
type: WorkflowEditorParameterTypes.Secret,
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|
|
@ -1559,6 +1559,13 @@ function convertParametersToParameterYAML(
|
||||||
default_value: parameter.default_value,
|
default_value: parameter.default_value,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
case WorkflowParameterTypes.Credential: {
|
||||||
|
return {
|
||||||
|
...base,
|
||||||
|
parameter_type: WorkflowParameterTypes.Credential,
|
||||||
|
credential_id: parameter.credential_id,
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,6 +59,16 @@ export type BitwardenCreditCardDataParameter = WorkflowParameterBase & {
|
||||||
deleted_at: string | null;
|
deleted_at: string | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type CredentialParameter = WorkflowParameterBase & {
|
||||||
|
parameter_type: "credential";
|
||||||
|
workflow_id: string;
|
||||||
|
credential_parameter_id: string;
|
||||||
|
credential_id: string;
|
||||||
|
created_at: string;
|
||||||
|
modified_at: string;
|
||||||
|
deleted_at: string | null;
|
||||||
|
};
|
||||||
|
|
||||||
export type WorkflowParameter = WorkflowParameterBase & {
|
export type WorkflowParameter = WorkflowParameterBase & {
|
||||||
parameter_type: "workflow";
|
parameter_type: "workflow";
|
||||||
workflow_id: string;
|
workflow_id: string;
|
||||||
|
@ -105,6 +115,7 @@ export const WorkflowParameterTypes = {
|
||||||
Bitwarden_Login_Credential: "bitwarden_login_credential",
|
Bitwarden_Login_Credential: "bitwarden_login_credential",
|
||||||
Bitwarden_Sensitive_Information: "bitwarden_sensitive_information",
|
Bitwarden_Sensitive_Information: "bitwarden_sensitive_information",
|
||||||
Bitwarden_Credit_Card_Data: "bitwarden_credit_card_data",
|
Bitwarden_Credit_Card_Data: "bitwarden_credit_card_data",
|
||||||
|
Credential: "credential",
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export type WorkflowParameterType =
|
export type WorkflowParameterType =
|
||||||
|
@ -117,7 +128,8 @@ export function isDisplayedInWorkflowEditor(
|
||||||
| ContextParameter
|
| ContextParameter
|
||||||
| BitwardenCreditCardDataParameter
|
| BitwardenCreditCardDataParameter
|
||||||
| BitwardenLoginCredentialParameter
|
| BitwardenLoginCredentialParameter
|
||||||
| BitwardenSensitiveInformationParameter {
|
| BitwardenSensitiveInformationParameter
|
||||||
|
| CredentialParameter {
|
||||||
return (
|
return (
|
||||||
parameter.parameter_type === WorkflowParameterTypes.Workflow ||
|
parameter.parameter_type === WorkflowParameterTypes.Workflow ||
|
||||||
parameter.parameter_type ===
|
parameter.parameter_type ===
|
||||||
|
@ -126,7 +138,8 @@ export function isDisplayedInWorkflowEditor(
|
||||||
parameter.parameter_type ===
|
parameter.parameter_type ===
|
||||||
WorkflowParameterTypes.Bitwarden_Sensitive_Information ||
|
WorkflowParameterTypes.Bitwarden_Sensitive_Information ||
|
||||||
parameter.parameter_type ===
|
parameter.parameter_type ===
|
||||||
WorkflowParameterTypes.Bitwarden_Credit_Card_Data
|
WorkflowParameterTypes.Bitwarden_Credit_Card_Data ||
|
||||||
|
parameter.parameter_type === WorkflowParameterTypes.Credential
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,7 +150,8 @@ export type Parameter =
|
||||||
| BitwardenLoginCredentialParameter
|
| BitwardenLoginCredentialParameter
|
||||||
| BitwardenSensitiveInformationParameter
|
| BitwardenSensitiveInformationParameter
|
||||||
| BitwardenCreditCardDataParameter
|
| BitwardenCreditCardDataParameter
|
||||||
| AWSSecretParameter;
|
| AWSSecretParameter
|
||||||
|
| CredentialParameter;
|
||||||
|
|
||||||
export type WorkflowBlock =
|
export type WorkflowBlock =
|
||||||
| TaskBlock
|
| TaskBlock
|
||||||
|
@ -199,6 +213,7 @@ export type WorkflowBlockType =
|
||||||
|
|
||||||
export const WorkflowEditorParameterTypes = {
|
export const WorkflowEditorParameterTypes = {
|
||||||
Workflow: "workflow",
|
Workflow: "workflow",
|
||||||
|
BitwardenLoginCredential: "bitwardenLoginCredential",
|
||||||
Credential: "credential",
|
Credential: "credential",
|
||||||
Secret: "secret",
|
Secret: "secret",
|
||||||
Context: "context",
|
Context: "context",
|
||||||
|
|
|
@ -20,6 +20,7 @@ export type ParameterYAML =
|
||||||
| WorkflowParameterYAML
|
| WorkflowParameterYAML
|
||||||
| BitwardenLoginCredentialParameterYAML
|
| BitwardenLoginCredentialParameterYAML
|
||||||
| AWSSecretParameterYAML
|
| AWSSecretParameterYAML
|
||||||
|
| CredentialParameterYAML
|
||||||
| ContextParameterYAML
|
| ContextParameterYAML
|
||||||
| OutputParameterYAML
|
| OutputParameterYAML
|
||||||
| BitwardenSensitiveInformationParameterYAML
|
| BitwardenSensitiveInformationParameterYAML
|
||||||
|
@ -82,6 +83,11 @@ export type OutputParameterYAML = ParameterYAMLBase & {
|
||||||
parameter_type: "output";
|
parameter_type: "output";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type CredentialParameterYAML = ParameterYAMLBase & {
|
||||||
|
parameter_type: "credential";
|
||||||
|
credential_id: string;
|
||||||
|
};
|
||||||
|
|
||||||
export type BlockYAML =
|
export type BlockYAML =
|
||||||
| TaskBlockYAML
|
| TaskBlockYAML
|
||||||
| CodeBlockYAML
|
| CodeBlockYAML
|
||||||
|
|
5
skyvern-frontend/src/store/CloudContext.ts
Normal file
5
skyvern-frontend/src/store/CloudContext.ts
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
import { createContext } from "react";
|
||||||
|
|
||||||
|
const CloudContext = createContext<boolean>(false);
|
||||||
|
|
||||||
|
export default CloudContext;
|
Loading…
Add table
Reference in a new issue