import { defaultInstanceIdForDriver, PROVIDER_DISPLAY_NAMES, type EnvironmentId, type ExecutionEnvironmentPlatformOs, type ProviderDriverKind, type ProviderInstanceId, type ServerProvider,} from "@t3tools/contracts";import { squashAtomCommandFailure, type AtomCommandResult,} from "@t3tools/client-runtime/state/runtime"; export type ProviderUpdateCandidate = ServerProvider & { readonly versionAdvisory: NonNullable<ServerProvider["versionAdvisory"]> & { readonly status: "behind_latest"; readonly latestVersion: string; };}; export type ProviderSettingsUpdateCandidate = ServerProvider & { readonly versionAdvisory: NonNullable<ServerProvider["versionAdvisory"]> & { readonly canUpdate: true; readonly updateCommand: string; };}; export type ProviderUpdateToastType = "warning" | "loading" | "error" | "success";export type ProviderUpdateToastPhase = "initial" | "running" | "failed" | "unchanged" | "succeeded"; export interface ProviderUpdateToastView { readonly phase: ProviderUpdateToastPhase; readonly type: ProviderUpdateToastType; readonly title: string; readonly description: string; readonly dismissAfterVisibleMs?: number;} /** * Terminal update phases — outcomes that are safe to persist as a one-shot row * result. A non-terminal ("initial"/"running") snapshot never re-polls itself, * so storing one pins an update row's spinner indefinitely once its pending flag * expires; such phases must be dropped in favor of the live per-environment * provider state instead of being persisted. */export function isTerminalProviderUpdatePhase(phase: ProviderUpdateToastPhase): boolean { return phase === "succeeded" || phase === "failed" || phase === "unchanged";} export type ProviderUpdateSidebarPillTone = "loading" | "warning" | "error" | "success"; export interface ProviderUpdateSidebarPillView { readonly key: string; readonly tone: ProviderUpdateSidebarPillTone; readonly title: string; readonly description: string; readonly dismissible?: boolean; readonly dismissAfterVisibleMs?: number;} interface ProviderUpdateSidebarPillOptions { readonly visibleAfterIso?: string; readonly dismissedKeys?: ReadonlySet<string>;} const PROVIDER_UPDATE_SUCCESS_VISIBLE_MS = 3_000; function formatVersion(value: string): string { return value.startsWith("v") ? value : `v${value}`;} function chooseRepresentativeProvider( current: ServerProvider | undefined, candidate: ServerProvider,): ServerProvider { if (!current) { return candidate; } const defaultInstanceId = defaultInstanceIdForDriver(candidate.driver); if (candidate.instanceId === defaultInstanceId) { return candidate; } if (current.instanceId === defaultInstanceId) { return current; } return candidate.checkedAt.localeCompare(current.checkedAt) >= 0 ? candidate : current;} function dedupeProvidersByDriver<T extends ServerProvider>(providers: ReadonlyArray<T>): T[] { const latestProviderByDriver = new Map<ProviderDriverKind, T>(); for (const provider of providers) { latestProviderByDriver.set( provider.driver, chooseRepresentativeProvider(latestProviderByDriver.get(provider.driver), provider) as T, ); } return [...latestProviderByDriver.values()];} function dedupeProvidersByInstanceId<T extends ServerProvider>(providers: ReadonlyArray<T>): T[] { const latestProviderByInstanceId = new Map<ProviderInstanceId, T>(); for (const provider of providers) { const current = latestProviderByInstanceId.get(provider.instanceId); if (!current || provider.checkedAt.localeCompare(current.checkedAt) >= 0) { latestProviderByInstanceId.set(provider.instanceId, provider); } } return [...latestProviderByInstanceId.values()];} function getProviderUpdatedTitle(provider: Pick<ServerProvider, "driver" | "version">): string { const providerName = PROVIDER_DISPLAY_NAMES[provider.driver] ?? provider.driver; return provider.version ? `${providerName} updated: ${formatVersion(provider.version)}` : `${providerName} updated`;} function getProviderUpdatedDescription(providerCount: number): string { return providerCount === 1 ? "New sessions will use the updated provider." : "New sessions will use the updated providers.";} function getProviderFailedUpdateTitle( provider: Pick<ServerProvider, "driver" | "versionAdvisory">,): string { const providerName = PROVIDER_DISPLAY_NAMES[provider.driver] ?? provider.driver; const attemptedVersion = provider.versionAdvisory?.latestVersion; return attemptedVersion ? `${providerName} ${formatVersion(attemptedVersion)} update failed` : `${providerName} update failed`;} export function isProviderUpdateCandidate( provider: ServerProvider,): provider is ProviderUpdateCandidate { return ( provider.enabled && provider.versionAdvisory?.status === "behind_latest" && provider.versionAdvisory.latestVersion !== null );} export function isProviderUpdateActive(provider: Pick<ServerProvider, "updateState">): boolean { return provider.updateState?.status === "queued" || provider.updateState?.status === "running";} export function collectProviderUpdateCandidates( providers: ReadonlyArray<ServerProvider>,): ProviderUpdateCandidate[] { return dedupeProvidersByDriver(providers.filter(isProviderUpdateCandidate));} export function isProviderSettingsUpdateCandidate( provider: ServerProvider,): provider is ProviderSettingsUpdateCandidate { return ( provider.enabled && provider.versionAdvisory?.status === "behind_latest" && provider.versionAdvisory.canUpdate === true && provider.versionAdvisory.updateCommand !== null );} export function hasOneClickUpdateProviderCandidate( candidate: ProviderUpdateCandidate, providers: ReadonlyArray<ServerProvider>,): boolean { if ( candidate.versionAdvisory.canUpdate !== true || candidate.versionAdvisory.updateCommand === null ) { return false; } const driverProviders = providers.filter((provider) => provider.driver === candidate.driver); if (driverProviders.length === 0) { return false; } const updateCommands = new Set<string>(); for (const provider of driverProviders) { if (!isProviderUpdateCandidate(provider)) { continue; } const advisory = provider.versionAdvisory; if (!advisory || advisory.canUpdate !== true || advisory.updateCommand === null) { return false; } updateCommands.add(advisory.updateCommand); } return updateCommands.size === 1;} export function canOneClickUpdateProviderCandidate( candidate: ProviderUpdateCandidate, providers: ReadonlyArray<ServerProvider>,): boolean { return ( !isProviderUpdateActive(candidate) && hasOneClickUpdateProviderCandidate(candidate, providers) );} export function providerUpdateNotificationKey( providers: ReadonlyArray<ProviderUpdateCandidate>,): string | null { const parts = dedupeProvidersByDriver(providers) .map((provider) => { const advisory = provider.versionAdvisory; return [provider.driver, advisory.latestVersion].join(":"); }) .toSorted(); return parts.length > 0 ? parts.join("|") : null;} function formatProviderList(providers: ReadonlyArray<Pick<ServerProvider, "driver">>) { const names = providers.map( (provider) => PROVIDER_DISPLAY_NAMES[provider.driver] ?? provider.driver, ); if (names.length <= 2) { return names.join(" and "); } return `${names.slice(0, -1).join(", ")}, and ${names[names.length - 1]}`;} export function getProviderUpdateInitialToastView(input: { readonly updateProviders: ReadonlyArray<ProviderUpdateCandidate>; readonly oneClickProviders: ReadonlyArray<ProviderUpdateCandidate>;}): ProviderUpdateToastView { return { phase: "initial", type: "warning", title: getProviderUpdateInitialToastTitle(input.updateProviders), description: input.oneClickProviders.length > 0 ? "Install the update now or review provider settings." : `${formatProviderList(input.updateProviders)} can be updated from provider settings.`, };} export function shouldShowPrimaryProviderUpdateToast(view: ProviderUpdateToastView): boolean { return view.phase !== "running";} function getProviderUpdateRunningToastView(providerCount: number): ProviderUpdateToastView { return { phase: "running", type: "loading", title: providerCount === 1 ? "Updating provider" : "Updating providers", description: "Running provider update command.", };} export function getProviderUpdateRejectedToastView( providerCount: number, message: string,): ProviderUpdateToastView { return { phase: "failed", type: "error", title: providerCount === 1 ? "Provider update failed" : "Provider updates failed", description: message, };} export function getProviderUpdateProgressToastView(input: { readonly providers: ReadonlyArray<ServerProvider>; readonly providerCount: number;}): ProviderUpdateToastView { const providers = dedupeProvidersByDriver(input.providers); const failedProviders = providers.filter((provider) => provider.updateState?.status === "failed"); if (failedProviders.length > 0) { return { phase: "failed", type: "error", title: failedProviders.length === 1 ? "Provider update failed" : "Provider updates failed", description: getFailedProviderUpdateDescription(failedProviders), }; } const unchangedProviders = providers.filter( (provider) => provider.updateState?.status === "unchanged", ); if (unchangedProviders.length > 0) { return { phase: "unchanged", type: "warning", title: unchangedProviders.length === 1 ? "Provider still needs an update" : "Providers still need updates", description: `${formatProviderList(unchangedProviders)} ${ unchangedProviders.length === 1 ? "still appears" : "still appear" } outdated. Check provider settings for details.`, }; } if (providers.some(isProviderUpdateActive)) { return getProviderUpdateRunningToastView(input.providerCount); } const hasCompleteProviderSnapshots = providers.length >= input.providerCount; const allProvidersUpdated = hasCompleteProviderSnapshots && providers.every( (provider) => provider.updateState?.status === "succeeded" || !isProviderUpdateCandidate(provider), ); if (allProvidersUpdated) { return { phase: "succeeded", type: "success", title: input.providerCount === 1 ? "Provider updated" : "Provider updates finished", description: getProviderUpdatedDescription(input.providerCount), dismissAfterVisibleMs: PROVIDER_UPDATE_SUCCESS_VISIBLE_MS, }; } return getProviderUpdateRunningToastView(input.providerCount);} export function collectUpdatedProviderSnapshots(input: { readonly results: ReadonlyArray< AtomCommandResult<{ readonly providers: ReadonlyArray<ServerProvider> }, unknown> >; readonly providerInstanceIds: ReadonlySet<ProviderInstanceId>;}): ServerProvider[] { const matchedProviders: ServerProvider[] = []; for (const result of input.results) { if (result._tag === "Failure") { continue; } for (const provider of result.value.providers) { if (input.providerInstanceIds.has(provider.instanceId)) { matchedProviders.push(provider); } } } return dedupeProvidersByInstanceId(matchedProviders);} export function firstFailedProviderUpdateMessage( results: ReadonlyArray<AtomCommandResult<unknown, unknown>>,): string | null { const failed = results.find((result) => result._tag === "Failure"); if (!failed || failed._tag !== "Failure") { return null; } const error = squashAtomCommandFailure(failed); return error instanceof Error ? error.message : "Provider update failed.";} function getUpdateFinishedAt(provider: ServerProvider): string | null { return provider.updateState?.finishedAt ?? null;} function isRecentTerminalProvider( provider: ServerProvider, visibleAfterIso: string | undefined,): boolean { const status = provider.updateState?.status; if (status !== "failed" && status !== "unchanged" && status !== "succeeded") { return false; } if (visibleAfterIso === undefined) { return true; } const finishedAt = getUpdateFinishedAt(provider); return finishedAt !== null && finishedAt >= visibleAfterIso;} function latestFinishedAtForProviders(providers: ReadonlyArray<ServerProvider>): string | null { return providers.reduce<string | null>((latest, provider) => { const finishedAt = getUpdateFinishedAt(provider); if (finishedAt === null) { return latest; } return latest === null || finishedAt > latest ? finishedAt : latest; }, null);} export function getProviderUpdateSidebarPillView( providers: ReadonlyArray<ServerProvider>, options?: ProviderUpdateSidebarPillOptions,): ProviderUpdateSidebarPillView | null { const dedupedProviders = dedupeProvidersByDriver(providers); const activeProviders = dedupedProviders.filter(isProviderUpdateActive); if (activeProviders.length > 0) { const activeProvider = activeProviders[0]!; const activeProviderName = PROVIDER_DISPLAY_NAMES[activeProvider.driver] ?? activeProvider.driver; return { key: `loading:${activeProviders .map((provider) => `${provider.driver}:${provider.updateState?.status ?? "idle"}`) .toSorted() .join("|")}`, tone: "loading", title: activeProviders.length === 1 ? `Updating ${activeProviderName}` : `Updating ${activeProviders.length} providers`, description: activeProviders.length === 1 ? `${formatProviderList(activeProviders)} update in progress.` : `${formatProviderList(activeProviders)} updates are in progress.`, }; } const recentTerminalProviders = dedupedProviders.filter((provider) => isRecentTerminalProvider(provider, options?.visibleAfterIso), ); const terminalCandidates: ProviderUpdateSidebarPillView[] = []; const failedProviders = recentTerminalProviders.filter( (provider) => provider.updateState?.status === "failed", ); if (failedProviders.length > 0) { const failedProvider = failedProviders[0]!; terminalCandidates.push({ key: `failed:${failedProviders .map( (provider) => `${provider.driver}:${provider.updateState?.finishedAt ?? "pending"}:${provider.updateState?.message ?? ""}`, ) .toSorted() .join("|")}`, tone: "error", title: failedProviders.length === 1 ? getProviderFailedUpdateTitle(failedProvider) : `${failedProviders.length} provider updates failed`, description: getFailedProviderUpdateDescription(failedProviders), dismissible: true, }); } const unchangedProviders = recentTerminalProviders.filter( (provider) => provider.updateState?.status === "unchanged", ); if (unchangedProviders.length > 0) { const unchangedProvider = unchangedProviders[0]!; const unchangedProviderName = PROVIDER_DISPLAY_NAMES[unchangedProvider.driver] ?? unchangedProvider.driver; terminalCandidates.push({ key: `unchanged:${unchangedProviders .map( (provider) => `${provider.driver}:${provider.updateState?.finishedAt ?? "pending"}:${provider.updateState?.message ?? ""}`, ) .toSorted() .join("|")}`, tone: "warning", title: unchangedProviders.length === 1 ? `${unchangedProviderName} still needs an update` : `${unchangedProviders.length} providers still need updates`, description: `${formatProviderList(unchangedProviders)} ${ unchangedProviders.length === 1 ? "still appears" : "still appear" } outdated. Review provider settings for details.`, dismissible: true, }); } const succeededProviders = recentTerminalProviders.filter( (provider) => provider.updateState?.status === "succeeded", ); if (succeededProviders.length > 0) { const succeededProvider = succeededProviders[0]!; terminalCandidates.push({ key: `succeeded:${succeededProviders .map( (provider) => `${provider.driver}:${provider.updateState?.finishedAt ?? "pending"}:${provider.updateState?.message ?? ""}`, ) .toSorted() .join("|")}`, tone: "success", title: succeededProviders.length === 1 ? getProviderUpdatedTitle(succeededProvider) : `${succeededProviders.length} providers updated`, description: getProviderUpdatedDescription(succeededProviders.length), dismissAfterVisibleMs: PROVIDER_UPDATE_SUCCESS_VISIBLE_MS, }); } return ( terminalCandidates .toSorted((left, right) => { const leftProviders = left.tone === "error"Lines 1–500 of 782. Load more
import { defaultInstanceIdForDriver, PROVIDER_DISPLAY_NAMES, type EnvironmentId, type ExecutionEnvironmentPlatformOs, type ProviderDriverKind, type ProviderInstanceId, type ServerProvider, } from "@t3tools/contracts"; import { squashAtomCommandFailure, type AtomCommandResult, } from "@t3tools/client-runtime/state/runtime"; export type ProviderUpdateCandidate = ServerProvider & { readonly versionAdvisory: NonNullable<ServerProvider["versionAdvisory"]> & { readonly status: "behind_latest"; readonly latestVersion: string; }; }; export type ProviderSettingsUpdateCandidate = ServerProvider & { readonly versionAdvisory: NonNullable<ServerProvider["versionAdvisory"]> & { readonly canUpdate: true; readonly updateCommand: string; }; }; export type ProviderUpdateToastType = "warning" | "loading" | "error" | "success"; export type ProviderUpdateToastPhase = "initial" | "running" | "failed" | "unchanged" | "succeeded"; export interface ProviderUpdateToastView { readonly phase: ProviderUpdateToastPhase; readonly type: ProviderUpdateToastType; readonly title: string; readonly description: string; readonly dismissAfterVisibleMs?: number; } /** * Terminal update phases — outcomes that are safe to persist as a one-shot row * result. A non-terminal ("initial"/"running") snapshot never re-polls itself, * so storing one pins an update row's spinner indefinitely once its pending flag * expires; such phases must be dropped in favor of the live per-environment * provider state instead of being persisted. */ export function isTerminalProviderUpdatePhase(phase: ProviderUpdateToastPhase): boolean { return phase === "succeeded" || phase === "failed" || phase === "unchanged"; } export type ProviderUpdateSidebarPillTone = "loading" | "warning" | "error" | "success"; export interface ProviderUpdateSidebarPillView { readonly key: string; readonly tone: ProviderUpdateSidebarPillTone; readonly title: string; readonly description: string; readonly dismissible?: boolean; readonly dismissAfterVisibleMs?: number; } interface ProviderUpdateSidebarPillOptions { readonly visibleAfterIso?: string; readonly dismissedKeys?: ReadonlySet<string>; } const PROVIDER_UPDATE_SUCCESS_VISIBLE_MS = 3_000; function formatVersion(value: string): string { return value.startsWith("v") ? value : `v${value}`; } function chooseRepresentativeProvider( current: ServerProvider | undefined, candidate: ServerProvider, ): ServerProvider { if (!current) { return candidate; } const defaultInstanceId = defaultInstanceIdForDriver(candidate.driver); if (candidate.instanceId === defaultInstanceId) { return candidate; } if (current.instanceId === defaultInstanceId) { return current; } return candidate.checkedAt.localeCompare(current.checkedAt) >= 0 ? candidate : current; } function dedupeProvidersByDriver<T extends ServerProvider>(providers: ReadonlyArray<T>): T[] { const latestProviderByDriver = new Map<ProviderDriverKind, T>(); for (const provider of providers) { latestProviderByDriver.set( provider.driver, chooseRepresentativeProvider(latestProviderByDriver.get(provider.driver), provider) as T, ); } return [...latestProviderByDriver.values()]; } function dedupeProvidersByInstanceId<T extends ServerProvider>(providers: ReadonlyArray<T>): T[] { const latestProviderByInstanceId = new Map<ProviderInstanceId, T>(); for (const provider of providers) { const current = latestProviderByInstanceId.get(provider.instanceId); if (!current || provider.checkedAt.localeCompare(current.checkedAt) >= 0) { latestProviderByInstanceId.set(provider.instanceId, provider); } } return [...latestProviderByInstanceId.values()]; } function getProviderUpdatedTitle(provider: Pick<ServerProvider, "driver" | "version">): string { const providerName = PROVIDER_DISPLAY_NAMES[provider.driver] ?? provider.driver; return provider.version ? `${providerName} updated: ${formatVersion(provider.version)}` : `${providerName} updated`; } function getProviderUpdatedDescription(providerCount: number): string { return providerCount === 1 ? "New sessions will use the updated provider." : "New sessions will use the updated providers."; } function getProviderFailedUpdateTitle( provider: Pick<ServerProvider, "driver" | "versionAdvisory">, ): string { const providerName = PROVIDER_DISPLAY_NAMES[provider.driver] ?? provider.driver; const attemptedVersion = provider.versionAdvisory?.latestVersion; return attemptedVersion ? `${providerName} ${formatVersion(attemptedVersion)} update failed` : `${providerName} update failed`; } export function isProviderUpdateCandidate( provider: ServerProvider, ): provider is ProviderUpdateCandidate { return ( provider.enabled && provider.versionAdvisory?.status === "behind_latest" && provider.versionAdvisory.latestVersion !== null ); } export function isProviderUpdateActive(provider: Pick<ServerProvider, "updateState">): boolean { return provider.updateState?.status === "queued" || provider.updateState?.status === "running"; } export function collectProviderUpdateCandidates( providers: ReadonlyArray<ServerProvider>, ): ProviderUpdateCandidate[] { return dedupeProvidersByDriver(providers.filter(isProviderUpdateCandidate)); } export function isProviderSettingsUpdateCandidate( provider: ServerProvider, ): provider is ProviderSettingsUpdateCandidate { return ( provider.enabled && provider.versionAdvisory?.status === "behind_latest" && provider.versionAdvisory.canUpdate === true && provider.versionAdvisory.updateCommand !== null ); } export function hasOneClickUpdateProviderCandidate( candidate: ProviderUpdateCandidate, providers: ReadonlyArray<ServerProvider>, ): boolean { if ( candidate.versionAdvisory.canUpdate !== true || candidate.versionAdvisory.updateCommand === null ) { return false; } const driverProviders = providers.filter((provider) => provider.driver === candidate.driver); if (driverProviders.length === 0) { return false; } const updateCommands = new Set<string>(); for (const provider of driverProviders) { if (!isProviderUpdateCandidate(provider)) { continue; } const advisory = provider.versionAdvisory; if (!advisory || advisory.canUpdate !== true || advisory.updateCommand === null) { return false; } updateCommands.add(advisory.updateCommand); } return updateCommands.size === 1; } export function canOneClickUpdateProviderCandidate( candidate: ProviderUpdateCandidate, providers: ReadonlyArray<ServerProvider>, ): boolean { return ( !isProviderUpdateActive(candidate) && hasOneClickUpdateProviderCandidate(candidate, providers) ); } export function providerUpdateNotificationKey( providers: ReadonlyArray<ProviderUpdateCandidate>, ): string | null { const parts = dedupeProvidersByDriver(providers) .map((provider) => { const advisory = provider.versionAdvisory; return [provider.driver, advisory.latestVersion].join(":"); }) .toSorted(); return parts.length > 0 ? parts.join("|") : null; } function formatProviderList(providers: ReadonlyArray<Pick<ServerProvider, "driver">>) { const names = providers.map( (provider) => PROVIDER_DISPLAY_NAMES[provider.driver] ?? provider.driver, ); if (names.length <= 2) { return names.join(" and "); } return `${names.slice(0, -1).join(", ")}, and ${names[names.length - 1]}`; } export function getProviderUpdateInitialToastView(input: { readonly updateProviders: ReadonlyArray<ProviderUpdateCandidate>; readonly oneClickProviders: ReadonlyArray<ProviderUpdateCandidate>; }): ProviderUpdateToastView { return { phase: "initial", type: "warning", title: getProviderUpdateInitialToastTitle(input.updateProviders), description: input.oneClickProviders.length > 0 ? "Install the update now or review provider settings." : `${formatProviderList(input.updateProviders)} can be updated from provider settings.`, }; } export function shouldShowPrimaryProviderUpdateToast(view: ProviderUpdateToastView): boolean { return view.phase !== "running"; } function getProviderUpdateRunningToastView(providerCount: number): ProviderUpdateToastView { return { phase: "running", type: "loading", title: providerCount === 1 ? "Updating provider" : "Updating providers", description: "Running provider update command.", }; } export function getProviderUpdateRejectedToastView( providerCount: number, message: string, ): ProviderUpdateToastView { return { phase: "failed", type: "error", title: providerCount === 1 ? "Provider update failed" : "Provider updates failed", description: message, }; } export function getProviderUpdateProgressToastView(input: { readonly providers: ReadonlyArray<ServerProvider>; readonly providerCount: number; }): ProviderUpdateToastView { const providers = dedupeProvidersByDriver(input.providers); const failedProviders = providers.filter((provider) => provider.updateState?.status === "failed"); if (failedProviders.length > 0) { return { phase: "failed", type: "error", title: failedProviders.length === 1 ? "Provider update failed" : "Provider updates failed", description: getFailedProviderUpdateDescription(failedProviders), }; } const unchangedProviders = providers.filter( (provider) => provider.updateState?.status === "unchanged", ); if (unchangedProviders.length > 0) { return { phase: "unchanged", type: "warning", title: unchangedProviders.length === 1 ? "Provider still needs an update" : "Providers still need updates", description: `${formatProviderList(unchangedProviders)} ${ unchangedProviders.length === 1 ? "still appears" : "still appear" } outdated. Check provider settings for details.`, }; } if (providers.some(isProviderUpdateActive)) { return getProviderUpdateRunningToastView(input.providerCount); } const hasCompleteProviderSnapshots = providers.length >= input.providerCount; const allProvidersUpdated = hasCompleteProviderSnapshots && providers.every( (provider) => provider.updateState?.status === "succeeded" || !isProviderUpdateCandidate(provider), ); if (allProvidersUpdated) { return { phase: "succeeded", type: "success", title: input.providerCount === 1 ? "Provider updated" : "Provider updates finished", description: getProviderUpdatedDescription(input.providerCount), dismissAfterVisibleMs: PROVIDER_UPDATE_SUCCESS_VISIBLE_MS, }; } return getProviderUpdateRunningToastView(input.providerCount); } export function collectUpdatedProviderSnapshots(input: { readonly results: ReadonlyArray< AtomCommandResult<{ readonly providers: ReadonlyArray<ServerProvider> }, unknown> >; readonly providerInstanceIds: ReadonlySet<ProviderInstanceId>; }): ServerProvider[] { const matchedProviders: ServerProvider[] = []; for (const result of input.results) { if (result._tag === "Failure") { continue; } for (const provider of result.value.providers) { if (input.providerInstanceIds.has(provider.instanceId)) { matchedProviders.push(provider); } } } return dedupeProvidersByInstanceId(matchedProviders); } export function firstFailedProviderUpdateMessage( results: ReadonlyArray<AtomCommandResult<unknown, unknown>>, ): string | null { const failed = results.find((result) => result._tag === "Failure"); if (!failed || failed._tag !== "Failure") { return null; } const error = squashAtomCommandFailure(failed); return error instanceof Error ? error.message : "Provider update failed."; } function getUpdateFinishedAt(provider: ServerProvider): string | null { return provider.updateState?.finishedAt ?? null; } function isRecentTerminalProvider( provider: ServerProvider, visibleAfterIso: string | undefined, ): boolean { const status = provider.updateState?.status; if (status !== "failed" && status !== "unchanged" && status !== "succeeded") { return false; } if (visibleAfterIso === undefined) { return true; } const finishedAt = getUpdateFinishedAt(provider); return finishedAt !== null && finishedAt >= visibleAfterIso; } function latestFinishedAtForProviders(providers: ReadonlyArray<ServerProvider>): string | null { return providers.reduce<string | null>((latest, provider) => { const finishedAt = getUpdateFinishedAt(provider); if (finishedAt === null) { return latest; } return latest === null || finishedAt > latest ? finishedAt : latest; }, null); } export function getProviderUpdateSidebarPillView( providers: ReadonlyArray<ServerProvider>, options?: ProviderUpdateSidebarPillOptions, ): ProviderUpdateSidebarPillView | null { const dedupedProviders = dedupeProvidersByDriver(providers); const activeProviders = dedupedProviders.filter(isProviderUpdateActive); if (activeProviders.length > 0) { const activeProvider = activeProviders[0]!; const activeProviderName = PROVIDER_DISPLAY_NAMES[activeProvider.driver] ?? activeProvider.driver; return { key: `loading:${activeProviders .map((provider) => `${provider.driver}:${provider.updateState?.status ?? "idle"}`) .toSorted() .join("|")}`, tone: "loading", title: activeProviders.length === 1 ? `Updating ${activeProviderName}` : `Updating ${activeProviders.length} providers`, description: activeProviders.length === 1 ? `${formatProviderList(activeProviders)} update in progress.` : `${formatProviderList(activeProviders)} updates are in progress.`, }; } const recentTerminalProviders = dedupedProviders.filter((provider) => isRecentTerminalProvider(provider, options?.visibleAfterIso), ); const terminalCandidates: ProviderUpdateSidebarPillView[] = []; const failedProviders = recentTerminalProviders.filter( (provider) => provider.updateState?.status === "failed", ); if (failedProviders.length > 0) { const failedProvider = failedProviders[0]!; terminalCandidates.push({ key: `failed:${failedProviders .map( (provider) => `${provider.driver}:${provider.updateState?.finishedAt ?? "pending"}:${provider.updateState?.message ?? ""}`, ) .toSorted() .join("|")}`, tone: "error", title: failedProviders.length === 1 ? getProviderFailedUpdateTitle(failedProvider) : `${failedProviders.length} provider updates failed`, description: getFailedProviderUpdateDescription(failedProviders), dismissible: true, }); } const unchangedProviders = recentTerminalProviders.filter( (provider) => provider.updateState?.status === "unchanged", ); if (unchangedProviders.length > 0) { const unchangedProvider = unchangedProviders[0]!; const unchangedProviderName = PROVIDER_DISPLAY_NAMES[unchangedProvider.driver] ?? unchangedProvider.driver; terminalCandidates.push({ key: `unchanged:${unchangedProviders .map( (provider) => `${provider.driver}:${provider.updateState?.finishedAt ?? "pending"}:${provider.updateState?.message ?? ""}`, ) .toSorted() .join("|")}`, tone: "warning", title: unchangedProviders.length === 1 ? `${unchangedProviderName} still needs an update` : `${unchangedProviders.length} providers still need updates`, description: `${formatProviderList(unchangedProviders)} ${ unchangedProviders.length === 1 ? "still appears" : "still appear" } outdated. Review provider settings for details.`, dismissible: true, }); } const succeededProviders = recentTerminalProviders.filter( (provider) => provider.updateState?.status === "succeeded", ); if (succeededProviders.length > 0) { const succeededProvider = succeededProviders[0]!; terminalCandidates.push({ key: `succeeded:${succeededProviders .map( (provider) => `${provider.driver}:${provider.updateState?.finishedAt ?? "pending"}:${provider.updateState?.message ?? ""}`, ) .toSorted() .join("|")}`, tone: "success", title: succeededProviders.length === 1 ? getProviderUpdatedTitle(succeededProvider) : `${succeededProviders.length} providers updated`, description: getProviderUpdatedDescription(succeededProviders.length), dismissAfterVisibleMs: PROVIDER_UPDATE_SUCCESS_VISIBLE_MS, }); } return ( terminalCandidates .toSorted((left, right) => { const leftProviders = left.tone === "error"