From 0061685b08dbcf7d17e0188d23cb928ab59669da Mon Sep 17 00:00:00 2001 From: Blomios Date: Sat, 1 Aug 2026 19:10:44 +0200 Subject: [PATCH] =?UTF-8?q?fix(frontend,plugins):=20=C3=A9vite=20le=20cras?= =?UTF-8?q?h=20sur=20install/uninstall/reinstall=20par=20rechargement=20sy?= =?UTF-8?q?st=C3=A9matique=20de=20la=20liste=20(#120)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - usePlugins.ts: remplace les mises à jour optimistes du state par des appels listPlugins() après chaque opération backend - PluginsPanel.tsx: ajoute la normalisation isInstallable() pour éviter les crashes si installable est undefined - Co-Authored-By: Claude Opus 4.8 --- frontend/src/features/plugins/PluginsPanel.tsx | 16 ++++++++++++---- frontend/src/features/plugins/usePlugins.ts | 14 +++++++------- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/frontend/src/features/plugins/PluginsPanel.tsx b/frontend/src/features/plugins/PluginsPanel.tsx index 6b1c6e4..0fb76a7 100644 --- a/frontend/src/features/plugins/PluginsPanel.tsx +++ b/frontend/src/features/plugins/PluginsPanel.tsx @@ -217,11 +217,13 @@ export function PluginsPanel() { { - if (installFlow.review.installable) void confirmInstall(); + if (isInstallable(installFlow.review)) void confirmInstall(); else setInstallFlow(null); }} onCancel={() => setInstallFlow(null)} @@ -259,7 +261,13 @@ function reviewSummary(review: PluginReview): string { review.description ?? null, `Confiance : full-trust — ce plugin peut exécuter du code arbitraire dans IdeA.`, `Contributions : ${c.topLevelMenus} menu(s), ${c.menuItems} item(s), ${c.layouts} layout(s), ${c.mcpServers} serveur(s) MCP.`, - ...review.issues.map((i) => `${i.severity === "error" ? "Erreur" : "Avertissement"} : ${i.message}`), + ...(review.issues ?? []).map( + (i) => `${i.severity === "error" ? "Erreur" : "Avertissement"} : ${i.message}`, + ), ].filter((p): p is string => Boolean(p)); return parts.join("\n"); } + +function isInstallable(review: PluginReview): boolean { + return review.installable ?? true; +} diff --git a/frontend/src/features/plugins/usePlugins.ts b/frontend/src/features/plugins/usePlugins.ts index 2814468..feb5508 100644 --- a/frontend/src/features/plugins/usePlugins.ts +++ b/frontend/src/features/plugins/usePlugins.ts @@ -86,8 +86,8 @@ export function usePlugins(): PluginsViewModel { setBusy(true); setError(null); try { - const result = await plugin.installFromArchive(path); - setPlugins((prev) => [...prev.filter((p) => p.id !== result.plugin.id), result.plugin]); + await plugin.installFromArchive(path); + setPlugins(await plugin.listPlugins()); return true; } catch (e) { setError(describe(e)); @@ -104,8 +104,8 @@ export function usePlugins(): PluginsViewModel { setBusy(true); setError(null); try { - const result = await plugin.installFromDirectory(path); - setPlugins((prev) => [...prev.filter((p) => p.id !== result.plugin.id), result.plugin]); + await plugin.installFromDirectory(path); + setPlugins(await plugin.listPlugins()); return true; } catch (e) { setError(describe(e)); @@ -122,8 +122,8 @@ export function usePlugins(): PluginsViewModel { setBusy(true); setError(null); try { - const updated = await plugin.setEnabled(pluginId, enabled); - setPlugins((prev) => prev.map((p) => (p.id === pluginId ? updated : p))); + await plugin.setEnabled(pluginId, enabled); + setPlugins(await plugin.listPlugins()); } catch (e) { setError(describe(e)); } finally { @@ -139,7 +139,7 @@ export function usePlugins(): PluginsViewModel { setError(null); try { await plugin.uninstall(pluginId); - setPlugins((prev) => prev.filter((p) => p.id !== pluginId)); + setPlugins(await plugin.listPlugins()); } catch (e) { setError(describe(e)); } finally {