"use client"; import { useTranslations } from "next-intl"; /** * Tenant warning shape received from the operator's status.warnings. * Mirror of the operator's `TenantWarning` type. See * pieced-operator/api/v1alpha1/piecedtenant_types.go. */ export interface TenantWarning { source: string; reason?: string; message?: string; since?: string; } interface Props { warnings: TenantWarning[]; } /** * Renders a small amber warning badge if there are any non-fatal * warnings on the tenant. The badge sits visually next to the phase * StatusBadge — they're separate concepts (phase = lifecycle, warnings * = observed sub-issues) and may both be present at once (e.g. tenant * is `Ready` but has a SkillPacksReady=False warning). * * Hover/focus reveals the warning detail. We don't truncate the message * inside the tooltip; OCI/CRD condition messages tend to be short and * include the actionable detail (which skill, which secret, which * resolver). If a future warning source has a 5-line stacktrace as a * message we'll need a different treatment; cross that bridge then. * * Returns null when there are no warnings — keep render-call sites * simple, they don't have to gate on length themselves. */ export function WarningBadge({ warnings }: Props) { const t = useTranslations("warnings"); if (!warnings || warnings.length === 0) return null; const tooltipLabel = (() => { try { return warnings.length === 1 ? t("oneTooltip") : t("manyTooltip", { count: warnings.length }); } catch { return warnings.length === 1 ? "1 warning" : `${warnings.length} warnings`; } })(); return ( {/* Tooltip. Hidden by default; shown on hover OR focus of the sibling button. Positioned below-right so it doesn't collide with the StatusBadge that typically sits left of this. Constrained width so long messages wrap. z-50 keeps it above table rows / cards. */}
{tooltipLabel}
); }