fix(updates): keep toolbar update entry hidden during component updates

This commit is contained in:
zipg authored and GitHub committed 2026-09-22 11:07:30 +08:00
1 parent 808317e0e7
commit 32189c7271
4 files changed
+80 -4

No files matched your search

+11 -3
View File
@@ -28,7 +28,7 @@ import { canDownloadAndInstallUpdate, useAppUpdater } from "@/composables/useApp
import { useMcpUpdateBadge } from "@/composables/useMcpUpdateBadge";
import { useComponentUpdates, type ComponentUpdateCategory } from "@/composables/useComponentUpdates";
import { COMPONENT_UPDATES_CHANGED_EVENT, notifyComponentPluginsUpdated, notifyComponentUpdatesChanged } from "@/lib/updates/componentUpdateEvents";
import { driverStoreUpdateBadgeCount, showMcpUpdateBadge } from "@/lib/updates/updateBadges";
import { driverStoreUpdateBadgeCount, showMcpUpdateBadge, showToolbarUpdateAction } from "@/lib/updates/updateBadges";
import { markPendingComponentUpdatesAfterAppUpdate, resolveUpdateAllAction, runPendingComponentUpdatePlan, shouldCloseUpdateCenterAfterComponentUpdate, takePendingComponentUpdatesAfterAppRestart, type PendingComponentUpdatePlan } from "@/lib/updates/componentUpdateOrchestration";
import { isUpdatePreviewMockEnabled } from "@/lib/updates/updatePreviewMock";
import { useExportTracker } from "@/composables/useExportTracker";
@@ -902,8 +902,16 @@ const toolbarAgentDriverUpdateCount = computed(() => Math.max(agentDriverUpdateC
const toolbarDriverUpdateCount = computed(() => toolbarAgentDriverUpdateCount.value);
const toolbarJdbcUpdateAvailable = computed(() => componentUpdates.jdbcUpdateAvailable.value);
const toolbarMcpUpdateAvailable = computed(() => mcpUpdateAvailable.value || componentUpdates.mcpUpdateAvailable.value);
const toolbarPluginUpdateAvailable = computed(() => componentUpdates.pluginUpdateCount.value > 0);
const toolbarHasUpdateAvailable = computed(() => hasUpdateAvailable.value || toolbarDriverUpdateCount.value > 0 || toolbarJdbcUpdateAvailable.value || toolbarMcpUpdateAvailable.value || toolbarPluginUpdateAvailable.value);
const toolbarHasUpdateAvailable = computed(() =>
showToolbarUpdateAction({
appUpdateAvailable: hasUpdateAvailable.value,
driverUpdateCount: toolbarDriverUpdateCount.value,
jdbcUpdateAvailable: toolbarJdbcUpdateAvailable.value,
mcpUpdateAvailable: toolbarMcpUpdateAvailable.value,
pluginUpdateCount: componentUpdates.pluginUpdateCount.value,
componentUpdatesRunning: componentUpdates.updating.value,
}),
);
const showDriverStoreUpdateBadge = computed(() => driverStoreUpdateBadgeCount(settingsStore.editorSettings.autoUpdateDrivers, settingsStore.editorSettings.autoUpdateJdbc, toolbarDriverUpdateCount.value, toolbarJdbcUpdateAvailable.value));
const showMcpSettingsUpdateBadge = computed(() => showMcpUpdateBadge(settingsStore.editorSettings.autoUpdateMcp, toolbarMcpUpdateAvailable.value));
const manualCheckingAllUpdates = ref(false);
@@ -1,6 +1,7 @@
import { beforeEach, describe, expect, it, vi } from "vitest";
import { useComponentUpdates } from "@/composables/useComponentUpdates";
import { runPendingComponentUpdatePlan, type PendingComponentUpdates } from "@/lib/updates/componentUpdateOrchestration";
import { showToolbarUpdateAction } from "@/lib/updates/updateBadges";
const mocks = vi.hoisted(() => ({
listInstalledAgents: vi.fn(),
@@ -215,6 +216,36 @@ describe("useComponentUpdates", () => {
expect(result).toEqual({ drivers: 1, jdbc: true, mcp: true, plugins: 1, skippedDrivers: 0, failed: [] });
});
it("keeps the toolbar update action hidden while a persisted restart plan is still installing", async () => {
const jdbcInstall = deferred<{ installed: boolean; update_available: boolean }>();
mocks.installJdbcPlugin.mockReturnValue(jdbcInstall.promise);
const updates = useComponentUpdates({ isDesktop: true });
const pending: PendingComponentUpdates = {
fromVersion: "0.6.18",
targetVersion: "0.6.19",
plan: { kind: "manual", categories: ["jdbc"] },
};
const updateOperation = runPendingComponentUpdatePlan(pending, updates);
await vi.waitFor(() => expect(mocks.installJdbcPlugin).toHaveBeenCalledOnce());
const toolbarOptions = {
appUpdateAvailable: false,
driverUpdateCount: updates.driverUpdateCount.value,
jdbcUpdateAvailable: updates.jdbcUpdateAvailable.value,
mcpUpdateAvailable: updates.mcpUpdateAvailable.value,
pluginUpdateCount: updates.pluginUpdateCount.value,
};
expect(updates.updating.value).toBe(true);
expect(showToolbarUpdateAction({ ...toolbarOptions, componentUpdatesRunning: updates.updating.value })).toBe(false);
jdbcInstall.resolve({ installed: true, update_available: false });
await updateOperation;
expect(updates.updating.value).toBe(false);
expect(showToolbarUpdateAction({ ...toolbarOptions, componentUpdatesRunning: updates.updating.value })).toBe(true);
});
it("skips blocked agent updates while allowing other component updates", async () => {
mocks.checkAgentUpdateBlockers.mockResolvedValue([{ db_type: "mysql", label: "MySQL" }]);
const updates = useComponentUpdates({ isDesktop: true });
+32 -1
View File
@@ -1,5 +1,5 @@
import { describe, expect, it } from "vitest";
import { driverStoreUpdateBadgeCount, showMcpUpdateBadge } from "@/lib/updates/updateBadges";
import { driverStoreUpdateBadgeCount, showMcpUpdateBadge, showToolbarUpdateAction } from "@/lib/updates/updateBadges";
describe("component update entry badges", () => {
it("hides separate driver and JDBC badges while their automatic updates are enabled", () => {
@@ -17,4 +17,35 @@ describe("component update entry badges", () => {
expect(showMcpUpdateBadge(false, true)).toBe(true);
expect(showMcpUpdateBadge(false, false)).toBe(false);
});
it("keeps the toolbar update action hidden while component updates are still running", () => {
expect(
showToolbarUpdateAction({
appUpdateAvailable: false,
driverUpdateCount: 1,
jdbcUpdateAvailable: true,
mcpUpdateAvailable: true,
pluginUpdateCount: 1,
componentUpdatesRunning: true,
}),
).toBe(false);
});
it("shows the toolbar update action for remaining updates after component updating stops", () => {
const base = {
appUpdateAvailable: false,
driverUpdateCount: 0,
jdbcUpdateAvailable: false,
mcpUpdateAvailable: false,
pluginUpdateCount: 0,
componentUpdatesRunning: false,
};
expect(showToolbarUpdateAction(base)).toBe(false);
expect(showToolbarUpdateAction({ ...base, appUpdateAvailable: true })).toBe(true);
expect(showToolbarUpdateAction({ ...base, driverUpdateCount: 1 })).toBe(true);
expect(showToolbarUpdateAction({ ...base, jdbcUpdateAvailable: true })).toBe(true);
expect(showToolbarUpdateAction({ ...base, mcpUpdateAvailable: true })).toBe(true);
expect(showToolbarUpdateAction({ ...base, pluginUpdateCount: 1 })).toBe(true);
});
});
@@ -5,3 +5,9 @@ export function driverStoreUpdateBadgeCount(autoUpdateDrivers: boolean, autoUpda
export function showMcpUpdateBadge(autoUpdateMcp: boolean, mcpUpdateAvailable: boolean): boolean {
return !autoUpdateMcp && mcpUpdateAvailable;
}
export function showToolbarUpdateAction(options: { appUpdateAvailable: boolean; driverUpdateCount: number; jdbcUpdateAvailable: boolean; mcpUpdateAvailable: boolean; pluginUpdateCount: number; componentUpdatesRunning: boolean }): boolean {
// Installation refreshes before replacing components, so discovery can report pending entries mid-operation.
if (options.componentUpdatesRunning) return false;
return options.appUpdateAvailable || options.driverUpdateCount > 0 || options.jdbcUpdateAvailable || options.mcpUpdateAvailable || options.pluginUpdateCount > 0;
}