From 77d1cb58ae426477dcda3c5d101c07ac521da926 Mon Sep 17 00:00:00 2001 From: Marco Beretta <81851188+berry-13@users.noreply.github.com> Date: Thu, 2 Jul 2026 03:49:07 +0200 Subject: [PATCH] feat: show a saving spinner and allow cancelling credential edits Drive the tool credential Save button from the real mutation state so it shows a spinner while the request is in flight, and add a Cancel button when re-editing already-saved credentials so the edit can be dismissed. --- .../Plugins/Store/PluginAuthForm.tsx | 35 ++++++++++++++++--- .../Store/__tests__/PluginAuthForm.spec.tsx | 27 +++++++++++++- .../Tools/ItemDialog/sections/ToolSection.tsx | 10 +++++- 3 files changed, 65 insertions(+), 7 deletions(-) diff --git a/client/src/components/Plugins/Store/PluginAuthForm.tsx b/client/src/components/Plugins/Store/PluginAuthForm.tsx index 91f46aaf39..3bf7b20a1e 100644 --- a/client/src/components/Plugins/Store/PluginAuthForm.tsx +++ b/client/src/components/Plugins/Store/PluginAuthForm.tsx @@ -1,5 +1,13 @@ import { useForm, useWatch } from 'react-hook-form'; -import { HoverCard, HoverCardTrigger, SecretInput, Input, Label, Button } from '@librechat/client'; +import { + Input, + Label, + Button, + Spinner, + HoverCard, + SecretInput, + HoverCardTrigger, +} from '@librechat/client'; import type { TPlugin, TPluginAuthConfig, TPluginAction } from 'librechat-data-provider'; import type { RegisterOptions } from 'react-hook-form'; import PluginTooltip from './PluginTooltip'; @@ -70,9 +78,19 @@ type TPluginAuthFormProps = { plugin: TPlugin | undefined; onSubmit: (installActionData: TPluginAction) => void; isEntityTool?: boolean; + /** External in-flight state (e.g. a mutation) so the button reflects the real save. */ + isSaving?: boolean; + /** When provided, renders a Cancel button (used when re-editing saved credentials). */ + onCancel?: () => void; }; -function PluginAuthForm({ plugin, onSubmit, isEntityTool }: TPluginAuthFormProps) { +function PluginAuthForm({ + plugin, + onSubmit, + isEntityTool, + isSaving, + onCancel, +}: TPluginAuthFormProps) { const { register, control, @@ -84,6 +102,7 @@ function PluginAuthForm({ plugin, onSubmit, isEntityTool }: TPluginAuthFormProps const watchedValues = useWatch({ control }); const authConfig = plugin?.authConfig ?? []; const allFieldsOptional = authConfig.length > 0 && authConfig.every((c) => c.optional === true); + const saving = isSubmitting || isSaving === true; const submit = handleSubmit((auth) => onSubmit({ @@ -178,14 +197,20 @@ function PluginAuthForm({ plugin, onSubmit, isEntityTool }: TPluginAuthFormProps ); })} -