Files
kandev/apps/web/components/settings/kubernetes-session-presentation.tsx
T
2026-09-10 11:05:05 +01:00

162 lines
5.6 KiB
TypeScript

"use client";
import { useTranslation } from "react-i18next";
import { Badge } from "@kandev/ui/badge";
import type { KubernetesSession } from "@/lib/types/http-kubernetes";
import {
normalizedState,
mainContainerStateValue,
podPhaseValue,
podStatusLabel,
retentionLabel,
sessionStateLabel,
formatCreatedAt,
workspaceLabel,
} from "./kubernetes-session-utils";
export function SessionIdentity({ session }: { session: KubernetesSession }) {
const { t } = useTranslation();
return (
<div className="min-w-0 space-y-1.5">
<p className="break-all font-mono text-sm">{session.pod_name || "-"}</p>
<SessionIdentityValue label={t("executors:task")} value={session.task_id} />
<SessionIdentityValue label={t("executors:session")} value={session.session_id} />
</div>
);
}
function SessionIdentityValue({ label, value }: { label: string; value: string }) {
return (
<p className="min-w-0 break-all font-mono text-xs text-muted-foreground">
<span className="font-sans">{label}: </span>
{value}
</p>
);
}
export function SessionStatusSummary({ session }: { session: KubernetesSession }) {
const { t } = useTranslation();
const sessionState = normalizedState(session.session_state);
const retentionState = normalizedState(session.retention_state);
const podPhase = podPhaseValue(session);
const mainContainerState = mainContainerStateValue(session);
return (
<div className="min-w-0 space-y-1.5" data-testid="kubernetes-session-status-summary">
<div className="flex flex-nowrap items-center gap-1.5">
<Badge variant={sessionState === "running" ? "default" : "secondary"}>
{sessionStateLabel(sessionState, t)}
</Badge>
<Badge variant={retentionState === "retained" ? "outline" : "secondary"}>
{retentionLabel(retentionState, t)}
</Badge>
</div>
<div className="flex min-w-0 flex-wrap items-center gap-1 text-xs text-muted-foreground md:flex-nowrap md:whitespace-nowrap">
<span>
{t("executors:kubernetesPodCompactValue", { value: podStatusLabel(podPhase, t) })}
</span>
<span aria-hidden="true">·</span>
<span>
{t("executors:kubernetesContainerCompactValue", {
value: podStatusLabel(mainContainerState, t),
})}
</span>
{session.restarts > 0 && (
<>
<span aria-hidden="true">·</span>
<RestartCount count={session.restarts} />
</>
)}
</div>
</div>
);
}
export function SessionRuntimeDetails({ session }: { session: KubernetesSession }) {
const { t } = useTranslation();
const retentionState = normalizedState(session.retention_state);
const podPhase = podPhaseValue(session);
const mainContainerState = mainContainerStateValue(session);
return (
<div
className="grid gap-x-6 gap-y-1 text-xs text-muted-foreground md:grid-cols-2 xl:grid-cols-4"
data-testid="kubernetes-session-runtime-details"
>
<p>
{t("executors:kubernetesSessionStateValue", {
value: sessionStateLabel(session.session_state, t),
})}
</p>
<p>
{t("executors:kubernetesRetentionStateValue", {
value: retentionLabel(retentionState, t),
})}
</p>
<p>{t("executors:kubernetesPodStateValue", { value: podStatusLabel(podPhase, t) })}</p>
<p>
{t("executors:kubernetesContainerStateValue", {
value: podStatusLabel(mainContainerState, t),
})}
</p>
<p>{t("executors:kubernetesRestarts", { count: session.restarts })}</p>
<p>
{t("executors:kubernetesWorkspaceValue", {
value: workspaceLabel(session.workspace_kind, t),
})}
</p>
<p>{t("executors:kubernetesCreatedValue", { value: formatCreatedAt(session.created_at) })}</p>
<RequestSummary session={session} showLabel />
<SessionFailureReason session={session} />
</div>
);
}
export function RequestSummary({
session,
showLabel = false,
}: {
session: KubernetesSession;
showLabel?: boolean;
}) {
const { t } = useTranslation();
const requests = session.main_container_requests;
const values = [
requests?.cpu ? t("executors:kubernetesRequestCpu", { value: requests.cpu }) : null,
requests?.memory ? t("executors:kubernetesRequestMemory", { value: requests.memory }) : null,
].filter((value): value is string => Boolean(value));
return (
<p
className="min-w-0 text-xs text-muted-foreground"
data-testid="kubernetes-session-request-summary"
>
{showLabel && <span>{t("executors:kubernetesMainContainerRequests")}: </span>}
{values.length > 0 ? values.join(" · ") : t("executors:kubernetesRequestsUnspecifiedValue")}
</p>
);
}
function RestartCount({ count }: { count: number }) {
const { t } = useTranslation();
return <span>{t("executors:kubernetesRestarts", { count })}</span>;
}
export function SessionDetails({ session }: { session: KubernetesSession }) {
const { t } = useTranslation();
return (
<div className="flex flex-wrap gap-x-3 gap-y-1 text-xs text-muted-foreground">
<p>
{t("executors:kubernetesWorkspaceValue", {
value: workspaceLabel(session.workspace_kind, t),
})}
</p>
<p>{t("executors:kubernetesCreatedValue", { value: formatCreatedAt(session.created_at) })}</p>
<SessionFailureReason session={session} />
</div>
);
}
export function SessionFailureReason({ session }: { session: KubernetesSession }) {
return session.failure_reason ? (
<p className="break-words text-xs text-destructive">{session.failure_reason}</p>
) : null;
}