refine deployment and runtime config behavior
ci/woodpecker/push/woodpecker Pipeline was successful

This commit is contained in:
2026-07-06 17:49:55 +09:00
parent db33ca9d6a
commit 762cd77539
2 changed files with 30 additions and 10 deletions
@@ -74,6 +74,16 @@ export function DeploymentManagementPage() {
() => releases.filter((release) => !selectedAppId || release.appId === selectedAppId),
[releases, selectedAppId]
);
const deployedReleaseIds = useMemo(
() => new Set(deployments
.filter((deployment) => deployment.status === 'SUCCEEDED' && deployment.releaseId)
.map((deployment) => deployment.releaseId!)),
[deployments]
);
const deployableReleases = useMemo(
() => filteredReleases.filter((release) => !deployedReleaseIds.has(release.id)),
[filteredReleases, deployedReleaseIds]
);
const filteredDeployments = useMemo(
() => deployments
.filter((deployment) => !selectedAppId || deployment.appId === selectedAppId)
@@ -110,11 +120,11 @@ export function DeploymentManagementPage() {
}, [selectedRelease?.id]);
useEffect(() => {
setReleaseId((prev) => filteredReleases.some((release) => release.id === prev) ? prev : filteredReleases[0]?.id || '');
setNamespace(filteredReleases[0]?.app?.namespace || '');
}, [filteredReleases]);
setReleaseId((prev) => deployableReleases.some((release) => release.id === prev) ? prev : deployableReleases[0]?.id || '');
setNamespace(deployableReleases[0]?.app?.namespace || '');
}, [deployableReleases]);
const deployableCards = useMemo(() => filteredReleases.slice(0, 8), [filteredReleases]);
const deployableCards = useMemo(() => deployableReleases.slice(0, 8), [deployableReleases]);
const openDeployModal = (release?: AppRelease) => {
if (release) {
@@ -145,7 +155,7 @@ export function DeploymentManagementPage() {
title="배포 관리"
description="생성된 릴리즈를 운영 환경에 배포하고 재배포와 롤백을 관리합니다."
actions={
<Button className="h-8 px-3 text-[13px]" disabled={filteredReleases.length === 0} onClick={() => openDeployModal()}>
<Button className="h-8 px-3 text-[13px]" disabled={deployableReleases.length === 0} onClick={() => openDeployModal()}>
<Plus className="size-4" />
배포 실행
</Button>
@@ -236,7 +246,7 @@ export function DeploymentManagementPage() {
</Card>
<Card className="min-w-0 overflow-hidden">
<CardHeader title="배포 가능 릴리즈" description="성공 상태의 릴리즈만 배포 대상으로 사용할 수 있습니다." />
<CardHeader title="배포 가능 릴리즈" description="아직 성공 배포되지 않은 릴리즈만 표시합니다." />
<div className="space-y-3 p-4">
{deployableCards.length === 0 ? (
<div className="rounded-md border border-border px-3 py-4 text-center text-sm text-muted-foreground">
@@ -269,7 +279,7 @@ export function DeploymentManagementPage() {
setNamespace(release?.app.namespace || '');
}}>
<option value="">릴리즈 선택</option>
{filteredReleases.map((release) => <option key={release.id} value={release.id}>{release.app.name} {release.version}</option>)}
{deployableReleases.map((release) => <option key={release.id} value={release.id}>{release.app.name} {release.version}</option>)}
</select>
<input className="h-9 w-full rounded-md border border-input bg-background px-3 text-sm outline-none" value={namespace} onChange={(event) => setNamespace(event.target.value)} placeholder="stdo-lms" />
<label className="flex items-center gap-2 rounded-md border border-border bg-muted/20 px-3 py-2 text-sm text-foreground">