refactor: enhance image generation configuration handling and user feedback messages for improved clarity and consistency

This commit is contained in:
Anish Sarkar 2026-03-29 19:14:46 +05:30
parent a5f41cfd8e
commit 4a05229476
3 changed files with 50 additions and 62 deletions

View file

@ -2,6 +2,8 @@ import { atomWithMutation } from "jotai-tanstack-query";
import { toast } from "sonner"; import { toast } from "sonner";
import type { import type {
CreateImageGenConfigRequest, CreateImageGenConfigRequest,
CreateImageGenConfigResponse,
DeleteImageGenConfigResponse,
GetImageGenConfigsResponse, GetImageGenConfigsResponse,
UpdateImageGenConfigRequest, UpdateImageGenConfigRequest,
UpdateImageGenConfigResponse, UpdateImageGenConfigResponse,
@ -23,8 +25,8 @@ export const createImageGenConfigMutationAtom = atomWithMutation((get) => {
mutationFn: async (request: CreateImageGenConfigRequest) => { mutationFn: async (request: CreateImageGenConfigRequest) => {
return imageGenConfigApiService.createConfig(request); return imageGenConfigApiService.createConfig(request);
}, },
onSuccess: () => { onSuccess: (_: CreateImageGenConfigResponse, request: CreateImageGenConfigRequest) => {
toast.success("Image model created"); toast.success(`${request.name} created`);
queryClient.invalidateQueries({ queryClient.invalidateQueries({
queryKey: cacheKeys.imageGenConfigs.all(Number(searchSpaceId)), queryKey: cacheKeys.imageGenConfigs.all(Number(searchSpaceId)),
}); });
@ -48,7 +50,7 @@ export const updateImageGenConfigMutationAtom = atomWithMutation((get) => {
return imageGenConfigApiService.updateConfig(request); return imageGenConfigApiService.updateConfig(request);
}, },
onSuccess: (_: UpdateImageGenConfigResponse, request: UpdateImageGenConfigRequest) => { onSuccess: (_: UpdateImageGenConfigResponse, request: UpdateImageGenConfigRequest) => {
toast.success("Image model updated"); toast.success(`${request.data.name ?? "Configuration"} updated`);
queryClient.invalidateQueries({ queryClient.invalidateQueries({
queryKey: cacheKeys.imageGenConfigs.all(Number(searchSpaceId)), queryKey: cacheKeys.imageGenConfigs.all(Number(searchSpaceId)),
}); });
@ -71,16 +73,16 @@ export const deleteImageGenConfigMutationAtom = atomWithMutation((get) => {
return { return {
mutationKey: ["image-gen-configs", "delete"], mutationKey: ["image-gen-configs", "delete"],
enabled: !!searchSpaceId, enabled: !!searchSpaceId,
mutationFn: async (id: number) => { mutationFn: async (request: { id: number; name: string }) => {
return imageGenConfigApiService.deleteConfig(id); return imageGenConfigApiService.deleteConfig(request.id);
}, },
onSuccess: (_, id: number) => { onSuccess: (_: DeleteImageGenConfigResponse, request: { id: number; name: string }) => {
toast.success("Image model deleted"); toast.success(`${request.name} deleted`);
queryClient.setQueryData( queryClient.setQueryData(
cacheKeys.imageGenConfigs.all(Number(searchSpaceId)), cacheKeys.imageGenConfigs.all(Number(searchSpaceId)),
(oldData: GetImageGenConfigsResponse | undefined) => { (oldData: GetImageGenConfigsResponse | undefined) => {
if (!oldData) return oldData; if (!oldData) return oldData;
return oldData.filter((config) => config.id !== id); return oldData.filter((config) => config.id !== request.id);
} }
); );
}, },

View file

@ -121,7 +121,7 @@ export function ImageModelManager({ searchSpaceId }: ImageModelManagerProps) {
const handleDelete = async () => { const handleDelete = async () => {
if (!configToDelete) return; if (!configToDelete) return;
try { try {
await deleteConfig(configToDelete.id); await deleteConfig({ id: configToDelete.id, name: configToDelete.name });
setConfigToDelete(null); setConfigToDelete(null);
} catch { } catch {
// Error handled by mutation // Error handled by mutation
@ -398,12 +398,11 @@ export function ImageModelManager({ searchSpaceId }: ImageModelManagerProps) {
open={!!configToDelete} open={!!configToDelete}
onOpenChange={(open) => !open && setConfigToDelete(null)} onOpenChange={(open) => !open && setConfigToDelete(null)}
> >
<AlertDialogContent> <AlertDialogContent className="select-none">
<AlertDialogHeader> <AlertDialogHeader>
<AlertDialogTitle className="flex items-center gap-2"> <AlertDialogTitle>
<Trash2 className="h-5 w-5 text-destructive" /> Delete Image Model
Delete Image Model </AlertDialogTitle>
</AlertDialogTitle>
<AlertDialogDescription> <AlertDialogDescription>
Are you sure you want to delete{" "} Are you sure you want to delete{" "}
<span className="font-semibold text-foreground">{configToDelete?.name}</span>? <span className="font-semibold text-foreground">{configToDelete?.name}</span>?
@ -411,23 +410,14 @@ export function ImageModelManager({ searchSpaceId }: ImageModelManagerProps) {
</AlertDialogHeader> </AlertDialogHeader>
<AlertDialogFooter> <AlertDialogFooter>
<AlertDialogCancel disabled={isDeleting}>Cancel</AlertDialogCancel> <AlertDialogCancel disabled={isDeleting}>Cancel</AlertDialogCancel>
<AlertDialogAction <AlertDialogAction
onClick={handleDelete} onClick={handleDelete}
disabled={isDeleting} disabled={isDeleting}
className="bg-destructive text-destructive-foreground hover:bg-destructive/90" className="relative bg-destructive text-destructive-foreground hover:bg-destructive/90"
> >
{isDeleting ? ( <span className={isDeleting ? "opacity-0" : ""}>Delete</span>
<> {isDeleting && <Spinner size="sm" className="absolute" />}
<Spinner size="sm" className="mr-2" /> </AlertDialogAction>
Deleting
</>
) : (
<>
<Trash2 className="mr-2 h-4 w-4" />
Delete
</>
)}
</AlertDialogAction>
</AlertDialogFooter> </AlertDialogFooter>
</AlertDialogContent> </AlertDialogContent>
</AlertDialog> </AlertDialog>

View file

@ -460,38 +460,34 @@ export function ImageConfigDialog({
Cancel Cancel
</Button> </Button>
{mode === "create" || (mode === "edit" && !isGlobal) ? ( {mode === "create" || (mode === "edit" && !isGlobal) ? (
<Button <Button
onClick={handleSubmit} onClick={handleSubmit}
disabled={isSubmitting || !isFormValid} disabled={isSubmitting || !isFormValid}
className="text-sm h-9 min-w-[120px]" className="relative text-sm h-9 min-w-[120px]"
> >
{isSubmitting ? ( <span className={isSubmitting ? "opacity-0" : ""}>
<> {mode === "edit" ? "Save Changes" : "Create & Use"}
<Spinner size="sm" /> </span>
{mode === "edit" ? "Saving" : "Creating"} {isSubmitting && <Spinner size="sm" className="absolute" />}
</> </Button>
) : mode === "edit" ? (
"Save Changes"
) : (
"Create & Use"
)}
</Button>
) : isAutoMode ? ( ) : isAutoMode ? (
<Button <Button
className="text-sm h-9 gap-2 bg-gradient-to-r from-violet-500 to-purple-600 hover:from-violet-600 hover:to-purple-700" className="relative text-sm h-9 bg-gradient-to-r from-violet-500 to-purple-600 hover:from-violet-600 hover:to-purple-700"
onClick={handleUseGlobalConfig} onClick={handleUseGlobalConfig}
disabled={isSubmitting} disabled={isSubmitting}
> >
{isSubmitting ? "Loading..." : "Use Auto Mode"} <span className={isSubmitting ? "opacity-0" : ""}>Use Auto Mode</span>
</Button> {isSubmitting && <Spinner size="sm" className="absolute" />}
</Button>
) : isGlobal && config ? ( ) : isGlobal && config ? (
<Button <Button
className="text-sm h-9 gap-2" className="relative text-sm h-9"
onClick={handleUseGlobalConfig} onClick={handleUseGlobalConfig}
disabled={isSubmitting} disabled={isSubmitting}
> >
{isSubmitting ? "Loading..." : "Use This Model"} <span className={isSubmitting ? "opacity-0" : ""}>Use This Model</span>
</Button> {isSubmitting && <Spinner size="sm" className="absolute" />}
</Button>
) : null} ) : null}
</div> </div>
</DialogContent> </DialogContent>