This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { ChevronLeft, ChevronRight, MoreHorizontal, Play, RotateCcw } from 'lucide-react';
|
||||
import { ChevronLeft, ChevronRight, MoreHorizontal, Play, Plus, RotateCcw, Trash2 } from 'lucide-react';
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import { Badge, Button, Card, CardHeader, Modal } from '../../components/ui';
|
||||
import { useToast } from '../../components/toast';
|
||||
@@ -8,10 +8,13 @@ import { LoadingModal, useMinimumLoading } from '../operations/operation-utils';
|
||||
import {
|
||||
createLauncherBuildJob,
|
||||
getLauncherSource,
|
||||
listLauncherBuildEnv,
|
||||
listLauncherBuildJobs,
|
||||
listLauncherVersions,
|
||||
saveLauncherBuildEnv,
|
||||
type LauncherSource,
|
||||
type LauncherBuildJob,
|
||||
type LauncherBuildEnvVariable,
|
||||
type LauncherVersion
|
||||
} from './launcher-api';
|
||||
|
||||
@@ -80,6 +83,8 @@ export function LauncherBuildPage() {
|
||||
const [branch, setBranch] = useState('release');
|
||||
const [commitSha, setCommitSha] = useState('');
|
||||
const [jobs, setJobs] = useState<LauncherBuildJob[]>([]);
|
||||
const [buildEnv, setBuildEnv] = useState<LauncherBuildEnvVariable[]>([]);
|
||||
const [buildEnvSaving, setBuildEnvSaving] = useState(false);
|
||||
const [selectedJob, setSelectedJob] = useState<LauncherBuildJob | null>(null);
|
||||
const [confirmOpen, setConfirmOpen] = useState(false);
|
||||
const [loading, setLoading] = useState(true);
|
||||
@@ -104,11 +109,12 @@ export function LauncherBuildPage() {
|
||||
|
||||
const refresh = () => {
|
||||
setLoading(true);
|
||||
Promise.all([listLauncherVersions(), listLauncherBuildJobs(), getLauncherSource()])
|
||||
.then(([nextVersions, nextJobs, nextSource]) => {
|
||||
Promise.all([listLauncherVersions(), listLauncherBuildJobs(), getLauncherSource(), listLauncherBuildEnv()])
|
||||
.then(([nextVersions, nextJobs, nextSource, nextBuildEnv]) => {
|
||||
setVersions(nextVersions);
|
||||
setJobs(nextJobs);
|
||||
setSource(nextSource.source);
|
||||
setBuildEnv(nextBuildEnv.variables ?? []);
|
||||
const nextVersion = nextVersions.find((item) => item.isActive) ?? nextVersions[0];
|
||||
setVersion(nextVersion?.version ?? '');
|
||||
setBranch(target === 'launcher-backend' ? nextSource.source.backend?.branch ?? 'release' : nextSource.source.client?.branch ?? nextVersion?.branch ?? 'release');
|
||||
@@ -181,6 +187,33 @@ export function LauncherBuildPage() {
|
||||
.finally(() => setLoading(false));
|
||||
};
|
||||
|
||||
const updateBuildEnv = (index: number, patch: Partial<LauncherBuildEnvVariable>) => {
|
||||
setBuildEnv((prev) => prev.map((variable, variableIndex) => (
|
||||
variableIndex === index ? { ...variable, ...patch } : variable
|
||||
)));
|
||||
};
|
||||
|
||||
const removeBuildEnv = (index: number) => {
|
||||
setBuildEnv((prev) => prev.filter((_, variableIndex) => variableIndex !== index));
|
||||
};
|
||||
|
||||
const persistBuildEnv = () => {
|
||||
setBuildEnvSaving(true);
|
||||
saveLauncherBuildEnv(
|
||||
buildEnv
|
||||
.map((variable) => ({ ...variable, key: variable.key.trim() }))
|
||||
.filter((variable) => variable.key)
|
||||
)
|
||||
.then((result) => {
|
||||
setBuildEnv(result.variables ?? []);
|
||||
toast({ type: 'success', title: '빌드 환경변수 저장', message: '런처 클라이언트 빌드 환경변수를 저장했습니다.' });
|
||||
})
|
||||
.catch((error: Error) => {
|
||||
toast({ type: 'error', title: '빌드 환경변수 저장 실패', message: error.message });
|
||||
})
|
||||
.finally(() => setBuildEnvSaving(false));
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<PageTitle
|
||||
@@ -232,7 +265,49 @@ export function LauncherBuildPage() {
|
||||
<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 className="rounded-md border border-border bg-background p-3">
|
||||
<div className="flex items-start justify-between gap-3">
|
||||
<div>
|
||||
<p className="text-xs font-medium text-muted-foreground">클라이언트 빌드 환경변수</p>
|
||||
<p className="mt-1 text-xs leading-5 text-muted-foreground">Vite 빌드 시점에 주입되는 값입니다. 저장 후 실행한 빌드부터 반영됩니다.</p>
|
||||
</div>
|
||||
<Button variant="outline" className="h-8 px-3 text-[13px]" onClick={persistBuildEnv} disabled={buildEnvSaving}>
|
||||
{buildEnvSaving ? '저장 중' : '저장'}
|
||||
</Button>
|
||||
</div>
|
||||
<div className="mt-3 space-y-2">
|
||||
{buildEnv.map((variable, index) => (
|
||||
<div key={`${variable.key}-${index}`} className="grid gap-2 md:grid-cols-[minmax(0,0.9fr)_minmax(0,1.1fr)_auto]">
|
||||
<input
|
||||
className="h-9 rounded-md border border-input bg-background px-3 font-mono text-xs outline-none focus:ring-2 focus:ring-ring"
|
||||
value={variable.key}
|
||||
onChange={(event) => updateBuildEnv(index, { key: event.target.value })}
|
||||
placeholder="VITE_ATNMY_STDO_API_BASE_URL"
|
||||
/>
|
||||
<input
|
||||
className="h-9 rounded-md border border-input bg-background px-3 font-mono text-xs outline-none focus:ring-2 focus:ring-ring"
|
||||
value={variable.value}
|
||||
onChange={(event) => updateBuildEnv(index, { value: event.target.value })}
|
||||
placeholder="https://portal-api.autonomystudio.net"
|
||||
/>
|
||||
<Button variant="outline" className="size-9 px-0" title="삭제" aria-label="삭제" onClick={() => removeBuildEnv(index)}>
|
||||
<Trash2 className="size-4" />
|
||||
</Button>
|
||||
</div>
|
||||
))}
|
||||
{buildEnv.length === 0 ? <p className="rounded-md border border-dashed border-border px-3 py-4 text-center text-xs text-muted-foreground">등록된 빌드 환경변수가 없습니다.</p> : null}
|
||||
</div>
|
||||
<Button
|
||||
variant="outline"
|
||||
className="mt-3 h-8 px-3 text-[13px]"
|
||||
onClick={() => setBuildEnv((prev) => [...prev, { key: '', value: '', isSecret: false }])}
|
||||
>
|
||||
<Plus className="size-4" />
|
||||
추가
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
|
||||
@@ -36,6 +36,12 @@ export type LauncherBuildJob = {
|
||||
updatedAt?: string;
|
||||
};
|
||||
|
||||
export type LauncherBuildEnvVariable = {
|
||||
key: string;
|
||||
value: string;
|
||||
isSecret: boolean;
|
||||
};
|
||||
|
||||
export type LauncherSource = {
|
||||
repository?: string | null;
|
||||
branch?: string | null;
|
||||
@@ -193,6 +199,17 @@ export function listLauncherBuildJobs() {
|
||||
return apiRequest<LauncherBuildJob[]>('/launcher/builds');
|
||||
}
|
||||
|
||||
export function listLauncherBuildEnv() {
|
||||
return apiRequest<{ variables: LauncherBuildEnvVariable[] }>('/launcher/build-env');
|
||||
}
|
||||
|
||||
export function saveLauncherBuildEnv(variables: LauncherBuildEnvVariable[]) {
|
||||
return apiRequest<{ variables: LauncherBuildEnvVariable[] }>('/launcher/build-env', {
|
||||
method: 'PUT',
|
||||
body: JSON.stringify({ variables })
|
||||
});
|
||||
}
|
||||
|
||||
export function createLauncherBuildJob(input: {
|
||||
target?: string;
|
||||
repository?: string;
|
||||
|
||||
Reference in New Issue
Block a user