merge develop into release
ci/woodpecker/push/woodpecker Pipeline was successful

This commit is contained in:
2026-07-07 09:24:37 +09:00
2 changed files with 38 additions and 17 deletions
+18 -16
View File
@@ -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<BuildRange>('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() {
새로고침
</Button>
</div>
<div className="space-y-3 p-4">
<div className="min-h-[638px] space-y-3 p-4">
{jobs.length === 0 ? (
<div className="flex min-h-44 items-center justify-center text-center text-sm text-muted-foreground">
빌드 작업이 없습니다.
@@ -429,7 +431,7 @@ export function LauncherBuildPage() {
</div>
<div className="flex items-center justify-between gap-4 border-t border-border px-5 py-3 text-sm">
<span className="text-xs text-muted-foreground">
{loading ? '불러오는 중' : `페이지 ${currentPage}`}
{loading ? '불러오는 중' : `총 ${totalJobs}건 · ${currentPage} / ${totalPages}`}
</span>
<div className="flex gap-2">
<Button
@@ -444,8 +446,8 @@ export function LauncherBuildPage() {
<Button
variant="outline"
className="h-8 px-3 text-[13px]"
disabled={!hasNextPage}
onClick={() => setPage((prev) => prev + 1)}
disabled={currentPage >= totalPages}
onClick={() => setPage((prev) => Math.min(totalPages, prev + 1))}
>
다음
<ChevronRight className="size-4" />
+20 -1
View File
@@ -239,7 +239,26 @@ export function listLauncherBuildJobs(options?: {
if (options?.limit) params.set('limit', String(options.limit));
if (options?.since) params.set('since', options.since);
const query = params.toString() ? `?${params.toString()}` : '';
return apiRequest<LauncherBuildJob[]>(`/launcher/builds${query}`);
if (query) {
return apiRequest<{ jobs: LauncherBuildJob[]; total: number; page: number; limit: number }>(`/launcher/builds${query}`)
.then((result) => result.jobs);
}
return apiRequest<LauncherBuildJob[]>('/launcher/builds');
}
export function listLauncherBuildJobsPage(options: {
target: string;
page: number;
limit: number;
since?: string;
}) {
const params = new URLSearchParams({
target: options.target,
page: String(options.page),
limit: String(options.limit)
});
if (options.since) params.set('since', options.since);
return apiRequest<{ jobs: LauncherBuildJob[]; total: number; page: number; limit: number }>(`/launcher/builds?${params.toString()}`);
}
export function getLauncherBackendDeployment() {