From 6c8465dd28797c628a96cdf0b1d2d9444eccb225 Mon Sep 17 00:00:00 2001 From: Minhyeok Date: Sun, 3 Aug 2025 20:09:50 +0900 Subject: [PATCH 01/76] =?UTF-8?q?workflow=20=EC=88=98=EB=8F=99=20=EC=8B=A4?= =?UTF-8?q?=ED=96=89=20=EA=B0=80=EB=8A=A5=ED=95=98=EB=8F=84=EB=A1=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/docker-image.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/docker-image.yaml b/.github/workflows/docker-image.yaml index ea6f341..c6adab1 100644 --- a/.github/workflows/docker-image.yaml +++ b/.github/workflows/docker-image.yaml @@ -4,6 +4,7 @@ on: push: branches: - main + workflow_dispatch: jobs: build-and-deploy: From 0af50acf35ae30d347cecdaf8b82a81da6181933 Mon Sep 17 00:00:00 2001 From: Junhyeok Date: Sun, 26 Oct 2025 15:01:13 +0900 Subject: [PATCH 02/76] =?UTF-8?q?feat:=20/vm/status=20=ED=98=B8=EC=B6=9C?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/VMManage.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/VMManage.tsx b/src/pages/VMManage.tsx index a5e9637..36b976a 100644 --- a/src/pages/VMManage.tsx +++ b/src/pages/VMManage.tsx @@ -54,8 +54,8 @@ const VMManage: React.FC = () => { useEffect(() => { try { const fetchData = async () => { - // const response = await axiosClient.get("/vm/status"); - // console.log(response); + const { data } = await axiosClient.get("/vm/status"); + console.log(data); const vmList: VM[] = [ { From 7fac17f63c16061583f5533724dd86616eb9db81 Mon Sep 17 00:00:00 2001 From: Junhyeok Date: Sun, 26 Oct 2025 15:36:37 +0900 Subject: [PATCH 03/76] =?UTF-8?q?test:=20console.log=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/VMCreate.tsx | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/pages/VMCreate.tsx b/src/pages/VMCreate.tsx index 5809e39..3162d4a 100644 --- a/src/pages/VMCreate.tsx +++ b/src/pages/VMCreate.tsx @@ -22,6 +22,14 @@ interface RequiredInput { showError: boolean; } +interface InstanceTypes { + id: number; + typename: string; + vcpu: number; + ram: number; + dsk: number; +} + const VMCreateContent: React.FC = () => { const [vmName, setVmName] = useState({ value: "", @@ -54,9 +62,7 @@ const VMCreateContent: React.FC = () => { const navigate = useNavigate(); // Backend에서 제공하는 인스턴스 타입/OS 목록 (id 매핑용) - const [instanceTypes, setInstanceTypes] = useState< - { id: number; typename: string; vcpu: number; ram: number; dsk: number }[] - >([]); + const [instanceTypes, setInstanceTypes] = useState([]); const [osOptions, setOsOptions] = useState<{ id: number; name: string }[]>( [] ); @@ -66,7 +72,9 @@ const VMCreateContent: React.FC = () => { try { const { data } = await axiosClient.get("/vm/"); setInstanceTypes(data.instance_types || []); + console.log(data.instance_types); setOsOptions(data.os || []); + console.log(data.os); } catch (error) { console.error("Failed to fetch VM requirements", error); } From 6b5ab5e8df714b91a92fc242e46e6a4cb8d6e0e2 Mon Sep 17 00:00:00 2001 From: Junhyeok Date: Sun, 26 Oct 2025 16:21:08 +0900 Subject: [PATCH 04/76] =?UTF-8?q?feat:=20VMCreate=20fetch=20data=20?= =?UTF-8?q?=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/VMCreate.tsx | 60 ++++++++++++++++++------------------------ src/types/vm.ts | 1 + 2 files changed, 26 insertions(+), 35 deletions(-) diff --git a/src/pages/VMCreate.tsx b/src/pages/VMCreate.tsx index 3162d4a..8286f8e 100644 --- a/src/pages/VMCreate.tsx +++ b/src/pages/VMCreate.tsx @@ -35,30 +35,15 @@ const VMCreateContent: React.FC = () => { value: "", showError: false, }); - const osList: OsList[] = [ - { - name: "Ubuntu", - img: ubuntu, - version: [ - { "24.04 LTS": "ubuntu-cloud-24.04.img" }, - { "22.04 LTS": "ubuntu-cloud-22.04.img" }, - // "20.04 LTS", - // "24.10", - // "23.10", - // "23.04", - ], - hardware: ["Light (Server)" /*, "Heavy (Storage)", "GPU (AI/ML)"*/], - }, - // { - // name: "CentOS", - // img: ubuntu, - // version: ["8 Stream", "7 Stream"], - // hardware: ["Light (Server)", "Heavy (Storage)"], - // }, - ]; - - const { os, osVersion, hw, setHw, openSharedUser, setOpenSharedUser } = - useContext(VMCreateContext)!; + const { + os, + osVersion, + osVersionImgName, + hw, + setHw, + openSharedUser, + setOpenSharedUser, + } = useContext(VMCreateContext)!; const navigate = useNavigate(); // Backend에서 제공하는 인스턴스 타입/OS 목록 (id 매핑용) @@ -67,14 +52,20 @@ const VMCreateContent: React.FC = () => { [] ); + const computedOsList: OsList[] = osOptions.map((o) => ({ + id: o.id, + name: o.name, + img: ubuntu, + version: [{ [o.name]: o.name }], + hardware: instanceTypes.map((t) => t.typename), + })); + useEffect(() => { const fetchVmRequirements = async () => { try { const { data } = await axiosClient.get("/vm/"); setInstanceTypes(data.instance_types || []); - console.log(data.instance_types); setOsOptions(data.os || []); - console.log(data.os); } catch (error) { console.error("Failed to fetch VM requirements", error); } @@ -84,13 +75,14 @@ const VMCreateContent: React.FC = () => { const onCreateVM = async () => { try { - // 선택된 OS 이름(`os`)과 매칭되는 id를 찾고, 없으면 첫 번째 항목 사용 + // 선택된 OS 이미지 파일명(`osVersionImgName`)과 매칭되는 id를 찾고, 없으면 첫 번째 항목 사용 const selectedOsId = - osOptions.find((o) => o.name === os)?.id ?? osOptions[0]?.id; + osOptions.find((o) => o.name === osVersionImgName)?.id ?? + osOptions[0]?.id; - // 인스턴스 타입 id: 현재 UI와 타입 매핑이 없으므로 일단 첫 번째 항목 사용 - // 추후 UI에서 실제 타입 선택과 매핑 필요 - const selectedTypeId = instanceTypes[0]?.id; + const selectedTypeId = + instanceTypes.find((t) => t.typename === hw)?.id ?? + instanceTypes[0]?.id; if (!selectedOsId || !selectedTypeId) { alert( @@ -152,16 +144,14 @@ const VMCreateContent: React.FC = () => {

OS 선택

- {osList.map((item) => ( + {computedOsList.map((item) => ( ))}

하드웨어 선택

item.name === os)?.hardware || [] - } + hardwareList={instanceTypes.map((t) => t.typename)} hw={hw} setHw={setHw} disabled={!osVersion} diff --git a/src/types/vm.ts b/src/types/vm.ts index a2e0074..fc8b4e6 100644 --- a/src/types/vm.ts +++ b/src/types/vm.ts @@ -17,6 +17,7 @@ export interface VM { } export interface OsList { + id?: number; name: string; img?: string; version: { [key: string]: string }[]; From a44efc2db8c7a1cd6648de2cf8cabd37d67413f9 Mon Sep 17 00:00:00 2001 From: Junhyeok Date: Sun, 26 Oct 2025 16:41:13 +0900 Subject: [PATCH 05/76] =?UTF-8?q?feat:=20OS=20=EC=9D=B4=EB=A6=84=EA=B3=BC?= =?UTF-8?q?=20=EB=B2=84=EC=A0=84=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/VMCreate.tsx | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/src/pages/VMCreate.tsx b/src/pages/VMCreate.tsx index 8286f8e..bcd4c43 100644 --- a/src/pages/VMCreate.tsx +++ b/src/pages/VMCreate.tsx @@ -52,13 +52,23 @@ const VMCreateContent: React.FC = () => { [] ); - const computedOsList: OsList[] = osOptions.map((o) => ({ - id: o.id, - name: o.name, - img: ubuntu, - version: [{ [o.name]: o.name }], - hardware: instanceTypes.map((t) => t.typename), - })); + const computedOsList: OsList[] = osOptions.map((o) => { + const [base, rest] = o.name.split("-", 2); + const nameLabel = base || o.name; + let versionLabel = ""; + if (rest) { + const lastDot = rest.lastIndexOf("."); + versionLabel = lastDot > -1 ? rest.slice(0, lastDot) : rest; + } + return { + id: o.id, + name: nameLabel, + img: ubuntu, + // label: parsed version text (e.g., 12.7.0), value: original filename (e.g., debian-12.7.0.qcow2) + version: [{ [versionLabel || o.name]: o.name }], + hardware: instanceTypes.map((t) => t.typename), + }; + }); useEffect(() => { const fetchVmRequirements = async () => { @@ -145,7 +155,7 @@ const VMCreateContent: React.FC = () => {

OS 선택

{computedOsList.map((item) => ( - + ))}
From 3302a01a33dbfcf3341fbcc68855e0f9322305b6 Mon Sep 17 00:00:00 2001 From: Junhyeok Date: Sun, 26 Oct 2025 16:52:46 +0900 Subject: [PATCH 06/76] =?UTF-8?q?feat:=20OS=20=EC=9D=B4=EB=A6=84=20?= =?UTF-8?q?=EB=B0=8F=20version=20parsing=20=EC=95=8C=EA=B3=A0=EB=A6=AC?= =?UTF-8?q?=EC=A6=98=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/VMCreate.tsx | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/pages/VMCreate.tsx b/src/pages/VMCreate.tsx index bcd4c43..796175f 100644 --- a/src/pages/VMCreate.tsx +++ b/src/pages/VMCreate.tsx @@ -52,20 +52,19 @@ const VMCreateContent: React.FC = () => { [] ); + // ubuntu-cloud-24.04.img -> nameLabel: ubuntu, versionLabel: 24.04 const computedOsList: OsList[] = osOptions.map((o) => { - const [base, rest] = o.name.split("-", 2); - const nameLabel = base || o.name; - let versionLabel = ""; - if (rest) { - const lastDot = rest.lastIndexOf("."); - versionLabel = lastDot > -1 ? rest.slice(0, lastDot) : rest; - } + const dotIdx = o.name.lastIndexOf("."); + const noExt = dotIdx > -1 ? o.name.slice(0, dotIdx) : o.name; + const parts = noExt.split("-"); + const nameLabel = parts[0] || noExt; + const versionLabel = parts.length > 1 ? parts[parts.length - 1] : ""; return { id: o.id, name: nameLabel, img: ubuntu, - // label: parsed version text (e.g., 12.7.0), value: original filename (e.g., debian-12.7.0.qcow2) - version: [{ [versionLabel || o.name]: o.name }], + // label: last segment (version), value: original filename + version: [{ [versionLabel || noExt]: o.name }], hardware: instanceTypes.map((t) => t.typename), }; }); @@ -155,7 +154,10 @@ const VMCreateContent: React.FC = () => {

OS 선택

{computedOsList.map((item) => ( - + ))}
From 87c3181936162eb7ec3b379fe0271fbcb720a79b Mon Sep 17 00:00:00 2001 From: Junhyeok Date: Sun, 26 Oct 2025 17:11:35 +0900 Subject: [PATCH 07/76] =?UTF-8?q?feat:=20VMInfo=20API=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/vmCreate/VMInfoToBeCreatedItem.tsx | 2 +- src/pages/VMCreate.tsx | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/components/vmCreate/VMInfoToBeCreatedItem.tsx b/src/components/vmCreate/VMInfoToBeCreatedItem.tsx index 340c04f..78aa220 100644 --- a/src/components/vmCreate/VMInfoToBeCreatedItem.tsx +++ b/src/components/vmCreate/VMInfoToBeCreatedItem.tsx @@ -1,6 +1,6 @@ interface VMInfoToBeCreatedItemProps { title: string; - content: string; + content: number | string; className?: string; } diff --git a/src/pages/VMCreate.tsx b/src/pages/VMCreate.tsx index 796175f..a6d24bb 100644 --- a/src/pages/VMCreate.tsx +++ b/src/pages/VMCreate.tsx @@ -223,18 +223,18 @@ const VMCreateContent: React.FC = () => {
t.typename === hw)?.vcpu || "(비어 있음)"} /> t.typename === hw)?.ram || "(비어 있음)"} /> t.typename === hw)?.dsk || "(비어 있음)"} />
From 5ed9be274b46e291797bf61092807d43ac406afd Mon Sep 17 00:00:00 2001 From: Junhyeok Date: Sun, 26 Oct 2025 20:51:06 +0900 Subject: [PATCH 08/76] =?UTF-8?q?feat:=20=EA=B8=B0=EB=B3=B8=20route=20Land?= =?UTF-8?q?ing=EC=9C=BC=EB=A1=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- index.html | 12 ++++++++---- src/App.tsx | 30 ++++++++++++++++-------------- src/layouts/DefaultLayout.tsx | 13 +++++++++++-- src/pages/Landing.tsx | 10 +++++++++- 4 files changed, 44 insertions(+), 21 deletions(-) diff --git a/index.html b/index.html index e4b78ea..cbaf1d7 100644 --- a/index.html +++ b/index.html @@ -1,10 +1,14 @@ - - + + - + - Vite + React + TS + 도들
diff --git a/src/App.tsx b/src/App.tsx index 2b027f9..ef43199 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -26,21 +26,23 @@ function App() { - }> - } /> - } /> + + }> + } /> + } /> + + }> + } /> + } /> + + } /> + } /> + } /> + } /> + } /> - } /> - } /> - } /> - } /> - } /> - } /> - - } /> - - }> - } /> + } /> + diff --git a/src/layouts/DefaultLayout.tsx b/src/layouts/DefaultLayout.tsx index 8d1e517..bdac528 100644 --- a/src/layouts/DefaultLayout.tsx +++ b/src/layouts/DefaultLayout.tsx @@ -1,10 +1,19 @@ -import { Outlet } from "react-router-dom"; +import { useContext } from "react"; +import { Outlet, Navigate, useLocation } from "react-router-dom"; -import NavBar from "../components/NavBar"; +import NavBar from "@/components/NavBar"; +import AuthContext from "@/contexts/AuthContext.tsx"; import "./DefaultLayout.css"; const DefaultLayout: React.FC = () => { + const auth = useContext(AuthContext); + const location = useLocation(); + + if (!auth?.isAuthenticated) { + return ; + } + return ( <> diff --git a/src/pages/Landing.tsx b/src/pages/Landing.tsx index b1377b1..5304442 100644 --- a/src/pages/Landing.tsx +++ b/src/pages/Landing.tsx @@ -1,3 +1,5 @@ +import { useNavigate } from "react-router-dom"; + import connectorLine from "@/assets/image/landing/connector_line.svg"; import horizontalArrow from "@/assets/image/landing/horizontal_arrow.svg"; import ic_baseline_copyright from "@/assets/image/landing/ic_baseline_copyright.svg"; @@ -5,6 +7,7 @@ import rectangle from "@/assets/image/landing/rectangle.svg"; import LandingInputField from "@/components/LandingInputField"; const Landing = () => { + const navigate = useNavigate(); return (
@@ -21,7 +24,12 @@ const Landing = () => {
도들에서 당신의 가상 머신을 만들어 보세요.

-
From f4b0e455f01dc5d019e60fe3fe16b9a602324dbb Mon Sep 17 00:00:00 2001 From: Junhyeok Date: Tue, 28 Oct 2025 18:01:25 +0900 Subject: [PATCH 09/76] =?UTF-8?q?feat:=20Landing=20routing=20=EB=B0=98?= =?UTF-8?q?=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/NavBar.tsx | 2 +- src/pages/Invitation.tsx | 2 +- src/pages/VMCreate.tsx | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/NavBar.tsx b/src/components/NavBar.tsx index 3191619..c517288 100644 --- a/src/components/NavBar.tsx +++ b/src/components/NavBar.tsx @@ -28,7 +28,7 @@ const NavBar = () => { return (