From 42cb5904c91e0d4f7f97699309c62c4143d935b7 Mon Sep 17 00:00:00 2001
From: chyoo
Date: Mon, 6 Jul 2026 10:39:22 +0900
Subject: [PATCH] manage launcher client build env
---
src/pages/launcher/LauncherBuildPage.tsx | 83 ++++++++++++++++++++++--
src/pages/launcher/launcher-api.ts | 17 +++++
2 files changed, 96 insertions(+), 4 deletions(-)
diff --git a/src/pages/launcher/LauncherBuildPage.tsx b/src/pages/launcher/LauncherBuildPage.tsx
index dc4d18f..d626546 100644
--- a/src/pages/launcher/LauncherBuildPage.tsx
+++ b/src/pages/launcher/LauncherBuildPage.tsx
@@ -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([]);
+ const [buildEnv, setBuildEnv] = useState([]);
+ const [buildEnvSaving, setBuildEnvSaving] = useState(false);
const [selectedJob, setSelectedJob] = useState(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) => {
+ 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 (
<>
Repository
{backendSource?.repository || '-'}
- ) : null}
+ ) : (
+
+
+
+
클라이언트 빌드 환경변수
+
Vite 빌드 시점에 주입되는 값입니다. 저장 후 실행한 빌드부터 반영됩니다.
+
+
+
+
+
+
+ )}
diff --git a/src/pages/launcher/launcher-api.ts b/src/pages/launcher/launcher-api.ts
index 8c39b87..43694d1 100644
--- a/src/pages/launcher/launcher-api.ts
+++ b/src/pages/launcher/launcher-api.ts
@@ -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('/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;