mirror of
https://github.com/Significant-Gravitas/AutoGPT.git
synced 2026-04-08 03:00:28 -04:00
fix(frontend): fix auto select credential mechanism in new builder (#11171)
We’re currently facing two problems with credentials: 1. When we change the discriminator input value, the form data credential field should be cleaned up completely. 2. When I select a different discriminator and if that provider has a value, it should select the latest one. So, in this PR, I’ve encountered both issues. ### Changes 🏗️ - Updated CredentialField to utilize a new setCredential function for managing selected credentials. - Implemented logic to auto-select the latest credential when none is selected and clear the credential if the provider changes. - Improved SelectCredential component with a defaultValue prop and adjusted styling for better UI consistency. - Removed unnecessary console logs from helper functions to clean up the code. <!-- Concisely describe all of the changes made in this pull request: --> ### Checklist 📋 #### For code changes: - [x] I have clearly listed my changes in the PR description - [x] I have made a test plan - [x] I have tested my changes according to the test plan: - [x] Credential selection works perfectly with both the discriminator and normal addition. - [x] Auto-select credential is also working.
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import React, { useEffect } from "react";
|
||||
import React from "react";
|
||||
import { FieldProps } from "@rjsf/utils";
|
||||
import { useCredentialField } from "./useCredentialField";
|
||||
import { SelectCredential } from "./SelectCredential";
|
||||
@@ -24,22 +24,14 @@ export const CredentialsField = (props: FieldProps) => {
|
||||
supportsUserPassword,
|
||||
credentialsExists,
|
||||
credentialProvider,
|
||||
setCredential,
|
||||
} = useCredentialField({
|
||||
credentialSchema: schema as BlockIOCredentialsSubSchema,
|
||||
formData,
|
||||
nodeId: formContext.nodeId,
|
||||
onChange,
|
||||
});
|
||||
|
||||
const setField = (key: string, value: any) =>
|
||||
onChange({ ...formData, [key]: value });
|
||||
|
||||
// This is to set the latest credential as the default one [currently, latest means last one in the list of credentials]
|
||||
useEffect(() => {
|
||||
if (!isCredentialListLoading && credentials.length > 0 && !formData.id) {
|
||||
const latestCredential = credentials[credentials.length - 1];
|
||||
setField("id", latestCredential.id);
|
||||
}
|
||||
}, [isCredentialListLoading, credentials, formData.id]);
|
||||
|
||||
if (isCredentialListLoading) {
|
||||
return (
|
||||
<div className="flex flex-col gap-2">
|
||||
@@ -58,8 +50,8 @@ export const CredentialsField = (props: FieldProps) => {
|
||||
{credentialsExists && (
|
||||
<SelectCredential
|
||||
credentials={credentials}
|
||||
value={formData.id}
|
||||
onChange={(value) => setField("id", value)}
|
||||
value={formData.id || ""}
|
||||
onChange={setCredential}
|
||||
disabled={false}
|
||||
label="Credential"
|
||||
placeholder="Select credential"
|
||||
|
||||
@@ -13,6 +13,7 @@ import { providerIcons } from "./helpers";
|
||||
type SelectCredentialProps = {
|
||||
credentials: CredentialsMetaResponse[];
|
||||
value?: string;
|
||||
defaultValue?: string;
|
||||
onChange: (credentialId: string) => void;
|
||||
disabled?: boolean;
|
||||
label?: string;
|
||||
@@ -67,7 +68,7 @@ export const SelectCredential: React.FC<SelectCredentialProps> = ({
|
||||
<Select
|
||||
label={label}
|
||||
id="select-credential"
|
||||
wrapperClassName="!mb-0 flex-1"
|
||||
wrapperClassName="!mb-0 flex-1 !max-w-[90%]"
|
||||
value={value}
|
||||
onValueChange={onChange}
|
||||
options={options}
|
||||
@@ -77,8 +78,12 @@ export const SelectCredential: React.FC<SelectCredentialProps> = ({
|
||||
hideLabel
|
||||
/>
|
||||
<Link href={`/profile/integrations`}>
|
||||
<Button variant="outline" size="icon" className="h-8 w-8 p-0">
|
||||
<ArrowSquareOutIcon className="h-4 w-4" />
|
||||
<Button
|
||||
variant="outline"
|
||||
size="icon"
|
||||
className="h-8 w-8 border-zinc-300 p-0"
|
||||
>
|
||||
<ArrowSquareOutIcon className="h-4 w-4 text-zinc-600" />
|
||||
</Button>
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
@@ -15,8 +15,6 @@ export const filterCredentialsByProvider = (
|
||||
credentials: CredentialsMetaResponse[] | undefined,
|
||||
provider: string,
|
||||
) => {
|
||||
console.log("provider", provider);
|
||||
console.log("credentials", credentials);
|
||||
const filtered =
|
||||
credentials?.filter((credential) => provider === credential.provider) ?? [];
|
||||
return {
|
||||
@@ -129,7 +127,6 @@ export const getCredentialProviderFromSchema = (
|
||||
);
|
||||
return null;
|
||||
}
|
||||
console.log("discriminatedProvider", discriminatedProvider);
|
||||
return discriminatedProvider;
|
||||
} else {
|
||||
return providers[0];
|
||||
|
||||
@@ -6,14 +6,21 @@ import {
|
||||
getCredentialProviderFromSchema,
|
||||
} from "./helpers";
|
||||
import { useNodeStore } from "@/app/(platform)/build/stores/nodeStore";
|
||||
import { useEffect, useRef } from "react";
|
||||
|
||||
export const useCredentialField = ({
|
||||
credentialSchema,
|
||||
formData,
|
||||
nodeId,
|
||||
onChange,
|
||||
}: {
|
||||
credentialSchema: BlockIOCredentialsSubSchema; // Here we are using manual typing, we need to fix it with automatic one
|
||||
formData: Record<string, any>;
|
||||
nodeId: string;
|
||||
onChange: (value: Record<string, any>) => void;
|
||||
}) => {
|
||||
const previousProviderRef = useRef<string | null>(null);
|
||||
|
||||
// Fetch all the credentials from the backend
|
||||
// We will save it in cache for 10 min, if user edits the credential, we will invalidate the cache
|
||||
// Whenever user adds a block, we filter the credentials list and check if this block's provider is in the list
|
||||
@@ -44,9 +51,71 @@ export const useCredentialField = ({
|
||||
const { credentials: filteredCredentials, exists: credentialsExists } =
|
||||
filterCredentialsByProvider(credentials, credentialProvider ?? "");
|
||||
|
||||
const setCredential = (credentialId: string) => {
|
||||
const selectedCredential = filteredCredentials.find(
|
||||
(c) => c.id === credentialId,
|
||||
);
|
||||
if (selectedCredential) {
|
||||
onChange({
|
||||
...formData,
|
||||
id: selectedCredential.id,
|
||||
provider: selectedCredential.provider,
|
||||
title: selectedCredential.title,
|
||||
type: selectedCredential.type,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// This side effect is used to clear the hardcoded value in credential formData when the provider changes
|
||||
useEffect(() => {
|
||||
if (!credentialProvider) return;
|
||||
// If provider has changed and we have a credential selected
|
||||
if (
|
||||
previousProviderRef.current !== null &&
|
||||
previousProviderRef.current !== credentialProvider &&
|
||||
formData.id
|
||||
) {
|
||||
// Check if the current credential belongs to the new provider
|
||||
const currentCredentialBelongsToProvider = filteredCredentials.some(
|
||||
(c) => c.id === formData.id,
|
||||
);
|
||||
|
||||
// If not, clear the credential
|
||||
if (!currentCredentialBelongsToProvider) {
|
||||
onChange({
|
||||
id: "",
|
||||
provider: "",
|
||||
title: "",
|
||||
type: "",
|
||||
});
|
||||
}
|
||||
}
|
||||
previousProviderRef.current = credentialProvider;
|
||||
}, [credentialProvider, formData.id, credentials, onChange]);
|
||||
|
||||
// This side effect is used to auto-select the latest credential when none is selected [latest means last one in the list of credentials]
|
||||
useEffect(() => {
|
||||
if (
|
||||
!isCredentialListLoading &&
|
||||
filteredCredentials.length > 0 &&
|
||||
!formData.id && // No credential currently selected
|
||||
credentialProvider // Provider is set
|
||||
) {
|
||||
const latestCredential =
|
||||
filteredCredentials[filteredCredentials.length - 1];
|
||||
setCredential(latestCredential.id);
|
||||
}
|
||||
}, [
|
||||
isCredentialListLoading,
|
||||
filteredCredentials.length,
|
||||
formData.id,
|
||||
credentialProvider,
|
||||
]);
|
||||
|
||||
return {
|
||||
credentials: filteredCredentials,
|
||||
isCredentialListLoading,
|
||||
setCredential,
|
||||
supportsApiKey,
|
||||
supportsOAuth2,
|
||||
supportsUserPassword,
|
||||
|
||||
Reference in New Issue
Block a user