Files
fusion/packages/dashboard/app/api/settings/settings.ts
gsxdsm ba643fc384 FN-9042: fix dashboard update installation feedback
Make dashboard update actions report clear terminal outcomes and avoid unsupported installs.

- Distinguish update checks, no-op responses, installation failures, and unsupported installation methods.
- Block source-checkout, Homebrew, and missing-npm global installation attempts with actionable guidance.
- Surface update results in dashboard controls and cover API, updater, and UI behavior with tests.

Files changed:
 .changeset/fn-9042-update-now-outcomes.md          |   7 ++
 docs/dashboard-guide.md                            |   2 +-
 docs/settings-reference.md                         |   2 +-
 packages/dashboard/app/api/settings/settings.ts    |   2 +
 .../dashboard/app/components/SettingsModal.tsx     |  18 +--
 .../app/components/UpdateAvailableBanner.tsx       |  11 +-
 .../__tests__/SettingsModal.general.test.tsx       |  20 ++++
 .../__tests__/UpdateAvailableBanner.test.tsx       |  19 ++++
 .../dashboard/src/__tests__/auto-update.test.ts    |  38 ++++++-
 .../dashboard/src/__tests__/update-check.test.ts   |  19 +++-
 packages/dashboard/src/auto-update.ts              |  33 +++++-
 .../__tests__/register-update-check-routes.test.ts | 104 ++++++++++++++++++
 .../src/routes/register-update-check-routes.ts     |  28 +++--
 packages/dashboard/src/server.ts                   |   9 +-
 packages/dashboard/src/update-check.ts             | 122 ++++++++++-----------
 15 files changed, 338 insertions(+), 96 deletions(-)

Fusion-Task-Id: FN-9042

Fusion-Task-Lineage: 22ae5540-e5b5-43cf-ad16-c7aa05782593

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-08-14 12:59:23 -07:00

59 lines
2.2 KiB
TypeScript

/**
* FNXC:CodeOrganization 2026-07-16-14:00:
* Settings/config/update client API peeled from legacy.ts.
*/
import type { Settings } from "@fusion/core";
import { api } from "../client/client.js";
import type { FetchOptions } from "../client/client.js";
import { withProjectId } from "../client/health.js";
import type { UpdateCheckResponse } from "../client/health.js";
import { dedupe } from "../client/dedupe.js";
export function fetchConfig(projectId?: string): Promise<{ maxConcurrent: number; rootDir: string }> {
const path = withProjectId("/config", projectId);
return dedupe(path, () => api<{ maxConcurrent: number; rootDir: string }>(path));
}
export function fetchSettings(projectId?: string, options?: FetchOptions): Promise<Settings> {
const path = withProjectId("/settings", projectId);
return dedupe(path, () => api<Settings>(path), options);
}
export function fetchTaskEffectiveSettings(taskId: string, projectId?: string, options?: FetchOptions): Promise<Settings> {
const path = withProjectId(`/tasks/${taskId}/effective-settings`, projectId);
return dedupe(path, () => api<Settings>(path), options);
}
export function updateSettings(settings: Partial<Settings>, projectId?: string): Promise<Settings> {
return api<Settings>(withProjectId("/settings", projectId), {
method: "PUT",
body: JSON.stringify(settings),
});
}
export function checkForUpdate(projectId?: string): Promise<UpdateCheckResponse> {
return api<UpdateCheckResponse>(withProjectId("/update-check", projectId));
}
export function refreshUpdateCheck(projectId?: string): Promise<UpdateCheckResponse> {
return api<UpdateCheckResponse>(withProjectId("/update-check/refresh", projectId), {
method: "POST",
});
}
export interface UpdateInstallResponse {
currentVersion: string;
latestVersion: string | null;
updated: boolean;
outcome?: "installed" | "no-update-available" | "check-failed" | "unsupported-install-method" | "failed";
message?: string;
error?: string;
}
export function installUpdate(projectId?: string): Promise<UpdateInstallResponse> {
return api<UpdateInstallResponse>(withProjectId("/update-check/install", projectId), {
method: "POST",
});
}