From 56ff75cc5a5e56b53c02bd4696f9034c2ad2de1c Mon Sep 17 00:00:00 2001 From: chyoo Date: Tue, 7 Jul 2026 09:24:31 +0900 Subject: [PATCH] paginate launcher source and build history --- src/pages/launcher/LauncherBuildPage.tsx | 34 +++++++++++++----------- src/pages/launcher/launcher-api.ts | 21 ++++++++++++++- 2 files changed, 38 insertions(+), 17 deletions(-) diff --git a/src/pages/launcher/LauncherBuildPage.tsx b/src/pages/launcher/LauncherBuildPage.tsx index 0f05336..1c5e530 100644 --- a/src/pages/launcher/LauncherBuildPage.tsx +++ b/src/pages/launcher/LauncherBuildPage.tsx @@ -10,6 +10,7 @@ import { getLauncherSource, listLauncherBuildEnv, listLauncherBuildJobs, + listLauncherBuildJobsPage, listLauncherVersions, saveLauncherBuildEnv, type LauncherSource, @@ -104,7 +105,7 @@ export function LauncherBuildPage() { const [loading, setLoading] = useState(true); const [page, setPage] = useState(1); const [range, setRange] = useState('week'); - const [hasNextPage, setHasNextPage] = useState(false); + const [totalJobs, setTotalJobs] = useState(0); const loadingVisible = useMinimumLoading(loading); const activeVersion = useMemo(() => versions.find((item) => item.isActive) ?? versions[0], [versions]); @@ -117,18 +118,19 @@ export function LauncherBuildPage() { const uploadPath = launcherArtifactKey(version || activeVersion?.version || '0.0.0', branch, commitSha, artifactName); const downloadUrl = r2PublicBaseUrl ? `${r2PublicBaseUrl.replace(/\/$/, '')}/${encodeObjectKey(uploadPath)}` : '백엔드 R2 설정 기준으로 생성됩니다.'; const currentPage = page; + const totalPages = Math.max(1, Math.ceil(totalJobs / launcherBuildJobPageSize)); const pagedJobs = jobs; const hasActiveJob = jobs.some((job) => job.status === 'PENDING' || job.status === 'RUNNING'); const loadBuildJobs = (nextPage = page, nextTarget = target, nextRange = range) => ( - listLauncherBuildJobs({ + listLauncherBuildJobsPage({ target: nextTarget, page: nextPage, - limit: launcherBuildJobPageSize + 1, + limit: launcherBuildJobPageSize, since: buildRangeSince(nextRange) - }).then((nextJobs) => { - setJobs(nextJobs.slice(0, launcherBuildJobPageSize)); - setHasNextPage(nextJobs.length > launcherBuildJobPageSize); + }).then((result) => { + setJobs(result.jobs); + setTotalJobs(result.total); }) ); @@ -136,10 +138,10 @@ export function LauncherBuildPage() { setLoading(true); Promise.all([ listLauncherVersions(), - listLauncherBuildJobs({ + listLauncherBuildJobsPage({ target, page, - limit: launcherBuildJobPageSize + 1, + limit: launcherBuildJobPageSize, since: buildRangeSince(range) }), getLauncherSource(), @@ -147,8 +149,8 @@ export function LauncherBuildPage() { ]) .then(([nextVersions, nextJobs, nextSource, nextBuildEnv]) => { setVersions(nextVersions); - setJobs(nextJobs.slice(0, launcherBuildJobPageSize)); - setHasNextPage(nextJobs.length > launcherBuildJobPageSize); + setJobs(nextJobs.jobs); + setTotalJobs(nextJobs.total); setSource(nextSource.source); setBuildEnv(nextBuildEnv.variables ?? []); const nextVersion = nextVersions.find((item) => item.isActive) ?? nextVersions[0]; @@ -173,7 +175,7 @@ export function LauncherBuildPage() { useEffect(() => { loadBuildJobs().catch((error: Error) => { setJobs([]); - setHasNextPage(false); + setTotalJobs(0); toast({ type: 'error', title: '빌드 작업 조회 실패', message: error.message }); }); }, [target, page, range]); @@ -226,7 +228,7 @@ export function LauncherBuildPage() { setPage(1); setRange('week'); setJobs((prev) => [job, ...prev].slice(0, launcherBuildJobPageSize)); - setHasNextPage(jobs.length >= launcherBuildJobPageSize); + setTotalJobs((prev) => prev + 1); setSelectedJob(job); toast({ type: 'success', title: '빌드 작업', message: '런처 빌드 작업이 생성되었습니다.' }); }) @@ -385,7 +387,7 @@ export function LauncherBuildPage() { 새로고침 -
+
{jobs.length === 0 ? (
빌드 작업이 없습니다. @@ -429,7 +431,7 @@ export function LauncherBuildPage() {
- {loading ? '불러오는 중' : `페이지 ${currentPage}`} + {loading ? '불러오는 중' : `총 ${totalJobs}건 · ${currentPage} / ${totalPages}`}