This commit is contained in:
+20
-6
@@ -865,6 +865,17 @@ function isRuntimeResourceHealthy(resource: DashboardRuntimeResource) {
|
||||
return Number.isFinite(ready) && Number.isFinite(total) && total > 0 && ready === total;
|
||||
}
|
||||
|
||||
function isIgnoredRuntimeResource(resource: DashboardRuntimeResource) {
|
||||
const normalizedName = resource.name.toLowerCase();
|
||||
const normalizedStatus = resource.status.toLowerCase();
|
||||
if (resource.kind === 'Pod' && normalizedStatus === 'completed') return true;
|
||||
if (resource.kind === 'Job' && ['completed', 'succeeded', 'success'].includes(normalizedStatus)) return true;
|
||||
if ((resource.kind === 'Pod' || resource.kind === 'Job') && normalizedName.includes('migration') && ['completed', 'succeeded', 'success'].includes(normalizedStatus)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function formatJobStatus(status?: string | null) {
|
||||
const labels: Record<string, string> = {
|
||||
PENDING: '대기',
|
||||
@@ -905,8 +916,9 @@ function MetricCards({
|
||||
const activeApps = dashboardApps.filter((app) => isActiveStatus(app.status)).length;
|
||||
const activeSessions = sessions.filter((session) => session.state === '활성').length;
|
||||
const activeWorkTotal = activeWork.builds + activeWork.releases + activeWork.deployments;
|
||||
const healthyRuntimeCount = runtimeResources.filter(isRuntimeResourceHealthy).length;
|
||||
const runtimeRate = runtimeResources.length ? Math.round((healthyRuntimeCount / runtimeResources.length) * 100) : null;
|
||||
const countedRuntimeResources = runtimeResources.filter((resource) => !isIgnoredRuntimeResource(resource));
|
||||
const healthyRuntimeCount = countedRuntimeResources.filter(isRuntimeResourceHealthy).length;
|
||||
const runtimeRate = countedRuntimeResources.length ? Math.round((healthyRuntimeCount / countedRuntimeResources.length) * 100) : null;
|
||||
const cards = [
|
||||
{
|
||||
label: '활성 앱',
|
||||
@@ -932,8 +944,8 @@ function MetricCards({
|
||||
{
|
||||
label: '런타임 정상률',
|
||||
value: loading || runtimeRate === null ? '-' : `${runtimeRate}%`,
|
||||
delta: runtimeResources.length ? `${healthyRuntimeCount}/${runtimeResources.length}` : '리소스 없음',
|
||||
hint: 'namespace 리소스 Ready 기준',
|
||||
delta: countedRuntimeResources.length ? `${healthyRuntimeCount}/${countedRuntimeResources.length}` : '리소스 없음',
|
||||
hint: '완료된 Job/마이그레이션 제외',
|
||||
tone: runtimeRate !== null && runtimeRate < 80 ? 'red' as const : 'green' as const
|
||||
}
|
||||
];
|
||||
@@ -1258,6 +1270,8 @@ function AppRegistryTable({
|
||||
}
|
||||
|
||||
function ContainerPanel({ resources, loading, onOpen }: { resources: DashboardRuntimeResource[]; loading: boolean; onOpen: () => void }) {
|
||||
const visibleResources = resources.filter((resource) => !isIgnoredRuntimeResource(resource));
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<CardHeader
|
||||
@@ -1297,10 +1311,10 @@ function ContainerPanel({ resources, loading, onOpen }: { resources: DashboardRu
|
||||
</div>
|
||||
</div>
|
||||
))
|
||||
) : resources.length === 0 ? (
|
||||
) : visibleResources.length === 0 ? (
|
||||
<div className="px-5 py-12 text-center text-sm text-muted-foreground">표시할 런타임 리소스가 없습니다.</div>
|
||||
) : null}
|
||||
{!loading && resources.slice(0, 8).map((item) => (
|
||||
{!loading && visibleResources.slice(0, 8).map((item) => (
|
||||
<div key={`${item.namespace}-${item.kind}-${item.name}`} className="px-5 py-4">
|
||||
<div className="flex items-center justify-between gap-3">
|
||||
<div className="min-w-0">
|
||||
|
||||
Reference in New Issue
Block a user