feat(apt): analyse des dépôts APT (lecture seule) (tâche 4)
- template repositories (deb lines + deb822), non destructif - analyzeRepositories (TDD) : composants, repos, détection Proxmox enterprise/no-subscription, warnings (pve_enterprise_without_subscription, pve_repo_missing) + notes Debian/Ubuntu composants manquants - route POST /machines/:id/apt-repositories ; api analyzeRepositories - popup config : bloc « Dépôts APT » (composants + warnings + notes) Analyse uniquement (modification = action validée séparée, future). tsc 0 · 113 tests · build OK. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
// client/src/features/machines/MachineTile.tsx
|
||||
import { useEffect, useState } from "react";
|
||||
import type { ActionType, AptProxyMode, MachineMetricsSimple, MachineStatus, MachineView } from "@shared/types.js";
|
||||
import type { ActionType, AptProxyMode, AptRepositoriesAnalysis, MachineMetricsSimple, MachineStatus, MachineView } from "@shared/types.js";
|
||||
import { Button, Icon, IconButton, Popup, StatusLed } from "../../components/ui-kit.js";
|
||||
import {
|
||||
api,
|
||||
@@ -218,6 +218,12 @@ function MachineConfigPopup({
|
||||
const [msg, setMsg] = useState<{ kind: "ok" | "err"; text: string } | null>(null);
|
||||
const [proxyMode, setProxyMode] = useState<AptProxyMode>(machine.aptProxyMode);
|
||||
const [proxyUrl, setProxyUrl] = useState(machine.aptProxyUrl ?? "");
|
||||
const [repos, setRepos] = useState<AptRepositoriesAnalysis | null>(null);
|
||||
|
||||
const analyzeRepos = () =>
|
||||
withBusy("repos", async () => {
|
||||
setRepos(await api.analyzeRepositories(machine.id));
|
||||
});
|
||||
|
||||
async function withBusy(key: string, fn: () => Promise<void>) {
|
||||
setBusy(key);
|
||||
@@ -355,6 +361,27 @@ function MachineConfigPopup({
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="cfg-block">
|
||||
<div className="cfg-block-head">
|
||||
<span className="label">Dépôts APT (analyse)</span>
|
||||
<Button icon="logs" size="sm" onClick={busy ? undefined : analyzeRepos}>
|
||||
{busy === "repos" ? "Analyse…" : "Analyser"}
|
||||
</Button>
|
||||
</div>
|
||||
{repos && (
|
||||
<div className="cfg-probe">
|
||||
<div className="mono cfg-facts">composants : {repos.components.join(", ") || "—"}</div>
|
||||
{repos.proxmox && (
|
||||
<div className="mono cfg-facts">
|
||||
pve enterprise={String(repos.proxmox.enterprise)} · no-subscription={String(repos.proxmox.noSubscription)}
|
||||
</div>
|
||||
)}
|
||||
{repos.warnings.map((w, i) => <span key={i} className="docker-msg docker-msg-err">{w.message}</span>)}
|
||||
{repos.notes.map((n, i) => <span key={i} className="cfg-nochange">{n}</span>)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{msg && <p className={`docker-msg ${msg.kind === "err" ? "docker-msg-err" : "docker-msg-ok"}`}>{msg.text}</p>}
|
||||
</div>
|
||||
</Popup>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// client/src/lib/api.ts
|
||||
import type { ActionType, AptProxyMode, MachineKind, MachineMetricsSimple, MachineView, OsFamily, SystemMetrics, UpdateSnapshot } from "@shared/types.js";
|
||||
import type { ActionType, AptProxyMode, AptRepositoriesAnalysis, MachineKind, MachineMetricsSimple, MachineView, OsFamily, SystemMetrics, UpdateSnapshot } from "@shared/types.js";
|
||||
|
||||
async function readJsonBody(res: Response): Promise<unknown> {
|
||||
const text = await res.text();
|
||||
@@ -62,6 +62,7 @@ export const api = {
|
||||
machineHardware: (id: string) => req<MachineHardwareView>(`/machines/${id}/hardware`),
|
||||
latestMetrics: (id: string) => req<MachineMetricsSimple | null>(`/machines/${id}/metrics`),
|
||||
collectMetrics: (id: string) => req<MachineMetricsSimple>(`/machines/${id}/metrics/collect`, { method: "POST" }),
|
||||
analyzeRepositories: (id: string) => req<AptRepositoriesAnalysis>(`/machines/${id}/apt-repositories`, { method: "POST" }),
|
||||
|
||||
// --- Docker ---
|
||||
dockerSettings: (id: string) => req<DockerSettingsView>(`/machines/${id}/docker/settings`),
|
||||
|
||||
Reference in New Issue
Block a user