Fix plugin update bugs from Bugbot review

- Fix SSE error handler not calling onEvent, leaving UI stuck in updating state
- Fix plugin name prefix matching to avoid corrupting wrong config entries
- Fix EventSource cleanup on component unmount using useRef
This commit is contained in:
Thomas Marchand
2026-01-17 15:12:43 +00:00
parent 5c2f898234
commit 81feecbd48
3 changed files with 21 additions and 4 deletions

View File

@@ -1,6 +1,6 @@
'use client';
import { useState, useMemo, useEffect } from 'react';
import { useState, useMemo, useEffect, useRef } from 'react';
import useSWR from 'swr';
import { toast } from '@/components/toast';
import { type Plugin, getInstalledPlugins, updatePlugin, type InstalledPluginInfo } from '@/lib/api';
@@ -585,6 +585,16 @@ function InstalledPluginsSection() {
const [updating, setUpdating] = useState<string | null>(null);
const [updateProgress, setUpdateProgress] = useState<string | null>(null);
const cleanupRef = useRef<(() => void) | null>(null);
// Cleanup EventSource on unmount
useEffect(() => {
return () => {
if (cleanupRef.current) {
cleanupRef.current();
}
};
}, []);
const handleUpdate = (packageName: string) => {
setUpdating(packageName);
@@ -597,16 +607,17 @@ function InstalledPluginsSection() {
toast.success(event.message);
setUpdating(null);
setUpdateProgress(null);
cleanupRef.current = null;
mutate(); // Refresh the list
} else if (event.event_type === 'error') {
toast.error(event.message);
setUpdating(null);
setUpdateProgress(null);
cleanupRef.current = null;
}
});
// Cleanup on unmount
return cleanup;
cleanupRef.current = cleanup;
};
if (isLoading) {

View File

@@ -1669,6 +1669,11 @@ export function updatePlugin(
eventSource.onerror = () => {
eventSource.close();
onEvent({
event_type: "error",
message: "Connection error: failed to connect to server",
progress: null,
});
};
return () => eventSource.close();

View File

@@ -1069,7 +1069,8 @@ fn stream_plugin_update(package: String) -> impl Stream<Item = Result<Event, std
// Update the plugin spec to @latest
for p in plugins.iter_mut() {
if let Some(s) = p.as_str() {
if s.starts_with(&package) {
// Match exact package name or package@version to avoid prefix collisions
if s == package || s.starts_with(&format!("{}@", package)) {
*p = serde_json::json!(format!("{}@latest", package));
}
}