mirror of
https://github.com/Significant-Gravitas/AutoGPT.git
synced 2026-04-08 03:00:28 -04:00
fix(frontend): replace duplicate host-scoped credentials and add delete support
- HostScopedCredentialsModal now deletes existing credentials for the same host before creating new ones, preventing duplicates - Wire up delete flow: CredentialsFlatView passes onDelete to CredentialRow, CredentialsInput renders DeleteConfirmationModal - Update button text to "Update headers" when credentials already exist - Dynamic modal title/button: "Update" vs "Add" based on existing creds
This commit is contained in:
@@ -10,6 +10,7 @@ import { toDisplayName } from "@/providers/agent-credentials/helper";
|
||||
import { APIKeyCredentialsModal } from "./components/APIKeyCredentialsModal/APIKeyCredentialsModal";
|
||||
import { CredentialsFlatView } from "./components/CredentialsFlatView/CredentialsFlatView";
|
||||
import { CredentialTypeSelector } from "./components/CredentialTypeSelector/CredentialTypeSelector";
|
||||
import { DeleteConfirmationModal } from "./components/DeleteConfirmationModal/DeleteConfirmationModal";
|
||||
import { HostScopedCredentialsModal } from "./components/HotScopedCredentialsModal/HotScopedCredentialsModal";
|
||||
import { OAuthFlowWaitingModal } from "./components/OAuthWaitingModal/OAuthWaitingModal";
|
||||
import { PasswordCredentialsModal } from "./components/PasswordCredentialsModal/PasswordCredentialsModal";
|
||||
@@ -90,6 +91,11 @@ export function CredentialsInput({
|
||||
handleActionButtonClick,
|
||||
handleCredentialSelect,
|
||||
handleOAuthLogin,
|
||||
handleDeleteCredential,
|
||||
handleDeleteConfirm,
|
||||
credentialToDelete,
|
||||
setCredentialToDelete,
|
||||
deleteCredentialsMutation,
|
||||
} = hookData;
|
||||
|
||||
const displayName = toDisplayName(provider);
|
||||
@@ -113,6 +119,7 @@ export function CredentialsInput({
|
||||
onSelectCredential={handleCredentialSelect}
|
||||
onClearCredential={() => onSelectCredential(undefined)}
|
||||
onAddCredential={handleActionButtonClick}
|
||||
onDeleteCredential={readOnly ? undefined : handleDeleteCredential}
|
||||
actionButtonText={actionButtonText}
|
||||
isOptional={isOptional}
|
||||
showTitle={showTitle}
|
||||
@@ -192,6 +199,13 @@ export function CredentialsInput({
|
||||
Error: {oAuthError}
|
||||
</Text>
|
||||
)}
|
||||
|
||||
<DeleteConfirmationModal
|
||||
credentialToDelete={credentialToDelete}
|
||||
isDeleting={deleteCredentialsMutation.isPending}
|
||||
onClose={() => setCredentialToDelete(null)}
|
||||
onConfirm={handleDeleteConfirm}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -31,6 +31,7 @@ type Props = {
|
||||
onSelectCredential: (credentialId: string) => void;
|
||||
onClearCredential: () => void;
|
||||
onAddCredential: () => void;
|
||||
onDeleteCredential?: (credential: { id: string; title: string }) => void;
|
||||
};
|
||||
|
||||
export function CredentialsFlatView({
|
||||
@@ -47,6 +48,7 @@ export function CredentialsFlatView({
|
||||
onSelectCredential,
|
||||
onClearCredential,
|
||||
onAddCredential,
|
||||
onDeleteCredential,
|
||||
}: Props) {
|
||||
const hasCredentials = credentials.length > 0;
|
||||
|
||||
@@ -99,6 +101,15 @@ export function CredentialsFlatView({
|
||||
provider={provider}
|
||||
displayName={displayName}
|
||||
onSelect={() => onSelectCredential(credential.id)}
|
||||
onDelete={
|
||||
onDeleteCredential
|
||||
? () =>
|
||||
onDeleteCredential({
|
||||
id: credential.id,
|
||||
title: credential.title || credential.id,
|
||||
})
|
||||
: undefined
|
||||
}
|
||||
readOnly={readOnly}
|
||||
/>
|
||||
))}
|
||||
|
||||
@@ -89,7 +89,20 @@ export function HostScopedCredentialsModal({
|
||||
return null;
|
||||
}
|
||||
|
||||
const { provider, providerName, createHostScopedCredentials } = credentials;
|
||||
const {
|
||||
provider,
|
||||
providerName,
|
||||
savedCredentials,
|
||||
createHostScopedCredentials,
|
||||
deleteCredentials,
|
||||
} = credentials;
|
||||
|
||||
const hasExistingForHost = savedCredentials.some(
|
||||
(c) =>
|
||||
c.type === "host_scoped" &&
|
||||
"host" in c &&
|
||||
c.host === (currentHost || form.getValues("host")),
|
||||
);
|
||||
|
||||
const addHeaderPair = () => {
|
||||
setHeaderPairs([...headerPairs, { key: "", value: "" }]);
|
||||
@@ -123,9 +136,18 @@ export function HostScopedCredentialsModal({
|
||||
{} as Record<string, string>,
|
||||
);
|
||||
|
||||
// Delete existing host-scoped credentials for the same host to avoid duplicates
|
||||
const host = values.host;
|
||||
const existingForHost = savedCredentials.filter(
|
||||
(c) => c.type === "host_scoped" && "host" in c && c.host === host,
|
||||
);
|
||||
for (const existing of existingForHost) {
|
||||
await deleteCredentials(existing.id, true);
|
||||
}
|
||||
|
||||
const newCredentials = await createHostScopedCredentials({
|
||||
host: values.host,
|
||||
title: currentHost || values.host,
|
||||
host,
|
||||
title: currentHost || host,
|
||||
headers,
|
||||
});
|
||||
|
||||
@@ -139,7 +161,11 @@ export function HostScopedCredentialsModal({
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
title={`Add sensitive headers for ${providerName}`}
|
||||
title={
|
||||
hasExistingForHost
|
||||
? `Update sensitive headers for ${providerName}`
|
||||
: `Add sensitive headers for ${providerName}`
|
||||
}
|
||||
controlled={{
|
||||
isOpen: open,
|
||||
set: (isOpen) => {
|
||||
@@ -241,7 +267,9 @@ export function HostScopedCredentialsModal({
|
||||
|
||||
<div className="pt-8">
|
||||
<Button type="submit" className="w-full" size="small">
|
||||
Save & use these credentials
|
||||
{hasExistingForHost
|
||||
? "Update & use these credentials"
|
||||
: "Save & use these credentials"}
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@@ -148,7 +148,7 @@ export function getActionButtonText(
|
||||
if (supportsOAuth2) return "Connect another account";
|
||||
if (supportsApiKey) return "Use a new API key";
|
||||
if (supportsUserPassword) return "Add a new username and password";
|
||||
if (supportsHostScoped) return "Add new headers";
|
||||
if (supportsHostScoped) return "Update headers";
|
||||
return "Add new credentials";
|
||||
} else {
|
||||
if (supportsOAuth2) return "Add account";
|
||||
|
||||
Reference in New Issue
Block a user