Credentials UI (#1828)

This commit is contained in:
Shuchang Zheng 2025-02-24 11:54:18 -08:00 committed by GitHub
parent 39ab9c0603
commit c5a2438e7f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 337 additions and 27 deletions

View file

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

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

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

View file

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

View file

@ -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 = {

View file

@ -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,

View file

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

View file

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

View file

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

View file

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

View file

@ -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",

View file

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

View file

@ -0,0 +1,5 @@
import { createContext } from "react";
const CloudContext = createContext<boolean>(false);
export default CloudContext;