Compare commits
2 Commits
f3e7f9cee1
...
71eeac278f
| Author | SHA1 | Date | |
|---|---|---|---|
| 71eeac278f | |||
| 68385aedc7 |
@@ -92,6 +92,7 @@ export function BuildManagementPage() {
|
|||||||
const [branch, setBranch] = useState('develop');
|
const [branch, setBranch] = useState('develop');
|
||||||
const [commitSha, setCommitSha] = useState('');
|
const [commitSha, setCommitSha] = useState('');
|
||||||
const [selectedJob, setSelectedJob] = useState<BuildJob | null>(null);
|
const [selectedJob, setSelectedJob] = useState<BuildJob | null>(null);
|
||||||
|
const [confirmOpen, setConfirmOpen] = useState(false);
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [page, setPage] = useState(1);
|
const [page, setPage] = useState(1);
|
||||||
const [range, setRange] = useState<BuildRange>('week');
|
const [range, setRange] = useState<BuildRange>('week');
|
||||||
@@ -199,6 +200,7 @@ export function BuildManagementPage() {
|
|||||||
const startBuild = async () => {
|
const startBuild = async () => {
|
||||||
if (!selectedComponent) return;
|
if (!selectedComponent) return;
|
||||||
try {
|
try {
|
||||||
|
setConfirmOpen(false);
|
||||||
const result = await createBuildJob({ componentId: selectedComponent.id, branch, commitSha });
|
const result = await createBuildJob({ componentId: selectedComponent.id, branch, commitSha });
|
||||||
toast({ type: 'success', message: '빌드 작업이 생성되었습니다.' });
|
toast({ type: 'success', message: '빌드 작업이 생성되었습니다.' });
|
||||||
setSelectedJob(result.buildJob);
|
setSelectedJob(result.buildJob);
|
||||||
@@ -300,7 +302,7 @@ export function BuildManagementPage() {
|
|||||||
<span className="text-muted-foreground">예상 결과물</span>
|
<span className="text-muted-foreground">예상 결과물</span>
|
||||||
<span className="truncate font-medium">{predicted}</span>
|
<span className="truncate font-medium">{predicted}</span>
|
||||||
</div>
|
</div>
|
||||||
<Button className="mt-1 h-8 px-3 text-[13px]" onClick={startBuild} disabled={!selectedComponent || appsLoading || loading}>
|
<Button className="mt-1 h-8 px-3 text-[13px]" onClick={() => setConfirmOpen(true)} disabled={!selectedComponent || appsLoading || loading}>
|
||||||
<Play className="size-4" />
|
<Play className="size-4" />
|
||||||
빌드 실행
|
빌드 실행
|
||||||
</Button>
|
</Button>
|
||||||
@@ -441,6 +443,53 @@ export function BuildManagementPage() {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</Modal>
|
</Modal>
|
||||||
|
<Modal
|
||||||
|
open={confirmOpen}
|
||||||
|
title="빌드 실행 확인"
|
||||||
|
onClose={() => {
|
||||||
|
if (!loading) setConfirmOpen(false);
|
||||||
|
}}
|
||||||
|
footer={
|
||||||
|
<>
|
||||||
|
<Button variant="outline" disabled={loading} onClick={() => setConfirmOpen(false)}>취소</Button>
|
||||||
|
<Button disabled={!selectedComponent || appsLoading || loading} onClick={startBuild}>
|
||||||
|
<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">{selectedComponent?.name ?? '-'} 구성요소 빌드를 실행합니다.</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="truncate font-medium">{selectedApp?.name ?? '-'}</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center justify-between gap-4">
|
||||||
|
<span className="text-muted-foreground">저장소</span>
|
||||||
|
<span className="truncate font-medium">{selectedComponent?.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>
|
||||||
|
<div className="flex items-center justify-between gap-4">
|
||||||
|
<span className="text-muted-foreground">빌드 대상</span>
|
||||||
|
<span className="truncate font-medium">{selectedTarget}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Modal>
|
||||||
<LoadingModal open={loadingVisible} />
|
<LoadingModal open={loadingVisible} />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -164,13 +164,14 @@ export function ReleaseManagementPage() {
|
|||||||
const [version, setVersion] = useState('');
|
const [version, setVersion] = useState('');
|
||||||
const [releaseModalOpen, setReleaseModalOpen] = useState(false);
|
const [releaseModalOpen, setReleaseModalOpen] = useState(false);
|
||||||
const [selectedBuildIds, setSelectedBuildIds] = useState<string[]>([]);
|
const [selectedBuildIds, setSelectedBuildIds] = useState<string[]>([]);
|
||||||
const [openLogReleaseId, setOpenLogReleaseId] = useState('');
|
const [selectedReleaseLogId, setSelectedReleaseLogId] = useState('');
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
const [page, setPage] = useState(1);
|
const [page, setPage] = useState(1);
|
||||||
const [range, setRange] = useState<ReleaseRange>('week');
|
const [range, setRange] = useState<ReleaseRange>('week');
|
||||||
const [totalReleases, setTotalReleases] = useState(0);
|
const [totalReleases, setTotalReleases] = useState(0);
|
||||||
const [usedBuildIdValues, setUsedBuildIdValues] = useState<string[]>([]);
|
const [usedBuildIdValues, setUsedBuildIdValues] = useState<string[]>([]);
|
||||||
const [usedReleaseValueValues, setUsedReleaseValueValues] = useState<string[]>([]);
|
const [usedReleaseValueValues, setUsedReleaseValueValues] = useState<string[]>([]);
|
||||||
|
const hasActiveRelease = releases.some((release) => release.status === 'PENDING' || release.status === 'RUNNING');
|
||||||
const loadingVisible = useMinimumLoading(loading);
|
const loadingVisible = useMinimumLoading(loading);
|
||||||
const usedValues = useMemo(() => new Set(usedReleaseValueValues), [usedReleaseValueValues]);
|
const usedValues = useMemo(() => new Set(usedReleaseValueValues), [usedReleaseValueValues]);
|
||||||
const usedBuildIds = useMemo(() => new Set(usedBuildIdValues), [usedBuildIdValues]);
|
const usedBuildIds = useMemo(() => new Set(usedBuildIdValues), [usedBuildIdValues]);
|
||||||
@@ -226,6 +227,28 @@ export function ReleaseManagementPage() {
|
|||||||
void refresh();
|
void refresh();
|
||||||
}, [selectedAppId, page, range, apps]);
|
}, [selectedAppId, page, range, apps]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!hasActiveRelease) return;
|
||||||
|
const timer = window.setInterval(() => {
|
||||||
|
listReleasesPage({
|
||||||
|
appKey: apps.find((app) => app.id === selectedAppId)?.key,
|
||||||
|
page,
|
||||||
|
limit: releasePageSize,
|
||||||
|
since: releaseRangeSince(range)
|
||||||
|
})
|
||||||
|
.then((nextReleases) => {
|
||||||
|
setReleases(nextReleases.releases);
|
||||||
|
setTotalReleases(nextReleases.total);
|
||||||
|
setUsedBuildIdValues(nextReleases.usedBuildIds ?? []);
|
||||||
|
setUsedReleaseValueValues(nextReleases.usedValues ?? []);
|
||||||
|
})
|
||||||
|
.catch((error: Error) => {
|
||||||
|
toast({ type: 'error', message: `릴리즈 목록 갱신 실패: ${error.message}` });
|
||||||
|
});
|
||||||
|
}, 2000);
|
||||||
|
return () => window.clearInterval(timer);
|
||||||
|
}, [hasActiveRelease, apps, selectedAppId, page, range, toast]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setPage(1);
|
setPage(1);
|
||||||
}, [selectedAppId, range]);
|
}, [selectedAppId, range]);
|
||||||
@@ -262,6 +285,8 @@ export function ReleaseManagementPage() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const selectedReleaseLog = releases.find((release) => release.id === selectedReleaseLogId) ?? null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<PageTitle
|
<PageTitle
|
||||||
@@ -306,7 +331,6 @@ export function ReleaseManagementPage() {
|
|||||||
) : null}
|
) : null}
|
||||||
{pagedReleases.map((release) => {
|
{pagedReleases.map((release) => {
|
||||||
const artifacts = releaseArtifacts(release);
|
const artifacts = releaseArtifacts(release);
|
||||||
const isLogOpen = openLogReleaseId === release.id;
|
|
||||||
return (
|
return (
|
||||||
<div key={release.id} className="rounded-md border border-border bg-background/70 p-4">
|
<div key={release.id} className="rounded-md border border-border bg-background/70 p-4">
|
||||||
<div className="flex flex-wrap items-center justify-between gap-3">
|
<div className="flex flex-wrap items-center justify-between gap-3">
|
||||||
@@ -319,9 +343,9 @@ export function ReleaseManagementPage() {
|
|||||||
variant="outline"
|
variant="outline"
|
||||||
className="size-8 px-0"
|
className="size-8 px-0"
|
||||||
disabled={!release.logs}
|
disabled={!release.logs}
|
||||||
title={isLogOpen ? '로그 닫기' : '로그'}
|
title="로그"
|
||||||
aria-label={isLogOpen ? '로그 닫기' : '로그'}
|
aria-label="로그"
|
||||||
onClick={() => setOpenLogReleaseId((prev) => prev === release.id ? '' : release.id)}
|
onClick={() => setSelectedReleaseLogId(release.id)}
|
||||||
>
|
>
|
||||||
<MoreHorizontal className="size-4" />
|
<MoreHorizontal className="size-4" />
|
||||||
</Button>
|
</Button>
|
||||||
@@ -342,11 +366,6 @@ export function ReleaseManagementPage() {
|
|||||||
<p className="mt-1 text-xs text-muted-foreground">-</p>
|
<p className="mt-1 text-xs text-muted-foreground">-</p>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
{isLogOpen ? (
|
|
||||||
<pre className="mt-3 max-h-72 overflow-auto rounded-md border border-border bg-black/70 p-3 font-mono text-xs leading-5 text-slate-100">
|
|
||||||
{release.logs}
|
|
||||||
</pre>
|
|
||||||
) : null}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
@@ -442,6 +461,23 @@ export function ReleaseManagementPage() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
<Modal
|
||||||
|
open={Boolean(selectedReleaseLog)}
|
||||||
|
title="릴리즈 로그"
|
||||||
|
onClose={() => setSelectedReleaseLogId('')}
|
||||||
|
className="log-modal-shell"
|
||||||
|
footer={<Button variant="outline" onClick={() => setSelectedReleaseLogId('')}>닫기</Button>}
|
||||||
|
>
|
||||||
|
{selectedReleaseLog?.logs ? (
|
||||||
|
<pre className="whitespace-pre-wrap rounded-md border border-border bg-background p-4 font-mono text-xs leading-5 text-muted-foreground">
|
||||||
|
{selectedReleaseLog.logs}
|
||||||
|
</pre>
|
||||||
|
) : (
|
||||||
|
<div className="flex min-h-44 items-center justify-center text-center text-sm text-muted-foreground">
|
||||||
|
로그가 없습니다.
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</Modal>
|
||||||
<LoadingModal open={loadingVisible} />
|
<LoadingModal open={loadingVisible} />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ export function RepositoryManagementPage() {
|
|||||||
const [isCreateRepoOpen, setIsCreateRepoOpen] = useState(false);
|
const [isCreateRepoOpen, setIsCreateRepoOpen] = useState(false);
|
||||||
const [repoName, setRepoName] = useState('');
|
const [repoName, setRepoName] = useState('');
|
||||||
const [repoDescription, setRepoDescription] = useState('');
|
const [repoDescription, setRepoDescription] = useState('');
|
||||||
const [repoPrivate, setRepoPrivate] = useState(true);
|
const [repoPrivate, setRepoPrivate] = useState(false);
|
||||||
const [createDevelopBranch, setCreateDevelopBranch] = useState(true);
|
const [createDevelopBranch, setCreateDevelopBranch] = useState(true);
|
||||||
const [createReleaseBranch, setCreateReleaseBranch] = useState(true);
|
const [createReleaseBranch, setCreateReleaseBranch] = useState(true);
|
||||||
const [repoCreateStatus, setRepoCreateStatus] = useState<'idle' | 'saving' | 'error'>('idle');
|
const [repoCreateStatus, setRepoCreateStatus] = useState<'idle' | 'saving' | 'error'>('idle');
|
||||||
@@ -165,7 +165,7 @@ export function RepositoryManagementPage() {
|
|||||||
.then(() => {
|
.then(() => {
|
||||||
setRepoName('');
|
setRepoName('');
|
||||||
setRepoDescription('');
|
setRepoDescription('');
|
||||||
setRepoPrivate(true);
|
setRepoPrivate(false);
|
||||||
setCreateDevelopBranch(true);
|
setCreateDevelopBranch(true);
|
||||||
setCreateReleaseBranch(true);
|
setCreateReleaseBranch(true);
|
||||||
setRepoCreateStatus('idle');
|
setRepoCreateStatus('idle');
|
||||||
|
|||||||
@@ -3,14 +3,12 @@ import { useEffect, useMemo, useRef, useState } from 'react';
|
|||||||
import { useToast } from '../../components/toast';
|
import { useToast } from '../../components/toast';
|
||||||
import { Badge, Button, Card, CardHeader, Modal } from '../../components/ui';
|
import { Badge, Button, Card, CardHeader, Modal } from '../../components/ui';
|
||||||
import { PageTitle } from '../../layout/AppLayout';
|
import { PageTitle } from '../../layout/AppLayout';
|
||||||
import type { AppRelease } from '../../types/application';
|
|
||||||
import type { ApiApp, ApiAppComponent } from '../../types/runtime';
|
import type { ApiApp, ApiAppComponent } from '../../types/runtime';
|
||||||
import { LoadingModal, useMinimumLoading } from '../operations/operation-utils';
|
import { LoadingModal, useMinimumLoading } from '../operations/operation-utils';
|
||||||
import { AppSelector, useApps } from './ApplicationControls';
|
import { AppSelector, useApps } from './ApplicationControls';
|
||||||
import {
|
import {
|
||||||
getGiteaCommitDiff,
|
getGiteaCommitDiff,
|
||||||
listGiteaCommitsPage,
|
listGiteaCommitsPage,
|
||||||
listReleases,
|
|
||||||
listSources,
|
listSources,
|
||||||
type GiteaCommit
|
type GiteaCommit
|
||||||
} from './application-api';
|
} from './application-api';
|
||||||
@@ -68,11 +66,6 @@ function repositoryGitUrl(repository?: string | null) {
|
|||||||
return normalized ? `${giteaBaseUrl.replace(/\/$/, '')}/${normalized}.git` : '-';
|
return normalized ? `${giteaBaseUrl.replace(/\/$/, '')}/${normalized}.git` : '-';
|
||||||
}
|
}
|
||||||
|
|
||||||
function releaseTime(release: AppRelease) {
|
|
||||||
const value = new Date(release.createdAt).getTime();
|
|
||||||
return Number.isNaN(value) ? 0 : value;
|
|
||||||
}
|
|
||||||
|
|
||||||
function commitAuthor(commit: GiteaCommit) {
|
function commitAuthor(commit: GiteaCommit) {
|
||||||
return commit.author?.login
|
return commit.author?.login
|
||||||
|| commit.author?.username
|
|| commit.author?.username
|
||||||
@@ -304,10 +297,9 @@ export function SourceManagementPage() {
|
|||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
const { apps, selectedAppId, loading: appsLoading, selectApp } = useApps();
|
const { apps, selectedAppId, loading: appsLoading, selectApp } = useApps();
|
||||||
const [sources, setSources] = useState<SourceComponent[]>([]);
|
const [sources, setSources] = useState<SourceComponent[]>([]);
|
||||||
const [releases, setReleases] = useState<AppRelease[]>([]);
|
|
||||||
const [sourcesLoading, setSourcesLoading] = useState(true);
|
const [sourcesLoading, setSourcesLoading] = useState(true);
|
||||||
const [selectedSourceId, setSelectedSourceId] = useState('');
|
const [selectedSourceId, setSelectedSourceId] = useState('');
|
||||||
const [selectedBranch, setSelectedBranch] = useState('release');
|
const [selectedBranch, setSelectedBranch] = useState('develop');
|
||||||
const [commitRange, setCommitRange] = useState<CommitRange>('week');
|
const [commitRange, setCommitRange] = useState<CommitRange>('week');
|
||||||
const [commitPage, setCommitPage] = useState(1);
|
const [commitPage, setCommitPage] = useState(1);
|
||||||
const [commits, setCommits] = useState<GiteaCommit[]>([]);
|
const [commits, setCommits] = useState<GiteaCommit[]>([]);
|
||||||
@@ -327,34 +319,20 @@ export function SourceManagementPage() {
|
|||||||
);
|
);
|
||||||
const selectedSource = filteredSources.find((source) => source.id === selectedSourceId) ?? filteredSources[0] ?? null;
|
const selectedSource = filteredSources.find((source) => source.id === selectedSourceId) ?? filteredSources[0] ?? null;
|
||||||
const repository = splitRepository(selectedSource?.repository);
|
const repository = splitRepository(selectedSource?.repository);
|
||||||
const branch = selectedBranch || 'release';
|
const branch = selectedBranch || 'develop';
|
||||||
|
const latestBranchSha = commits.length > 0 ? commits[0]?.sha ?? '' : '';
|
||||||
const branchOptions = useMemo(
|
const branchOptions = useMemo(
|
||||||
() => [...new Set(['release', 'develop', 'main', selectedSource?.branch].filter((item): item is string => Boolean(item)))],
|
() => [...new Set(['develop', 'release', 'main', selectedSource?.branch].filter((item): item is string => Boolean(item)))],
|
||||||
[selectedSource?.branch]
|
[selectedSource?.branch]
|
||||||
);
|
);
|
||||||
const latestRelease = useMemo(
|
|
||||||
() => releases
|
|
||||||
.filter((release) => release.appId === selectedSource?.appId && release.status === 'SUCCEEDED')
|
|
||||||
.sort((a, b) => releaseTime(b) - releaseTime(a))[0],
|
|
||||||
[releases, selectedSource?.appId]
|
|
||||||
);
|
|
||||||
const totalCommitPages = totalCommits === null ? null : Math.max(1, Math.ceil(totalCommits / commitPageSize));
|
const totalCommitPages = totalCommits === null ? null : Math.max(1, Math.ceil(totalCommits / commitPageSize));
|
||||||
const selectedRepositoryGitUrl = repositoryGitUrl(selectedSource?.repository);
|
const selectedRepositoryGitUrl = repositoryGitUrl(selectedSource?.repository);
|
||||||
|
|
||||||
const refreshSources = () => {
|
const refreshSources = () => {
|
||||||
setSourcesLoading(true);
|
setSourcesLoading(true);
|
||||||
Promise.all([
|
listSources()
|
||||||
listSources(),
|
.then((sourceItems) => setSources(sourceItems))
|
||||||
listReleases().catch(() => [])
|
.catch(() => setSources([]))
|
||||||
])
|
|
||||||
.then(([sourceItems, releaseItems]) => {
|
|
||||||
setSources(sourceItems);
|
|
||||||
setReleases(releaseItems);
|
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
setSources([]);
|
|
||||||
setReleases([]);
|
|
||||||
})
|
|
||||||
.finally(() => setSourcesLoading(false));
|
.finally(() => setSourcesLoading(false));
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -464,6 +442,18 @@ export function SourceManagementPage() {
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div className="grid gap-3 rounded-md border border-border bg-muted/20 p-3 text-sm md:grid-cols-2">
|
<div className="grid gap-3 rounded-md border border-border bg-muted/20 p-3 text-sm md:grid-cols-2">
|
||||||
|
<div>
|
||||||
|
<p className="text-xs text-muted-foreground">조회 브랜치</p>
|
||||||
|
<select
|
||||||
|
className="mt-2 h-9 w-full rounded-md border border-input bg-background px-3 text-sm font-medium text-foreground outline-none focus:ring-2 focus:ring-ring"
|
||||||
|
value={branch}
|
||||||
|
onChange={(event) => setSelectedBranch(event.target.value)}
|
||||||
|
>
|
||||||
|
{branchOptions.map((option) => (
|
||||||
|
<option key={option} value={option}>{option}</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
<div className="min-w-0 md:col-span-2">
|
<div className="min-w-0 md:col-span-2">
|
||||||
<p className="text-xs text-muted-foreground">저장소</p>
|
<p className="text-xs text-muted-foreground">저장소</p>
|
||||||
<div className="mt-2 rounded-md border border-border bg-background px-3 py-2">
|
<div className="mt-2 rounded-md border border-border bg-background px-3 py-2">
|
||||||
@@ -479,24 +469,14 @@ export function SourceManagementPage() {
|
|||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div className="min-w-0 md:col-span-2">
|
||||||
<p className="text-xs text-muted-foreground">버전</p>
|
<p className="text-xs text-muted-foreground">SHA1</p>
|
||||||
<div className="mt-2 rounded-md border border-border bg-background px-3 py-2">
|
<div className="mt-2 rounded-md border border-border bg-background px-3 py-2">
|
||||||
<p className="truncate text-sm font-medium">{latestRelease?.version ?? '-'}</p>
|
<p className="truncate font-mono text-sm font-medium" title={latestBranchSha || '-'}>
|
||||||
|
{latestBranchSha || '-'}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
|
||||||
<p className="text-xs text-muted-foreground">조회 브랜치</p>
|
|
||||||
<select
|
|
||||||
className="mt-2 h-9 w-full rounded-md border border-input bg-background px-3 text-sm font-medium text-foreground outline-none focus:ring-2 focus:ring-ring"
|
|
||||||
value={branch}
|
|
||||||
onChange={(event) => setSelectedBranch(event.target.value)}
|
|
||||||
>
|
|
||||||
{branchOptions.map((option) => (
|
|
||||||
<option key={option} value={option}>{option}</option>
|
|
||||||
))}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
|
|||||||
@@ -378,7 +378,7 @@ export function LauncherSourcePage() {
|
|||||||
'launcher-backend': emptyForm()
|
'launcher-backend': emptyForm()
|
||||||
});
|
});
|
||||||
const [commits, setCommits] = useState<GiteaCommit[]>([]);
|
const [commits, setCommits] = useState<GiteaCommit[]>([]);
|
||||||
const [sourceBranch, setSourceBranch] = useState('release');
|
const [sourceBranch, setSourceBranch] = useState('develop');
|
||||||
const [commitRange, setCommitRange] = useState<CommitRange>('week');
|
const [commitRange, setCommitRange] = useState<CommitRange>('week');
|
||||||
const [commitPage, setCommitPage] = useState(1);
|
const [commitPage, setCommitPage] = useState(1);
|
||||||
const [hasNextCommitPage, setHasNextCommitPage] = useState(false);
|
const [hasNextCommitPage, setHasNextCommitPage] = useState(false);
|
||||||
@@ -392,7 +392,7 @@ export function LauncherSourcePage() {
|
|||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
const [saving, setSaving] = useState(false);
|
const [saving, setSaving] = useState(false);
|
||||||
const loadingVisible = useMinimumLoading(loading);
|
const loadingVisible = useMinimumLoading(loading);
|
||||||
const branchOptions = ['release', 'develop', 'main'];
|
const branchOptions = ['develop', 'release', 'main'];
|
||||||
|
|
||||||
const activeVersion = useMemo(() => versions.find((version) => version.isActive) ?? versions[0], [versions]);
|
const activeVersion = useMemo(() => versions.find((version) => version.isActive) ?? versions[0], [versions]);
|
||||||
const activeForm = forms[activeTarget];
|
const activeForm = forms[activeTarget];
|
||||||
|
|||||||
Reference in New Issue
Block a user