import { Loader2, RotateCcw } from 'lucide-react'; import { useEffect, useMemo, useState } from 'react'; import { Badge, Button, Card, CardHeader } from '../../components/ui'; import { useToast } from '../../components/toast'; import { PageTitle } from '../../layout/AppLayout'; import { cn } from '../../lib/utils'; import { LoadingModal, useMinimumLoading } from '../operations/operation-utils'; import { listCommonAppPipelineHistory, listCommonAppPipelines, type CommonAppPipeline } from './common-app-api'; import { formatDuration, formatPipelineRelativeTime, formatRepositoryName, formatShortSha, isActivePipelineStatus, pipelineStatusDotClass, pipelineStatusTone } from './common-app-utils'; const historyPageSize = 6; export function CommonAppBuildPage() { const { toast } = useToast(); const [pipelines, setPipelines] = useState([]); const [selectedRepoId, setSelectedRepoId] = useState(''); const [history, setHistory] = useState([]); const [historyPage, setHistoryPage] = useState(1); const [historyTotal, setHistoryTotal] = useState(null); const [historyTotalPages, setHistoryTotalPages] = useState(null); const [hasNextHistoryPage, setHasNextHistoryPage] = useState(false); const [loading, setLoading] = useState(true); const [historyLoading, setHistoryLoading] = useState(false); const [lastLoadedAt, setLastLoadedAt] = useState(null); const loadingVisible = useMinimumLoading(loading || historyLoading); const runningCount = useMemo( () => pipelines.filter((pipeline) => isActivePipelineStatus(pipeline.status)).length, [pipelines] ); const selectedPipeline = pipelines.find((pipeline) => pipeline.repoId === selectedRepoId) ?? pipelines[0]; const refresh = (silent = false) => { if (!silent) setLoading(true); listCommonAppPipelines() .then((nextPipelines) => { setPipelines(nextPipelines); setLastLoadedAt(Date.now()); setSelectedRepoId((current) => { if (current && nextPipelines.some((pipeline) => pipeline.repoId === current)) return current; return nextPipelines.find((pipeline) => pipeline.repoId)?.repoId ?? ''; }); }) .catch((error: Error) => { if (!silent) toast({ type: 'error', title: '공통앱 빌드 조회 실패', message: error.message }); }) .finally(() => { if (!silent) setLoading(false); }); }; useEffect(() => { refresh(); }, []); useEffect(() => { const timer = window.setInterval(() => refresh(true), 5000); return () => window.clearInterval(timer); }, []); useEffect(() => { setHistoryPage(1); }, [selectedRepoId]); useEffect(() => { let canceled = false; if (!selectedRepoId) { setHistory([]); setHistoryTotal(null); setHistoryTotalPages(null); setHasNextHistoryPage(false); return; } setHistoryLoading(true); listCommonAppPipelineHistory(selectedRepoId, historyPage, historyPageSize) .then((result) => { if (canceled) return; setHistory(result.pipelines ?? []); setHistoryTotal(result.total ?? null); setHistoryTotalPages(result.totalPages ?? null); setHasNextHistoryPage(Boolean(result.hasNext)); }) .catch((error: Error) => { if (canceled) return; setHistory([]); setHistoryTotal(null); setHistoryTotalPages(null); setHasNextHistoryPage(false); toast({ type: 'error', title: '파이프라인 이력 조회 실패', message: error.message }); }) .finally(() => { if (!canceled) setHistoryLoading(false); }); return () => { canceled = true; }; }, [historyPage, selectedRepoId, toast]); return ( <> refresh()} disabled={loading}> 새로고침 } />
{runningCount > 0 ? `진행 중 ${runningCount}개` : lastLoadedAt ? `${formatPipelineRelativeTime(lastLoadedAt)} 갱신` : '5초마다 갱신'} 0 ? 'blue' : 'neutral'}>{pipelines.length}개
} />
{pipelines.length === 0 && !loading ? (
표시할 저장소가 없습니다.
) : null}
{pipelines.map((pipeline) => { const selected = pipeline.repoId === selectedRepoId; return ( ); })}
{history.length === 0 && !historyLoading ? (
표시할 파이프라인 이력이 없습니다.
) : null} {history.map((pipeline) => (
#{pipeline.number ?? pipeline.id}

{pipeline.message || '-'}

{isActivePipelineStatus(pipeline.status) ? : null} {pipeline.status || '-'}
{pipeline.branch || '-'} SHA1 {formatShortSha(pipeline.commitSha)} 소요 {formatDuration(pipeline.durationSeconds)} {formatPipelineRelativeTime(pipeline.createdAt)}
))}
{historyTotal !== null && historyTotalPages !== null ? `총 ${historyTotal}건 · ${historyPage} / ${historyTotalPages}` : `현재 ${historyPage}페이지`}
); }