This commit is contained in:
@@ -81,6 +81,7 @@ export function LauncherBuildPage() {
|
||||
const [commitSha, setCommitSha] = useState('');
|
||||
const [jobs, setJobs] = useState<LauncherBuildJob[]>([]);
|
||||
const [selectedJob, setSelectedJob] = useState<LauncherBuildJob | null>(null);
|
||||
const [confirmOpen, setConfirmOpen] = useState(false);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [page, setPage] = useState(1);
|
||||
const loadingVisible = useMinimumLoading(loading);
|
||||
@@ -90,7 +91,6 @@ export function LauncherBuildPage() {
|
||||
const backendSource = source?.backend;
|
||||
const clientSource = source?.client;
|
||||
const artifactName = `autonomy-studio-launcher-${version || activeVersion?.version || '0.0.0'}.deb`;
|
||||
const clientArtifactPreview = 'package.json 버전과 실제 .deb 파일명 기준으로 빌드 후 자동 확정';
|
||||
const backendImageName = backendSource?.image || 'localhost:5000/studio-launcher-be';
|
||||
const backendImageTag = `${backendImageName.replace(/\/$/, '')}:${version || '0.1.0'}`;
|
||||
const backendDockerfile = backendSource?.dockerfile || 'Dockerfile';
|
||||
@@ -158,6 +158,7 @@ export function LauncherBuildPage() {
|
||||
}, [jobs, selectedJob]);
|
||||
|
||||
const createJob = () => {
|
||||
setConfirmOpen(false);
|
||||
setLoading(true);
|
||||
createLauncherBuildJob({
|
||||
target,
|
||||
@@ -188,7 +189,7 @@ export function LauncherBuildPage() {
|
||||
title="빌드 관리"
|
||||
description="런처 클라이언트 설치 파일과 백엔드 컨테이너 이미지를 구성요소별로 빌드합니다."
|
||||
actions={
|
||||
<Button className="h-8 px-3 text-[13px]" onClick={createJob} disabled={isBackend && !version.trim()}>
|
||||
<Button className="h-8 px-3 text-[13px]" onClick={() => setConfirmOpen(true)} disabled={isBackend && !version.trim()}>
|
||||
<Play className="size-4" />
|
||||
실행
|
||||
</Button>
|
||||
@@ -231,14 +232,14 @@ export function LauncherBuildPage() {
|
||||
<span className="text-xs font-medium text-muted-foreground">Commit SHA</span>
|
||||
<input className="mt-2 h-9 w-full rounded-md border border-input bg-background px-3 font-mono text-sm text-foreground outline-none placeholder:text-muted-foreground focus:ring-2 focus:ring-ring" value={commitSha} onChange={(event) => setCommitSha(event.target.value)} placeholder="비워두면 브랜치 최신 커밋" />
|
||||
</label>
|
||||
<div className="rounded-md border border-border bg-background p-3">
|
||||
<p className="text-xs text-muted-foreground">{isBackend ? '이미지' : '산출물'}</p>
|
||||
<p className="mt-2 break-all font-mono text-xs text-foreground">{isBackend ? backendImageTag : clientArtifactPreview}</p>
|
||||
<p className="mt-2 text-xs text-muted-foreground">{isBackend ? 'Dockerfile' : 'R2 Object Key'}</p>
|
||||
<p className="mt-1 break-all font-mono text-xs text-foreground">{isBackend ? backendDockerfile : clientArtifactPreview}</p>
|
||||
<p className="mt-2 text-xs text-muted-foreground">{isBackend ? 'Repository' : '다운로드 URL'}</p>
|
||||
<p className="mt-1 break-all font-mono text-xs text-foreground">{isBackend ? backendSource?.repository || '-' : clientArtifactPreview}</p>
|
||||
</div>
|
||||
{isBackend ? (
|
||||
<div className="rounded-md border border-border bg-background p-3">
|
||||
<p className="text-xs text-muted-foreground">이미지</p>
|
||||
<p className="mt-2 break-all font-mono text-xs text-foreground">{backendImageTag}</p>
|
||||
<p className="mt-2 text-xs text-muted-foreground">Repository</p>
|
||||
<p className="mt-1 break-all font-mono text-xs text-foreground">{backendSource?.repository || '-'}</p>
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
@@ -331,6 +332,55 @@ export function LauncherBuildPage() {
|
||||
{selectedJob?.logs || '작업을 선택하면 로그가 표시됩니다.'}
|
||||
</pre>
|
||||
</Modal>
|
||||
<Modal
|
||||
open={confirmOpen}
|
||||
title="빌드 실행 확인"
|
||||
onClose={() => setConfirmOpen(false)}
|
||||
footer={
|
||||
<>
|
||||
<Button variant="outline" onClick={() => setConfirmOpen(false)}>취소</Button>
|
||||
<Button onClick={createJob} disabled={loading || (isBackend && !version.trim())}>
|
||||
<Play className="size-4" />
|
||||
실행
|
||||
</Button>
|
||||
</>
|
||||
}
|
||||
>
|
||||
<div className="space-y-3 text-sm">
|
||||
<div className="rounded-md border border-border bg-muted/20 px-4 py-3">
|
||||
<p className="font-medium">{isBackend ? '런처 백엔드 이미지 빌드' : '런처 클라이언트 설치 파일 빌드'}를 실행합니다.</p>
|
||||
<p className="mt-1 text-xs leading-5 text-muted-foreground">
|
||||
실행 후 빌드 작업이 생성되고, 작업 목록에서 진행 상태와 로그를 확인할 수 있습니다.
|
||||
</p>
|
||||
</div>
|
||||
<div className="grid gap-2 rounded-md border border-border bg-background p-4">
|
||||
<div className="flex items-center justify-between gap-4">
|
||||
<span className="text-muted-foreground">대상</span>
|
||||
<span className="font-medium">{isBackend ? '백엔드' : '클라이언트'}</span>
|
||||
</div>
|
||||
<div className="flex items-center justify-between gap-4">
|
||||
<span className="text-muted-foreground">저장소</span>
|
||||
<span className="truncate font-medium">
|
||||
{isBackend ? backendSource?.repository || '-' : clientSource?.repository || activeVersion?.repository || '-'}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center justify-between gap-4">
|
||||
<span className="text-muted-foreground">브랜치</span>
|
||||
<span className="font-medium">{branch}</span>
|
||||
</div>
|
||||
<div className="flex items-center justify-between gap-4">
|
||||
<span className="text-muted-foreground">커밋</span>
|
||||
<span className="font-mono text-xs font-medium">{commitSha.trim() || '브랜치 최신'}</span>
|
||||
</div>
|
||||
{isBackend ? (
|
||||
<div className="flex items-center justify-between gap-4">
|
||||
<span className="text-muted-foreground">이미지</span>
|
||||
<span className="truncate font-mono text-xs font-medium">{backendImageTag}</span>
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
<LoadingModal open={loadingVisible} />
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -25,10 +25,7 @@ type SourceTarget = 'launcher-client' | 'launcher-backend';
|
||||
|
||||
type SourceForm = {
|
||||
repository: string;
|
||||
branch: string;
|
||||
commitSha: string;
|
||||
image: string;
|
||||
dockerfile: string;
|
||||
};
|
||||
|
||||
const targetLabels: Record<SourceTarget, { title: string; description: string; defaultOrg: string }> = {
|
||||
@@ -74,10 +71,7 @@ function sshCloneUrl(repository?: string | null, fallbackOrg?: string) {
|
||||
function emptyForm(): SourceForm {
|
||||
return {
|
||||
repository: '',
|
||||
branch: 'release',
|
||||
commitSha: '',
|
||||
image: 'localhost:5000/studio-launcher-be',
|
||||
dockerfile: 'Dockerfile'
|
||||
image: 'localhost:5000/studio-launcher-be'
|
||||
};
|
||||
}
|
||||
|
||||
@@ -135,6 +129,7 @@ export function LauncherSourcePage() {
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [saving, setSaving] = useState(false);
|
||||
const loadingVisible = useMinimumLoading(loading);
|
||||
const sourceBranch = 'develop';
|
||||
|
||||
const activeVersion = useMemo(() => versions.find((version) => version.isActive) ?? versions[0], [versions]);
|
||||
const activeForm = forms[activeTarget];
|
||||
@@ -164,17 +159,11 @@ export function LauncherSourcePage() {
|
||||
setForms({
|
||||
'launcher-client': {
|
||||
repository: clientRepository,
|
||||
branch: sourceResult.source.client?.branch ?? sourceResult.source.branch ?? nextVersion?.branch ?? 'release',
|
||||
commitSha: sourceResult.source.client?.commitSha ?? sourceResult.source.commitSha ?? nextVersion?.commitSha ?? '',
|
||||
image: '',
|
||||
dockerfile: ''
|
||||
image: ''
|
||||
},
|
||||
'launcher-backend': {
|
||||
repository: backendRepository,
|
||||
branch: sourceResult.source.backend?.branch ?? 'release',
|
||||
commitSha: sourceResult.source.backend?.commitSha ?? '',
|
||||
image: sourceResult.source.backend?.image ?? 'localhost:5000/studio-launcher-be',
|
||||
dockerfile: sourceResult.source.backend?.dockerfile ?? 'Dockerfile'
|
||||
image: sourceResult.source.backend?.image ?? 'localhost:5000/studio-launcher-be'
|
||||
}
|
||||
});
|
||||
})
|
||||
@@ -199,7 +188,7 @@ export function LauncherSourcePage() {
|
||||
let canceled = false;
|
||||
setCommitsLoading(true);
|
||||
setCommitsError('');
|
||||
listGiteaCommits(repository.owner, repository.repo, activeForm.branch || 'develop', 5)
|
||||
listGiteaCommits(repository.owner, repository.repo, sourceBranch, 5)
|
||||
.then((nextCommits) => {
|
||||
if (!canceled) setCommits(nextCommits);
|
||||
})
|
||||
@@ -216,7 +205,7 @@ export function LauncherSourcePage() {
|
||||
return () => {
|
||||
canceled = true;
|
||||
};
|
||||
}, [activeForm.repository, activeForm.branch, activeTargetMeta.defaultOrg]);
|
||||
}, [activeForm.repository, activeTargetMeta.defaultOrg, sourceBranch]);
|
||||
|
||||
const save = () => {
|
||||
if (!activeForm.repository.trim()) return;
|
||||
@@ -224,10 +213,10 @@ export function LauncherSourcePage() {
|
||||
updateLauncherSource({
|
||||
target: activeTarget,
|
||||
repository: activeForm.repository.trim(),
|
||||
branch: activeForm.branch.trim() || undefined,
|
||||
commitSha: activeForm.commitSha.trim() || undefined,
|
||||
branch: sourceBranch,
|
||||
commitSha: '',
|
||||
image: activeTarget === 'launcher-backend' ? activeForm.image.trim() || undefined : undefined,
|
||||
dockerfile: activeTarget === 'launcher-backend' ? activeForm.dockerfile.trim() || undefined : undefined
|
||||
dockerfile: activeTarget === 'launcher-backend' ? 'Dockerfile' : undefined
|
||||
})
|
||||
.then(() => {
|
||||
toast({ type: 'success', title: '소스 연결', message: `${activeTargetMeta.title} 소스 연결을 저장했습니다.` });
|
||||
@@ -287,30 +276,13 @@ export function LauncherSourcePage() {
|
||||
{repos.map((repo) => <option key={repoFullName(repo)} value={repoFullName(repo)} />)}
|
||||
</datalist>
|
||||
</label>
|
||||
<label className="block">
|
||||
<span className="text-xs font-medium text-muted-foreground">브랜치</span>
|
||||
<select
|
||||
className="mt-2 h-9 w-full rounded-md border border-input bg-background px-3 text-sm text-foreground outline-none focus:ring-2 focus:ring-ring"
|
||||
value={activeForm.branch}
|
||||
onChange={(event) => updateForm({ branch: event.target.value })}
|
||||
>
|
||||
<option value="develop">develop</option>
|
||||
<option value="release">release</option>
|
||||
<option value="main">main</option>
|
||||
</select>
|
||||
</label>
|
||||
<label className="block md:col-span-3">
|
||||
<span className="text-xs font-medium text-muted-foreground">Commit SHA</span>
|
||||
<input
|
||||
className="mt-2 h-9 w-full rounded-md border border-input bg-background px-3 font-mono text-sm text-foreground outline-none placeholder:text-muted-foreground focus:ring-2 focus:ring-ring"
|
||||
value={activeForm.commitSha}
|
||||
onChange={(event) => updateForm({ commitSha: event.target.value })}
|
||||
placeholder="비워두면 브랜치 최신 커밋 기준"
|
||||
/>
|
||||
</label>
|
||||
<div className="rounded-md border border-border bg-muted/20 px-3 py-2">
|
||||
<p className="text-xs font-medium text-muted-foreground">빌드 기준</p>
|
||||
<p className="mt-1 text-sm font-medium text-foreground">develop 최신 성공 빌드</p>
|
||||
</div>
|
||||
{activeTarget === 'launcher-backend' ? (
|
||||
<>
|
||||
<label className="block md:col-span-2">
|
||||
<label className="block md:col-span-3">
|
||||
<span className="text-xs font-medium text-muted-foreground">이미지 이름</span>
|
||||
<input
|
||||
className="mt-2 h-9 w-full rounded-md border border-input bg-background px-3 font-mono text-sm text-foreground outline-none placeholder:text-muted-foreground focus:ring-2 focus:ring-ring"
|
||||
@@ -319,21 +291,12 @@ export function LauncherSourcePage() {
|
||||
placeholder="localhost:5000/studio-launcher-be"
|
||||
/>
|
||||
</label>
|
||||
<label className="block">
|
||||
<span className="text-xs font-medium text-muted-foreground">Dockerfile</span>
|
||||
<input
|
||||
className="mt-2 h-9 w-full rounded-md border border-input bg-background px-3 font-mono text-sm text-foreground outline-none placeholder:text-muted-foreground focus:ring-2 focus:ring-ring"
|
||||
value={activeForm.dockerfile}
|
||||
onChange={(event) => updateForm({ dockerfile: event.target.value })}
|
||||
placeholder="Dockerfile"
|
||||
/>
|
||||
</label>
|
||||
</>
|
||||
) : null}
|
||||
<div className="flex justify-end md:col-span-3">
|
||||
<Button onClick={save} disabled={!activeForm.repository.trim() || saving}>
|
||||
<Link2 className="size-4" />
|
||||
저장
|
||||
저장소 연결 저장
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -377,10 +340,7 @@ export function LauncherSourcePage() {
|
||||
</div>
|
||||
|
||||
<Card className="mt-4 min-w-0 overflow-hidden">
|
||||
<CardHeader
|
||||
title="최근 커밋"
|
||||
description={`${activeTargetMeta.title} 저장소의 ${activeForm.branch || 'develop'} 브랜치 기준 최근 5개 커밋입니다.`}
|
||||
/>
|
||||
<CardHeader title="최근 커밋" description={`${activeTargetMeta.title} 저장소의 develop 브랜치 기준 최근 5개 커밋입니다.`} />
|
||||
<div className="overflow-x-auto">
|
||||
<table className="min-w-[760px] w-full text-left text-sm">
|
||||
<thead className="border-y border-border bg-muted/30 text-xs text-muted-foreground">
|
||||
|
||||
@@ -174,7 +174,11 @@ export function LauncherVersionsPage() {
|
||||
</Card>
|
||||
<Card>
|
||||
<CardHeader title="릴리즈 노트" description="최근 런처 배포 메모입니다." />
|
||||
<div className="p-5 text-sm leading-6 text-muted-foreground">{launcher.releaseNotes || '-'}</div>
|
||||
<div className="p-5">
|
||||
<div className="min-h-32 rounded-md border border-neutral-800 bg-neutral-950 px-4 py-3 text-sm leading-6 text-neutral-100">
|
||||
<p className="whitespace-pre-wrap">{launcher.releaseNotes || '-'}</p>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
Reference in New Issue
Block a user