fix: build out the credentials provider on the front and backend a bit more
This commit is contained in:
parent
5720225a75
commit
e933502cbd
|
@ -197,7 +197,10 @@ class OAuth2Credentials(_BaseCredentials):
|
|||
class APIKeyCredentials(_BaseCredentials):
|
||||
type: Literal["api_key"] = "api_key"
|
||||
api_key: SecretStr
|
||||
expires_at: Optional[int]
|
||||
expires_at: Optional[int] = Field(
|
||||
default=None,
|
||||
description="Unix timestamp (seconds) indicating when the API key expires (if at all)",
|
||||
)
|
||||
"""Unix timestamp (seconds) indicating when the API key expires (if at all)"""
|
||||
|
||||
def bearer(self) -> str:
|
||||
|
|
|
@ -17,6 +17,7 @@ from backend.data.model import (
|
|||
Credentials,
|
||||
CredentialsType,
|
||||
OAuth2Credentials,
|
||||
UserPasswordCredentials,
|
||||
)
|
||||
from backend.executor.manager import ExecutionManager
|
||||
from backend.integrations.creds_manager import IntegrationCredentialsManager
|
||||
|
@ -196,22 +197,15 @@ def get_credential(
|
|||
|
||||
|
||||
@router.post("/{provider}/credentials", status_code=201)
|
||||
def create_api_key_credentials(
|
||||
def create_credentials(
|
||||
user_id: Annotated[str, Depends(get_user_id)],
|
||||
provider: Annotated[
|
||||
ProviderName, Path(title="The provider to create credentials for")
|
||||
],
|
||||
api_key: Annotated[str, Body(title="The API key to store")],
|
||||
title: Annotated[str, Body(title="Optional title for the credentials")],
|
||||
expires_at: Annotated[
|
||||
int | None, Body(title="Unix timestamp when the key expires")
|
||||
] = None,
|
||||
) -> APIKeyCredentials:
|
||||
new_credentials = APIKeyCredentials(
|
||||
provider=provider,
|
||||
api_key=SecretStr(api_key),
|
||||
title=title,
|
||||
expires_at=expires_at,
|
||||
credential: Credentials,
|
||||
) -> Credentials:
|
||||
new_credentials = credential.__class__(
|
||||
provider=provider, **credential.model_dump(exclude={"provider"})
|
||||
)
|
||||
|
||||
try:
|
||||
|
|
|
@ -123,7 +123,11 @@ export default function PrivatePage() {
|
|||
|
||||
const allCredentials = providers
|
||||
? Object.values(providers).flatMap((provider) =>
|
||||
[...provider.savedOAuthCredentials, ...provider.savedApiKeys]
|
||||
[
|
||||
...provider.savedOAuthCredentials,
|
||||
...provider.savedApiKeys,
|
||||
...provider.savedUserPasswordCredentials,
|
||||
]
|
||||
.filter((cred) => !hiddenCredentials.includes(cred.id))
|
||||
.map((credentials) => ({
|
||||
...credentials,
|
||||
|
|
|
@ -123,14 +123,22 @@ export default function PrivatePage() {
|
|||
|
||||
const allCredentials = providers
|
||||
? Object.values(providers).flatMap((provider) =>
|
||||
[...provider.savedOAuthCredentials, ...provider.savedApiKeys]
|
||||
[
|
||||
...provider.savedOAuthCredentials,
|
||||
...provider.savedApiKeys,
|
||||
...provider.savedUserPasswordCredentials,
|
||||
]
|
||||
.filter((cred) => !hiddenCredentials.includes(cred.id))
|
||||
.map((credentials) => ({
|
||||
...credentials,
|
||||
provider: provider.provider,
|
||||
providerName: provider.providerName,
|
||||
ProviderIcon: providerIcons[provider.provider],
|
||||
TypeIcon: { oauth2: IconUser, api_key: IconKey }[credentials.type],
|
||||
TypeIcon: {
|
||||
oauth2: IconUser,
|
||||
api_key: IconKey,
|
||||
user_password: IconKey,
|
||||
}[credentials.type],
|
||||
})),
|
||||
)
|
||||
: [];
|
||||
|
|
|
@ -246,13 +246,18 @@ export const CredentialsInput: FC<{
|
|||
selectedCredentials &&
|
||||
!savedApiKeys
|
||||
.concat(savedOAuthCredentials)
|
||||
.concat(savedUserPasswordCredentials)
|
||||
.some((c) => c.id === selectedCredentials.id)
|
||||
) {
|
||||
onSelectCredentials(undefined);
|
||||
}
|
||||
|
||||
// No saved credentials yet
|
||||
if (savedApiKeys.length === 0 && savedOAuthCredentials.length === 0) {
|
||||
if (
|
||||
savedApiKeys.length === 0 &&
|
||||
savedOAuthCredentials.length === 0 &&
|
||||
savedUserPasswordCredentials.length === 0
|
||||
) {
|
||||
return (
|
||||
<>
|
||||
<div className="mb-2 flex gap-1">
|
||||
|
@ -287,6 +292,7 @@ export const CredentialsInput: FC<{
|
|||
);
|
||||
}
|
||||
|
||||
//TODO: This is a mess that won't scale. We need to refactor this single credential logic
|
||||
const singleCredential =
|
||||
savedApiKeys.length === 1 && savedOAuthCredentials.length === 0
|
||||
? savedApiKeys[0]
|
||||
|
@ -316,6 +322,7 @@ export const CredentialsInput: FC<{
|
|||
} else {
|
||||
const selectedCreds = savedApiKeys
|
||||
.concat(savedOAuthCredentials)
|
||||
.concat(savedUserPasswordCredentials)
|
||||
.find((c) => c.id == newValue)!;
|
||||
|
||||
onSelectCredentials({
|
||||
|
@ -576,6 +583,45 @@ export const UserPasswordCredentialsModal: FC<{
|
|||
</DialogHeader>
|
||||
<Form {...form}>
|
||||
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="username"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Username</FormLabel>
|
||||
<FormControl>
|
||||
<Input type="text" placeholder="Enter username..." {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="password"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Password</FormLabel>
|
||||
<FormControl>
|
||||
<Input type="password" placeholder="Enter password..." {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="title"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Name</FormLabel>
|
||||
<FormControl>
|
||||
<Input type="text" placeholder="Enter a name for this user password..." {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<Button type="submit" className="w-full">
|
||||
Save & use this user password
|
||||
</Button>
|
||||
|
|
|
@ -116,6 +116,9 @@ export default function CredentialsProvider({
|
|||
credentials,
|
||||
];
|
||||
} else if (credentials.type === "user_password") {
|
||||
console.log("Adding user password credentials", credentials);
|
||||
console.log("Updated provider", updatedProvider);
|
||||
console.log("Updated provider savedUserPasswordCredentials", updatedProvider.savedUserPasswordCredentials);
|
||||
updatedProvider.savedUserPasswordCredentials = [
|
||||
...updatedProvider.savedUserPasswordCredentials,
|
||||
credentials,
|
||||
|
@ -201,7 +204,10 @@ export default function CredentialsProvider({
|
|||
updatedProvider.savedOAuthCredentials.filter(
|
||||
(cred) => cred.id !== id,
|
||||
);
|
||||
|
||||
updatedProvider.savedUserPasswordCredentials =
|
||||
updatedProvider.savedUserPasswordCredentials.filter(
|
||||
(cred) => cred.id !== id,
|
||||
);
|
||||
return {
|
||||
...prev,
|
||||
[provider]: updatedProvider,
|
||||
|
@ -257,6 +263,8 @@ export default function CredentialsProvider({
|
|||
savedApiKeys: credentialsByProvider[provider]?.apiKeys ?? [],
|
||||
savedOAuthCredentials:
|
||||
credentialsByProvider[provider]?.oauthCreds ?? [],
|
||||
savedUserPasswordCredentials:
|
||||
credentialsByProvider[provider]?.userPasswordCreds ?? [],
|
||||
oAuthCallback: (code: string, state_token: string) =>
|
||||
oAuthCallback(
|
||||
provider as CredentialsProviderName,
|
||||
|
|
|
@ -30,6 +30,7 @@ import {
|
|||
ScheduleCreatable,
|
||||
Schedule,
|
||||
UserPasswordCredentials,
|
||||
Credentials,
|
||||
} from "./types";
|
||||
import { createBrowserClient } from "@supabase/ssr";
|
||||
import getServerSupabase from "../supabase/getServerSupabase";
|
||||
|
@ -189,7 +190,7 @@ export default class BackendAPI {
|
|||
return this._request(
|
||||
"POST",
|
||||
`/integrations/${credentials.provider}/credentials`,
|
||||
credentials,
|
||||
{ ...credentials, type: "api_key" },
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -199,7 +200,7 @@ export default class BackendAPI {
|
|||
return this._request(
|
||||
"POST",
|
||||
`/integrations/${credentials.provider}/credentials`,
|
||||
credentials,
|
||||
{ ...credentials, type: "user_password" },
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -211,10 +212,7 @@ export default class BackendAPI {
|
|||
);
|
||||
}
|
||||
|
||||
getCredentials(
|
||||
provider: string,
|
||||
id: string,
|
||||
): Promise<APIKeyCredentials | OAuth2Credentials> {
|
||||
getCredentials(provider: string, id: string): Promise<Credentials> {
|
||||
return this._get(`/integrations/${provider}/credentials/${id}`);
|
||||
}
|
||||
|
||||
|
|
|
@ -99,6 +99,11 @@ export type BlockIOBooleanSubSchema = BlockIOSubSchemaMeta & {
|
|||
|
||||
export type CredentialsType = "api_key" | "oauth2" | "user_password";
|
||||
|
||||
export type Credentials =
|
||||
| APIKeyCredentials
|
||||
| OAuth2Credentials
|
||||
| UserPasswordCredentials;
|
||||
|
||||
// --8<-- [start:BlockIOCredentialsSubSchema]
|
||||
export const PROVIDER_NAMES = {
|
||||
ANTHROPIC: "anthropic",
|
||||
|
|
Loading…
Reference in New Issue