feat: show Ubuntu phased updates apart and leave them out of pending counts
Chart Release / chart (push) Successful in 29s
Server Deploy / deploy (push) Successful in 5m9s

apt lists phased updates as upgradable while an upgrade defers them until
Ubuntu selects the host, so a freshly patched server kept reporting pending
updates. The agent now flags them; the server stores the flag and leaves them
out of patch run counts, and the server page shows them in their own section.
This commit is contained in:
2026-09-15 14:55:30 +00:00
parent 0e464c4bb8
commit fbcf436ef6
13 changed files with 87 additions and 15 deletions
+2 -2
View File
@@ -4,7 +4,7 @@ import { useMemo, useRef, useState } from "react";
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
import { useParams, useRouter, useSearchParams } from "next/navigation";
import Link from "next/link";
import { api, GenerateKeyOptions, ServerStatus, vulnerabilities, workloads as workloadsApi } from "@/lib/api";
import { api, GenerateKeyOptions, installableUpdates, ServerStatus, vulnerabilities, workloads as workloadsApi } from "@/lib/api";
import { Badge, friendlyMessage, useToast } from "@/components/ui";
import { useLicense } from "@/lib/useLicense";
import { TagChips } from "@/components/servers/TagChips";
@@ -163,7 +163,7 @@ export default function ServerDetailPage() {
const openFindings = useMemo(() => (findings ?? []).filter((f) => f.state === "open"), [findings]);
const seriousFindings = openFindings.filter((f) => f.severity === "critical" || f.severity === "high").length;
const updateCount = server?.available_updates?.length ?? 0;
const updateCount = installableUpdates(server?.available_updates).length;
const workloadCount = workloadSnapshot?.workloads?.length ?? 0;
const activeKeys = (server?.keys ?? []).filter((a) => a.key && !a.revoked_at).length;
const agentOutOfDate = !!latestVersion && !!server?.agent_version && server.agent_version !== latestVersion.version;
+3 -2
View File
@@ -3,7 +3,7 @@
import { Suspense, useMemo, useState } from "react";
import { useQuery } from "@tanstack/react-query";
import { useRouter, useSearchParams } from "next/navigation";
import { api, Server } from "@/lib/api";
import { api, installableUpdates, Server } from "@/lib/api";
import { AsyncBoundary, Button, Card, CenteredSpinner, EmptyState, TableSkeleton } from "@/components/ui";
import { Table, Thead, Tbody, Tr, Th, Td } from "@/components/ui";
import { TagChips } from "@/components/servers/TagChips";
@@ -32,7 +32,8 @@ const STATUS_ORDER: Record<DotStatus, number> = {
function resolveStatus(server: Server, latestVersion: string | undefined): DotStatus {
if (server.status === "offline" || server.status === "pending") return "offline";
if (latestVersion && server.agent_version && server.agent_version !== latestVersion) return "needs-update";
if (server.available_updates && server.available_updates.length > 0) return "has-package-updates";
// Phased updates are deferred by apt, so they do not make a server need patching.
if (installableUpdates(server.available_updates).length > 0) return "has-package-updates";
return "ok";
}